···35353636config SECURITY3737 bool "Enable different security models"3838+ depends on SYSFS3839 help3940 This allows you to choose different security modules to be4041 configured into your kernel.
+1-1
security/Makefile
···1111endif12121313# Object file lists1414-obj-$(CONFIG_SECURITY) += security.o dummy.o1414+obj-$(CONFIG_SECURITY) += security.o dummy.o inode.o1515# Must precede capability.o in order to stack properly.1616obj-$(CONFIG_SECURITY_SELINUX) += selinux/built-in.o1717obj-$(CONFIG_SECURITY_CAPABILITIES) += commoncap.o capability.o
+347
security/inode.c
···11+/*22+ * inode.c - securityfs33+ *44+ * Copyright (C) 2005 Greg Kroah-Hartman <gregkh@suse.de>55+ *66+ * This program is free software; you can redistribute it and/or77+ * modify it under the terms of the GNU General Public License version88+ * 2 as published by the Free Software Foundation.99+ *1010+ * Based on fs/debugfs/inode.c which had the following copyright notice:1111+ * Copyright (C) 2004 Greg Kroah-Hartman <greg@kroah.com>1212+ * Copyright (C) 2004 IBM Inc.1313+ */1414+1515+/* #define DEBUG */1616+#include <linux/config.h>1717+#include <linux/module.h>1818+#include <linux/fs.h>1919+#include <linux/mount.h>2020+#include <linux/pagemap.h>2121+#include <linux/init.h>2222+#include <linux/namei.h>2323+#include <linux/security.h>2424+2525+#define SECURITYFS_MAGIC 0x736366732626+2727+static struct vfsmount *mount;2828+static int mount_count;2929+3030+/*3131+ * TODO:3232+ * I think I can get rid of these default_file_ops, but not quite sure...3333+ */3434+static ssize_t default_read_file(struct file *file, char __user *buf,3535+ size_t count, loff_t *ppos)3636+{3737+ return 0;3838+}3939+4040+static ssize_t default_write_file(struct file *file, const char __user *buf,4141+ size_t count, loff_t *ppos)4242+{4343+ return count;4444+}4545+4646+static int default_open(struct inode *inode, struct file *file)4747+{4848+ if (inode->u.generic_ip)4949+ file->private_data = inode->u.generic_ip;5050+5151+ return 0;5252+}5353+5454+static struct file_operations default_file_ops = {5555+ .read = default_read_file,5656+ .write = default_write_file,5757+ .open = default_open,5858+};5959+6060+static struct inode *get_inode(struct super_block *sb, int mode, dev_t dev)6161+{6262+ struct inode *inode = new_inode(sb);6363+6464+ if (inode) {6565+ inode->i_mode = mode;6666+ inode->i_uid = 0;6767+ inode->i_gid = 0;6868+ inode->i_blksize = PAGE_CACHE_SIZE;6969+ inode->i_blocks = 0;7070+ inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;7171+ switch (mode & S_IFMT) {7272+ default:7373+ init_special_inode(inode, mode, dev);7474+ break;7575+ case S_IFREG:7676+ inode->i_fop = &default_file_ops;7777+ break;7878+ case S_IFDIR:7979+ inode->i_op = &simple_dir_inode_operations;8080+ inode->i_fop = &simple_dir_operations;8181+8282+ /* directory inodes start off with i_nlink == 2 (for "." entry) */8383+ inode->i_nlink++;8484+ break;8585+ }8686+ }8787+ return inode;8888+}8989+9090+/* SMP-safe */9191+static int mknod(struct inode *dir, struct dentry *dentry,9292+ int mode, dev_t dev)9393+{9494+ struct inode *inode;9595+ int error = -EPERM;9696+9797+ if (dentry->d_inode)9898+ return -EEXIST;9999+100100+ inode = get_inode(dir->i_sb, mode, dev);101101+ if (inode) {102102+ d_instantiate(dentry, inode);103103+ dget(dentry);104104+ error = 0;105105+ }106106+ return error;107107+}108108+109109+static int mkdir(struct inode *dir, struct dentry *dentry, int mode)110110+{111111+ int res;112112+113113+ mode = (mode & (S_IRWXUGO | S_ISVTX)) | S_IFDIR;114114+ res = mknod(dir, dentry, mode, 0);115115+ if (!res)116116+ dir->i_nlink++;117117+ return res;118118+}119119+120120+static int create(struct inode *dir, struct dentry *dentry, int mode)121121+{122122+ mode = (mode & S_IALLUGO) | S_IFREG;123123+ return mknod(dir, dentry, mode, 0);124124+}125125+126126+static inline int positive(struct dentry *dentry)127127+{128128+ return dentry->d_inode && !d_unhashed(dentry);129129+}130130+131131+static int fill_super(struct super_block *sb, void *data, int silent)132132+{133133+ static struct tree_descr files[] = {{""}};134134+135135+ return simple_fill_super(sb, SECURITYFS_MAGIC, files);136136+}137137+138138+static struct super_block *get_sb(struct file_system_type *fs_type,139139+ int flags, const char *dev_name,140140+ void *data)141141+{142142+ return get_sb_single(fs_type, flags, data, fill_super);143143+}144144+145145+static struct file_system_type fs_type = {146146+ .owner = THIS_MODULE,147147+ .name = "securityfs",148148+ .get_sb = get_sb,149149+ .kill_sb = kill_litter_super,150150+};151151+152152+static int create_by_name(const char *name, mode_t mode,153153+ struct dentry *parent,154154+ struct dentry **dentry)155155+{156156+ int error = 0;157157+158158+ *dentry = NULL;159159+160160+ /* If the parent is not specified, we create it in the root.161161+ * We need the root dentry to do this, which is in the super162162+ * block. A pointer to that is in the struct vfsmount that we163163+ * have around.164164+ */165165+ if (!parent ) {166166+ if (mount && mount->mnt_sb) {167167+ parent = mount->mnt_sb->s_root;168168+ }169169+ }170170+ if (!parent) {171171+ pr_debug("securityfs: Ah! can not find a parent!\n");172172+ return -EFAULT;173173+ }174174+175175+ down(&parent->d_inode->i_sem);176176+ *dentry = lookup_one_len(name, parent, strlen(name));177177+ if (!IS_ERR(dentry)) {178178+ if ((mode & S_IFMT) == S_IFDIR)179179+ error = mkdir(parent->d_inode, *dentry, mode);180180+ else181181+ error = create(parent->d_inode, *dentry, mode);182182+ } else183183+ error = PTR_ERR(dentry);184184+ up(&parent->d_inode->i_sem);185185+186186+ return error;187187+}188188+189189+/**190190+ * securityfs_create_file - create a file in the securityfs filesystem191191+ *192192+ * @name: a pointer to a string containing the name of the file to create.193193+ * @mode: the permission that the file should have194194+ * @parent: a pointer to the parent dentry for this file. This should be a195195+ * directory dentry if set. If this paramater is NULL, then the196196+ * file will be created in the root of the securityfs filesystem.197197+ * @data: a pointer to something that the caller will want to get to later198198+ * on. The inode.u.generic_ip pointer will point to this value on199199+ * the open() call.200200+ * @fops: a pointer to a struct file_operations that should be used for201201+ * this file.202202+ *203203+ * This is the basic "create a file" function for securityfs. It allows for a204204+ * wide range of flexibility in createing a file, or a directory (if you205205+ * want to create a directory, the securityfs_create_dir() function is206206+ * recommended to be used instead.)207207+ *208208+ * This function will return a pointer to a dentry if it succeeds. This209209+ * pointer must be passed to the securityfs_remove() function when the file is210210+ * to be removed (no automatic cleanup happens if your module is unloaded,211211+ * you are responsible here.) If an error occurs, NULL will be returned.212212+ *213213+ * If securityfs is not enabled in the kernel, the value -ENODEV will be214214+ * returned. It is not wise to check for this value, but rather, check for215215+ * NULL or !NULL instead as to eliminate the need for #ifdef in the calling216216+ * code.217217+ */218218+struct dentry *securityfs_create_file(const char *name, mode_t mode,219219+ struct dentry *parent, void *data,220220+ struct file_operations *fops)221221+{222222+ struct dentry *dentry = NULL;223223+ int error;224224+225225+ pr_debug("securityfs: creating file '%s'\n",name);226226+227227+ error = simple_pin_fs("securityfs", &mount, &mount_count);228228+ if (error) {229229+ dentry = ERR_PTR(error);230230+ goto exit;231231+ }232232+233233+ error = create_by_name(name, mode, parent, &dentry);234234+ if (error) {235235+ dentry = ERR_PTR(error);236236+ simple_release_fs(&mount, &mount_count);237237+ goto exit;238238+ }239239+240240+ if (dentry->d_inode) {241241+ if (fops)242242+ dentry->d_inode->i_fop = fops;243243+ if (data)244244+ dentry->d_inode->u.generic_ip = data;245245+ }246246+exit:247247+ return dentry;248248+}249249+EXPORT_SYMBOL_GPL(securityfs_create_file);250250+251251+/**252252+ * securityfs_create_dir - create a directory in the securityfs filesystem253253+ *254254+ * @name: a pointer to a string containing the name of the directory to255255+ * create.256256+ * @parent: a pointer to the parent dentry for this file. This should be a257257+ * directory dentry if set. If this paramater is NULL, then the258258+ * directory will be created in the root of the securityfs filesystem.259259+ *260260+ * This function creates a directory in securityfs with the given name.261261+ *262262+ * This function will return a pointer to a dentry if it succeeds. This263263+ * pointer must be passed to the securityfs_remove() function when the file is264264+ * to be removed (no automatic cleanup happens if your module is unloaded,265265+ * you are responsible here.) If an error occurs, NULL will be returned.266266+ *267267+ * If securityfs is not enabled in the kernel, the value -ENODEV will be268268+ * returned. It is not wise to check for this value, but rather, check for269269+ * NULL or !NULL instead as to eliminate the need for #ifdef in the calling270270+ * code.271271+ */272272+struct dentry *securityfs_create_dir(const char *name, struct dentry *parent)273273+{274274+ return securityfs_create_file(name,275275+ S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO,276276+ parent, NULL, NULL);277277+}278278+EXPORT_SYMBOL_GPL(securityfs_create_dir);279279+280280+/**281281+ * securityfs_remove - removes a file or directory from the securityfs filesystem282282+ *283283+ * @dentry: a pointer to a the dentry of the file or directory to be284284+ * removed.285285+ *286286+ * This function removes a file or directory in securityfs that was previously287287+ * created with a call to another securityfs function (like288288+ * securityfs_create_file() or variants thereof.)289289+ *290290+ * This function is required to be called in order for the file to be291291+ * removed, no automatic cleanup of files will happen when a module is292292+ * removed, you are responsible here.293293+ */294294+void securityfs_remove(struct dentry *dentry)295295+{296296+ struct dentry *parent;297297+298298+ if (!dentry)299299+ return;300300+301301+ parent = dentry->d_parent;302302+ if (!parent || !parent->d_inode)303303+ return;304304+305305+ down(&parent->d_inode->i_sem);306306+ if (positive(dentry)) {307307+ if (dentry->d_inode) {308308+ if (S_ISDIR(dentry->d_inode->i_mode))309309+ simple_rmdir(parent->d_inode, dentry);310310+ else311311+ simple_unlink(parent->d_inode, dentry);312312+ dput(dentry);313313+ }314314+ }315315+ up(&parent->d_inode->i_sem);316316+ simple_release_fs(&mount, &mount_count);317317+}318318+EXPORT_SYMBOL_GPL(securityfs_remove);319319+320320+static decl_subsys(security, NULL, NULL);321321+322322+static int __init securityfs_init(void)323323+{324324+ int retval;325325+326326+ kset_set_kset_s(&security_subsys, kernel_subsys);327327+ retval = subsystem_register(&security_subsys);328328+ if (retval)329329+ return retval;330330+331331+ retval = register_filesystem(&fs_type);332332+ if (retval)333333+ subsystem_unregister(&security_subsys);334334+ return retval;335335+}336336+337337+static void __exit securityfs_exit(void)338338+{339339+ simple_release_fs(&mount, &mount_count);340340+ unregister_filesystem(&fs_type);341341+ subsystem_unregister(&security_subsys);342342+}343343+344344+core_initcall(securityfs_init);345345+module_exit(securityfs_exit);346346+MODULE_LICENSE("GPL");347347+
+70-158
security/seclvl.c
···119119 } while (0)120120121121/**122122- * kobject stuff123123- */124124-125125-struct subsystem seclvl_subsys;126126-127127-struct seclvl_obj {128128- char *name;129129- struct list_head slot_list;130130- struct kobject kobj;131131-};132132-133133-/**134134- * There is a seclvl_attribute struct for each file in sysfs.135135- *136136- * In our case, we have one of these structs for "passwd" and another137137- * for "seclvl".138138- */139139-struct seclvl_attribute {140140- struct attribute attr;141141- ssize_t(*show) (struct seclvl_obj *, char *);142142- ssize_t(*store) (struct seclvl_obj *, const char *, size_t);143143-};144144-145145-/**146146- * When this function is called, one of the files in sysfs is being147147- * written to. attribute->store is a function pointer to whatever the148148- * struct seclvl_attribute store function pointer points to. It is149149- * unique for "passwd" and "seclvl".150150- */151151-static ssize_t152152-seclvl_attr_store(struct kobject *kobj,153153- struct attribute *attr, const char *buf, size_t len)154154-{155155- struct seclvl_obj *obj = container_of(kobj, struct seclvl_obj, kobj);156156- struct seclvl_attribute *attribute =157157- container_of(attr, struct seclvl_attribute, attr);158158- return attribute->store ? attribute->store(obj, buf, len) : -EIO;159159-}160160-161161-static ssize_t162162-seclvl_attr_show(struct kobject *kobj, struct attribute *attr, char *buf)163163-{164164- struct seclvl_obj *obj = container_of(kobj, struct seclvl_obj, kobj);165165- struct seclvl_attribute *attribute =166166- container_of(attr, struct seclvl_attribute, attr);167167- return attribute->show ? attribute->show(obj, buf) : -EIO;168168-}169169-170170-/**171171- * Callback function pointers for show and store172172- */173173-static struct sysfs_ops seclvlfs_sysfs_ops = {174174- .show = seclvl_attr_show,175175- .store = seclvl_attr_store,176176-};177177-178178-static struct kobj_type seclvl_ktype = {179179- .sysfs_ops = &seclvlfs_sysfs_ops180180-};181181-182182-decl_subsys(seclvl, &seclvl_ktype, NULL);183183-184184-/**185122 * The actual security level. Ranges between -1 and 2 inclusive.186123 */187124static int seclvl;···150213}151214152215/**153153- * Called whenever the user reads the sysfs handle to this kernel154154- * object155155- */156156-static ssize_t seclvl_read_file(struct seclvl_obj *obj, char *buff)157157-{158158- return snprintf(buff, PAGE_SIZE, "%d\n", seclvl);159159-}160160-161161-/**162216 * security level advancement rules:163217 * Valid levels are -1 through 2, inclusive.164218 * From -1, stuck. [ in case compiled into kernel ]165219 * From 0 or above, can only increment.166220 */167167-static int do_seclvl_advance(int newlvl)221221+static void do_seclvl_advance(void *data, u64 val)168222{169169- if (newlvl <= seclvl) {170170- seclvl_printk(1, KERN_WARNING, "Cannot advance to seclvl "171171- "[%d]\n", newlvl);172172- return -EINVAL;173173- }223223+ int ret;224224+ int newlvl = (int)val;225225+226226+ ret = seclvl_sanity(newlvl);227227+ if (ret)228228+ return;229229+174230 if (newlvl > 2) {175231 seclvl_printk(1, KERN_WARNING, "Cannot advance to seclvl "176232 "[%d]\n", newlvl);177177- return -EINVAL;233233+ return;178234 }179235 if (seclvl == -1) {180236 seclvl_printk(1, KERN_WARNING, "Not allowed to advance to "181237 "seclvl [%d]\n", seclvl);182182- return -EPERM;238238+ return;183239 }184184- seclvl = newlvl;185185- return 0;240240+ seclvl = newlvl; /* would it be more "correct" to set *data? */241241+ return;186242}187243188188-/**189189- * Called whenever the user writes to the sysfs handle to this kernel190190- * object (seclvl/seclvl). It expects a single-digit number.191191- */192192-static ssize_t193193-seclvl_write_file(struct seclvl_obj *obj, const char *buff, size_t count)244244+static u64 seclvl_int_get(void *data)194245{195195- unsigned long val;196196- if (count > 2 || (count == 2 && buff[1] != '\n')) {197197- seclvl_printk(1, KERN_WARNING, "Invalid value passed to "198198- "seclvl: [%s]\n", buff);199199- return -EINVAL;200200- }201201- val = buff[0] - 48;202202- if (seclvl_sanity(val)) {203203- seclvl_printk(1, KERN_WARNING, "Illegal secure level "204204- "requested: [%d]\n", (int)val);205205- return -EPERM;206206- }207207- if (do_seclvl_advance(val)) {208208- seclvl_printk(0, KERN_ERR, "Failure advancing security level "209209- "to %lu\n", val);210210- }211211- return count;246246+ return *(int *)data;212247}213248214214-/* Generate sysfs_attr_seclvl */215215-static struct seclvl_attribute sysfs_attr_seclvl =216216-__ATTR(seclvl, (S_IFREG | S_IRUGO | S_IWUSR), seclvl_read_file,217217- seclvl_write_file);249249+DEFINE_SIMPLE_ATTRIBUTE(seclvl_file_ops, seclvl_int_get, do_seclvl_advance, "%lld\n");218250219251static unsigned char hashedPassword[SHA1_DIGEST_SIZE];220220-221221-/**222222- * Called whenever the user reads the sysfs passwd handle.223223- */224224-static ssize_t seclvl_read_passwd(struct seclvl_obj *obj, char *buff)225225-{226226- /* So just how good *is* your password? :-) */227227- char tmp[3];228228- int i = 0;229229- buff[0] = '\0';230230- if (hideHash) {231231- /* Security through obscurity */232232- return 0;233233- }234234- while (i < SHA1_DIGEST_SIZE) {235235- snprintf(tmp, 3, "%02x", hashedPassword[i]);236236- strncat(buff, tmp, 2);237237- i++;238238- }239239- strcat(buff, "\n");240240- return ((SHA1_DIGEST_SIZE * 2) + 1);241241-}242252243253/**244254 * Converts a block of plaintext of into its SHA1 hashed value.···231347 * object. It hashes the password and compares the hashed results.232348 */233349static ssize_t234234-seclvl_write_passwd(struct seclvl_obj *obj, const char *buff, size_t count)350350+passwd_write_file(struct file * file, const char __user * buf,351351+ size_t count, loff_t *ppos)235352{236353 int i;237354 unsigned char tmp[SHA1_DIGEST_SIZE];355355+ char *page;238356 int rc;239357 int len;358358+240359 if (!*passwd && !*sha1_passwd) {241360 seclvl_printk(0, KERN_ERR, "Attempt to password-unlock the "242361 "seclvl module, but neither a plain text "···250363 "maintainer about this event.\n");251364 return -EINVAL;252365 }253253- len = strlen(buff);366366+367367+ if (count < 0 || count >= PAGE_SIZE)368368+ return -ENOMEM;369369+ if (*ppos != 0) {370370+ return -EINVAL;371371+ }372372+ page = (char *)get_zeroed_page(GFP_KERNEL);373373+ if (!page)374374+ return -ENOMEM;375375+ len = -EFAULT;376376+ if (copy_from_user(page, buf, count))377377+ goto out;378378+379379+ len = strlen(page);254380 /* ``echo "secret" > seclvl/passwd'' includes a newline */255255- if (buff[len - 1] == '\n') {381381+ if (page[len - 1] == '\n') {256382 len--;257383 }258384 /* Hash the password, then compare the hashed values */259259- if ((rc = plaintext_to_sha1(tmp, buff, len))) {385385+ if ((rc = plaintext_to_sha1(tmp, page, len))) {260386 seclvl_printk(0, KERN_ERR, "Error hashing password: rc = "261387 "[%d]\n", rc);262388 return rc;···282382 seclvl_printk(0, KERN_INFO,283383 "Password accepted; seclvl reduced to 0.\n");284384 seclvl = 0;285285- return count;385385+ len = count;386386+387387+out:388388+ free_page((unsigned long)page);389389+ return len;286390}287391288288-/* Generate sysfs_attr_passwd */289289-static struct seclvl_attribute sysfs_attr_passwd =290290-__ATTR(passwd, (S_IFREG | S_IRUGO | S_IWUSR), seclvl_read_passwd,291291- seclvl_write_passwd);392392+static struct file_operations passwd_file_ops = {393393+ .write = passwd_write_file,394394+};292395293396/**294397 * Explicitely disallow ptrace'ing the init process.···550647}551648552649/**553553- * Sysfs registrations650650+ * securityfs registrations554651 */555555-static int doSysfsRegistrations(void)652652+struct dentry *dir_ino, *seclvl_ino, *passwd_ino;653653+654654+static int seclvlfs_register(void)556655{557557- int rc = 0;558558- if ((rc = subsystem_register(&seclvl_subsys))) {559559- seclvl_printk(0, KERN_WARNING,560560- "Error [%d] registering seclvl subsystem\n", rc);561561- return rc;562562- }563563- sysfs_create_file(&seclvl_subsys.kset.kobj, &sysfs_attr_seclvl.attr);656656+ dir_ino = securityfs_create_dir("seclvl", NULL);657657+ if (!dir_ino)658658+ return -EFAULT;659659+660660+ seclvl_ino = securityfs_create_file("seclvl", S_IRUGO | S_IWUSR,661661+ dir_ino, &seclvl, &seclvl_file_ops);662662+ if (!seclvl_ino)663663+ goto out_deldir;564664 if (*passwd || *sha1_passwd) {565565- sysfs_create_file(&seclvl_subsys.kset.kobj,566566- &sysfs_attr_passwd.attr);665665+ passwd_ino = securityfs_create_file("passwd", S_IRUGO | S_IWUSR,666666+ dir_ino, NULL, &passwd_file_ops);667667+ if (!passwd_ino)668668+ goto out_delf;567669 }568670 return 0;671671+672672+out_deldir:673673+ securityfs_remove(dir_ino);674674+out_delf:675675+ securityfs_remove(seclvl_ino);676676+677677+ return -EFAULT;569678}570679571680/**···592677 rc = -EINVAL;593678 goto exit;594679 }595595- sysfs_attr_seclvl.attr.owner = THIS_MODULE;596596- sysfs_attr_passwd.attr.owner = THIS_MODULE;597680 if (initlvl < -1 || initlvl > 2) {598681 seclvl_printk(0, KERN_ERR, "Error: bad initial securelevel "599682 "[%d].\n", initlvl);···619706 } /* if primary module registered */620707 secondary = 1;621708 } /* if we registered ourselves with the security framework */622622- if ((rc = doSysfsRegistrations())) {709709+ if ((rc = seclvlfs_register())) {623710 seclvl_printk(0, KERN_ERR, "Error registering with sysfs\n");624711 goto exit;625712 }···637724 */638725static void __exit seclvl_exit(void)639726{640640- sysfs_remove_file(&seclvl_subsys.kset.kobj, &sysfs_attr_seclvl.attr);727727+ securityfs_remove(seclvl_ino);641728 if (*passwd || *sha1_passwd) {642642- sysfs_remove_file(&seclvl_subsys.kset.kobj,643643- &sysfs_attr_passwd.attr);729729+ securityfs_remove(passwd_ino);644730 }645645- subsystem_unregister(&seclvl_subsys);731731+ securityfs_remove(dir_ino);646732 if (secondary == 1) {647733 mod_unreg_security(MY_NAME, &seclvl_ops);648734 } else if (unregister_security(&seclvl_ops)) {