[PATCH] add securityfs for all LSMs to use

Here's a small patch against 2.6.13-rc2 that adds securityfs, a virtual
fs that all LSMs can use instead of creating their own. The fs should
be mounted at /sys/kernel/security, and the fs creates that mount point.
This will make the LSB people happy that we aren't creating a new
/my_lsm_fs directory in the root for every different LSM.

It has changed a bit since the last version, thanks to comments from
Mike Waychison.

Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Signed-off-by: Chris Wright <chrisw@osdl.org>

authored by Greg KH and committed by Chris Wright b67dbf9d 043d0516

+353 -1
+5
include/linux/security.h
··· 1983 extern int unregister_security (struct security_operations *ops); 1984 extern int mod_reg_security (const char *name, struct security_operations *ops); 1985 extern int mod_unreg_security (const char *name, struct security_operations *ops); 1986 1987 1988 #else /* CONFIG_SECURITY */
··· 1983 extern int unregister_security (struct security_operations *ops); 1984 extern int mod_reg_security (const char *name, struct security_operations *ops); 1985 extern int mod_unreg_security (const char *name, struct security_operations *ops); 1986 + extern struct dentry *securityfs_create_file(const char *name, mode_t mode, 1987 + struct dentry *parent, void *data, 1988 + struct file_operations *fops); 1989 + extern struct dentry *securityfs_create_dir(const char *name, struct dentry *parent); 1990 + extern void securityfs_remove(struct dentry *dentry); 1991 1992 1993 #else /* CONFIG_SECURITY */
+1 -1
security/Makefile
··· 11 endif 12 13 # Object file lists 14 - obj-$(CONFIG_SECURITY) += security.o dummy.o 15 # Must precede capability.o in order to stack properly. 16 obj-$(CONFIG_SECURITY_SELINUX) += selinux/built-in.o 17 obj-$(CONFIG_SECURITY_CAPABILITIES) += commoncap.o capability.o
··· 11 endif 12 13 # Object file lists 14 + obj-$(CONFIG_SECURITY) += security.o dummy.o inode.o 15 # Must precede capability.o in order to stack properly. 16 obj-$(CONFIG_SECURITY_SELINUX) += selinux/built-in.o 17 obj-$(CONFIG_SECURITY_CAPABILITIES) += commoncap.o capability.o
+347
security/inode.c
···
··· 1 + /* 2 + * inode.c - securityfs 3 + * 4 + * Copyright (C) 2005 Greg Kroah-Hartman <gregkh@suse.de> 5 + * 6 + * This program is free software; you can redistribute it and/or 7 + * modify it under the terms of the GNU General Public License version 8 + * 2 as published by the Free Software Foundation. 9 + * 10 + * Based on fs/debugfs/inode.c which had the following copyright notice: 11 + * Copyright (C) 2004 Greg Kroah-Hartman <greg@kroah.com> 12 + * Copyright (C) 2004 IBM Inc. 13 + */ 14 + 15 + /* #define DEBUG */ 16 + #include <linux/config.h> 17 + #include <linux/module.h> 18 + #include <linux/fs.h> 19 + #include <linux/mount.h> 20 + #include <linux/pagemap.h> 21 + #include <linux/init.h> 22 + #include <linux/namei.h> 23 + #include <linux/security.h> 24 + 25 + #define SECURITYFS_MAGIC 0x73636673 26 + 27 + static struct vfsmount *mount; 28 + static int mount_count; 29 + 30 + /* 31 + * TODO: 32 + * I think I can get rid of these default_file_ops, but not quite sure... 33 + */ 34 + static ssize_t default_read_file(struct file *file, char __user *buf, 35 + size_t count, loff_t *ppos) 36 + { 37 + return 0; 38 + } 39 + 40 + static ssize_t default_write_file(struct file *file, const char __user *buf, 41 + size_t count, loff_t *ppos) 42 + { 43 + return count; 44 + } 45 + 46 + static int default_open(struct inode *inode, struct file *file) 47 + { 48 + if (inode->u.generic_ip) 49 + file->private_data = inode->u.generic_ip; 50 + 51 + return 0; 52 + } 53 + 54 + static struct file_operations default_file_ops = { 55 + .read = default_read_file, 56 + .write = default_write_file, 57 + .open = default_open, 58 + }; 59 + 60 + static struct inode *get_inode(struct super_block *sb, int mode, dev_t dev) 61 + { 62 + struct inode *inode = new_inode(sb); 63 + 64 + if (inode) { 65 + inode->i_mode = mode; 66 + inode->i_uid = 0; 67 + inode->i_gid = 0; 68 + inode->i_blksize = PAGE_CACHE_SIZE; 69 + inode->i_blocks = 0; 70 + inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; 71 + switch (mode & S_IFMT) { 72 + default: 73 + init_special_inode(inode, mode, dev); 74 + break; 75 + case S_IFREG: 76 + inode->i_fop = &default_file_ops; 77 + break; 78 + case S_IFDIR: 79 + inode->i_op = &simple_dir_inode_operations; 80 + inode->i_fop = &simple_dir_operations; 81 + 82 + /* directory inodes start off with i_nlink == 2 (for "." entry) */ 83 + inode->i_nlink++; 84 + break; 85 + } 86 + } 87 + return inode; 88 + } 89 + 90 + /* SMP-safe */ 91 + static int mknod(struct inode *dir, struct dentry *dentry, 92 + int mode, dev_t dev) 93 + { 94 + struct inode *inode; 95 + int error = -EPERM; 96 + 97 + if (dentry->d_inode) 98 + return -EEXIST; 99 + 100 + inode = get_inode(dir->i_sb, mode, dev); 101 + if (inode) { 102 + d_instantiate(dentry, inode); 103 + dget(dentry); 104 + error = 0; 105 + } 106 + return error; 107 + } 108 + 109 + static int mkdir(struct inode *dir, struct dentry *dentry, int mode) 110 + { 111 + int res; 112 + 113 + mode = (mode & (S_IRWXUGO | S_ISVTX)) | S_IFDIR; 114 + res = mknod(dir, dentry, mode, 0); 115 + if (!res) 116 + dir->i_nlink++; 117 + return res; 118 + } 119 + 120 + static int create(struct inode *dir, struct dentry *dentry, int mode) 121 + { 122 + mode = (mode & S_IALLUGO) | S_IFREG; 123 + return mknod(dir, dentry, mode, 0); 124 + } 125 + 126 + static inline int positive(struct dentry *dentry) 127 + { 128 + return dentry->d_inode && !d_unhashed(dentry); 129 + } 130 + 131 + static int fill_super(struct super_block *sb, void *data, int silent) 132 + { 133 + static struct tree_descr files[] = {{""}}; 134 + 135 + return simple_fill_super(sb, SECURITYFS_MAGIC, files); 136 + } 137 + 138 + static struct super_block *get_sb(struct file_system_type *fs_type, 139 + int flags, const char *dev_name, 140 + void *data) 141 + { 142 + return get_sb_single(fs_type, flags, data, fill_super); 143 + } 144 + 145 + static struct file_system_type fs_type = { 146 + .owner = THIS_MODULE, 147 + .name = "securityfs", 148 + .get_sb = get_sb, 149 + .kill_sb = kill_litter_super, 150 + }; 151 + 152 + static int create_by_name(const char *name, mode_t mode, 153 + struct dentry *parent, 154 + struct dentry **dentry) 155 + { 156 + int error = 0; 157 + 158 + *dentry = NULL; 159 + 160 + /* If the parent is not specified, we create it in the root. 161 + * We need the root dentry to do this, which is in the super 162 + * block. A pointer to that is in the struct vfsmount that we 163 + * have around. 164 + */ 165 + if (!parent ) { 166 + if (mount && mount->mnt_sb) { 167 + parent = mount->mnt_sb->s_root; 168 + } 169 + } 170 + if (!parent) { 171 + pr_debug("securityfs: Ah! can not find a parent!\n"); 172 + return -EFAULT; 173 + } 174 + 175 + down(&parent->d_inode->i_sem); 176 + *dentry = lookup_one_len(name, parent, strlen(name)); 177 + if (!IS_ERR(dentry)) { 178 + if ((mode & S_IFMT) == S_IFDIR) 179 + error = mkdir(parent->d_inode, *dentry, mode); 180 + else 181 + error = create(parent->d_inode, *dentry, mode); 182 + } else 183 + error = PTR_ERR(dentry); 184 + up(&parent->d_inode->i_sem); 185 + 186 + return error; 187 + } 188 + 189 + /** 190 + * securityfs_create_file - create a file in the securityfs filesystem 191 + * 192 + * @name: a pointer to a string containing the name of the file to create. 193 + * @mode: the permission that the file should have 194 + * @parent: a pointer to the parent dentry for this file. This should be a 195 + * directory dentry if set. If this paramater is NULL, then the 196 + * file will be created in the root of the securityfs filesystem. 197 + * @data: a pointer to something that the caller will want to get to later 198 + * on. The inode.u.generic_ip pointer will point to this value on 199 + * the open() call. 200 + * @fops: a pointer to a struct file_operations that should be used for 201 + * this file. 202 + * 203 + * This is the basic "create a file" function for securityfs. It allows for a 204 + * wide range of flexibility in createing a file, or a directory (if you 205 + * want to create a directory, the securityfs_create_dir() function is 206 + * recommended to be used instead.) 207 + * 208 + * This function will return a pointer to a dentry if it succeeds. This 209 + * pointer must be passed to the securityfs_remove() function when the file is 210 + * to be removed (no automatic cleanup happens if your module is unloaded, 211 + * you are responsible here.) If an error occurs, NULL will be returned. 212 + * 213 + * If securityfs is not enabled in the kernel, the value -ENODEV will be 214 + * returned. It is not wise to check for this value, but rather, check for 215 + * NULL or !NULL instead as to eliminate the need for #ifdef in the calling 216 + * code. 217 + */ 218 + struct dentry *securityfs_create_file(const char *name, mode_t mode, 219 + struct dentry *parent, void *data, 220 + struct file_operations *fops) 221 + { 222 + struct dentry *dentry = NULL; 223 + int error; 224 + 225 + pr_debug("securityfs: creating file '%s'\n",name); 226 + 227 + error = simple_pin_fs("securityfs", &mount, &mount_count); 228 + if (error) { 229 + dentry = ERR_PTR(error); 230 + goto exit; 231 + } 232 + 233 + error = create_by_name(name, mode, parent, &dentry); 234 + if (error) { 235 + dentry = ERR_PTR(error); 236 + simple_release_fs(&mount, &mount_count); 237 + goto exit; 238 + } 239 + 240 + if (dentry->d_inode) { 241 + if (fops) 242 + dentry->d_inode->i_fop = fops; 243 + if (data) 244 + dentry->d_inode->u.generic_ip = data; 245 + } 246 + exit: 247 + return dentry; 248 + } 249 + EXPORT_SYMBOL_GPL(securityfs_create_file); 250 + 251 + /** 252 + * securityfs_create_dir - create a directory in the securityfs filesystem 253 + * 254 + * @name: a pointer to a string containing the name of the directory to 255 + * create. 256 + * @parent: a pointer to the parent dentry for this file. This should be a 257 + * directory dentry if set. If this paramater is NULL, then the 258 + * directory will be created in the root of the securityfs filesystem. 259 + * 260 + * This function creates a directory in securityfs with the given name. 261 + * 262 + * This function will return a pointer to a dentry if it succeeds. This 263 + * pointer must be passed to the securityfs_remove() function when the file is 264 + * to be removed (no automatic cleanup happens if your module is unloaded, 265 + * you are responsible here.) If an error occurs, NULL will be returned. 266 + * 267 + * If securityfs is not enabled in the kernel, the value -ENODEV will be 268 + * returned. It is not wise to check for this value, but rather, check for 269 + * NULL or !NULL instead as to eliminate the need for #ifdef in the calling 270 + * code. 271 + */ 272 + struct dentry *securityfs_create_dir(const char *name, struct dentry *parent) 273 + { 274 + return securityfs_create_file(name, 275 + S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO, 276 + parent, NULL, NULL); 277 + } 278 + EXPORT_SYMBOL_GPL(securityfs_create_dir); 279 + 280 + /** 281 + * securityfs_remove - removes a file or directory from the securityfs filesystem 282 + * 283 + * @dentry: a pointer to a the dentry of the file or directory to be 284 + * removed. 285 + * 286 + * This function removes a file or directory in securityfs that was previously 287 + * created with a call to another securityfs function (like 288 + * securityfs_create_file() or variants thereof.) 289 + * 290 + * This function is required to be called in order for the file to be 291 + * removed, no automatic cleanup of files will happen when a module is 292 + * removed, you are responsible here. 293 + */ 294 + void securityfs_remove(struct dentry *dentry) 295 + { 296 + struct dentry *parent; 297 + 298 + if (!dentry) 299 + return; 300 + 301 + parent = dentry->d_parent; 302 + if (!parent || !parent->d_inode) 303 + return; 304 + 305 + down(&parent->d_inode->i_sem); 306 + if (positive(dentry)) { 307 + if (dentry->d_inode) { 308 + if (S_ISDIR(dentry->d_inode->i_mode)) 309 + simple_rmdir(parent->d_inode, dentry); 310 + else 311 + simple_unlink(parent->d_inode, dentry); 312 + dput(dentry); 313 + } 314 + } 315 + up(&parent->d_inode->i_sem); 316 + simple_release_fs(&mount, &mount_count); 317 + } 318 + EXPORT_SYMBOL_GPL(securityfs_remove); 319 + 320 + static decl_subsys(security, NULL, NULL); 321 + 322 + static int __init securityfs_init(void) 323 + { 324 + int retval; 325 + 326 + kset_set_kset_s(&security_subsys, kernel_subsys); 327 + retval = subsystem_register(&security_subsys); 328 + if (retval) 329 + return retval; 330 + 331 + retval = register_filesystem(&fs_type); 332 + if (retval) 333 + subsystem_unregister(&security_subsys); 334 + return retval; 335 + } 336 + 337 + static void __exit securityfs_exit(void) 338 + { 339 + simple_release_fs(&mount, &mount_count); 340 + unregister_filesystem(&fs_type); 341 + subsystem_unregister(&security_subsys); 342 + } 343 + 344 + core_initcall(securityfs_init); 345 + module_exit(securityfs_exit); 346 + MODULE_LICENSE("GPL"); 347 +