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
init_pivot_root(const char * new_root,const char * put_old)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
init_mount(const char * dev_name,const char * dir_name,const char * type_page,unsigned long flags,void * data_page)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
init_umount(const char * name,int flags)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
init_chdir(const char * filename)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
init_chroot(const char * filename)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
init_chown(const char * filename,uid_t user,gid_t group,int flags)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
init_chmod(const char * filename,umode_t mode)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
init_eaccess(const char * filename)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
init_stat(const char * filename,struct kstat * stat,int flags)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
init_mknod(const char * filename,umode_t mode,unsigned int dev)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
init_link(const char * oldname,const char * newname)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
init_symlink(const char * oldname,const char * newname)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
init_unlink(const char * pathname)178 int __init init_unlink(const char *pathname)
179 {
180 CLASS(filename_kernel, name)(pathname);
181 return filename_unlinkat(AT_FDCWD, name);
182 }
183
init_mkdir(const char * pathname,umode_t mode)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
init_rmdir(const char * pathname)190 int __init init_rmdir(const char *pathname)
191 {
192 CLASS(filename_kernel, name)(pathname);
193 return filename_rmdir(AT_FDCWD, name);
194 }
195
init_utimes(char * filename,struct timespec64 * ts)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
init_dup(struct file * file)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