2019-06-04 11:11:33 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2005-07-08 01:37:53 +04:00
/*
* inode . c - securityfs
*
* Copyright ( C ) 2005 Greg Kroah - Hartman < gregkh @ suse . de >
*
* Based on fs / debugfs / inode . c which had the following copyright notice :
* Copyright ( C ) 2004 Greg Kroah - Hartman < greg @ kroah . com >
* Copyright ( C ) 2004 IBM Inc .
*/
/* #define DEBUG */
2018-12-09 23:36:31 +03:00
# include <linux/sysfs.h>
# include <linux/kobject.h>
2005-07-08 01:37:53 +04:00
# include <linux/fs.h>
2019-03-25 19:38:30 +03:00
# include <linux/fs_context.h>
2005-07-08 01:37:53 +04:00
# include <linux/mount.h>
# include <linux/pagemap.h>
# include <linux/init.h>
# include <linux/namei.h>
# include <linux/security.h>
2017-01-19 04:09:05 +03:00
# include <linux/lsm_hooks.h>
2008-10-07 22:00:12 +04:00
# include <linux/magic.h>
2005-07-08 01:37:53 +04:00
static struct vfsmount * mount ;
static int mount_count ;
2019-04-16 05:34:28 +03:00
static void securityfs_free_inode ( struct inode * inode )
2017-05-07 15:53:37 +03:00
{
if ( S_ISLNK ( inode - > i_mode ) )
kfree ( inode - > i_link ) ;
2019-04-10 21:03:45 +03:00
free_inode_nonrcu ( inode ) ;
}
2017-05-07 15:53:37 +03:00
static const struct super_operations securityfs_super_operations = {
. statfs = simple_statfs ,
2019-04-16 05:34:28 +03:00
. free_inode = securityfs_free_inode ,
2017-05-07 15:53:37 +03:00
} ;
2019-03-25 19:38:30 +03:00
static int securityfs_fill_super ( struct super_block * sb , struct fs_context * fc )
2005-07-08 01:37:53 +04:00
{
2017-03-26 07:15:37 +03:00
static const struct tree_descr files [ ] = { { " " } } ;
2017-05-07 15:53:37 +03:00
int error ;
error = simple_fill_super ( sb , SECURITYFS_MAGIC , files ) ;
if ( error )
return error ;
sb - > s_op = & securityfs_super_operations ;
2005-07-08 01:37:53 +04:00
2017-05-07 15:53:37 +03:00
return 0 ;
2005-07-08 01:37:53 +04:00
}
2019-03-25 19:38:30 +03:00
static int securityfs_get_tree ( struct fs_context * fc )
2005-07-08 01:37:53 +04:00
{
2019-03-25 19:38:30 +03:00
return get_tree_single ( fc , securityfs_fill_super ) ;
}
static const struct fs_context_operations securityfs_context_ops = {
. get_tree = securityfs_get_tree ,
} ;
static int securityfs_init_fs_context ( struct fs_context * fc )
{
fc - > ops = & securityfs_context_ops ;
return 0 ;
2005-07-08 01:37:53 +04:00
}
static struct file_system_type fs_type = {
. owner = THIS_MODULE ,
. name = " securityfs " ,
2019-03-25 19:38:30 +03:00
. init_fs_context = securityfs_init_fs_context ,
2005-07-08 01:37:53 +04:00
. kill_sb = kill_litter_super ,
} ;
/**
2017-05-07 15:53:37 +03:00
* securityfs_create_dentry - create a dentry in the securityfs filesystem
2005-07-08 01:37:53 +04:00
*
* @ name : a pointer to a string containing the name of the file to create .
* @ mode : the permission that the file should have
* @ parent : a pointer to the parent dentry for this file . This should be a
2008-08-18 08:44:22 +04:00
* directory dentry if set . If this parameter is % NULL , then the
2005-07-08 01:37:53 +04:00
* file will be created in the root of the securityfs filesystem .
* @ data : a pointer to something that the caller will want to get to later
2006-09-27 12:50:46 +04:00
* on . The inode . i_private pointer will point to this value on
2005-07-08 01:37:53 +04:00
* the open ( ) call .
* @ fops : a pointer to a struct file_operations that should be used for
* this file .
2017-05-07 15:53:37 +03:00
* @ iops : a point to a struct of inode_operations that should be used for
* this file / dir
2005-07-08 01:37:53 +04:00
*
2017-05-07 15:53:37 +03:00
* This is the basic " create a file/dir/symlink " function for
* securityfs . It allows for a wide range of flexibility in creating
* a file , or a directory ( if you want to create a directory , the
* securityfs_create_dir ( ) function is recommended to be used
* instead ) .
2005-07-08 01:37:53 +04:00
*
2008-08-18 08:44:22 +04:00
* This function returns a pointer to a dentry if it succeeds . This
2017-05-07 15:53:37 +03:00
* pointer must be passed to the securityfs_remove ( ) function when the
* file is to be removed ( no automatic cleanup happens if your module
* is unloaded , you are responsible here ) . If an error occurs , the
* function will return the error value ( via ERR_PTR ) .
2005-07-08 01:37:53 +04:00
*
2008-08-18 08:44:22 +04:00
* If securityfs is not enabled in the kernel , the value % - ENODEV is
2009-02-03 02:07:33 +03:00
* returned .
2005-07-08 01:37:53 +04:00
*/
2017-05-07 15:53:37 +03:00
static struct dentry * securityfs_create_dentry ( const char * name , umode_t mode ,
struct dentry * parent , void * data ,
const struct file_operations * fops ,
const struct inode_operations * iops )
2005-07-08 01:37:53 +04:00
{
2012-01-10 19:20:35 +04:00
struct dentry * dentry ;
struct inode * dir , * inode ;
2005-07-08 01:37:53 +04:00
int error ;
2017-05-07 15:53:37 +03:00
if ( ! ( mode & S_IFMT ) )
2012-01-10 19:20:35 +04:00
mode = ( mode & S_IALLUGO ) | S_IFREG ;
2005-07-08 01:37:53 +04:00
pr_debug ( " securityfs: creating file '%s' \n " , name ) ;
2006-06-09 17:34:16 +04:00
error = simple_pin_fs ( & fs_type , & mount , & mount_count ) ;
2012-01-10 19:20:35 +04:00
if ( error )
return ERR_PTR ( error ) ;
if ( ! parent )
parent = mount - > mnt_root ;
2015-02-19 13:47:02 +03:00
dir = d_inode ( parent ) ;
2012-01-10 19:20:35 +04:00
2016-01-22 23:40:57 +03:00
inode_lock ( dir ) ;
2012-01-10 19:20:35 +04:00
dentry = lookup_one_len ( name , parent , strlen ( name ) ) ;
if ( IS_ERR ( dentry ) )
goto out ;
2015-02-19 13:47:02 +03:00
if ( d_really_is_positive ( dentry ) ) {
2012-01-10 19:20:35 +04:00
error = - EEXIST ;
goto out1 ;
2005-07-08 01:37:53 +04:00
}
2012-01-10 19:20:35 +04:00
inode = new_inode ( dir - > i_sb ) ;
if ( ! inode ) {
error = - ENOMEM ;
goto out1 ;
2005-07-08 01:37:53 +04:00
}
2012-01-10 19:20:35 +04:00
inode - > i_ino = get_next_ino ( ) ;
inode - > i_mode = mode ;
2023-10-04 21:53:11 +03:00
simple_inode_init_ts ( inode ) ;
2012-01-10 19:20:35 +04:00
inode - > i_private = data ;
2017-05-07 15:53:37 +03:00
if ( S_ISDIR ( mode ) ) {
2012-01-10 19:20:35 +04:00
inode - > i_op = & simple_dir_inode_operations ;
inode - > i_fop = & simple_dir_operations ;
inc_nlink ( inode ) ;
inc_nlink ( dir ) ;
2017-05-07 15:53:37 +03:00
} else if ( S_ISLNK ( mode ) ) {
inode - > i_op = iops ? iops : & simple_symlink_inode_operations ;
inode - > i_link = data ;
2012-01-10 19:20:35 +04:00
} else {
inode - > i_fop = fops ;
2005-07-08 01:37:53 +04:00
}
2012-01-10 19:20:35 +04:00
d_instantiate ( dentry , inode ) ;
dget ( dentry ) ;
2016-01-22 23:40:57 +03:00
inode_unlock ( dir ) ;
2012-01-10 19:20:35 +04:00
return dentry ;
out1 :
dput ( dentry ) ;
dentry = ERR_PTR ( error ) ;
out :
2016-01-22 23:40:57 +03:00
inode_unlock ( dir ) ;
2012-01-10 19:20:35 +04:00
simple_release_fs ( & mount , & mount_count ) ;
2005-07-08 01:37:53 +04:00
return dentry ;
}
2017-05-07 15:53:37 +03:00
/**
* securityfs_create_file - create a file in the securityfs filesystem
*
* @ name : a pointer to a string containing the name of the file to create .
* @ mode : the permission that the file should have
* @ parent : a pointer to the parent dentry for this file . This should be a
* directory dentry if set . If this parameter is % NULL , then the
* file will be created in the root of the securityfs filesystem .
* @ data : a pointer to something that the caller will want to get to later
* on . The inode . i_private pointer will point to this value on
* the open ( ) call .
* @ fops : a pointer to a struct file_operations that should be used for
* this file .
*
* This function creates a file in securityfs with the given @ name .
*
* This function returns a pointer to a dentry if it succeeds . This
* pointer must be passed to the securityfs_remove ( ) function when the file is
* to be removed ( no automatic cleanup happens if your module is unloaded ,
* you are responsible here ) . If an error occurs , the function will return
* the error value ( via ERR_PTR ) .
*
* If securityfs is not enabled in the kernel , the value % - ENODEV is
* returned .
*/
struct dentry * securityfs_create_file ( const char * name , umode_t mode ,
struct dentry * parent , void * data ,
const struct file_operations * fops )
{
return securityfs_create_dentry ( name , mode , parent , data , fops , NULL ) ;
}
2005-07-08 01:37:53 +04:00
EXPORT_SYMBOL_GPL ( securityfs_create_file ) ;
/**
* securityfs_create_dir - create a directory in the securityfs filesystem
*
* @ name : a pointer to a string containing the name of the directory to
* create .
* @ parent : a pointer to the parent dentry for this file . This should be a
2008-08-18 08:44:22 +04:00
* directory dentry if set . If this parameter is % NULL , then the
2005-07-08 01:37:53 +04:00
* directory will be created in the root of the securityfs filesystem .
*
2008-08-18 08:44:22 +04:00
* This function creates a directory in securityfs with the given @ name .
2005-07-08 01:37:53 +04:00
*
2008-08-18 08:44:22 +04:00
* This function returns a pointer to a dentry if it succeeds . This
2005-07-08 01:37:53 +04:00
* pointer must be passed to the securityfs_remove ( ) function when the file is
* to be removed ( no automatic cleanup happens if your module is unloaded ,
2016-07-13 09:58:40 +03:00
* you are responsible here ) . If an error occurs , the function will return
* the error value ( via ERR_PTR ) .
2005-07-08 01:37:53 +04:00
*
2008-08-18 08:44:22 +04:00
* If securityfs is not enabled in the kernel , the value % - ENODEV is
2016-07-13 09:58:40 +03:00
* returned .
2005-07-08 01:37:53 +04:00
*/
struct dentry * securityfs_create_dir ( const char * name , struct dentry * parent )
{
2017-05-07 15:53:37 +03:00
return securityfs_create_file ( name , S_IFDIR | 0755 , parent , NULL , NULL ) ;
2005-07-08 01:37:53 +04:00
}
EXPORT_SYMBOL_GPL ( securityfs_create_dir ) ;
2017-05-07 15:53:37 +03:00
/**
* securityfs_create_symlink - create a symlink in the securityfs filesystem
*
* @ name : a pointer to a string containing the name of the symlink to
* create .
* @ parent : a pointer to the parent dentry for the symlink . This should be a
* directory dentry if set . If this parameter is % NULL , then the
* directory will be created in the root of the securityfs filesystem .
* @ target : a pointer to a string containing the name of the symlink ' s target .
* If this parameter is % NULL , then the @ iops parameter needs to be
* setup to handle . readlink and . get_link inode_operations .
* @ iops : a pointer to the struct inode_operations to use for the symlink . If
* this parameter is % NULL , then the default simple_symlink_inode
* operations will be used .
*
* This function creates a symlink in securityfs with the given @ name .
*
* This function returns a pointer to a dentry if it succeeds . This
* pointer must be passed to the securityfs_remove ( ) function when the file is
* to be removed ( no automatic cleanup happens if your module is unloaded ,
* you are responsible here ) . If an error occurs , the function will return
* the error value ( via ERR_PTR ) .
*
* If securityfs is not enabled in the kernel , the value % - ENODEV is
* returned .
*/
struct dentry * securityfs_create_symlink ( const char * name ,
struct dentry * parent ,
const char * target ,
const struct inode_operations * iops )
{
struct dentry * dent ;
char * link = NULL ;
if ( target ) {
link = kstrdup ( target , GFP_KERNEL ) ;
if ( ! link )
return ERR_PTR ( - ENOMEM ) ;
}
dent = securityfs_create_dentry ( name , S_IFLNK | 0444 , parent ,
link , NULL , iops ) ;
if ( IS_ERR ( dent ) )
kfree ( link ) ;
return dent ;
}
EXPORT_SYMBOL_GPL ( securityfs_create_symlink ) ;
2005-07-08 01:37:53 +04:00
/**
* securityfs_remove - removes a file or directory from the securityfs filesystem
*
2008-08-18 08:44:22 +04:00
* @ dentry : a pointer to a the dentry of the file or directory to be removed .
2005-07-08 01:37:53 +04:00
*
* This function removes a file or directory in securityfs that was previously
* created with a call to another securityfs function ( like
* securityfs_create_file ( ) or variants thereof . )
*
* This function is required to be called in order for the file to be
2008-08-18 08:44:22 +04:00
* removed . No automatic cleanup of files will happen when a module is
* removed ; you are responsible here .
2005-07-08 01:37:53 +04:00
*/
void securityfs_remove ( struct dentry * dentry )
{
2016-05-29 21:54:04 +03:00
struct inode * dir ;
2005-07-08 01:37:53 +04:00
2009-05-12 04:47:15 +04:00
if ( ! dentry | | IS_ERR ( dentry ) )
2005-07-08 01:37:53 +04:00
return ;
2016-05-29 21:54:04 +03:00
dir = d_inode ( dentry - > d_parent ) ;
inode_lock ( dir ) ;
2015-05-18 17:10:34 +03:00
if ( simple_positive ( dentry ) ) {
if ( d_is_dir ( dentry ) )
2016-05-29 21:54:04 +03:00
simple_rmdir ( dir , dentry ) ;
2015-05-18 17:10:34 +03:00
else
2016-05-29 21:54:04 +03:00
simple_unlink ( dir , dentry ) ;
2015-05-18 17:10:34 +03:00
dput ( dentry ) ;
2005-07-08 01:37:53 +04:00
}
2016-05-29 21:54:04 +03:00
inode_unlock ( dir ) ;
2005-07-08 01:37:53 +04:00
simple_release_fs ( & mount , & mount_count ) ;
}
EXPORT_SYMBOL_GPL ( securityfs_remove ) ;
2017-01-19 04:09:05 +03:00
# ifdef CONFIG_SECURITY
static struct dentry * lsm_dentry ;
static ssize_t lsm_read ( struct file * filp , char __user * buf , size_t count ,
loff_t * ppos )
{
return simple_read_from_buffer ( buf , count , ppos , lsm_names ,
strlen ( lsm_names ) ) ;
}
static const struct file_operations lsm_ops = {
. read = lsm_read ,
. llseek = generic_file_llseek ,
} ;
# endif
2005-07-08 01:37:53 +04:00
static int __init securityfs_init ( void )
{
int retval ;
2015-05-14 01:35:41 +03:00
retval = sysfs_create_mount_point ( kernel_kobj , " security " ) ;
if ( retval )
return retval ;
2005-07-08 01:37:53 +04:00
retval = register_filesystem ( & fs_type ) ;
2017-01-19 04:09:05 +03:00
if ( retval ) {
2015-05-14 01:35:41 +03:00
sysfs_remove_mount_point ( kernel_kobj , " security " ) ;
2017-01-19 04:09:05 +03:00
return retval ;
}
# ifdef CONFIG_SECURITY
lsm_dentry = securityfs_create_file ( " lsm " , 0444 , NULL , NULL ,
& lsm_ops ) ;
# endif
return 0 ;
2005-07-08 01:37:53 +04:00
}
core_initcall ( securityfs_init ) ;