blob: 145fb31b7a5f2ddd43eb5ad6887768c0b87ea5a2 [file] [log] [blame]
Christoph Hellwigc60166f2020-07-21 11:12:08 +02001// 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>
Christoph Hellwigdb63f1e2020-07-22 11:25:21 +020010#include <linux/fs_struct.h>
Christoph Hellwigc60166f2020-07-21 11:12:08 +020011#include <linux/init_syscalls.h>
Christoph Hellwig4b7ca502020-07-22 11:26:13 +020012#include <linux/security.h>
Christoph Hellwigc60166f2020-07-21 11:12:08 +020013#include "internal.h"
14
15int __init init_mount(const char *dev_name, const char *dir_name,
16 const char *type_page, unsigned long flags, void *data_page)
17{
18 struct path path;
19 int ret;
20
21 ret = kern_path(dir_name, LOOKUP_FOLLOW, &path);
22 if (ret)
23 return ret;
24 ret = path_mount(dev_name, &path, type_page, flags, data_page);
25 path_put(&path);
26 return ret;
27}
Christoph Hellwig09267de2020-07-23 08:23:08 +020028
29int __init init_umount(const char *name, int flags)
30{
31 int lookup_flags = LOOKUP_MOUNTPOINT;
32 struct path path;
33 int ret;
34
35 if (!(flags & UMOUNT_NOFOLLOW))
36 lookup_flags |= LOOKUP_FOLLOW;
37 ret = kern_path(name, lookup_flags, &path);
38 if (ret)
39 return ret;
40 return path_umount(&path, flags);
41}
Christoph Hellwig8fb9f732020-07-23 08:23:40 +020042
Christoph Hellwigdb63f1e2020-07-22 11:25:21 +020043int __init init_chdir(const char *filename)
44{
45 struct path path;
46 int error;
47
48 error = kern_path(filename, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &path);
49 if (error)
50 return error;
51 error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_CHDIR);
52 if (!error)
53 set_fs_pwd(current->fs, &path);
54 path_put(&path);
55 return error;
56}
57
Christoph Hellwig4b7ca502020-07-22 11:26:13 +020058int __init init_chroot(const char *filename)
59{
60 struct path path;
61 int error;
62
63 error = kern_path(filename, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &path);
64 if (error)
65 return error;
66 error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_CHDIR);
67 if (error)
68 goto dput_and_out;
69 error = -EPERM;
70 if (!ns_capable(current_user_ns(), CAP_SYS_CHROOT))
71 goto dput_and_out;
72 error = security_path_chroot(&path);
73 if (error)
74 goto dput_and_out;
75 set_fs_root(current->fs, &path);
76dput_and_out:
77 path_put(&path);
78 return error;
79}
80
Christoph Hellwigb8734982020-07-22 11:13:26 +020081int __init init_chown(const char *filename, uid_t user, gid_t group, int flags)
82{
83 int lookup_flags = (flags & AT_SYMLINK_NOFOLLOW) ? 0 : LOOKUP_FOLLOW;
84 struct path path;
85 int error;
86
87 error = kern_path(filename, lookup_flags, &path);
88 if (error)
89 return error;
90 error = mnt_want_write(path.mnt);
91 if (!error) {
92 error = chown_common(&path, user, group);
93 mnt_drop_write(path.mnt);
94 }
95 path_put(&path);
96 return error;
97}
98
Christoph Hellwig10977422020-07-22 11:41:02 +020099int __init init_chmod(const char *filename, umode_t mode)
100{
101 struct path path;
102 int error;
103
104 error = kern_path(filename, LOOKUP_FOLLOW, &path);
105 if (error)
106 return error;
107 error = chmod_common(&path, mode);
108 path_put(&path);
109 return error;
110}
111
Christoph Hellwigeb9d7d32020-07-22 11:14:02 +0200112int __init init_eaccess(const char *filename)
113{
114 struct path path;
115 int error;
116
117 error = kern_path(filename, LOOKUP_FOLLOW, &path);
118 if (error)
119 return error;
120 error = inode_permission(d_inode(path.dentry), MAY_ACCESS);
121 path_put(&path);
122 return error;
123}
124
Christoph Hellwig5fee64f2020-07-22 11:41:20 +0200125int __init init_mknod(const char *filename, umode_t mode, unsigned int dev)
126{
127 struct dentry *dentry;
128 struct path path;
129 int error;
130
131 if (S_ISFIFO(mode) || S_ISSOCK(mode))
132 dev = 0;
133 else if (!(S_ISBLK(mode) || S_ISCHR(mode)))
134 return -EINVAL;
135
136 dentry = kern_path_create(AT_FDCWD, filename, &path, 0);
137 if (IS_ERR(dentry))
138 return PTR_ERR(dentry);
139
140 if (!IS_POSIXACL(path.dentry->d_inode))
141 mode &= ~current_umask();
142 error = security_path_mknod(&path, dentry, mode, dev);
143 if (!error)
144 error = vfs_mknod(path.dentry->d_inode, dentry, mode,
145 new_decode_dev(dev));
146 done_path_create(&path, dentry);
147 return error;
148}
149
Christoph Hellwig812931d2020-07-22 11:14:19 +0200150int __init init_link(const char *oldname, const char *newname)
151{
152 struct dentry *new_dentry;
153 struct path old_path, new_path;
154 int error;
155
156 error = kern_path(oldname, 0, &old_path);
157 if (error)
158 return error;
159
160 new_dentry = kern_path_create(AT_FDCWD, newname, &new_path, 0);
161 error = PTR_ERR(new_dentry);
162 if (IS_ERR(new_dentry))
163 goto out;
164
165 error = -EXDEV;
166 if (old_path.mnt != new_path.mnt)
167 goto out_dput;
168 error = may_linkat(&old_path);
169 if (unlikely(error))
170 goto out_dput;
171 error = security_path_link(old_path.dentry, &new_path, new_dentry);
172 if (error)
173 goto out_dput;
174 error = vfs_link(old_path.dentry, new_path.dentry->d_inode, new_dentry,
175 NULL);
176out_dput:
177 done_path_create(&new_path, new_dentry);
178out:
179 path_put(&old_path);
180 return error;
181}
182
Christoph Hellwigcd3acb62020-07-22 11:14:36 +0200183int __init init_symlink(const char *oldname, const char *newname)
184{
185 struct dentry *dentry;
186 struct path path;
187 int error;
188
189 dentry = kern_path_create(AT_FDCWD, newname, &path, 0);
190 if (IS_ERR(dentry))
191 return PTR_ERR(dentry);
192 error = security_path_symlink(&path, dentry, oldname);
193 if (!error)
194 error = vfs_symlink(path.dentry->d_inode, dentry, oldname);
195 done_path_create(&path, dentry);
196 return error;
197}
198
Christoph Hellwig8fb9f732020-07-23 08:23:40 +0200199int __init init_unlink(const char *pathname)
200{
201 return do_unlinkat(AT_FDCWD, getname_kernel(pathname));
202}
Christoph Hellwig20cce022020-07-22 11:11:45 +0200203
Christoph Hellwig83ff98c2020-07-22 11:14:59 +0200204int __init init_mkdir(const char *pathname, umode_t mode)
205{
206 struct dentry *dentry;
207 struct path path;
208 int error;
209
210 dentry = kern_path_create(AT_FDCWD, pathname, &path, LOOKUP_DIRECTORY);
211 if (IS_ERR(dentry))
212 return PTR_ERR(dentry);
213 if (!IS_POSIXACL(path.dentry->d_inode))
214 mode &= ~current_umask();
215 error = security_path_mkdir(&path, dentry, mode);
216 if (!error)
217 error = vfs_mkdir(path.dentry->d_inode, dentry, mode);
218 done_path_create(&path, dentry);
219 return error;
220}
221
Christoph Hellwig20cce022020-07-22 11:11:45 +0200222int __init init_rmdir(const char *pathname)
223{
224 return do_rmdir(AT_FDCWD, getname_kernel(pathname));
225}