xref: /linux/fs/init.c (revision 37a93dd5c49b5fda807fd204edf2547c3493319c)
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