162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * inode.c - securityfs 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2005 Greg Kroah-Hartman <gregkh@suse.de> 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Based on fs/debugfs/inode.c which had the following copyright notice: 862306a36Sopenharmony_ci * Copyright (C) 2004 Greg Kroah-Hartman <greg@kroah.com> 962306a36Sopenharmony_ci * Copyright (C) 2004 IBM Inc. 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci/* #define DEBUG */ 1362306a36Sopenharmony_ci#include <linux/sysfs.h> 1462306a36Sopenharmony_ci#include <linux/kobject.h> 1562306a36Sopenharmony_ci#include <linux/fs.h> 1662306a36Sopenharmony_ci#include <linux/fs_context.h> 1762306a36Sopenharmony_ci#include <linux/mount.h> 1862306a36Sopenharmony_ci#include <linux/pagemap.h> 1962306a36Sopenharmony_ci#include <linux/init.h> 2062306a36Sopenharmony_ci#include <linux/namei.h> 2162306a36Sopenharmony_ci#include <linux/security.h> 2262306a36Sopenharmony_ci#include <linux/lsm_hooks.h> 2362306a36Sopenharmony_ci#include <linux/magic.h> 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_cistatic struct vfsmount *mount; 2662306a36Sopenharmony_cistatic int mount_count; 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistatic void securityfs_free_inode(struct inode *inode) 2962306a36Sopenharmony_ci{ 3062306a36Sopenharmony_ci if (S_ISLNK(inode->i_mode)) 3162306a36Sopenharmony_ci kfree(inode->i_link); 3262306a36Sopenharmony_ci free_inode_nonrcu(inode); 3362306a36Sopenharmony_ci} 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_cistatic const struct super_operations securityfs_super_operations = { 3662306a36Sopenharmony_ci .statfs = simple_statfs, 3762306a36Sopenharmony_ci .free_inode = securityfs_free_inode, 3862306a36Sopenharmony_ci}; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_cistatic int securityfs_fill_super(struct super_block *sb, struct fs_context *fc) 4162306a36Sopenharmony_ci{ 4262306a36Sopenharmony_ci static const struct tree_descr files[] = {{""}}; 4362306a36Sopenharmony_ci int error; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci error = simple_fill_super(sb, SECURITYFS_MAGIC, files); 4662306a36Sopenharmony_ci if (error) 4762306a36Sopenharmony_ci return error; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci sb->s_op = &securityfs_super_operations; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci return 0; 5262306a36Sopenharmony_ci} 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_cistatic int securityfs_get_tree(struct fs_context *fc) 5562306a36Sopenharmony_ci{ 5662306a36Sopenharmony_ci return get_tree_single(fc, securityfs_fill_super); 5762306a36Sopenharmony_ci} 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_cistatic const struct fs_context_operations securityfs_context_ops = { 6062306a36Sopenharmony_ci .get_tree = securityfs_get_tree, 6162306a36Sopenharmony_ci}; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_cistatic int securityfs_init_fs_context(struct fs_context *fc) 6462306a36Sopenharmony_ci{ 6562306a36Sopenharmony_ci fc->ops = &securityfs_context_ops; 6662306a36Sopenharmony_ci return 0; 6762306a36Sopenharmony_ci} 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_cistatic struct file_system_type fs_type = { 7062306a36Sopenharmony_ci .owner = THIS_MODULE, 7162306a36Sopenharmony_ci .name = "securityfs", 7262306a36Sopenharmony_ci .init_fs_context = securityfs_init_fs_context, 7362306a36Sopenharmony_ci .kill_sb = kill_litter_super, 7462306a36Sopenharmony_ci}; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci/** 7762306a36Sopenharmony_ci * securityfs_create_dentry - create a dentry in the securityfs filesystem 7862306a36Sopenharmony_ci * 7962306a36Sopenharmony_ci * @name: a pointer to a string containing the name of the file to create. 8062306a36Sopenharmony_ci * @mode: the permission that the file should have 8162306a36Sopenharmony_ci * @parent: a pointer to the parent dentry for this file. This should be a 8262306a36Sopenharmony_ci * directory dentry if set. If this parameter is %NULL, then the 8362306a36Sopenharmony_ci * file will be created in the root of the securityfs filesystem. 8462306a36Sopenharmony_ci * @data: a pointer to something that the caller will want to get to later 8562306a36Sopenharmony_ci * on. The inode.i_private pointer will point to this value on 8662306a36Sopenharmony_ci * the open() call. 8762306a36Sopenharmony_ci * @fops: a pointer to a struct file_operations that should be used for 8862306a36Sopenharmony_ci * this file. 8962306a36Sopenharmony_ci * @iops: a point to a struct of inode_operations that should be used for 9062306a36Sopenharmony_ci * this file/dir 9162306a36Sopenharmony_ci * 9262306a36Sopenharmony_ci * This is the basic "create a file/dir/symlink" function for 9362306a36Sopenharmony_ci * securityfs. It allows for a wide range of flexibility in creating 9462306a36Sopenharmony_ci * a file, or a directory (if you want to create a directory, the 9562306a36Sopenharmony_ci * securityfs_create_dir() function is recommended to be used 9662306a36Sopenharmony_ci * instead). 9762306a36Sopenharmony_ci * 9862306a36Sopenharmony_ci * This function returns a pointer to a dentry if it succeeds. This 9962306a36Sopenharmony_ci * pointer must be passed to the securityfs_remove() function when the 10062306a36Sopenharmony_ci * file is to be removed (no automatic cleanup happens if your module 10162306a36Sopenharmony_ci * is unloaded, you are responsible here). If an error occurs, the 10262306a36Sopenharmony_ci * function will return the error value (via ERR_PTR). 10362306a36Sopenharmony_ci * 10462306a36Sopenharmony_ci * If securityfs is not enabled in the kernel, the value %-ENODEV is 10562306a36Sopenharmony_ci * returned. 10662306a36Sopenharmony_ci */ 10762306a36Sopenharmony_cistatic struct dentry *securityfs_create_dentry(const char *name, umode_t mode, 10862306a36Sopenharmony_ci struct dentry *parent, void *data, 10962306a36Sopenharmony_ci const struct file_operations *fops, 11062306a36Sopenharmony_ci const struct inode_operations *iops) 11162306a36Sopenharmony_ci{ 11262306a36Sopenharmony_ci struct dentry *dentry; 11362306a36Sopenharmony_ci struct inode *dir, *inode; 11462306a36Sopenharmony_ci int error; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci if (!(mode & S_IFMT)) 11762306a36Sopenharmony_ci mode = (mode & S_IALLUGO) | S_IFREG; 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci pr_debug("securityfs: creating file '%s'\n",name); 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci error = simple_pin_fs(&fs_type, &mount, &mount_count); 12262306a36Sopenharmony_ci if (error) 12362306a36Sopenharmony_ci return ERR_PTR(error); 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci if (!parent) 12662306a36Sopenharmony_ci parent = mount->mnt_root; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci dir = d_inode(parent); 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci inode_lock(dir); 13162306a36Sopenharmony_ci dentry = lookup_one_len(name, parent, strlen(name)); 13262306a36Sopenharmony_ci if (IS_ERR(dentry)) 13362306a36Sopenharmony_ci goto out; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci if (d_really_is_positive(dentry)) { 13662306a36Sopenharmony_ci error = -EEXIST; 13762306a36Sopenharmony_ci goto out1; 13862306a36Sopenharmony_ci } 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci inode = new_inode(dir->i_sb); 14162306a36Sopenharmony_ci if (!inode) { 14262306a36Sopenharmony_ci error = -ENOMEM; 14362306a36Sopenharmony_ci goto out1; 14462306a36Sopenharmony_ci } 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci inode->i_ino = get_next_ino(); 14762306a36Sopenharmony_ci inode->i_mode = mode; 14862306a36Sopenharmony_ci inode->i_atime = inode->i_mtime = inode_set_ctime_current(inode); 14962306a36Sopenharmony_ci inode->i_private = data; 15062306a36Sopenharmony_ci if (S_ISDIR(mode)) { 15162306a36Sopenharmony_ci inode->i_op = &simple_dir_inode_operations; 15262306a36Sopenharmony_ci inode->i_fop = &simple_dir_operations; 15362306a36Sopenharmony_ci inc_nlink(inode); 15462306a36Sopenharmony_ci inc_nlink(dir); 15562306a36Sopenharmony_ci } else if (S_ISLNK(mode)) { 15662306a36Sopenharmony_ci inode->i_op = iops ? iops : &simple_symlink_inode_operations; 15762306a36Sopenharmony_ci inode->i_link = data; 15862306a36Sopenharmony_ci } else { 15962306a36Sopenharmony_ci inode->i_fop = fops; 16062306a36Sopenharmony_ci } 16162306a36Sopenharmony_ci d_instantiate(dentry, inode); 16262306a36Sopenharmony_ci dget(dentry); 16362306a36Sopenharmony_ci inode_unlock(dir); 16462306a36Sopenharmony_ci return dentry; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ciout1: 16762306a36Sopenharmony_ci dput(dentry); 16862306a36Sopenharmony_ci dentry = ERR_PTR(error); 16962306a36Sopenharmony_ciout: 17062306a36Sopenharmony_ci inode_unlock(dir); 17162306a36Sopenharmony_ci simple_release_fs(&mount, &mount_count); 17262306a36Sopenharmony_ci return dentry; 17362306a36Sopenharmony_ci} 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci/** 17662306a36Sopenharmony_ci * securityfs_create_file - create a file in the securityfs filesystem 17762306a36Sopenharmony_ci * 17862306a36Sopenharmony_ci * @name: a pointer to a string containing the name of the file to create. 17962306a36Sopenharmony_ci * @mode: the permission that the file should have 18062306a36Sopenharmony_ci * @parent: a pointer to the parent dentry for this file. This should be a 18162306a36Sopenharmony_ci * directory dentry if set. If this parameter is %NULL, then the 18262306a36Sopenharmony_ci * file will be created in the root of the securityfs filesystem. 18362306a36Sopenharmony_ci * @data: a pointer to something that the caller will want to get to later 18462306a36Sopenharmony_ci * on. The inode.i_private pointer will point to this value on 18562306a36Sopenharmony_ci * the open() call. 18662306a36Sopenharmony_ci * @fops: a pointer to a struct file_operations that should be used for 18762306a36Sopenharmony_ci * this file. 18862306a36Sopenharmony_ci * 18962306a36Sopenharmony_ci * This function creates a file in securityfs with the given @name. 19062306a36Sopenharmony_ci * 19162306a36Sopenharmony_ci * This function returns a pointer to a dentry if it succeeds. This 19262306a36Sopenharmony_ci * pointer must be passed to the securityfs_remove() function when the file is 19362306a36Sopenharmony_ci * to be removed (no automatic cleanup happens if your module is unloaded, 19462306a36Sopenharmony_ci * you are responsible here). If an error occurs, the function will return 19562306a36Sopenharmony_ci * the error value (via ERR_PTR). 19662306a36Sopenharmony_ci * 19762306a36Sopenharmony_ci * If securityfs is not enabled in the kernel, the value %-ENODEV is 19862306a36Sopenharmony_ci * returned. 19962306a36Sopenharmony_ci */ 20062306a36Sopenharmony_cistruct dentry *securityfs_create_file(const char *name, umode_t mode, 20162306a36Sopenharmony_ci struct dentry *parent, void *data, 20262306a36Sopenharmony_ci const struct file_operations *fops) 20362306a36Sopenharmony_ci{ 20462306a36Sopenharmony_ci return securityfs_create_dentry(name, mode, parent, data, fops, NULL); 20562306a36Sopenharmony_ci} 20662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(securityfs_create_file); 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci/** 20962306a36Sopenharmony_ci * securityfs_create_dir - create a directory in the securityfs filesystem 21062306a36Sopenharmony_ci * 21162306a36Sopenharmony_ci * @name: a pointer to a string containing the name of the directory to 21262306a36Sopenharmony_ci * create. 21362306a36Sopenharmony_ci * @parent: a pointer to the parent dentry for this file. This should be a 21462306a36Sopenharmony_ci * directory dentry if set. If this parameter is %NULL, then the 21562306a36Sopenharmony_ci * directory will be created in the root of the securityfs filesystem. 21662306a36Sopenharmony_ci * 21762306a36Sopenharmony_ci * This function creates a directory in securityfs with the given @name. 21862306a36Sopenharmony_ci * 21962306a36Sopenharmony_ci * This function returns a pointer to a dentry if it succeeds. This 22062306a36Sopenharmony_ci * pointer must be passed to the securityfs_remove() function when the file is 22162306a36Sopenharmony_ci * to be removed (no automatic cleanup happens if your module is unloaded, 22262306a36Sopenharmony_ci * you are responsible here). If an error occurs, the function will return 22362306a36Sopenharmony_ci * the error value (via ERR_PTR). 22462306a36Sopenharmony_ci * 22562306a36Sopenharmony_ci * If securityfs is not enabled in the kernel, the value %-ENODEV is 22662306a36Sopenharmony_ci * returned. 22762306a36Sopenharmony_ci */ 22862306a36Sopenharmony_cistruct dentry *securityfs_create_dir(const char *name, struct dentry *parent) 22962306a36Sopenharmony_ci{ 23062306a36Sopenharmony_ci return securityfs_create_file(name, S_IFDIR | 0755, parent, NULL, NULL); 23162306a36Sopenharmony_ci} 23262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(securityfs_create_dir); 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci/** 23562306a36Sopenharmony_ci * securityfs_create_symlink - create a symlink in the securityfs filesystem 23662306a36Sopenharmony_ci * 23762306a36Sopenharmony_ci * @name: a pointer to a string containing the name of the symlink to 23862306a36Sopenharmony_ci * create. 23962306a36Sopenharmony_ci * @parent: a pointer to the parent dentry for the symlink. This should be a 24062306a36Sopenharmony_ci * directory dentry if set. If this parameter is %NULL, then the 24162306a36Sopenharmony_ci * directory will be created in the root of the securityfs filesystem. 24262306a36Sopenharmony_ci * @target: a pointer to a string containing the name of the symlink's target. 24362306a36Sopenharmony_ci * If this parameter is %NULL, then the @iops parameter needs to be 24462306a36Sopenharmony_ci * setup to handle .readlink and .get_link inode_operations. 24562306a36Sopenharmony_ci * @iops: a pointer to the struct inode_operations to use for the symlink. If 24662306a36Sopenharmony_ci * this parameter is %NULL, then the default simple_symlink_inode 24762306a36Sopenharmony_ci * operations will be used. 24862306a36Sopenharmony_ci * 24962306a36Sopenharmony_ci * This function creates a symlink in securityfs with the given @name. 25062306a36Sopenharmony_ci * 25162306a36Sopenharmony_ci * This function returns a pointer to a dentry if it succeeds. This 25262306a36Sopenharmony_ci * pointer must be passed to the securityfs_remove() function when the file is 25362306a36Sopenharmony_ci * to be removed (no automatic cleanup happens if your module is unloaded, 25462306a36Sopenharmony_ci * you are responsible here). If an error occurs, the function will return 25562306a36Sopenharmony_ci * the error value (via ERR_PTR). 25662306a36Sopenharmony_ci * 25762306a36Sopenharmony_ci * If securityfs is not enabled in the kernel, the value %-ENODEV is 25862306a36Sopenharmony_ci * returned. 25962306a36Sopenharmony_ci */ 26062306a36Sopenharmony_cistruct dentry *securityfs_create_symlink(const char *name, 26162306a36Sopenharmony_ci struct dentry *parent, 26262306a36Sopenharmony_ci const char *target, 26362306a36Sopenharmony_ci const struct inode_operations *iops) 26462306a36Sopenharmony_ci{ 26562306a36Sopenharmony_ci struct dentry *dent; 26662306a36Sopenharmony_ci char *link = NULL; 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci if (target) { 26962306a36Sopenharmony_ci link = kstrdup(target, GFP_KERNEL); 27062306a36Sopenharmony_ci if (!link) 27162306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 27262306a36Sopenharmony_ci } 27362306a36Sopenharmony_ci dent = securityfs_create_dentry(name, S_IFLNK | 0444, parent, 27462306a36Sopenharmony_ci link, NULL, iops); 27562306a36Sopenharmony_ci if (IS_ERR(dent)) 27662306a36Sopenharmony_ci kfree(link); 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci return dent; 27962306a36Sopenharmony_ci} 28062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(securityfs_create_symlink); 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_ci/** 28362306a36Sopenharmony_ci * securityfs_remove - removes a file or directory from the securityfs filesystem 28462306a36Sopenharmony_ci * 28562306a36Sopenharmony_ci * @dentry: a pointer to a the dentry of the file or directory to be removed. 28662306a36Sopenharmony_ci * 28762306a36Sopenharmony_ci * This function removes a file or directory in securityfs that was previously 28862306a36Sopenharmony_ci * created with a call to another securityfs function (like 28962306a36Sopenharmony_ci * securityfs_create_file() or variants thereof.) 29062306a36Sopenharmony_ci * 29162306a36Sopenharmony_ci * This function is required to be called in order for the file to be 29262306a36Sopenharmony_ci * removed. No automatic cleanup of files will happen when a module is 29362306a36Sopenharmony_ci * removed; you are responsible here. 29462306a36Sopenharmony_ci */ 29562306a36Sopenharmony_civoid securityfs_remove(struct dentry *dentry) 29662306a36Sopenharmony_ci{ 29762306a36Sopenharmony_ci struct inode *dir; 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci if (!dentry || IS_ERR(dentry)) 30062306a36Sopenharmony_ci return; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci dir = d_inode(dentry->d_parent); 30362306a36Sopenharmony_ci inode_lock(dir); 30462306a36Sopenharmony_ci if (simple_positive(dentry)) { 30562306a36Sopenharmony_ci if (d_is_dir(dentry)) 30662306a36Sopenharmony_ci simple_rmdir(dir, dentry); 30762306a36Sopenharmony_ci else 30862306a36Sopenharmony_ci simple_unlink(dir, dentry); 30962306a36Sopenharmony_ci dput(dentry); 31062306a36Sopenharmony_ci } 31162306a36Sopenharmony_ci inode_unlock(dir); 31262306a36Sopenharmony_ci simple_release_fs(&mount, &mount_count); 31362306a36Sopenharmony_ci} 31462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(securityfs_remove); 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci#ifdef CONFIG_SECURITY 31762306a36Sopenharmony_cistatic struct dentry *lsm_dentry; 31862306a36Sopenharmony_cistatic ssize_t lsm_read(struct file *filp, char __user *buf, size_t count, 31962306a36Sopenharmony_ci loff_t *ppos) 32062306a36Sopenharmony_ci{ 32162306a36Sopenharmony_ci return simple_read_from_buffer(buf, count, ppos, lsm_names, 32262306a36Sopenharmony_ci strlen(lsm_names)); 32362306a36Sopenharmony_ci} 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_cistatic const struct file_operations lsm_ops = { 32662306a36Sopenharmony_ci .read = lsm_read, 32762306a36Sopenharmony_ci .llseek = generic_file_llseek, 32862306a36Sopenharmony_ci}; 32962306a36Sopenharmony_ci#endif 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_cistatic int __init securityfs_init(void) 33262306a36Sopenharmony_ci{ 33362306a36Sopenharmony_ci int retval; 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci retval = sysfs_create_mount_point(kernel_kobj, "security"); 33662306a36Sopenharmony_ci if (retval) 33762306a36Sopenharmony_ci return retval; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci retval = register_filesystem(&fs_type); 34062306a36Sopenharmony_ci if (retval) { 34162306a36Sopenharmony_ci sysfs_remove_mount_point(kernel_kobj, "security"); 34262306a36Sopenharmony_ci return retval; 34362306a36Sopenharmony_ci } 34462306a36Sopenharmony_ci#ifdef CONFIG_SECURITY 34562306a36Sopenharmony_ci lsm_dentry = securityfs_create_file("lsm", 0444, NULL, NULL, 34662306a36Sopenharmony_ci &lsm_ops); 34762306a36Sopenharmony_ci#endif 34862306a36Sopenharmony_ci return 0; 34962306a36Sopenharmony_ci} 35062306a36Sopenharmony_cicore_initcall(securityfs_init); 351