1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Routines that mimic syscalls, but don't use the user address space or file 4 * descriptors. Only for init/ and related early init code. 5 */ 6 #include <linux/init.h> 7 #include <linux/mount.h> 8 #include <linux/namei.h> 9 #include <linux/fs.h> 10 #include <linux/fs_struct.h> 11 #include <linux/file.h> 12 #include <linux/init_syscalls.h> 13 #include <linux/security.h> 14 #include "internal.h" 15 16 int __init init_pivot_root(const char *new_root, const char *put_old) 17 { 18 struct path new_path __free(path_put) = {}; 19 struct path old_path __free(path_put) = {}; 20 int ret; 21 22 ret = kern_path(new_root, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &new_path); 23 if (ret) 24 return ret; 25 26 ret = kern_path(put_old, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &old_path); 27 if (ret) 28 return ret; 29 30 return path_pivot_root(&new_path, &old_path); 31 } 32 33 int __init init_mount(const char *dev_name, const char *dir_name, 34 const char *type_page, unsigned long flags, void *data_page) 35 { 36 struct path path; 37 int ret; 38 39 ret = kern_path(dir_name, LOOKUP_FOLLOW, &path); 40 if (ret) 41 return ret; 42 ret = path_mount(dev_name, &path, type_page, flags, data_page); 43 path_put(&path); 44 return ret; 45 } 46 47 int __init init_umount(const char *name, int flags) 48 { 49 int lookup_flags = LOOKUP_MOUNTPOINT; 50 struct path path; 51 int ret; 52 53 if (!(flags & UMOUNT_NOFOLLOW)) 54 lookup_flags |= LOOKUP_FOLLOW; 55 ret = kern_path(name, lookup_flags, &path); 56 if (ret) 57 return ret; 58 return path_umount(&path, flags); 59 } 60 61 int __init init_chdir(const char *filename) 62 { 63 struct path path; 64 int error; 65 66 error = kern_path(filename, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &path); 67 if (error) 68 return error; 69 error = path_permission(&path, MAY_EXEC | MAY_CHDIR); 70 if (!error) 71 set_fs_pwd(current->fs, &path); 72 path_put(&path); 73 return error; 74 } 75 76 int __init init_chroot(const char *filename) 77 { 78 struct path path; 79 int error; 80 81 error = kern_path(filename, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &path); 82 if (error) 83 return error; 84 error = path_permission(&path, MAY_EXEC | MAY_CHDIR); 85 if (error) 86 goto dput_and_out; 87 error = -EPERM; 88 if (!ns_capable(current_user_ns(), CAP_SYS_CHROOT)) 89 goto dput_and_out; 90 error = security_path_chroot(&path); 91 if (error) 92 goto dput_and_out; 93 set_fs_root(current->fs, &path); 94 dput_and_out: 95 path_put(&path); 96 return error; 97 } 98 99 int __init init_chown(const char *filename, uid_t user, gid_t group, int flags) 100 { 101 int lookup_flags = (flags & AT_SYMLINK_NOFOLLOW) ? 0 : LOOKUP_FOLLOW; 102 struct path path; 103 int error; 104 105 error = kern_path(filename, lookup_flags, &path); 106 if (error) 107 return error; 108 error = mnt_want_write(path.mnt); 109 if (!error) { 110 error = chown_common(&path, user, group); 111 mnt_drop_write(path.mnt); 112 } 113 path_put(&path); 114 return error; 115 } 116 117 int __init init_chmod(const char *filename, umode_t mode) 118 { 119 struct path path; 120 int error; 121 122 error = kern_path(filename, LOOKUP_FOLLOW, &path); 123 if (error) 124 return error; 125 error = chmod_common(&path, mode); 126 path_put(&path); 127 return error; 128 } 129 130 int __init init_eaccess(const char *filename) 131 { 132 struct path path; 133 int error; 134 135 error = kern_path(filename, LOOKUP_FOLLOW, &path); 136 if (error) 137 return error; 138 error = path_permission(&path, MAY_ACCESS); 139 path_put(&path); 140 return error; 141 } 142 143 int __init init_stat(const char *filename, struct kstat *stat, int flags) 144 { 145 int lookup_flags = (flags & AT_SYMLINK_NOFOLLOW) ? 0 : LOOKUP_FOLLOW; 146 struct path path; 147 int error; 148 149 error = kern_path(filename, lookup_flags, &path); 150 if (error) 151 return error; 152 error = vfs_getattr(&path, stat, STATX_BASIC_STATS, 153 flags | AT_NO_AUTOMOUNT); 154 path_put(&path); 155 return error; 156 } 157 158 int __init init_mknod(const char *filename, umode_t mode, unsigned int dev) 159 { 160 CLASS(filename_kernel, name)(filename); 161 return filename_mknodat(AT_FDCWD, name, mode, dev); 162 } 163 164 int __init init_link(const char *oldname, const char *newname) 165 { 166 CLASS(filename_kernel, old)(oldname); 167 CLASS(filename_kernel, new)(newname); 168 return filename_linkat(AT_FDCWD, old, AT_FDCWD, new, 0); 169 } 170 171 int __init init_symlink(const char *oldname, const char *newname) 172 { 173 CLASS(filename_kernel, old)(oldname); 174 CLASS(filename_kernel, new)(newname); 175 return filename_symlinkat(old, AT_FDCWD, new); 176 } 177 178 int __init init_unlink(const char *pathname) 179 { 180 CLASS(filename_kernel, name)(pathname); 181 return filename_unlinkat(AT_FDCWD, name); 182 } 183 184 int __init init_mkdir(const char *pathname, umode_t mode) 185 { 186 CLASS(filename_kernel, name)(pathname); 187 return filename_mkdirat(AT_FDCWD, name, mode); 188 } 189 190 int __init init_rmdir(const char *pathname) 191 { 192 CLASS(filename_kernel, name)(pathname); 193 return filename_rmdir(AT_FDCWD, name); 194 } 195 196 int __init init_utimes(char *filename, struct timespec64 *ts) 197 { 198 struct path path; 199 int error; 200 201 error = kern_path(filename, 0, &path); 202 if (error) 203 return error; 204 error = vfs_utimes(&path, ts); 205 path_put(&path); 206 return error; 207 } 208 209 int __init init_dup(struct file *file) 210 { 211 int fd; 212 213 fd = get_unused_fd_flags(0); 214 if (fd < 0) 215 return fd; 216 fd_install(fd, get_file(file)); 217 return 0; 218 } 219