18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Routines that mimic syscalls, but don't use the user address space or file
48c2ecf20Sopenharmony_ci * descriptors.  Only for init/ and related early init code.
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci#include <linux/init.h>
78c2ecf20Sopenharmony_ci#include <linux/mount.h>
88c2ecf20Sopenharmony_ci#include <linux/namei.h>
98c2ecf20Sopenharmony_ci#include <linux/fs.h>
108c2ecf20Sopenharmony_ci#include <linux/fs_struct.h>
118c2ecf20Sopenharmony_ci#include <linux/file.h>
128c2ecf20Sopenharmony_ci#include <linux/init_syscalls.h>
138c2ecf20Sopenharmony_ci#include <linux/security.h>
148c2ecf20Sopenharmony_ci#include "internal.h"
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ciint __init init_mount(const char *dev_name, const char *dir_name,
178c2ecf20Sopenharmony_ci		const char *type_page, unsigned long flags, void *data_page)
188c2ecf20Sopenharmony_ci{
198c2ecf20Sopenharmony_ci	struct path path;
208c2ecf20Sopenharmony_ci	int ret;
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci	ret = kern_path(dir_name, LOOKUP_FOLLOW, &path);
238c2ecf20Sopenharmony_ci	if (ret)
248c2ecf20Sopenharmony_ci		return ret;
258c2ecf20Sopenharmony_ci	ret = path_mount(dev_name, &path, type_page, flags, data_page);
268c2ecf20Sopenharmony_ci	path_put(&path);
278c2ecf20Sopenharmony_ci	return ret;
288c2ecf20Sopenharmony_ci}
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ciint __init init_umount(const char *name, int flags)
318c2ecf20Sopenharmony_ci{
328c2ecf20Sopenharmony_ci	int lookup_flags = LOOKUP_MOUNTPOINT;
338c2ecf20Sopenharmony_ci	struct path path;
348c2ecf20Sopenharmony_ci	int ret;
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci	if (!(flags & UMOUNT_NOFOLLOW))
378c2ecf20Sopenharmony_ci		lookup_flags |= LOOKUP_FOLLOW;
388c2ecf20Sopenharmony_ci	ret = kern_path(name, lookup_flags, &path);
398c2ecf20Sopenharmony_ci	if (ret)
408c2ecf20Sopenharmony_ci		return ret;
418c2ecf20Sopenharmony_ci	return path_umount(&path, flags);
428c2ecf20Sopenharmony_ci}
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ciint __init init_chdir(const char *filename)
458c2ecf20Sopenharmony_ci{
468c2ecf20Sopenharmony_ci	struct path path;
478c2ecf20Sopenharmony_ci	int error;
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci	error = kern_path(filename, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &path);
508c2ecf20Sopenharmony_ci	if (error)
518c2ecf20Sopenharmony_ci		return error;
528c2ecf20Sopenharmony_ci	error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_CHDIR);
538c2ecf20Sopenharmony_ci	if (!error)
548c2ecf20Sopenharmony_ci		set_fs_pwd(current->fs, &path);
558c2ecf20Sopenharmony_ci	path_put(&path);
568c2ecf20Sopenharmony_ci	return error;
578c2ecf20Sopenharmony_ci}
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ciint __init init_chroot(const char *filename)
608c2ecf20Sopenharmony_ci{
618c2ecf20Sopenharmony_ci	struct path path;
628c2ecf20Sopenharmony_ci	int error;
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci	error = kern_path(filename, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &path);
658c2ecf20Sopenharmony_ci	if (error)
668c2ecf20Sopenharmony_ci		return error;
678c2ecf20Sopenharmony_ci	error = inode_permission(path.dentry->d_inode, MAY_EXEC | MAY_CHDIR);
688c2ecf20Sopenharmony_ci	if (error)
698c2ecf20Sopenharmony_ci		goto dput_and_out;
708c2ecf20Sopenharmony_ci	error = -EPERM;
718c2ecf20Sopenharmony_ci	if (!ns_capable(current_user_ns(), CAP_SYS_CHROOT))
728c2ecf20Sopenharmony_ci		goto dput_and_out;
738c2ecf20Sopenharmony_ci	error = security_path_chroot(&path);
748c2ecf20Sopenharmony_ci	if (error)
758c2ecf20Sopenharmony_ci		goto dput_and_out;
768c2ecf20Sopenharmony_ci	set_fs_root(current->fs, &path);
778c2ecf20Sopenharmony_cidput_and_out:
788c2ecf20Sopenharmony_ci	path_put(&path);
798c2ecf20Sopenharmony_ci	return error;
808c2ecf20Sopenharmony_ci}
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ciint __init init_chown(const char *filename, uid_t user, gid_t group, int flags)
838c2ecf20Sopenharmony_ci{
848c2ecf20Sopenharmony_ci	int lookup_flags = (flags & AT_SYMLINK_NOFOLLOW) ? 0 : LOOKUP_FOLLOW;
858c2ecf20Sopenharmony_ci	struct path path;
868c2ecf20Sopenharmony_ci	int error;
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	error = kern_path(filename, lookup_flags, &path);
898c2ecf20Sopenharmony_ci	if (error)
908c2ecf20Sopenharmony_ci		return error;
918c2ecf20Sopenharmony_ci	error = mnt_want_write(path.mnt);
928c2ecf20Sopenharmony_ci	if (!error) {
938c2ecf20Sopenharmony_ci		error = chown_common(&path, user, group);
948c2ecf20Sopenharmony_ci		mnt_drop_write(path.mnt);
958c2ecf20Sopenharmony_ci	}
968c2ecf20Sopenharmony_ci	path_put(&path);
978c2ecf20Sopenharmony_ci	return error;
988c2ecf20Sopenharmony_ci}
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ciint __init init_chmod(const char *filename, umode_t mode)
1018c2ecf20Sopenharmony_ci{
1028c2ecf20Sopenharmony_ci	struct path path;
1038c2ecf20Sopenharmony_ci	int error;
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	error = kern_path(filename, LOOKUP_FOLLOW, &path);
1068c2ecf20Sopenharmony_ci	if (error)
1078c2ecf20Sopenharmony_ci		return error;
1088c2ecf20Sopenharmony_ci	error = chmod_common(&path, mode);
1098c2ecf20Sopenharmony_ci	path_put(&path);
1108c2ecf20Sopenharmony_ci	return error;
1118c2ecf20Sopenharmony_ci}
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ciint __init init_eaccess(const char *filename)
1148c2ecf20Sopenharmony_ci{
1158c2ecf20Sopenharmony_ci	struct path path;
1168c2ecf20Sopenharmony_ci	int error;
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	error = kern_path(filename, LOOKUP_FOLLOW, &path);
1198c2ecf20Sopenharmony_ci	if (error)
1208c2ecf20Sopenharmony_ci		return error;
1218c2ecf20Sopenharmony_ci	error = inode_permission(d_inode(path.dentry), MAY_ACCESS);
1228c2ecf20Sopenharmony_ci	path_put(&path);
1238c2ecf20Sopenharmony_ci	return error;
1248c2ecf20Sopenharmony_ci}
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ciint __init init_stat(const char *filename, struct kstat *stat, int flags)
1278c2ecf20Sopenharmony_ci{
1288c2ecf20Sopenharmony_ci	int lookup_flags = (flags & AT_SYMLINK_NOFOLLOW) ? 0 : LOOKUP_FOLLOW;
1298c2ecf20Sopenharmony_ci	struct path path;
1308c2ecf20Sopenharmony_ci	int error;
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	error = kern_path(filename, lookup_flags, &path);
1338c2ecf20Sopenharmony_ci	if (error)
1348c2ecf20Sopenharmony_ci		return error;
1358c2ecf20Sopenharmony_ci	error = vfs_getattr(&path, stat, STATX_BASIC_STATS,
1368c2ecf20Sopenharmony_ci			    flags | AT_NO_AUTOMOUNT);
1378c2ecf20Sopenharmony_ci	path_put(&path);
1388c2ecf20Sopenharmony_ci	return error;
1398c2ecf20Sopenharmony_ci}
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ciint __init init_mknod(const char *filename, umode_t mode, unsigned int dev)
1428c2ecf20Sopenharmony_ci{
1438c2ecf20Sopenharmony_ci	struct dentry *dentry;
1448c2ecf20Sopenharmony_ci	struct path path;
1458c2ecf20Sopenharmony_ci	int error;
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	if (S_ISFIFO(mode) || S_ISSOCK(mode))
1488c2ecf20Sopenharmony_ci		dev = 0;
1498c2ecf20Sopenharmony_ci	else if (!(S_ISBLK(mode) || S_ISCHR(mode)))
1508c2ecf20Sopenharmony_ci		return -EINVAL;
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci	dentry = kern_path_create(AT_FDCWD, filename, &path, 0);
1538c2ecf20Sopenharmony_ci	if (IS_ERR(dentry))
1548c2ecf20Sopenharmony_ci		return PTR_ERR(dentry);
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci	if (!IS_POSIXACL(path.dentry->d_inode))
1578c2ecf20Sopenharmony_ci		mode &= ~current_umask();
1588c2ecf20Sopenharmony_ci	error = security_path_mknod(&path, dentry, mode, dev);
1598c2ecf20Sopenharmony_ci	if (!error)
1608c2ecf20Sopenharmony_ci		error = vfs_mknod(path.dentry->d_inode, dentry, mode,
1618c2ecf20Sopenharmony_ci				  new_decode_dev(dev));
1628c2ecf20Sopenharmony_ci	done_path_create(&path, dentry);
1638c2ecf20Sopenharmony_ci	return error;
1648c2ecf20Sopenharmony_ci}
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ciint __init init_link(const char *oldname, const char *newname)
1678c2ecf20Sopenharmony_ci{
1688c2ecf20Sopenharmony_ci	struct dentry *new_dentry;
1698c2ecf20Sopenharmony_ci	struct path old_path, new_path;
1708c2ecf20Sopenharmony_ci	int error;
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	error = kern_path(oldname, 0, &old_path);
1738c2ecf20Sopenharmony_ci	if (error)
1748c2ecf20Sopenharmony_ci		return error;
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci	new_dentry = kern_path_create(AT_FDCWD, newname, &new_path, 0);
1778c2ecf20Sopenharmony_ci	error = PTR_ERR(new_dentry);
1788c2ecf20Sopenharmony_ci	if (IS_ERR(new_dentry))
1798c2ecf20Sopenharmony_ci		goto out;
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	error = -EXDEV;
1828c2ecf20Sopenharmony_ci	if (old_path.mnt != new_path.mnt)
1838c2ecf20Sopenharmony_ci		goto out_dput;
1848c2ecf20Sopenharmony_ci	error = may_linkat(&old_path);
1858c2ecf20Sopenharmony_ci	if (unlikely(error))
1868c2ecf20Sopenharmony_ci		goto out_dput;
1878c2ecf20Sopenharmony_ci	error = security_path_link(old_path.dentry, &new_path, new_dentry);
1888c2ecf20Sopenharmony_ci	if (error)
1898c2ecf20Sopenharmony_ci		goto out_dput;
1908c2ecf20Sopenharmony_ci	error = vfs_link(old_path.dentry, new_path.dentry->d_inode, new_dentry,
1918c2ecf20Sopenharmony_ci			 NULL);
1928c2ecf20Sopenharmony_ciout_dput:
1938c2ecf20Sopenharmony_ci	done_path_create(&new_path, new_dentry);
1948c2ecf20Sopenharmony_ciout:
1958c2ecf20Sopenharmony_ci	path_put(&old_path);
1968c2ecf20Sopenharmony_ci	return error;
1978c2ecf20Sopenharmony_ci}
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ciint __init init_symlink(const char *oldname, const char *newname)
2008c2ecf20Sopenharmony_ci{
2018c2ecf20Sopenharmony_ci	struct dentry *dentry;
2028c2ecf20Sopenharmony_ci	struct path path;
2038c2ecf20Sopenharmony_ci	int error;
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci	dentry = kern_path_create(AT_FDCWD, newname, &path, 0);
2068c2ecf20Sopenharmony_ci	if (IS_ERR(dentry))
2078c2ecf20Sopenharmony_ci		return PTR_ERR(dentry);
2088c2ecf20Sopenharmony_ci	error = security_path_symlink(&path, dentry, oldname);
2098c2ecf20Sopenharmony_ci	if (!error)
2108c2ecf20Sopenharmony_ci		error = vfs_symlink(path.dentry->d_inode, dentry, oldname);
2118c2ecf20Sopenharmony_ci	done_path_create(&path, dentry);
2128c2ecf20Sopenharmony_ci	return error;
2138c2ecf20Sopenharmony_ci}
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ciint __init init_unlink(const char *pathname)
2168c2ecf20Sopenharmony_ci{
2178c2ecf20Sopenharmony_ci	return do_unlinkat(AT_FDCWD, getname_kernel(pathname));
2188c2ecf20Sopenharmony_ci}
2198c2ecf20Sopenharmony_ci
2208c2ecf20Sopenharmony_ciint __init init_mkdir(const char *pathname, umode_t mode)
2218c2ecf20Sopenharmony_ci{
2228c2ecf20Sopenharmony_ci	struct dentry *dentry;
2238c2ecf20Sopenharmony_ci	struct path path;
2248c2ecf20Sopenharmony_ci	int error;
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci	dentry = kern_path_create(AT_FDCWD, pathname, &path, LOOKUP_DIRECTORY);
2278c2ecf20Sopenharmony_ci	if (IS_ERR(dentry))
2288c2ecf20Sopenharmony_ci		return PTR_ERR(dentry);
2298c2ecf20Sopenharmony_ci	if (!IS_POSIXACL(path.dentry->d_inode))
2308c2ecf20Sopenharmony_ci		mode &= ~current_umask();
2318c2ecf20Sopenharmony_ci	error = security_path_mkdir(&path, dentry, mode);
2328c2ecf20Sopenharmony_ci	if (!error)
2338c2ecf20Sopenharmony_ci		error = vfs_mkdir(path.dentry->d_inode, dentry, mode);
2348c2ecf20Sopenharmony_ci	done_path_create(&path, dentry);
2358c2ecf20Sopenharmony_ci	return error;
2368c2ecf20Sopenharmony_ci}
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ciint __init init_rmdir(const char *pathname)
2398c2ecf20Sopenharmony_ci{
2408c2ecf20Sopenharmony_ci	return do_rmdir(AT_FDCWD, getname_kernel(pathname));
2418c2ecf20Sopenharmony_ci}
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ciint __init init_utimes(char *filename, struct timespec64 *ts)
2448c2ecf20Sopenharmony_ci{
2458c2ecf20Sopenharmony_ci	struct path path;
2468c2ecf20Sopenharmony_ci	int error;
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci	error = kern_path(filename, 0, &path);
2498c2ecf20Sopenharmony_ci	if (error)
2508c2ecf20Sopenharmony_ci		return error;
2518c2ecf20Sopenharmony_ci	error = vfs_utimes(&path, ts);
2528c2ecf20Sopenharmony_ci	path_put(&path);
2538c2ecf20Sopenharmony_ci	return error;
2548c2ecf20Sopenharmony_ci}
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ciint __init init_dup(struct file *file)
2578c2ecf20Sopenharmony_ci{
2588c2ecf20Sopenharmony_ci	int fd;
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci	fd = get_unused_fd_flags(0);
2618c2ecf20Sopenharmony_ci	if (fd < 0)
2628c2ecf20Sopenharmony_ci		return fd;
2638c2ecf20Sopenharmony_ci	fd_install(fd, get_file(file));
2648c2ecf20Sopenharmony_ci	return 0;
2658c2ecf20Sopenharmony_ci}
266