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