2020-07-21 12:12:08 +03:00
// SPDX-License-Identifier: GPL-2.0
/*
* Routines that mimic syscalls , but don ' t use the user address space or file
* descriptors . Only for init / and related early init code .
*/
# include <linux/init.h>
# include <linux/mount.h>
# include <linux/namei.h>
# include <linux/fs.h>
2020-07-22 12:25:21 +03:00
# include <linux/fs_struct.h>
2020-07-28 18:49:47 +03:00
# include <linux/file.h>
2020-07-21 12:12:08 +03:00
# include <linux/init_syscalls.h>
2020-07-22 12:26:13 +03:00
# include <linux/security.h>
2020-07-21 12:12:08 +03:00
# include "internal.h"
int __init init_mount ( const char * dev_name , const char * dir_name ,
const char * type_page , unsigned long flags , void * data_page )
{
struct path path ;
int ret ;
ret = kern_path ( dir_name , LOOKUP_FOLLOW , & path ) ;
if ( ret )
return ret ;
ret = path_mount ( dev_name , & path , type_page , flags , data_page ) ;
path_put ( & path ) ;
return ret ;
}
2020-07-23 09:23:08 +03:00
int __init init_umount ( const char * name , int flags )
{
int lookup_flags = LOOKUP_MOUNTPOINT ;
struct path path ;
int ret ;
if ( ! ( flags & UMOUNT_NOFOLLOW ) )
lookup_flags | = LOOKUP_FOLLOW ;
ret = kern_path ( name , lookup_flags , & path ) ;
if ( ret )
return ret ;
return path_umount ( & path , flags ) ;
}
2020-07-23 09:23:40 +03:00
2020-07-22 12:25:21 +03:00
int __init init_chdir ( const char * filename )
{
struct path path ;
int error ;
error = kern_path ( filename , LOOKUP_FOLLOW | LOOKUP_DIRECTORY , & path ) ;
if ( error )
return error ;
2021-01-21 16:19:22 +03:00
error = path_permission ( & path , MAY_EXEC | MAY_CHDIR ) ;
2020-07-22 12:25:21 +03:00
if ( ! error )
set_fs_pwd ( current - > fs , & path ) ;
path_put ( & path ) ;
return error ;
}
2020-07-22 12:26:13 +03:00
int __init init_chroot ( const char * filename )
{
struct path path ;
int error ;
error = kern_path ( filename , LOOKUP_FOLLOW | LOOKUP_DIRECTORY , & path ) ;
if ( error )
return error ;
2021-01-21 16:19:22 +03:00
error = path_permission ( & path , MAY_EXEC | MAY_CHDIR ) ;
2020-07-22 12:26:13 +03:00
if ( error )
goto dput_and_out ;
error = - EPERM ;
if ( ! ns_capable ( current_user_ns ( ) , CAP_SYS_CHROOT ) )
goto dput_and_out ;
error = security_path_chroot ( & path ) ;
if ( error )
goto dput_and_out ;
set_fs_root ( current - > fs , & path ) ;
dput_and_out :
path_put ( & path ) ;
return error ;
}
2020-07-22 12:13:26 +03:00
int __init init_chown ( const char * filename , uid_t user , gid_t group , int flags )
{
int lookup_flags = ( flags & AT_SYMLINK_NOFOLLOW ) ? 0 : LOOKUP_FOLLOW ;
struct path path ;
int error ;
error = kern_path ( filename , lookup_flags , & path ) ;
if ( error )
return error ;
error = mnt_want_write ( path . mnt ) ;
if ( ! error ) {
error = chown_common ( & path , user , group ) ;
mnt_drop_write ( path . mnt ) ;
}
path_put ( & path ) ;
return error ;
}
2020-07-22 12:41:02 +03:00
int __init init_chmod ( const char * filename , umode_t mode )
{
struct path path ;
int error ;
error = kern_path ( filename , LOOKUP_FOLLOW , & path ) ;
if ( error )
return error ;
error = chmod_common ( & path , mode ) ;
path_put ( & path ) ;
return error ;
}
2020-07-22 12:14:02 +03:00
int __init init_eaccess ( const char * filename )
{
struct path path ;
int error ;
error = kern_path ( filename , LOOKUP_FOLLOW , & path ) ;
if ( error )
return error ;
2021-01-21 16:19:22 +03:00
error = path_permission ( & path , MAY_ACCESS ) ;
2020-07-22 12:14:02 +03:00
path_put ( & path ) ;
return error ;
}
2020-07-22 12:15:40 +03:00
int __init init_stat ( const char * filename , struct kstat * stat , int flags )
{
int lookup_flags = ( flags & AT_SYMLINK_NOFOLLOW ) ? 0 : LOOKUP_FOLLOW ;
struct path path ;
int error ;
error = kern_path ( filename , lookup_flags , & path ) ;
if ( error )
return error ;
error = vfs_getattr ( & path , stat , STATX_BASIC_STATS ,
flags | AT_NO_AUTOMOUNT ) ;
path_put ( & path ) ;
return error ;
}
2020-07-22 12:41:20 +03:00
int __init init_mknod ( const char * filename , umode_t mode , unsigned int dev )
{
struct dentry * dentry ;
struct path path ;
int error ;
if ( S_ISFIFO ( mode ) | | S_ISSOCK ( mode ) )
dev = 0 ;
else if ( ! ( S_ISBLK ( mode ) | | S_ISCHR ( mode ) ) )
return - EINVAL ;
dentry = kern_path_create ( AT_FDCWD , filename , & path , 0 ) ;
if ( IS_ERR ( dentry ) )
return PTR_ERR ( dentry ) ;
if ( ! IS_POSIXACL ( path . dentry - > d_inode ) )
mode & = ~ current_umask ( ) ;
error = security_path_mknod ( & path , dentry , mode , dev ) ;
if ( ! error )
2021-01-21 16:19:39 +03:00
error = vfs_mknod ( mnt_user_ns ( path . mnt ) , path . dentry - > d_inode ,
dentry , mode , new_decode_dev ( dev ) ) ;
2020-07-22 12:41:20 +03:00
done_path_create ( & path , dentry ) ;
return error ;
}
2020-07-22 12:14:19 +03:00
int __init init_link ( const char * oldname , const char * newname )
{
struct dentry * new_dentry ;
struct path old_path , new_path ;
2021-01-21 16:19:39 +03:00
struct user_namespace * mnt_userns ;
2020-07-22 12:14:19 +03:00
int error ;
error = kern_path ( oldname , 0 , & old_path ) ;
if ( error )
return error ;
new_dentry = kern_path_create ( AT_FDCWD , newname , & new_path , 0 ) ;
error = PTR_ERR ( new_dentry ) ;
if ( IS_ERR ( new_dentry ) )
goto out ;
error = - EXDEV ;
if ( old_path . mnt ! = new_path . mnt )
goto out_dput ;
2021-01-21 16:19:39 +03:00
mnt_userns = mnt_user_ns ( new_path . mnt ) ;
error = may_linkat ( mnt_userns , & old_path ) ;
2020-07-22 12:14:19 +03:00
if ( unlikely ( error ) )
goto out_dput ;
error = security_path_link ( old_path . dentry , & new_path , new_dentry ) ;
if ( error )
goto out_dput ;
2021-01-21 16:19:39 +03:00
error = vfs_link ( old_path . dentry , mnt_userns , new_path . dentry - > d_inode ,
new_dentry , NULL ) ;
2020-07-22 12:14:19 +03:00
out_dput :
done_path_create ( & new_path , new_dentry ) ;
out :
path_put ( & old_path ) ;
return error ;
}
2020-07-22 12:14:36 +03:00
int __init init_symlink ( const char * oldname , const char * newname )
{
struct dentry * dentry ;
struct path path ;
int error ;
dentry = kern_path_create ( AT_FDCWD , newname , & path , 0 ) ;
if ( IS_ERR ( dentry ) )
return PTR_ERR ( dentry ) ;
error = security_path_symlink ( & path , dentry , oldname ) ;
if ( ! error )
2021-01-21 16:19:39 +03:00
error = vfs_symlink ( mnt_user_ns ( path . mnt ) , path . dentry - > d_inode ,
dentry , oldname ) ;
2020-07-22 12:14:36 +03:00
done_path_create ( & path , dentry ) ;
return error ;
}
2020-07-23 09:23:40 +03:00
int __init init_unlink ( const char * pathname )
{
return do_unlinkat ( AT_FDCWD , getname_kernel ( pathname ) ) ;
}
2020-07-22 12:11:45 +03:00
2020-07-22 12:14:59 +03:00
int __init init_mkdir ( const char * pathname , umode_t mode )
{
struct dentry * dentry ;
struct path path ;
int error ;
dentry = kern_path_create ( AT_FDCWD , pathname , & path , LOOKUP_DIRECTORY ) ;
if ( IS_ERR ( dentry ) )
return PTR_ERR ( dentry ) ;
if ( ! IS_POSIXACL ( path . dentry - > d_inode ) )
mode & = ~ current_umask ( ) ;
error = security_path_mkdir ( & path , dentry , mode ) ;
if ( ! error )
2021-01-21 16:19:39 +03:00
error = vfs_mkdir ( mnt_user_ns ( path . mnt ) , path . dentry - > d_inode ,
dentry , mode ) ;
2020-07-22 12:14:59 +03:00
done_path_create ( & path , dentry ) ;
return error ;
}
2020-07-22 12:11:45 +03:00
int __init init_rmdir ( const char * pathname )
{
return do_rmdir ( AT_FDCWD , getname_kernel ( pathname ) ) ;
}
2020-07-21 17:05:31 +03:00
int __init init_utimes ( char * filename , struct timespec64 * ts )
{
struct path path ;
int error ;
error = kern_path ( filename , 0 , & path ) ;
if ( error )
return error ;
error = vfs_utimes ( & path , ts ) ;
path_put ( & path ) ;
return error ;
}
2020-07-28 18:49:47 +03:00
int __init init_dup ( struct file * file )
{
int fd ;
fd = get_unused_fd_flags ( 0 ) ;
if ( fd < 0 )
return fd ;
fd_install ( fd , get_file ( file ) ) ;
return 0 ;
}