xref: /openbmc/linux/fs/init.c (revision 4609e1f1)
1c60166f0SChristoph Hellwig // SPDX-License-Identifier: GPL-2.0
2c60166f0SChristoph Hellwig /*
3c60166f0SChristoph Hellwig  * Routines that mimic syscalls, but don't use the user address space or file
4c60166f0SChristoph Hellwig  * descriptors.  Only for init/ and related early init code.
5c60166f0SChristoph Hellwig  */
6c60166f0SChristoph Hellwig #include <linux/init.h>
7c60166f0SChristoph Hellwig #include <linux/mount.h>
8c60166f0SChristoph Hellwig #include <linux/namei.h>
9c60166f0SChristoph Hellwig #include <linux/fs.h>
10db63f1e3SChristoph Hellwig #include <linux/fs_struct.h>
11f0735310SChristoph Hellwig #include <linux/file.h>
12c60166f0SChristoph Hellwig #include <linux/init_syscalls.h>
134b7ca501SChristoph Hellwig #include <linux/security.h>
14c60166f0SChristoph Hellwig #include "internal.h"
15c60166f0SChristoph Hellwig 
init_mount(const char * dev_name,const char * dir_name,const char * type_page,unsigned long flags,void * data_page)16c60166f0SChristoph Hellwig int __init init_mount(const char *dev_name, const char *dir_name,
17c60166f0SChristoph Hellwig 		const char *type_page, unsigned long flags, void *data_page)
18c60166f0SChristoph Hellwig {
19c60166f0SChristoph Hellwig 	struct path path;
20c60166f0SChristoph Hellwig 	int ret;
21c60166f0SChristoph Hellwig 
22c60166f0SChristoph Hellwig 	ret = kern_path(dir_name, LOOKUP_FOLLOW, &path);
23c60166f0SChristoph Hellwig 	if (ret)
24c60166f0SChristoph Hellwig 		return ret;
25c60166f0SChristoph Hellwig 	ret = path_mount(dev_name, &path, type_page, flags, data_page);
26c60166f0SChristoph Hellwig 	path_put(&path);
27c60166f0SChristoph Hellwig 	return ret;
28c60166f0SChristoph Hellwig }
2909267defSChristoph Hellwig 
init_umount(const char * name,int flags)3009267defSChristoph Hellwig int __init init_umount(const char *name, int flags)
3109267defSChristoph Hellwig {
3209267defSChristoph Hellwig 	int lookup_flags = LOOKUP_MOUNTPOINT;
3309267defSChristoph Hellwig 	struct path path;
3409267defSChristoph Hellwig 	int ret;
3509267defSChristoph Hellwig 
3609267defSChristoph Hellwig 	if (!(flags & UMOUNT_NOFOLLOW))
3709267defSChristoph Hellwig 		lookup_flags |= LOOKUP_FOLLOW;
3809267defSChristoph Hellwig 	ret = kern_path(name, lookup_flags, &path);
3909267defSChristoph Hellwig 	if (ret)
4009267defSChristoph Hellwig 		return ret;
4109267defSChristoph Hellwig 	return path_umount(&path, flags);
4209267defSChristoph Hellwig }
438fb9f73eSChristoph Hellwig 
init_chdir(const char * filename)44db63f1e3SChristoph Hellwig int __init init_chdir(const char *filename)
45db63f1e3SChristoph Hellwig {
46db63f1e3SChristoph Hellwig 	struct path path;
47db63f1e3SChristoph Hellwig 	int error;
48db63f1e3SChristoph Hellwig 
49db63f1e3SChristoph Hellwig 	error = kern_path(filename, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &path);
50db63f1e3SChristoph Hellwig 	if (error)
51db63f1e3SChristoph Hellwig 		return error;
5202f92b38SChristian Brauner 	error = path_permission(&path, MAY_EXEC | MAY_CHDIR);
53db63f1e3SChristoph Hellwig 	if (!error)
54db63f1e3SChristoph Hellwig 		set_fs_pwd(current->fs, &path);
55db63f1e3SChristoph Hellwig 	path_put(&path);
56db63f1e3SChristoph Hellwig 	return error;
57db63f1e3SChristoph Hellwig }
58db63f1e3SChristoph Hellwig 
init_chroot(const char * filename)594b7ca501SChristoph Hellwig int __init init_chroot(const char *filename)
604b7ca501SChristoph Hellwig {
614b7ca501SChristoph Hellwig 	struct path path;
624b7ca501SChristoph Hellwig 	int error;
634b7ca501SChristoph Hellwig 
644b7ca501SChristoph Hellwig 	error = kern_path(filename, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &path);
654b7ca501SChristoph Hellwig 	if (error)
664b7ca501SChristoph Hellwig 		return error;
6702f92b38SChristian Brauner 	error = path_permission(&path, MAY_EXEC | MAY_CHDIR);
684b7ca501SChristoph Hellwig 	if (error)
694b7ca501SChristoph Hellwig 		goto dput_and_out;
704b7ca501SChristoph Hellwig 	error = -EPERM;
714b7ca501SChristoph Hellwig 	if (!ns_capable(current_user_ns(), CAP_SYS_CHROOT))
724b7ca501SChristoph Hellwig 		goto dput_and_out;
734b7ca501SChristoph Hellwig 	error = security_path_chroot(&path);
744b7ca501SChristoph Hellwig 	if (error)
754b7ca501SChristoph Hellwig 		goto dput_and_out;
764b7ca501SChristoph Hellwig 	set_fs_root(current->fs, &path);
774b7ca501SChristoph Hellwig dput_and_out:
784b7ca501SChristoph Hellwig 	path_put(&path);
794b7ca501SChristoph Hellwig 	return error;
804b7ca501SChristoph Hellwig }
814b7ca501SChristoph Hellwig 
init_chown(const char * filename,uid_t user,gid_t group,int flags)82b873498fSChristoph Hellwig int __init init_chown(const char *filename, uid_t user, gid_t group, int flags)
83b873498fSChristoph Hellwig {
84b873498fSChristoph Hellwig 	int lookup_flags = (flags & AT_SYMLINK_NOFOLLOW) ? 0 : LOOKUP_FOLLOW;
85b873498fSChristoph Hellwig 	struct path path;
86b873498fSChristoph Hellwig 	int error;
87b873498fSChristoph Hellwig 
88b873498fSChristoph Hellwig 	error = kern_path(filename, lookup_flags, &path);
89b873498fSChristoph Hellwig 	if (error)
90b873498fSChristoph Hellwig 		return error;
91b873498fSChristoph Hellwig 	error = mnt_want_write(path.mnt);
92b873498fSChristoph Hellwig 	if (!error) {
93b873498fSChristoph Hellwig 		error = chown_common(&path, user, group);
94b873498fSChristoph Hellwig 		mnt_drop_write(path.mnt);
95b873498fSChristoph Hellwig 	}
96b873498fSChristoph Hellwig 	path_put(&path);
97b873498fSChristoph Hellwig 	return error;
98b873498fSChristoph Hellwig }
99b873498fSChristoph Hellwig 
init_chmod(const char * filename,umode_t mode)1001097742eSChristoph Hellwig int __init init_chmod(const char *filename, umode_t mode)
1011097742eSChristoph Hellwig {
1021097742eSChristoph Hellwig 	struct path path;
1031097742eSChristoph Hellwig 	int error;
1041097742eSChristoph Hellwig 
1051097742eSChristoph Hellwig 	error = kern_path(filename, LOOKUP_FOLLOW, &path);
1061097742eSChristoph Hellwig 	if (error)
1071097742eSChristoph Hellwig 		return error;
1081097742eSChristoph Hellwig 	error = chmod_common(&path, mode);
1091097742eSChristoph Hellwig 	path_put(&path);
1101097742eSChristoph Hellwig 	return error;
1111097742eSChristoph Hellwig }
1121097742eSChristoph Hellwig 
init_eaccess(const char * filename)113eb9d7d39SChristoph Hellwig int __init init_eaccess(const char *filename)
114eb9d7d39SChristoph Hellwig {
115eb9d7d39SChristoph Hellwig 	struct path path;
116eb9d7d39SChristoph Hellwig 	int error;
117eb9d7d39SChristoph Hellwig 
118eb9d7d39SChristoph Hellwig 	error = kern_path(filename, LOOKUP_FOLLOW, &path);
119eb9d7d39SChristoph Hellwig 	if (error)
120eb9d7d39SChristoph Hellwig 		return error;
12102f92b38SChristian Brauner 	error = path_permission(&path, MAY_ACCESS);
122eb9d7d39SChristoph Hellwig 	path_put(&path);
123eb9d7d39SChristoph Hellwig 	return error;
124eb9d7d39SChristoph Hellwig }
125eb9d7d39SChristoph Hellwig 
init_stat(const char * filename,struct kstat * stat,int flags)126716308a5SChristoph Hellwig int __init init_stat(const char *filename, struct kstat *stat, int flags)
127716308a5SChristoph Hellwig {
128716308a5SChristoph Hellwig 	int lookup_flags = (flags & AT_SYMLINK_NOFOLLOW) ? 0 : LOOKUP_FOLLOW;
129716308a5SChristoph Hellwig 	struct path path;
130716308a5SChristoph Hellwig 	int error;
131716308a5SChristoph Hellwig 
132716308a5SChristoph Hellwig 	error = kern_path(filename, lookup_flags, &path);
133716308a5SChristoph Hellwig 	if (error)
134716308a5SChristoph Hellwig 		return error;
135716308a5SChristoph Hellwig 	error = vfs_getattr(&path, stat, STATX_BASIC_STATS,
136716308a5SChristoph Hellwig 			    flags | AT_NO_AUTOMOUNT);
137716308a5SChristoph Hellwig 	path_put(&path);
138716308a5SChristoph Hellwig 	return error;
139716308a5SChristoph Hellwig }
140716308a5SChristoph Hellwig 
init_mknod(const char * filename,umode_t mode,unsigned int dev)1415fee64fcSChristoph Hellwig int __init init_mknod(const char *filename, umode_t mode, unsigned int dev)
1425fee64fcSChristoph Hellwig {
1435fee64fcSChristoph Hellwig 	struct dentry *dentry;
1445fee64fcSChristoph Hellwig 	struct path path;
1455fee64fcSChristoph Hellwig 	int error;
1465fee64fcSChristoph Hellwig 
1475fee64fcSChristoph Hellwig 	if (S_ISFIFO(mode) || S_ISSOCK(mode))
1485fee64fcSChristoph Hellwig 		dev = 0;
1495fee64fcSChristoph Hellwig 	else if (!(S_ISBLK(mode) || S_ISCHR(mode)))
1505fee64fcSChristoph Hellwig 		return -EINVAL;
1515fee64fcSChristoph Hellwig 
1525fee64fcSChristoph Hellwig 	dentry = kern_path_create(AT_FDCWD, filename, &path, 0);
1535fee64fcSChristoph Hellwig 	if (IS_ERR(dentry))
1545fee64fcSChristoph Hellwig 		return PTR_ERR(dentry);
1555fee64fcSChristoph Hellwig 
1565fee64fcSChristoph Hellwig 	if (!IS_POSIXACL(path.dentry->d_inode))
1575fee64fcSChristoph Hellwig 		mode &= ~current_umask();
1585fee64fcSChristoph Hellwig 	error = security_path_mknod(&path, dentry, mode, dev);
1595fee64fcSChristoph Hellwig 	if (!error)
160abf08576SChristian Brauner 		error = vfs_mknod(mnt_idmap(path.mnt), path.dentry->d_inode,
161b816dd5dSChristian Brauner 				  dentry, mode, new_decode_dev(dev));
1625fee64fcSChristoph Hellwig 	done_path_create(&path, dentry);
1635fee64fcSChristoph Hellwig 	return error;
1645fee64fcSChristoph Hellwig }
1655fee64fcSChristoph Hellwig 
init_link(const char * oldname,const char * newname)166812931d6SChristoph Hellwig int __init init_link(const char *oldname, const char *newname)
167812931d6SChristoph Hellwig {
168812931d6SChristoph Hellwig 	struct dentry *new_dentry;
169812931d6SChristoph Hellwig 	struct path old_path, new_path;
170abf08576SChristian Brauner 	struct mnt_idmap *idmap;
171812931d6SChristoph Hellwig 	int error;
172812931d6SChristoph Hellwig 
173812931d6SChristoph Hellwig 	error = kern_path(oldname, 0, &old_path);
174812931d6SChristoph Hellwig 	if (error)
175812931d6SChristoph Hellwig 		return error;
176812931d6SChristoph Hellwig 
177812931d6SChristoph Hellwig 	new_dentry = kern_path_create(AT_FDCWD, newname, &new_path, 0);
178812931d6SChristoph Hellwig 	error = PTR_ERR(new_dentry);
179812931d6SChristoph Hellwig 	if (IS_ERR(new_dentry))
180812931d6SChristoph Hellwig 		goto out;
181812931d6SChristoph Hellwig 
182812931d6SChristoph Hellwig 	error = -EXDEV;
183812931d6SChristoph Hellwig 	if (old_path.mnt != new_path.mnt)
184812931d6SChristoph Hellwig 		goto out_dput;
185abf08576SChristian Brauner 	idmap = mnt_idmap(new_path.mnt);
186*4609e1f1SChristian Brauner 	error = may_linkat(idmap, &old_path);
187812931d6SChristoph Hellwig 	if (unlikely(error))
188812931d6SChristoph Hellwig 		goto out_dput;
189812931d6SChristoph Hellwig 	error = security_path_link(old_path.dentry, &new_path, new_dentry);
190812931d6SChristoph Hellwig 	if (error)
191812931d6SChristoph Hellwig 		goto out_dput;
192abf08576SChristian Brauner 	error = vfs_link(old_path.dentry, idmap, new_path.dentry->d_inode,
193b816dd5dSChristian Brauner 			 new_dentry, NULL);
194812931d6SChristoph Hellwig out_dput:
195812931d6SChristoph Hellwig 	done_path_create(&new_path, new_dentry);
196812931d6SChristoph Hellwig out:
197812931d6SChristoph Hellwig 	path_put(&old_path);
198812931d6SChristoph Hellwig 	return error;
199812931d6SChristoph Hellwig }
200812931d6SChristoph Hellwig 
init_symlink(const char * oldname,const char * newname)201cd3acb6aSChristoph Hellwig int __init init_symlink(const char *oldname, const char *newname)
202cd3acb6aSChristoph Hellwig {
203cd3acb6aSChristoph Hellwig 	struct dentry *dentry;
204cd3acb6aSChristoph Hellwig 	struct path path;
205cd3acb6aSChristoph Hellwig 	int error;
206cd3acb6aSChristoph Hellwig 
207cd3acb6aSChristoph Hellwig 	dentry = kern_path_create(AT_FDCWD, newname, &path, 0);
208cd3acb6aSChristoph Hellwig 	if (IS_ERR(dentry))
209cd3acb6aSChristoph Hellwig 		return PTR_ERR(dentry);
210cd3acb6aSChristoph Hellwig 	error = security_path_symlink(&path, dentry, oldname);
211cd3acb6aSChristoph Hellwig 	if (!error)
212abf08576SChristian Brauner 		error = vfs_symlink(mnt_idmap(path.mnt), path.dentry->d_inode,
213b816dd5dSChristian Brauner 				    dentry, oldname);
214cd3acb6aSChristoph Hellwig 	done_path_create(&path, dentry);
215cd3acb6aSChristoph Hellwig 	return error;
216cd3acb6aSChristoph Hellwig }
217cd3acb6aSChristoph Hellwig 
init_unlink(const char * pathname)2188fb9f73eSChristoph Hellwig int __init init_unlink(const char *pathname)
2198fb9f73eSChristoph Hellwig {
2208fb9f73eSChristoph Hellwig 	return do_unlinkat(AT_FDCWD, getname_kernel(pathname));
2218fb9f73eSChristoph Hellwig }
22220cce026SChristoph Hellwig 
init_mkdir(const char * pathname,umode_t mode)22383ff98c3SChristoph Hellwig int __init init_mkdir(const char *pathname, umode_t mode)
22483ff98c3SChristoph Hellwig {
22583ff98c3SChristoph Hellwig 	struct dentry *dentry;
22683ff98c3SChristoph Hellwig 	struct path path;
22783ff98c3SChristoph Hellwig 	int error;
22883ff98c3SChristoph Hellwig 
22983ff98c3SChristoph Hellwig 	dentry = kern_path_create(AT_FDCWD, pathname, &path, LOOKUP_DIRECTORY);
23083ff98c3SChristoph Hellwig 	if (IS_ERR(dentry))
23183ff98c3SChristoph Hellwig 		return PTR_ERR(dentry);
23283ff98c3SChristoph Hellwig 	if (!IS_POSIXACL(path.dentry->d_inode))
23383ff98c3SChristoph Hellwig 		mode &= ~current_umask();
23483ff98c3SChristoph Hellwig 	error = security_path_mkdir(&path, dentry, mode);
23583ff98c3SChristoph Hellwig 	if (!error)
236abf08576SChristian Brauner 		error = vfs_mkdir(mnt_idmap(path.mnt), path.dentry->d_inode,
237b816dd5dSChristian Brauner 				  dentry, mode);
23883ff98c3SChristoph Hellwig 	done_path_create(&path, dentry);
23983ff98c3SChristoph Hellwig 	return error;
24083ff98c3SChristoph Hellwig }
24183ff98c3SChristoph Hellwig 
init_rmdir(const char * pathname)24220cce026SChristoph Hellwig int __init init_rmdir(const char *pathname)
24320cce026SChristoph Hellwig {
24420cce026SChristoph Hellwig 	return do_rmdir(AT_FDCWD, getname_kernel(pathname));
24520cce026SChristoph Hellwig }
246235e5793SChristoph Hellwig 
init_utimes(char * filename,struct timespec64 * ts)247235e5793SChristoph Hellwig int __init init_utimes(char *filename, struct timespec64 *ts)
248235e5793SChristoph Hellwig {
249235e5793SChristoph Hellwig 	struct path path;
250235e5793SChristoph Hellwig 	int error;
251235e5793SChristoph Hellwig 
252235e5793SChristoph Hellwig 	error = kern_path(filename, 0, &path);
253235e5793SChristoph Hellwig 	if (error)
254235e5793SChristoph Hellwig 		return error;
255235e5793SChristoph Hellwig 	error = vfs_utimes(&path, ts);
256235e5793SChristoph Hellwig 	path_put(&path);
257235e5793SChristoph Hellwig 	return error;
258235e5793SChristoph Hellwig }
259f0735310SChristoph Hellwig 
init_dup(struct file * file)260f0735310SChristoph Hellwig int __init init_dup(struct file *file)
261f0735310SChristoph Hellwig {
262f0735310SChristoph Hellwig 	int fd;
263f0735310SChristoph Hellwig 
264f0735310SChristoph Hellwig 	fd = get_unused_fd_flags(0);
265f0735310SChristoph Hellwig 	if (fd < 0)
266f0735310SChristoph Hellwig 		return fd;
267f0735310SChristoph Hellwig 	fd_install(fd, get_file(file));
268f0735310SChristoph Hellwig 	return 0;
269f0735310SChristoph Hellwig }
270