18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Routines that mimic syscalls, but don't use the user address space or file 48c2ecf20Sopenharmony_ci * descriptors. Only for init/ and related early init code. 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci#include <linux/init.h> 78c2ecf20Sopenharmony_ci#include <linux/mount.h> 88c2ecf20Sopenharmony_ci#include <linux/namei.h> 98c2ecf20Sopenharmony_ci#include <linux/fs.h> 108c2ecf20Sopenharmony_ci#include <linux/fs_struct.h> 118c2ecf20Sopenharmony_ci#include <linux/file.h> 128c2ecf20Sopenharmony_ci#include <linux/init_syscalls.h> 138c2ecf20Sopenharmony_ci#include <linux/security.h> 148c2ecf20Sopenharmony_ci#include "internal.h" 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ciint __init init_mount(const char *dev_name, const char *dir_name, 178c2ecf20Sopenharmony_ci const char *type_page, unsigned long flags, void *data_page) 188c2ecf20Sopenharmony_ci{ 198c2ecf20Sopenharmony_ci struct path path; 208c2ecf20Sopenharmony_ci int ret; 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci ret = kern_path(dir_name, LOOKUP_FOLLOW, &path); 238c2ecf20Sopenharmony_ci if (ret) 248c2ecf20Sopenharmony_ci return ret; 258c2ecf20Sopenharmony_ci ret = path_mount(dev_name, &path, type_page, flags, data_page); 268c2ecf20Sopenharmony_ci path_put(&path); 278c2ecf20Sopenharmony_ci return ret; 288c2ecf20Sopenharmony_ci} 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ciint __init init_umount(const char *name, int flags) 318c2ecf20Sopenharmony_ci{ 328c2ecf20Sopenharmony_ci int lookup_flags = LOOKUP_MOUNTPOINT; 338c2ecf20Sopenharmony_ci struct path path; 348c2ecf20Sopenharmony_ci int ret; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci if (!(flags & UMOUNT_NOFOLLOW)) 378c2ecf20Sopenharmony_ci lookup_flags |= LOOKUP_FOLLOW; 388c2ecf20Sopenharmony_ci ret = kern_path(name, lookup_flags, &path); 398c2ecf20Sopenharmony_ci if (ret) 408c2ecf20Sopenharmony_ci return ret; 418c2ecf20Sopenharmony_ci return path_umount(&path, flags); 428c2ecf20Sopenharmony_ci} 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ciint __init init_chdir(const char *filename) 458c2ecf20Sopenharmony_ci{ 468c2ecf20Sopenharmony_ci struct path path; 478c2ecf20Sopenharmony_ci int error; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci error = kern_path(filename, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &path); 508c2ecf20Sopenharmony_ci if (error) 518c2ecf20Sopenharmony_ci return error; 528c2ecf20Sopenharmony_ci error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_CHDIR); 538c2ecf20Sopenharmony_ci if (!error) 548c2ecf20Sopenharmony_ci set_fs_pwd(current->fs, &path); 558c2ecf20Sopenharmony_ci path_put(&path); 568c2ecf20Sopenharmony_ci return error; 578c2ecf20Sopenharmony_ci} 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ciint __init init_chroot(const char *filename) 608c2ecf20Sopenharmony_ci{ 618c2ecf20Sopenharmony_ci struct path path; 628c2ecf20Sopenharmony_ci int error; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci error = kern_path(filename, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &path); 658c2ecf20Sopenharmony_ci if (error) 668c2ecf20Sopenharmony_ci return error; 678c2ecf20Sopenharmony_ci error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_CHDIR); 688c2ecf20Sopenharmony_ci if (error) 698c2ecf20Sopenharmony_ci goto dput_and_out; 708c2ecf20Sopenharmony_ci error = -EPERM; 718c2ecf20Sopenharmony_ci if (!ns_capable(current_user_ns(), CAP_SYS_CHROOT)) 728c2ecf20Sopenharmony_ci goto dput_and_out; 738c2ecf20Sopenharmony_ci error = security_path_chroot(&path); 748c2ecf20Sopenharmony_ci if (error) 758c2ecf20Sopenharmony_ci goto dput_and_out; 768c2ecf20Sopenharmony_ci set_fs_root(current->fs, &path); 778c2ecf20Sopenharmony_cidput_and_out: 788c2ecf20Sopenharmony_ci path_put(&path); 798c2ecf20Sopenharmony_ci return error; 808c2ecf20Sopenharmony_ci} 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ciint __init init_chown(const char *filename, uid_t user, gid_t group, int flags) 838c2ecf20Sopenharmony_ci{ 848c2ecf20Sopenharmony_ci int lookup_flags = (flags & AT_SYMLINK_NOFOLLOW) ? 0 : LOOKUP_FOLLOW; 858c2ecf20Sopenharmony_ci struct path path; 868c2ecf20Sopenharmony_ci int error; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci error = kern_path(filename, lookup_flags, &path); 898c2ecf20Sopenharmony_ci if (error) 908c2ecf20Sopenharmony_ci return error; 918c2ecf20Sopenharmony_ci error = mnt_want_write(path.mnt); 928c2ecf20Sopenharmony_ci if (!error) { 938c2ecf20Sopenharmony_ci error = chown_common(&path, user, group); 948c2ecf20Sopenharmony_ci mnt_drop_write(path.mnt); 958c2ecf20Sopenharmony_ci } 968c2ecf20Sopenharmony_ci path_put(&path); 978c2ecf20Sopenharmony_ci return error; 988c2ecf20Sopenharmony_ci} 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ciint __init init_chmod(const char *filename, umode_t mode) 1018c2ecf20Sopenharmony_ci{ 1028c2ecf20Sopenharmony_ci struct path path; 1038c2ecf20Sopenharmony_ci int error; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci error = kern_path(filename, LOOKUP_FOLLOW, &path); 1068c2ecf20Sopenharmony_ci if (error) 1078c2ecf20Sopenharmony_ci return error; 1088c2ecf20Sopenharmony_ci error = chmod_common(&path, mode); 1098c2ecf20Sopenharmony_ci path_put(&path); 1108c2ecf20Sopenharmony_ci return error; 1118c2ecf20Sopenharmony_ci} 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ciint __init init_eaccess(const char *filename) 1148c2ecf20Sopenharmony_ci{ 1158c2ecf20Sopenharmony_ci struct path path; 1168c2ecf20Sopenharmony_ci int error; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci error = kern_path(filename, LOOKUP_FOLLOW, &path); 1198c2ecf20Sopenharmony_ci if (error) 1208c2ecf20Sopenharmony_ci return error; 1218c2ecf20Sopenharmony_ci error = inode_permission(d_inode(path.dentry), MAY_ACCESS); 1228c2ecf20Sopenharmony_ci path_put(&path); 1238c2ecf20Sopenharmony_ci return error; 1248c2ecf20Sopenharmony_ci} 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ciint __init init_stat(const char *filename, struct kstat *stat, int flags) 1278c2ecf20Sopenharmony_ci{ 1288c2ecf20Sopenharmony_ci int lookup_flags = (flags & AT_SYMLINK_NOFOLLOW) ? 0 : LOOKUP_FOLLOW; 1298c2ecf20Sopenharmony_ci struct path path; 1308c2ecf20Sopenharmony_ci int error; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci error = kern_path(filename, lookup_flags, &path); 1338c2ecf20Sopenharmony_ci if (error) 1348c2ecf20Sopenharmony_ci return error; 1358c2ecf20Sopenharmony_ci error = vfs_getattr(&path, stat, STATX_BASIC_STATS, 1368c2ecf20Sopenharmony_ci flags | AT_NO_AUTOMOUNT); 1378c2ecf20Sopenharmony_ci path_put(&path); 1388c2ecf20Sopenharmony_ci return error; 1398c2ecf20Sopenharmony_ci} 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ciint __init init_mknod(const char *filename, umode_t mode, unsigned int dev) 1428c2ecf20Sopenharmony_ci{ 1438c2ecf20Sopenharmony_ci struct dentry *dentry; 1448c2ecf20Sopenharmony_ci struct path path; 1458c2ecf20Sopenharmony_ci int error; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci if (S_ISFIFO(mode) || S_ISSOCK(mode)) 1488c2ecf20Sopenharmony_ci dev = 0; 1498c2ecf20Sopenharmony_ci else if (!(S_ISBLK(mode) || S_ISCHR(mode))) 1508c2ecf20Sopenharmony_ci return -EINVAL; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci dentry = kern_path_create(AT_FDCWD, filename, &path, 0); 1538c2ecf20Sopenharmony_ci if (IS_ERR(dentry)) 1548c2ecf20Sopenharmony_ci return PTR_ERR(dentry); 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci if (!IS_POSIXACL(path.dentry->d_inode)) 1578c2ecf20Sopenharmony_ci mode &= ~current_umask(); 1588c2ecf20Sopenharmony_ci error = security_path_mknod(&path, dentry, mode, dev); 1598c2ecf20Sopenharmony_ci if (!error) 1608c2ecf20Sopenharmony_ci error = vfs_mknod(path.dentry->d_inode, dentry, mode, 1618c2ecf20Sopenharmony_ci new_decode_dev(dev)); 1628c2ecf20Sopenharmony_ci done_path_create(&path, dentry); 1638c2ecf20Sopenharmony_ci return error; 1648c2ecf20Sopenharmony_ci} 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ciint __init init_link(const char *oldname, const char *newname) 1678c2ecf20Sopenharmony_ci{ 1688c2ecf20Sopenharmony_ci struct dentry *new_dentry; 1698c2ecf20Sopenharmony_ci struct path old_path, new_path; 1708c2ecf20Sopenharmony_ci int error; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci error = kern_path(oldname, 0, &old_path); 1738c2ecf20Sopenharmony_ci if (error) 1748c2ecf20Sopenharmony_ci return error; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci new_dentry = kern_path_create(AT_FDCWD, newname, &new_path, 0); 1778c2ecf20Sopenharmony_ci error = PTR_ERR(new_dentry); 1788c2ecf20Sopenharmony_ci if (IS_ERR(new_dentry)) 1798c2ecf20Sopenharmony_ci goto out; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci error = -EXDEV; 1828c2ecf20Sopenharmony_ci if (old_path.mnt != new_path.mnt) 1838c2ecf20Sopenharmony_ci goto out_dput; 1848c2ecf20Sopenharmony_ci error = may_linkat(&old_path); 1858c2ecf20Sopenharmony_ci if (unlikely(error)) 1868c2ecf20Sopenharmony_ci goto out_dput; 1878c2ecf20Sopenharmony_ci error = security_path_link(old_path.dentry, &new_path, new_dentry); 1888c2ecf20Sopenharmony_ci if (error) 1898c2ecf20Sopenharmony_ci goto out_dput; 1908c2ecf20Sopenharmony_ci error = vfs_link(old_path.dentry, new_path.dentry->d_inode, new_dentry, 1918c2ecf20Sopenharmony_ci NULL); 1928c2ecf20Sopenharmony_ciout_dput: 1938c2ecf20Sopenharmony_ci done_path_create(&new_path, new_dentry); 1948c2ecf20Sopenharmony_ciout: 1958c2ecf20Sopenharmony_ci path_put(&old_path); 1968c2ecf20Sopenharmony_ci return error; 1978c2ecf20Sopenharmony_ci} 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ciint __init init_symlink(const char *oldname, const char *newname) 2008c2ecf20Sopenharmony_ci{ 2018c2ecf20Sopenharmony_ci struct dentry *dentry; 2028c2ecf20Sopenharmony_ci struct path path; 2038c2ecf20Sopenharmony_ci int error; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci dentry = kern_path_create(AT_FDCWD, newname, &path, 0); 2068c2ecf20Sopenharmony_ci if (IS_ERR(dentry)) 2078c2ecf20Sopenharmony_ci return PTR_ERR(dentry); 2088c2ecf20Sopenharmony_ci error = security_path_symlink(&path, dentry, oldname); 2098c2ecf20Sopenharmony_ci if (!error) 2108c2ecf20Sopenharmony_ci error = vfs_symlink(path.dentry->d_inode, dentry, oldname); 2118c2ecf20Sopenharmony_ci done_path_create(&path, dentry); 2128c2ecf20Sopenharmony_ci return error; 2138c2ecf20Sopenharmony_ci} 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ciint __init init_unlink(const char *pathname) 2168c2ecf20Sopenharmony_ci{ 2178c2ecf20Sopenharmony_ci return do_unlinkat(AT_FDCWD, getname_kernel(pathname)); 2188c2ecf20Sopenharmony_ci} 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ciint __init init_mkdir(const char *pathname, umode_t mode) 2218c2ecf20Sopenharmony_ci{ 2228c2ecf20Sopenharmony_ci struct dentry *dentry; 2238c2ecf20Sopenharmony_ci struct path path; 2248c2ecf20Sopenharmony_ci int error; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci dentry = kern_path_create(AT_FDCWD, pathname, &path, LOOKUP_DIRECTORY); 2278c2ecf20Sopenharmony_ci if (IS_ERR(dentry)) 2288c2ecf20Sopenharmony_ci return PTR_ERR(dentry); 2298c2ecf20Sopenharmony_ci if (!IS_POSIXACL(path.dentry->d_inode)) 2308c2ecf20Sopenharmony_ci mode &= ~current_umask(); 2318c2ecf20Sopenharmony_ci error = security_path_mkdir(&path, dentry, mode); 2328c2ecf20Sopenharmony_ci if (!error) 2338c2ecf20Sopenharmony_ci error = vfs_mkdir(path.dentry->d_inode, dentry, mode); 2348c2ecf20Sopenharmony_ci done_path_create(&path, dentry); 2358c2ecf20Sopenharmony_ci return error; 2368c2ecf20Sopenharmony_ci} 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ciint __init init_rmdir(const char *pathname) 2398c2ecf20Sopenharmony_ci{ 2408c2ecf20Sopenharmony_ci return do_rmdir(AT_FDCWD, getname_kernel(pathname)); 2418c2ecf20Sopenharmony_ci} 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ciint __init init_utimes(char *filename, struct timespec64 *ts) 2448c2ecf20Sopenharmony_ci{ 2458c2ecf20Sopenharmony_ci struct path path; 2468c2ecf20Sopenharmony_ci int error; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci error = kern_path(filename, 0, &path); 2498c2ecf20Sopenharmony_ci if (error) 2508c2ecf20Sopenharmony_ci return error; 2518c2ecf20Sopenharmony_ci error = vfs_utimes(&path, ts); 2528c2ecf20Sopenharmony_ci path_put(&path); 2538c2ecf20Sopenharmony_ci return error; 2548c2ecf20Sopenharmony_ci} 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ciint __init init_dup(struct file *file) 2578c2ecf20Sopenharmony_ci{ 2588c2ecf20Sopenharmony_ci int fd; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci fd = get_unused_fd_flags(0); 2618c2ecf20Sopenharmony_ci if (fd < 0) 2628c2ecf20Sopenharmony_ci return fd; 2638c2ecf20Sopenharmony_ci fd_install(fd, get_file(file)); 2648c2ecf20Sopenharmony_ci return 0; 2658c2ecf20Sopenharmony_ci} 266