162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Routines that mimic syscalls, but don't use the user address space or file 462306a36Sopenharmony_ci * descriptors. Only for init/ and related early init code. 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci#include <linux/init.h> 762306a36Sopenharmony_ci#include <linux/mount.h> 862306a36Sopenharmony_ci#include <linux/namei.h> 962306a36Sopenharmony_ci#include <linux/fs.h> 1062306a36Sopenharmony_ci#include <linux/fs_struct.h> 1162306a36Sopenharmony_ci#include <linux/file.h> 1262306a36Sopenharmony_ci#include <linux/init_syscalls.h> 1362306a36Sopenharmony_ci#include <linux/security.h> 1462306a36Sopenharmony_ci#include "internal.h" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ciint __init init_mount(const char *dev_name, const char *dir_name, 1762306a36Sopenharmony_ci const char *type_page, unsigned long flags, void *data_page) 1862306a36Sopenharmony_ci{ 1962306a36Sopenharmony_ci struct path path; 2062306a36Sopenharmony_ci int ret; 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci ret = kern_path(dir_name, LOOKUP_FOLLOW, &path); 2362306a36Sopenharmony_ci if (ret) 2462306a36Sopenharmony_ci return ret; 2562306a36Sopenharmony_ci ret = path_mount(dev_name, &path, type_page, flags, data_page); 2662306a36Sopenharmony_ci path_put(&path); 2762306a36Sopenharmony_ci return ret; 2862306a36Sopenharmony_ci} 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ciint __init init_umount(const char *name, int flags) 3162306a36Sopenharmony_ci{ 3262306a36Sopenharmony_ci int lookup_flags = LOOKUP_MOUNTPOINT; 3362306a36Sopenharmony_ci struct path path; 3462306a36Sopenharmony_ci int ret; 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci if (!(flags & UMOUNT_NOFOLLOW)) 3762306a36Sopenharmony_ci lookup_flags |= LOOKUP_FOLLOW; 3862306a36Sopenharmony_ci ret = kern_path(name, lookup_flags, &path); 3962306a36Sopenharmony_ci if (ret) 4062306a36Sopenharmony_ci return ret; 4162306a36Sopenharmony_ci return path_umount(&path, flags); 4262306a36Sopenharmony_ci} 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ciint __init init_chdir(const char *filename) 4562306a36Sopenharmony_ci{ 4662306a36Sopenharmony_ci struct path path; 4762306a36Sopenharmony_ci int error; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci error = kern_path(filename, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &path); 5062306a36Sopenharmony_ci if (error) 5162306a36Sopenharmony_ci return error; 5262306a36Sopenharmony_ci error = path_permission(&path, MAY_EXEC | MAY_CHDIR); 5362306a36Sopenharmony_ci if (!error) 5462306a36Sopenharmony_ci set_fs_pwd(current->fs, &path); 5562306a36Sopenharmony_ci path_put(&path); 5662306a36Sopenharmony_ci return error; 5762306a36Sopenharmony_ci} 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ciint __init init_chroot(const char *filename) 6062306a36Sopenharmony_ci{ 6162306a36Sopenharmony_ci struct path path; 6262306a36Sopenharmony_ci int error; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci error = kern_path(filename, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &path); 6562306a36Sopenharmony_ci if (error) 6662306a36Sopenharmony_ci return error; 6762306a36Sopenharmony_ci error = path_permission(&path, MAY_EXEC | MAY_CHDIR); 6862306a36Sopenharmony_ci if (error) 6962306a36Sopenharmony_ci goto dput_and_out; 7062306a36Sopenharmony_ci error = -EPERM; 7162306a36Sopenharmony_ci if (!ns_capable(current_user_ns(), CAP_SYS_CHROOT)) 7262306a36Sopenharmony_ci goto dput_and_out; 7362306a36Sopenharmony_ci error = security_path_chroot(&path); 7462306a36Sopenharmony_ci if (error) 7562306a36Sopenharmony_ci goto dput_and_out; 7662306a36Sopenharmony_ci set_fs_root(current->fs, &path); 7762306a36Sopenharmony_cidput_and_out: 7862306a36Sopenharmony_ci path_put(&path); 7962306a36Sopenharmony_ci return error; 8062306a36Sopenharmony_ci} 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ciint __init init_chown(const char *filename, uid_t user, gid_t group, int flags) 8362306a36Sopenharmony_ci{ 8462306a36Sopenharmony_ci int lookup_flags = (flags & AT_SYMLINK_NOFOLLOW) ? 0 : LOOKUP_FOLLOW; 8562306a36Sopenharmony_ci struct path path; 8662306a36Sopenharmony_ci int error; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci error = kern_path(filename, lookup_flags, &path); 8962306a36Sopenharmony_ci if (error) 9062306a36Sopenharmony_ci return error; 9162306a36Sopenharmony_ci error = mnt_want_write(path.mnt); 9262306a36Sopenharmony_ci if (!error) { 9362306a36Sopenharmony_ci error = chown_common(&path, user, group); 9462306a36Sopenharmony_ci mnt_drop_write(path.mnt); 9562306a36Sopenharmony_ci } 9662306a36Sopenharmony_ci path_put(&path); 9762306a36Sopenharmony_ci return error; 9862306a36Sopenharmony_ci} 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ciint __init init_chmod(const char *filename, umode_t mode) 10162306a36Sopenharmony_ci{ 10262306a36Sopenharmony_ci struct path path; 10362306a36Sopenharmony_ci int error; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci error = kern_path(filename, LOOKUP_FOLLOW, &path); 10662306a36Sopenharmony_ci if (error) 10762306a36Sopenharmony_ci return error; 10862306a36Sopenharmony_ci error = chmod_common(&path, mode); 10962306a36Sopenharmony_ci path_put(&path); 11062306a36Sopenharmony_ci return error; 11162306a36Sopenharmony_ci} 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ciint __init init_eaccess(const char *filename) 11462306a36Sopenharmony_ci{ 11562306a36Sopenharmony_ci struct path path; 11662306a36Sopenharmony_ci int error; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci error = kern_path(filename, LOOKUP_FOLLOW, &path); 11962306a36Sopenharmony_ci if (error) 12062306a36Sopenharmony_ci return error; 12162306a36Sopenharmony_ci error = path_permission(&path, MAY_ACCESS); 12262306a36Sopenharmony_ci path_put(&path); 12362306a36Sopenharmony_ci return error; 12462306a36Sopenharmony_ci} 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ciint __init init_stat(const char *filename, struct kstat *stat, int flags) 12762306a36Sopenharmony_ci{ 12862306a36Sopenharmony_ci int lookup_flags = (flags & AT_SYMLINK_NOFOLLOW) ? 0 : LOOKUP_FOLLOW; 12962306a36Sopenharmony_ci struct path path; 13062306a36Sopenharmony_ci int error; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci error = kern_path(filename, lookup_flags, &path); 13362306a36Sopenharmony_ci if (error) 13462306a36Sopenharmony_ci return error; 13562306a36Sopenharmony_ci error = vfs_getattr(&path, stat, STATX_BASIC_STATS, 13662306a36Sopenharmony_ci flags | AT_NO_AUTOMOUNT); 13762306a36Sopenharmony_ci path_put(&path); 13862306a36Sopenharmony_ci return error; 13962306a36Sopenharmony_ci} 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ciint __init init_mknod(const char *filename, umode_t mode, unsigned int dev) 14262306a36Sopenharmony_ci{ 14362306a36Sopenharmony_ci struct dentry *dentry; 14462306a36Sopenharmony_ci struct path path; 14562306a36Sopenharmony_ci int error; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci if (S_ISFIFO(mode) || S_ISSOCK(mode)) 14862306a36Sopenharmony_ci dev = 0; 14962306a36Sopenharmony_ci else if (!(S_ISBLK(mode) || S_ISCHR(mode))) 15062306a36Sopenharmony_ci return -EINVAL; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci dentry = kern_path_create(AT_FDCWD, filename, &path, 0); 15362306a36Sopenharmony_ci if (IS_ERR(dentry)) 15462306a36Sopenharmony_ci return PTR_ERR(dentry); 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci if (!IS_POSIXACL(path.dentry->d_inode)) 15762306a36Sopenharmony_ci mode &= ~current_umask(); 15862306a36Sopenharmony_ci error = security_path_mknod(&path, dentry, mode, dev); 15962306a36Sopenharmony_ci if (!error) 16062306a36Sopenharmony_ci error = vfs_mknod(mnt_idmap(path.mnt), path.dentry->d_inode, 16162306a36Sopenharmony_ci dentry, mode, new_decode_dev(dev)); 16262306a36Sopenharmony_ci done_path_create(&path, dentry); 16362306a36Sopenharmony_ci return error; 16462306a36Sopenharmony_ci} 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ciint __init init_link(const char *oldname, const char *newname) 16762306a36Sopenharmony_ci{ 16862306a36Sopenharmony_ci struct dentry *new_dentry; 16962306a36Sopenharmony_ci struct path old_path, new_path; 17062306a36Sopenharmony_ci struct mnt_idmap *idmap; 17162306a36Sopenharmony_ci int error; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci error = kern_path(oldname, 0, &old_path); 17462306a36Sopenharmony_ci if (error) 17562306a36Sopenharmony_ci return error; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci new_dentry = kern_path_create(AT_FDCWD, newname, &new_path, 0); 17862306a36Sopenharmony_ci error = PTR_ERR(new_dentry); 17962306a36Sopenharmony_ci if (IS_ERR(new_dentry)) 18062306a36Sopenharmony_ci goto out; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci error = -EXDEV; 18362306a36Sopenharmony_ci if (old_path.mnt != new_path.mnt) 18462306a36Sopenharmony_ci goto out_dput; 18562306a36Sopenharmony_ci idmap = mnt_idmap(new_path.mnt); 18662306a36Sopenharmony_ci error = may_linkat(idmap, &old_path); 18762306a36Sopenharmony_ci if (unlikely(error)) 18862306a36Sopenharmony_ci goto out_dput; 18962306a36Sopenharmony_ci error = security_path_link(old_path.dentry, &new_path, new_dentry); 19062306a36Sopenharmony_ci if (error) 19162306a36Sopenharmony_ci goto out_dput; 19262306a36Sopenharmony_ci error = vfs_link(old_path.dentry, idmap, new_path.dentry->d_inode, 19362306a36Sopenharmony_ci new_dentry, NULL); 19462306a36Sopenharmony_ciout_dput: 19562306a36Sopenharmony_ci done_path_create(&new_path, new_dentry); 19662306a36Sopenharmony_ciout: 19762306a36Sopenharmony_ci path_put(&old_path); 19862306a36Sopenharmony_ci return error; 19962306a36Sopenharmony_ci} 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ciint __init init_symlink(const char *oldname, const char *newname) 20262306a36Sopenharmony_ci{ 20362306a36Sopenharmony_ci struct dentry *dentry; 20462306a36Sopenharmony_ci struct path path; 20562306a36Sopenharmony_ci int error; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci dentry = kern_path_create(AT_FDCWD, newname, &path, 0); 20862306a36Sopenharmony_ci if (IS_ERR(dentry)) 20962306a36Sopenharmony_ci return PTR_ERR(dentry); 21062306a36Sopenharmony_ci error = security_path_symlink(&path, dentry, oldname); 21162306a36Sopenharmony_ci if (!error) 21262306a36Sopenharmony_ci error = vfs_symlink(mnt_idmap(path.mnt), path.dentry->d_inode, 21362306a36Sopenharmony_ci dentry, oldname); 21462306a36Sopenharmony_ci done_path_create(&path, dentry); 21562306a36Sopenharmony_ci return error; 21662306a36Sopenharmony_ci} 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ciint __init init_unlink(const char *pathname) 21962306a36Sopenharmony_ci{ 22062306a36Sopenharmony_ci return do_unlinkat(AT_FDCWD, getname_kernel(pathname)); 22162306a36Sopenharmony_ci} 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ciint __init init_mkdir(const char *pathname, umode_t mode) 22462306a36Sopenharmony_ci{ 22562306a36Sopenharmony_ci struct dentry *dentry; 22662306a36Sopenharmony_ci struct path path; 22762306a36Sopenharmony_ci int error; 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci dentry = kern_path_create(AT_FDCWD, pathname, &path, LOOKUP_DIRECTORY); 23062306a36Sopenharmony_ci if (IS_ERR(dentry)) 23162306a36Sopenharmony_ci return PTR_ERR(dentry); 23262306a36Sopenharmony_ci if (!IS_POSIXACL(path.dentry->d_inode)) 23362306a36Sopenharmony_ci mode &= ~current_umask(); 23462306a36Sopenharmony_ci error = security_path_mkdir(&path, dentry, mode); 23562306a36Sopenharmony_ci if (!error) 23662306a36Sopenharmony_ci error = vfs_mkdir(mnt_idmap(path.mnt), path.dentry->d_inode, 23762306a36Sopenharmony_ci dentry, mode); 23862306a36Sopenharmony_ci done_path_create(&path, dentry); 23962306a36Sopenharmony_ci return error; 24062306a36Sopenharmony_ci} 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ciint __init init_rmdir(const char *pathname) 24362306a36Sopenharmony_ci{ 24462306a36Sopenharmony_ci return do_rmdir(AT_FDCWD, getname_kernel(pathname)); 24562306a36Sopenharmony_ci} 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ciint __init init_utimes(char *filename, struct timespec64 *ts) 24862306a36Sopenharmony_ci{ 24962306a36Sopenharmony_ci struct path path; 25062306a36Sopenharmony_ci int error; 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci error = kern_path(filename, 0, &path); 25362306a36Sopenharmony_ci if (error) 25462306a36Sopenharmony_ci return error; 25562306a36Sopenharmony_ci error = vfs_utimes(&path, ts); 25662306a36Sopenharmony_ci path_put(&path); 25762306a36Sopenharmony_ci return error; 25862306a36Sopenharmony_ci} 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ciint __init init_dup(struct file *file) 26162306a36Sopenharmony_ci{ 26262306a36Sopenharmony_ci int fd; 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci fd = get_unused_fd_flags(0); 26562306a36Sopenharmony_ci if (fd < 0) 26662306a36Sopenharmony_ci return fd; 26762306a36Sopenharmony_ci fd_install(fd, get_file(file)); 26862306a36Sopenharmony_ci return 0; 26962306a36Sopenharmony_ci} 270