lsm stacking v0.2: intro
Subsystems (9)
cover lsm stacking v0.2: intro
Hi,
The set of patches to follow introduces support for stacking LSMs. This is its second posting to lkml. I am sending it out in the hopes of soliciting feedback and testing, with the obvious eventual goal of mainline adoption.
The patches mainly do the following:
1. Introduce the stacker LSM.
2. Change the kernel object void * security fields to be hlists, and introduce an api for modules to share these.
3. Modify SELinux to make use of stacker.
4. Modify seclvl to use stacker.
Motivation:
The purpose of these patches is to enable stacking multiple security modules. There are several cases where this would be very useful. It eases the testing of new modules with distro kernels, as it makes it possible to stack new modules with selinux and capabilities -- for instance if a user is running fedora. Second, it enables running selinux (or LIDS, etc) with integrity verification modules. (Digsig is an example of these, and within a few months hopefully the TPM-enabled slim+evm modules, which verifies integrity of file contents and extended attributes such as selinux contexts
(http://www.acsac.org/2004/workshop/David-Safford.pdf) will be released for mainline inclusion). Thirdly, there are systems where running selinux is not practical for footprint reasons, and the security goals are easily expressed as a very small module. For instance, it might be desirable to confine a web browser on a zaurus, or to implement a site security policy on old hardware as per
http://mail.wirex.com/pipermail/linux-security-module/2005-May/6071.html
Performance impact of the actual stacker module is negligable. The security_{get,set,del,add}_value API does have a small performance impact. Please see
http://marc.theaimsgroup.com/?l=linux-security-module&m=111820455332752&w=2
and
http://marc.theaimsgroup.com/?l=linux-security-module&m=111824326500837&w=2
if interested in the performance results. I am certainly interested in ways to further speed up security_get_value.
thanks,
-serge
PATCH 1/12 lsm stacking v0.2: don't default to dummy_##hook
When stacking multiple LSMs, we do not want hooks which are undefined to be substituted with the dummy_##hook.
--- security.c | 12 ++++++------ 1 files changed, 6 insertions(+), 6 deletions(-)
security/security.c +6 -6
@@ -81,15 +81,15 @@ int __init security_init(void)*/ int register_security (struct security_operations *ops) { +if (security_ops != &dummy_security_ops) +return -EAGAIN ; +if (verify (ops)) {printk (KERN_DEBUG "%s could not verify " "security_operations structure.\n" , __FUNCTION__);return -EINVAL ; } -if (security_ops != &dummy_security_ops) -return -EAGAIN ; - security_ops = ops;return 0 ;
@@ -134,9 +134,9 @@ int unregister_security(struct security_*/ int mod_reg_security (const char *name,struct security_operations *ops) { -if (verify (ops)) { -printk (KERN_INFO "%s could not verify " -"security operations.\n" , __FUNCTION__); +if (!ops) { +printk (KERN_INFO "%s received NULL security operations" , + __FUNCTION__);return -EINVAL ; }
PATCH 2/12 lsm stacking v0.2: replace void* security with hlist
In reply to [email protected]Replace kernel object ->security void*'s with hlists. This will permit multiple LSMs to each store information under one kernel object.
--- fs/compat.c | 4 ++-- fs/exec.c | 4 ++-- fs/inode.c | 2 +- include/linux/binfmts.h | 2 +- include/linux/fs.h | 8 ++++---- include/linux/ipc.h | 3 ++- include/linux/msg.h | 2 +- include/linux/sched.h | 2 +- include/net/sock.h | 2 +- ipc/msg.c | 2 +- ipc/msgutil.c | 2 +- ipc/sem.c | 2 +- ipc/shm.c | 2 +- kernel/fork.c | 2 +- 14 files changed, 20 insertions(+), 19 deletions(-)
fs/compat.c +2 -2
@@ -1519,6 +1519,7 @@ int compat_do_execve(char * filename, bprm->file = file; bprm->filename = filename; bprm->interp = filename; +INIT_HLIST_HEAD (&bprm->security); bprm->mm =mm_alloc (); retval = -ENOMEM ;if (!bprm->mm)
@@ -1575,8 +1576,7 @@ out:__free_page (page); } -if (bprm->security) -security_bprm_free (bprm); +security_bprm_free (bprm); out_mm:if (bprm->mm)
fs/exec.c +2 -2
@@ -1154,6 +1154,7 @@ int do_execve(char * filename, bprm->file = file; bprm->filename = filename; bprm->interp = filename; +INIT_HLIST_HEAD (&bprm->security); bprm->mm =mm_alloc (); retval = -ENOMEM ;if (!bprm->mm)
@@ -1212,8 +1213,7 @@ out:__free_page (page); } -if (bprm->security) -security_bprm_free (bprm); +security_bprm_free (bprm); out_mm:if (bprm->mm)
fs/inode.c +1 -1
@@ -132,7 +132,7 @@ static struct inode *alloc_inode(struct inode->i_bdev =NULL ; inode->i_cdev =NULL ; inode->i_rdev =0 ; - inode->i_security =NULL ; +INIT_HLIST_HEAD (&inode->i_security); inode->dirtied_when =0 ;if (security_inode_alloc (inode)) {if (inode->i_sb->s_op->destroy_inode)
include/linux/binfmts.h +1 -1
@@ -29,7 +29,7 @@ struct linux_binprm{struct file * file;int e_uid, e_gid;kernel_cap_t cap_inheritable, cap_permitted, cap_effective; -void *security; +struct hlist_head security;int argc, envc;char * filename;/* Name of binary as seen by procps */ char * interp;/* Name of the binary really executed. Most
include/linux/fs.h +4 -4
@@ -480,7 +480,7 @@ struct inode {unsigned int i_flags;atomic_t i_writecount; -void *i_security; +struct hlist_head i_security;union {void *generic_ip; } u;
@@ -554,7 +554,7 @@ struct fown_struct {rwlock_t lock;/* protects pid, uid, euid fields */ int pid;/* pid or -pgrp where SIGIO should be sent */ uid_t uid, euid;/* uid/euid of process setting the owner */ -void *security; +struct hlist_head security;int signum;/* posix.1b rt signal to be delivered on IO */ };
@@ -591,7 +591,7 @@ struct file {size_t f_maxcount;unsigned long f_version; -void *f_security; +struct hlist_head f_security;/* needed for tty driver, and maybe others */ void *private_data;
@@ -778,7 +778,7 @@ struct super_block {int s_syncing;int s_need_sync_fs;atomic_t s_active; -void *s_security; +struct hlist_head s_security;struct xattr_handler **s_xattr;struct list_head s_inodes;/* all inodes */
include/linux/ipc.h +2 -1
@@ -2,6 +2,7 @@#define _LINUX_IPC_H#include <linux/types.h> +#include <linux/list.h> #define IPC_PRIVATE ((__kernel_key_t) 0)
@@ -65,7 +66,7 @@ struct kern_ipc_permgid_t cgid;mode_t mode;unsigned long seq; - void *security; + struct hlist_head security; };#endif /* __KERNEL__ */
include/linux/msg.h +1 -1
@@ -70,7 +70,7 @@ struct msg_msg {long m_type;int m_ts;/* message text size */ struct msg_msgseg * next; -void *security; +struct hlist_head security;/* the actual message follows immediately */ };
include/linux/sched.h +1 -1
@@ -717,7 +717,7 @@ struct task_struct {void *notifier_data;sigset_t *notifier_mask; -void *security; +struct hlist_head security;struct audit_context *audit_context;seccomp_t seccomp;
include/net/sock.h +1 -1
@@ -240,7 +240,7 @@ struct sock {struct sk_buff *sk_send_head;__u32 sk_sndmsg_off;int sk_write_pending; -void *sk_security; +struct hlist_head sk_security;void (*sk_state_change)(struct sock *sk);void (*sk_data_ready)(struct sock *sk,int bytes);void (*sk_write_space)(struct sock *sk);
ipc/msg.c +1 -1
@@ -99,7 +99,7 @@ static int newque (key_t key, int msgflg msq->q_perm.mode = (msgflg &S_IRWXUGO ); msq->q_perm.key = key; - msq->q_perm.security =NULL ; +INIT_HLIST_HEAD (&msq->q_perm.security); retval =security_msg_queue_alloc (msq);if (retval) {ipc_rcu_putref (msq);
ipc/msgutil.c +1 -1
@@ -41,7 +41,7 @@ struct msg_msg *load_msg(const void __usreturn ERR_PTR (-ENOMEM ); msg->next =NULL ; - msg->security =NULL ; +INIT_HLIST_HEAD (&msg->security);if (copy_from_user (msg +1 , src, alen)) { err = -EFAULT ;
ipc/sem.c +1 -1
@@ -178,7 +178,7 @@ static int newary (key_t key, int nsems, sma->sem_perm.mode = (semflg &S_IRWXUGO ); sma->sem_perm.key = key; - sma->sem_perm.security =NULL ; +INIT_HLIST_HEAD (&sma->sem_perm.security); retval =security_sem_alloc (sma);if (retval) {ipc_rcu_putref (sma);
ipc/shm.c +1 -1
@@ -199,7 +199,7 @@ static int newseg (key_t key, int shmflg shp->shm_flags = (shmflg &S_IRWXUGO ); shp->mlock_user =NULL ; - shp->shm_perm.security =NULL ; +INIT_HLIST_HEAD (&shp->shm_perm.security); error =security_shm_alloc (shp);if (error) {ipc_rcu_putref (shp);
kernel/fork.c +1 -1
@@ -939,7 +939,7 @@ static task_t *copy_process(unsigned lon p->lock_depth =-1 ;/* -1 = no lock */ do_posix_clock_monotonic_gettime (&p->start_time); - p->security =NULL ; +INIT_HLIST_HEAD (&p->security); p->io_context =NULL ; p->io_wait =NULL ; p->audit_context =NULL ;
PATCH 3/12 lsm stacking v0.2: introduce security_*_value API
In reply to [email protected]Define the functions to be used by LSMs to add, retrieve, and remove elements to the kernel object ->security hlists.
--- include/linux/security-stack.h | 51 +++++++++++++++++++++++++++ include/linux/security.h | 29 +++++++++++++++ security/security.c | 75 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 155 insertions(+)
include/linux/security-stack.h new file +51 -0
@@ -0,0 +1,51 @@ +/* +* security-stack.h +* +* Contains function prototypes or inline definitions for the +* function which manipulate kernel object security annotations. +* +* If stacker is compiled in, then we use the full functions as +* defined in security/security.c. Otherwise we use the #defines +* here. +*/ + +#ifdef CONFIG_SECURITY_STACKER +extern struct security_list *security_get_value (struct hlist_head *head, +int security_id); + +extern struct security_list *security_set_value (struct hlist_head *head, +int security_id,struct security_list *obj_node); +extern struct security_list *security_add_value (struct hlist_head *head, +int security_id,struct security_list *obj_node); +extern struct security_list *security_del_value (struct hlist_head *head, +int security_id); +#else +static inline struct security_list * +security_get_value (struct hlist_head *head,int security_id) +{ +struct hlist_node *tmp = head->first; + return tmp ? hlist_entry(tmp, struct security_list, list) : NULL; +} + +static inline struct security_list * +security_set_value (struct hlist_head *head,int security_id, +struct security_list *obj_node) +{ + head->first = &obj_node->list; +} + +static inline struct security_list * +security_add_value (struct hlist_head *head,int security_id, +struct security_list *obj_node) +{ + head->first = &obj_node->list; +} + +static inline struct security_list * +security_del_value (struct hlist_head *head,int security_id) +{ +struct hlist_node *tmp = head->first; + head->first =NULL ; + return tmp ? hlist_entry(tmp, struct security_list, list) : NULL; +} +#endif
include/linux/security.h +29 -0
@@ -34,6 +34,35 @@struct ctl_table ;/* +* structure to be embedded at top of each LSM's security +* objects. +*/ +struct security_list { +struct hlist_node list; +int security_id; +}; + + +/* +* These #defines present more convenient interfaces to +* LSMs for using the security{g,d,s}et_value functions. +*/ +#define security_get_value_type (head, id, type) ( { \ + struct security_list *v = security_get_value(head, id); \ + v ? hlist_entry(v, type, lsm_list) : NULL; } ) + +#define security_set_value_type (head, id, value) \ + security_set_value(head, id, &value->lsm_list); + +#define security_add_value_type (head, id, value) \ + security_add_value(head, id, &value->lsm_list); + +#define security_del_value_type (head, id, type) ( { \ + struct security_list *v; \ + v = security_del_value(head, id); \ + v ? hlist_entry(v, type, lsm_list) : NULL; } ) + +/* * These functions are in security/capability.c and are used * as the default capabilities functions */
security/security.c +75 -0
81 lines not on this page · raw message
PATCH 4/12 lsm stacking v0.2: stacker documentation
In reply to [email protected]Add documentation about stacker and its usage.
--- LSM-stacking.txt | 157 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 157 insertions(+)
Documentation/LSM-stacking.txt new file +157 -0
@@ -0,0 +1,157 @@ +------------ +LSM stacking +------------ + +This document consists of two parts. The first describes the stacker LSM. +The second describes what is needed from an LSM in order to permit it to +stack with other LSMs. + +-------------------------------------------------------- +stacker LSM - enable stacking multiple security modules. +-------------------------------------------------------- + +Stacker is compiled into the kernel. Find the "Stacker" option under +the Security submenu, and say 'Y'. Now, any security modules which are +loaded or compiled into the kernel will be managed by stacker. + +You may interact with stacker through its sysfs interface, located +under /sys/stacker/. This consists of the following files: + +/sys/stacker/lockdown: +Once you write to this file, you will no longer be able to load +LSMs. + +/sys/stacker/list_modules: +Reading this file will show which LSMs are being stacked. + +/sys/stacker/stop_responding: +Unregisters the /sys/stacker directory, so that you can no longer +interact with stacker. + +/sys/stacker/unload: +Disables the specified module. The module will actually still be +loaded, but will no longer be asked to mediate accesses or update +security information. It will still be consulted on kernel object +deletions. Please see further down why. + +--------------------------------------------- +Readying an LSM for stacking with other LSMs. +--------------------------------------------- + +LSM stacking is not a simple matter. You must consider the behavior of +all stacked LSMs very carefully, as well as certain subtle effects of +the LSM implementation. Please do not try to stack arbitrary modules! +For instance, while SELinux and cap-stack should always be used +together, SELinux cannot be combined with the original capability +module. The reason for this is that capability enforces that +a process must have CAP_SYS_ADMIN when writing "security.*" extended +attributes. However selinux requires that non-CAP_SYS_ADMIN processes +be able to write security.selinux attributes, instead enforcing its +own permission check. More subtle interactions are certainly +imaginable, such as a first security module updating state on a kernel +object such that a second security module denies or allows the action +when it otherwise would not have. + +If you have any questions about the proper or actual behavior of +modules, whether existing or ones to be written by yourself, a good +place to engage in discussion is the lsm mailing list, [email protected]. Information about the mailing list can +be found at lsm.immunix.org. + +For performance reasons, stacker currently does not permit unloading +of stacked modules. They may be disabled while loaded by using the +/sys/stacker/unload file. Stacker attempts to prevent the unloads by +incrementing the usage count on the module's struct security_operations. + +If your module will be annotating security information to kernel +objects, then you should use the provided API. The functions intended +for use by modules are defined in include/linux/security.h. A +good example of a user of these functions is the SELinux module. The +following describes the API usage. + +Assume you wish to annotate an instance of the following struct to the +inode_struct: + +struct my_security_info { + int a; + struct list_head some_list; + spinlock_t lock; +}; + +At the top of the struct, you must add a struct security_list lsm_list, +as follows: + +struct my_security_info { ++ struct security_list lsm_list; + int count; + struct list_head some_list; + spinlock_t lock; +}; + +This will add the information which the API will need to tell your +information apart from that of other modules. You also need to define a +unique ID to distinguish information owned by your module. Usually you +can just "echo <module_name> | sha1sum" and use the first 8 digits. +For instance, if +#echo seclvl | sha1sum | awk --field-separator="" '{ print \ +$1$2$3$4$5$6$7$8 '} +40e81e47 + +then in your my_lsm.h, add +#define MY_LSM_ID 0x40e81e47 + +Do make sure that no other module happens to have the same ID. + +Now when the kernel object is created, you may use +security_set_value_type to append the struct to the object's list of +security information. Note that you may ONLY use this while the kernel +object is being created, ie during the security_<KERNEL_OBJECT>_alloc +function. Since you are appending my_security_info to the inode, you +will do so during the security_inode_alloc() hook. For instance, + +static inline int my_inode_alloc(struct inode *inode) +{ + struct my_security_info *my_data; + + my_data = kmalloc(sizeof(struct my_security_info), GFP_KERNEL); + if (!my_data) + return -ENOMEM; + init_inode_data(my_data); + + security_set_value_type(&inode->i_security, MY_LSM_ID, my_data); +} + +If you need to append your information after the kernel object has been +created, you may do so using security_add_value_type() hook. However, +for both performance and security reasons, it is preferable to compile +your module into the kernel and always append your info while the object +is created. + +To get your information back, you may use security_get_value_type. +For instance, + +static inline int my_inode_create(struct inode *dir, + struct dentry *dentry, + int mode) +{ + struct my_security_info *my_data; + + my_data = security_get_value_type(&dir->i_security, + MY_LSM_ID, struct my_security_info); + if (!my_data || my_data->count) + return -EPERM; + return 0; +} + +Finally, data appended to kernel objects must (for now) be removed +during the security_<KERNEL_OBJECT>_free() function only. This is a +limitation for performance reasons. Allowing data to be freed anytime +would only be needed if security modules could be unloaded, which would +then require two additions to the locking scheme: We would have to +protect the object->security readers from data deletions, and likewise +protect the actual security_operations structures from being unloaded +while one of its member functions is executed. It is possible that the +latter is sufficiently taken care of by the module unloading logic. The +former would require waiting for a full rcu cycle between removing an +element from the list, and actually deleting the element. Additional +locking (ie a refcount) would be up to the module itself.
PATCH 5/12 lsm stacking v0.2: actual stacker module
In reply to [email protected]Adds the actual stacker LSM.
Changelog:
1. Stack the dummy LSM by default whenever no other modules are loaded.
2. When no modules are stacked which define security_vm_enough, use stacker_capable() rather than capable() so that PF_SUPERPRIV does not get automatically set.
3. Register the stop_responding sysfs file which unregisters stacker's sysfs files to prevent LSMs being unloaded from now on.
Thanks to Tony Jones for pointing the first two errors.
--- Kconfig | 6 Makefile | 1 stacker.c | 1495 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 1502 insertions(+)
security/Kconfig +6 -0
@@ -87,5 +87,11 @@ config SECURITY_SECLVL source security/selinux/Kconfig +config SECURITY_STACKER + boolean "LSM Stacking" + depends on SECURITY + help + Stack multiple LSMs. + endmenu
security/Makefile +1 -0
@@ -3,6 +3,7 @@ # obj-$(CONFIG_KEYS) += keys/ +obj-$(CONFIG_SECURITY_STACKER) += stacker.o subdir-$(CONFIG_SECURITY_SELINUX) += selinux # if we don't select a security model, use the default capabilities
security/stacker.c new file +1495 -0
1,495 lines not on this page · raw message
Re: [patch 5/12] lsm stacking v0.2: actual stacker module
Quoted 6 lines · On Thu, 30 Jun 2005 [email protected] wrote:
security/stacker.c new file +6
-0+/* list modules */ +static ssize_t listmodules_read (struct stacker_kobj *obj,char *buff) +{ +ssize_t len =0 ; +struct module_entry *m; +
security/stacker.c line 1329
Quoted 10 lines
security/stacker.c new file +10
-0+rcu_read_lock (); +stack_for_each_entry (m, &stacked_modules, lsm_list) { + len +=snprintf (buff+len,PAGE_SIZE - len,"%s\n" , + m->module_name); + } +rcu_read_unlock (); + +return len; +} +
As far as I'm aware, sysfs nodes are supposed to contain one entity per file. Not sure what the alternative here is, though.
- James
Signature · 2 lines
James Morris <[email protected]>
[email protected]
maintainerRe: [patch 5/12] lsm stacking v0.2: actual stacker module
Quoted 13 lines · James Morris
Quoted 11 lines · On Thu, 30 Jun 2005 [email protected] wrote:
security/stacker.c new file +11
-0+/* list modules */ +static ssize_t listmodules_read (struct stacker_kobj *obj,char *buff) +{ +ssize_t len =0 ; +struct module_entry *m; + +rcu_read_lock (); +stack_for_each_entry (m, &stacked_modules, lsm_list) { + len +=snprintf (buff+len,PAGE_SIZE - len,"%s\n" , + m->module_name); + }
Quoted 8 lines
security/stacker.c line 1329
Quoted 5 lines
security/stacker.c new file +5
-0+rcu_read_unlock (); + +return len; +} +As far as I'm aware, sysfs nodes are supposed to contain one entity per file. Not sure what the alternative here is, though.
Thanks James, good point.
Documentation/filesystems/sysfs.txt seems a little soft on the issue, saying it's "preferable". So just to make sure:
Greg, should stacker be using its own filesystem? There are 4 files:
stop_responding: takes one input ("1")
unload: takes one string
lockdown: takes one input ("1")
list_modules: outputs a list of strings, ie
selinux
cap_stack
under a patched fedora kernel.
thanks,
-serge
Re: [patch 5/12] lsm stacking v0.2: actual stacker module
In reply to [email protected]security/stacker.c line 1257
Quoted 2 lines · On Thu, Jun 30, 2005 at 02:50:43PM -0500, [email protected] wrote:
security/stacker.c new file +2
-0+/* variables to hold kobject/sysfs data */ +static struct subsystem stacker_subsys;
Use decl_subsys please.
And yes, James is right, only value per sysfs file is allowed.
security/stacker.c line 1420
Quoted 1 line
security/stacker.c new file +1
-0+ result =subsystem_register (&stacker_subsys);
Why are you putting this at the root of sysfs. It should go in /sys/kernel/security/ right? Please put it there.
security/stacker.c line 1435
Quoted 8 lines
security/stacker.c new file +8
-0+sysfs_create_file (&stacker_subsys.kset.kobj, + &stacker_attr_lockdown.attr); +sysfs_create_file (&stacker_subsys.kset.kobj, + &stacker_attr_listmodules.attr); +sysfs_create_file (&stacker_subsys.kset.kobj, + &stacker_attr_stop_responding.attr); +sysfs_create_file (&stacker_subsys.kset.kobj, + &stacker_attr_unload.attr);
Hm, I think those functions return error values, you might want to check them...
security/stacker.c line 1436
Quoted 1 line
security/stacker.c new file +1
-0+ sysfsfiles_registered =1 ;
Why? You know if this works or not, otherwise you would have failed here.
security/stacker.c line 1472
Quoted 2 lines
security/stacker.c new file +2
-0+printk (KERN_NOTICE "LSM stacker registered as the primary " +"security module\n" );
And everyone really wants to see this in their logs?
security/stacker.c line 1487
Quoted 4 lines
security/stacker.c new file +4
-0+if (unregister_security (&stacker_ops)) +printk (KERN_WARNING "Error unregistering LSM stacker.\n" ); +else +printk (KERN_WARNING "LSM stacker removed.\n" );
Same here as above...
thanks,
greg k-h
[email protected]
maintainerRe: [patch 5/12] lsm stacking v0.2: actual stacker module
Thanks for all your comments.
Quoted 7 lines · Greg KH
security/stacker.c line 1257
Quoted 2 lines · On Thu, Jun 30, 2005 at 02:50:43PM -0500, [email protected] wrote:
security/stacker.c new file +2
-0+/* variables to hold kobject/sysfs data */ +static struct subsystem stacker_subsys;Use
decl_subsysplease.And yes, James is right, only value per sysfs file is allowed.
Hmm, I could instead have one file per loaded LSM, which could obviate the need for the stacker/unload file, but that would make it more work for a user to find the ordering of the LSMs. I wonder how much that would matter.
I'll implement your other changes, and consider switching to a stackerfs (versus changing the content presentation under sysfs).
thanks,
-serge
Re: [patch 5/12] lsm stacking v0.2: actual stacker module
Quoted 7 lines · On Sat, Jul 02, 2005 at 07:24:41PM -0500, [email protected] wrote:
Hmm, I could instead have one file per loaded LSM, which could obviate the need for the stacker/unload file, but that would make it more work for a user to find the ordering of the LSMs. I wonder how much that would matter.
I'll implement your other changes, and consider switching to a stackerfs (versus changing the content presentation under sysfs).
I'd prefer each file (per loaded LSM) when read returned it's ordering position, even though it's much clumsier than your current implementation.
There just isn't enough content to justify a stacker specific filesystem IMHO.
Tony
Re: [patch 5/12] lsm stacking v0.2: actual stacker module
Quoted 1 line · Tony Jones
There just isn't enough content to justify a stacker specific filesystem IMHO.
It might be worth thinking about a more general securityfs as part of LSM, to be used by stacker and LSM modules. SELinux could use this instead of managing its own selinuxfs.
- James
Signature · 2 lines
James Morris <[email protected]>
Re: [patch 5/12] lsm stacking v0.2: actual stacker module
Quoted 3 lines · James Morris
It might be worth thinking about a more general securityfs as part of LSM, to be used by stacker and LSM modules. SELinux could use this instead of managing its own selinuxfs.
Good idea. In the case of stacked modules each with a custom fs, having them
be part of a common hierarchy makes a lot of sense.
I'm assuming you are advocating for adding LSM support to provide some level of consistency in presentation rather than it _just_ being a new mount point for every module to live under?
Take the discussion to the LSM list?
Thanks!
Tony
PATCH 1/1 securityfs
In reply to James MorrisQuoted 7 lines · James Morris
Quoted 1 line · Tony Jones
There just isn't enough content to justify a stacker specific filesystem IMHO.
It might be worth thinking about a more general securityfs as part of LSM, to be used by stacker and LSM modules. SELinux could use this instead of managing its own selinuxfs.
Good idea. Here's a patch to do just that (compile tested only...)
Comments?
thanks,
greg k-h
include/linux/security.h | 5 security/Makefile | 2 security/inode.c | 336 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 342 insertions(+), 1 deletion(-)
security/Makefile +1 -1
@@ -11,7 +11,7 @@ endif # Object file lists -obj-$(CONFIG_SECURITY) += security.o dummy.o +obj-$(CONFIG_SECURITY) += security.o dummy.o inode.o # Must precede capability.o in order to stack properly. obj-$(CONFIG_SECURITY_SELINUX) += selinux/built-in.o obj-$(CONFIG_SECURITY_CAPABILITIES) += commoncap.o capability.o
security/inode.c new file +336 -0
336 lines not on this page · raw message
include/linux/security.h +5 -0
@@ -1983,6 +1983,11 @@extern int unregister_security (struct security_operations *ops);extern int mod_reg_security (const char *name,struct security_operations *ops);extern int mod_unreg_security (const char *name,struct security_operations *ops); +extern struct dentry *securityfs_create_file (const char *name,mode_t mode, +struct dentry *parent,void *data, +struct file_operations *fops); +extern struct dentry *securityfs_create_dir (const char *name,struct dentry *parent); +extern void securityfs_remove (struct dentry *dentry);#else /* CONFIG_SECURITY */
[email protected]
maintainerRe: [PATCH] securityfs
Quoted 10 lines · Greg KH
Quoted 7 lines · James Morris
Quoted 1 line · Tony Jones
There just isn't enough content to justify a stacker specific filesystem IMHO.
It might be worth thinking about a more general securityfs as part of LSM, to be used by stacker and LSM modules. SELinux could use this instead of managing its own selinuxfs.
Good idea. Here's a patch to do just that (compile tested only...)
Having all the security relevant stuff under one place has been something we've wanted to do for awhile :) Thanks, Greg!
All my good machines are down right now, so compiling is slow, but I'm attempting to convert seclvl to use securityfs. So far the resulting code is quite nice. I'll hopefully send something out tomorrow.
thanks,
-serge
[email protected]
maintainerRe: [PATCH] securityfs
In reply to Greg KHQuoted 5 lines · Greg KH
Quoted 4 lines · James Morris
Quoted 1 line · Tony Jones
There just isn't enough content to justify a stacker specific filesystem IMHO.
Quoted 7 lines
Quoted 3 lines
It might be worth thinking about a more general securityfs as part of LSM, to be used by stacker and LSM modules. SELinux could use this instead of managing its own selinuxfs.
Good idea. Here's a patch to do just that (compile tested only...)
Comments?
Tested without a hitch.
In addition, the attached patch converts seclvl to use the securityfs. Also tested without any problems. (Only meant as proof of concept:
Mike, you'll probably want to at least add the passwd_read_file function back in, I assume?)
thanks,
-serge
--seclvl.c | 226
+++++++++++++++++++++++++++------------------------------------
1 files changed, 99 insertions(+), 127 deletions(-)
security/seclvl.c +99 -127
@@ -119,69 +119,6 @@ }while (0 )/** -* kobject stuff -*/ - -struct subsystem seclvl_subsys; - -struct seclvl_obj { -char *name; -struct list_head slot_list; -struct kobject kobj; -}; - -/** -* There is a seclvl_attribute struct for each file in sysfs. -* -* In our case, we have one of these structs for "passwd" and another -* for "seclvl". -*/ -struct seclvl_attribute { -struct attribute attr; -ssize_t (*show) (struct seclvl_obj *,char *); -ssize_t (*store) (struct seclvl_obj *,const char *,size_t ); -}; - -/** -* When this function is called, one of the files in sysfs is being -* written to. attribute->store is a function pointer to whatever the -* struct seclvl_attribute store function pointer points to. It is -* unique for "passwd" and "seclvl". -*/ -static ssize_t -seclvl_attr_store (struct kobject *kobj, -struct attribute *attr,const char *buf,size_t len) -{ - struct seclvl_obj *obj = container_of(kobj, struct seclvl_obj, kobj); -struct seclvl_attribute *attribute = - container_of(attr, struct seclvl_attribute, attr); -return attribute->store ? attribute->store (obj, buf, len) : -EIO ; -} - -static ssize_t -seclvl_attr_show (struct kobject *kobj,struct attribute *attr,char *buf) -{ - struct seclvl_obj *obj = container_of(kobj, struct seclvl_obj, kobj); -struct seclvl_attribute *attribute = - container_of(attr, struct seclvl_attribute, attr); -return attribute->show ? attribute->show (obj, buf) : -EIO ; -} - -/** -* Callback function pointers for show and store -*/ -static struct sysfs_ops seclvlfs_sysfs_ops = { - .show = seclvl_attr_show, - .store = seclvl_attr_store, -}; - -static struct kobj_type seclvl_ktype = { - .sysfs_ops = &seclvlfs_sysfs_ops -}; - -decl_subsys (seclvl, &seclvl_ktype,NULL ); - -/** * The actual security level. Ranges between -1 and 2 inclusive. */ static int seclvl;
@@ -216,9 +153,15 @@* Called whenever the user reads the sysfs handle to this kernel * object */ -static ssize_t seclvl_read_file (struct seclvl_obj *obj,char *buff) +#define TMPBUFLEN 12 +static ssize_t seclvl_read_file (struct file *filp,char __user *buf, +size_t count,loff_t *ppos) { -return snprintf (buff,PAGE_SIZE ,"%d\n" , seclvl); +char tmpbuf[TMPBUFLEN ]; +ssize_t length; + + length =scnprintf (tmpbuf,TMPBUFLEN ,"%d" , seclvl); +return simple_read_from_buffer (buf, count, ppos, tmpbuf, length); }/**
@@ -253,57 +196,58 @@* object (seclvl/seclvl). It expects a single-digit number. */ static ssize_t -seclvl_write_file (struct seclvl_obj *obj,const char *buff,size_t count) +seclvl_write_file (struct file * file,const char __user * buf, +size_t count,loff_t *ppos) { -unsigned long val; -if (count >2 || (count ==2 && buff[1 ] !='\n' )) { -seclvl_printk (1 ,KERN_WARNING ,"Invalid value passed to " -"seclvl: [%s]\n" , buff); +int val; +int err; +char *page; + +if (count >2 )return -EINVAL ; +if (*ppos !=0 ) +return -EINVAL ; + + page = (char *)get_zeroed_page (GFP_KERNEL ); +if (!page) +return -ENOMEM ; + +if (copy_from_user (page, buf, count)) { + err = -EFAULT ; + goto out; + } + +if (sscanf (page,"%d" , &val) !=1 ) { + err = -EINVAL ; + goto out; } - val = buff[0 ] -48 ; +if (seclvl_sanity (val)) {seclvl_printk (1 ,KERN_WARNING ,"Illegal secure level " "requested: [%d]\n" , (int )val); -return -EPERM ; + err = -EINVAL ; + goto out; } + err = count;if (do_seclvl_advance (val)) {seclvl_printk (0 ,KERN_ERR ,"Failure advancing security level " -"to %lu\n" , val); +"to %d\n" , val); + err = -EINVAL ; } -return count; + +out: +free_page ((unsigned long )page); +return err; } -/* Generate sysfs_attr_seclvl */ -static struct seclvl_attribute sysfs_attr_seclvl = -__ATTR (seclvl, (S_IFREG |S_IRUGO |S_IWUSR ), seclvl_read_file, - seclvl_write_file); +static struct file_operations seclvl_file_ops = { + .read = seclvl_read_file, + .write = seclvl_write_file, +};static unsigned char hashedPassword[SHA1_DIGEST_SIZE ];/** -* Called whenever the user reads the sysfs passwd handle. -*/ -static ssize_t seclvl_read_passwd (struct seclvl_obj *obj,char *buff) -{ -/* So just how good *is* your password? :-) */ -char tmp[3 ]; -int i =0 ; - buff[0 ] ='\0' ; -if (hideHash) { -/* Security through obscurity */ -return 0 ; - } -while (i <SHA1_DIGEST_SIZE ) { -snprintf (tmp,3 ,"%02x" , hashedPassword[i]); -strncat (buff, tmp,2 ); - i++; - } -strcat (buff,"\n" ); -return ((SHA1_DIGEST_SIZE *2 ) +1 ); -} - -/** * Converts a block of plaintext of into its SHA1 hashed value. * * It would be nice if crypto had a wrapper to do this for us linear
@@ -347,12 +291,15 @@* object. It hashes the password and compares the hashed results. */ static ssize_t -seclvl_write_passwd (struct seclvl_obj *obj,const char *buff,size_t count) +passwd_write_file (struct file * file,const char __user * buf, +size_t count,loff_t *ppos) {int i;unsigned char tmp[SHA1_DIGEST_SIZE ]; +char *page;int rc;int len; +if (!*passwd && !*sha1_passwd) {seclvl_printk (0 ,KERN_ERR ,"Attempt to password-unlock the " "seclvl module, but neither a plain text "
@@ -363,13 +310,26 @@ "maintainer about this event.\n");return -EINVAL ; } - len =strlen (buff); + +if (count <0 || count >=PAGE_SIZE ) +return -ENOMEM ; +if (*ppos !=0 ) { +return -EINVAL ; + } + page = (char *)get_zeroed_page (GFP_KERNEL ); +if (!page) +return -ENOMEM ; + len = -EFAULT ; +if (copy_from_user (page, buf, count)) + goto out; + + len =strlen (page);/* ``echo "secret" > seclvl/passwd'' includes a newline */ -if (buff[len -1 ] =='\n' ) { +if (page[len -1 ] =='\n' ) { len--; }/* Hash the password, then compare the hashed values */ -if ((rc =plaintext_to_sha1 (tmp, buff, len))) { +if ((rc =plaintext_to_sha1 (tmp, page, len))) {seclvl_printk (0 ,KERN_ERR ,"Error hashing password: rc = " "[%d]\n" , rc);return rc;
@@ -382,13 +342,16 @@seclvl_printk (0 ,KERN_INFO ,"Password accepted; seclvl reduced to 0.\n" ); seclvl =0 ; -return count; + len = count; + +out: +free_page ((unsigned long )page); +return len; } -/* Generate sysfs_attr_passwd */ -static struct seclvl_attribute sysfs_attr_passwd = -__ATTR (passwd, (S_IFREG |S_IRUGO |S_IWUSR ), seclvl_read_passwd, - seclvl_write_passwd); +static struct file_operations passwd_file_ops = { + .write = passwd_write_file, +};/** * Explicitely disallow ptrace'ing the init process.
@@ -647,22 +610,34 @@ }/** -* Sysfs registrations +* securityfs registrations */ -static int doSysfsRegistrations (void ) +struct dentry *dir_ino, *seclvl_ino, *passwd_ino; + +static int seclvlfs_register (void ) { -int rc =0 ; -if ((rc =subsystem_register (&seclvl_subsys))) { -seclvl_printk (0 ,KERN_WARNING , -"Error [%d] registering seclvl subsystem\n" , rc); -return rc; - } -sysfs_create_file (&seclvl_subsys.kset.kobj, &sysfs_attr_seclvl.attr); + dir_ino =securityfs_create_dir ("seclvl" ,NULL ); +if (!dir_ino) +return -EFAULT ; + + seclvl_ino =securityfs_create_file ("seclvl" ,S_IRUGO |S_IWUSR , + dir_ino,NULL , &seclvl_file_ops); +if (!seclvl_ino) + goto out_deldir;if (*passwd || *sha1_passwd) { -sysfs_create_file (&seclvl_subsys.kset.kobj, - &sysfs_attr_passwd.attr); + passwd_ino =securityfs_create_file ("passwd" ,S_IRUGO |S_IWUSR , + dir_ino,NULL , &passwd_file_ops); +if (!passwd_ino) + goto out_delf; }return 0 ; + +out_deldir: +securityfs_remove (dir_ino); +out_delf: +securityfs_remove (seclvl_ino); + +return -EFAULT ; }/**
@@ -677,8 +652,6 @@ rc = -EINVAL ; goto exit; } - sysfs_attr_seclvl.attr.owner =THIS_MODULE ; - sysfs_attr_passwd.attr.owner =THIS_MODULE ;if (initlvl <-1 || initlvl >2 ) {seclvl_printk (0 ,KERN_ERR ,"Error: bad initial securelevel " "[%d].\n" , initlvl);
@@ -706,7 +679,7 @@ }/* if primary module registered */ secondary =1 ; }/* if we registered ourselves with the security framework */ -if ((rc =doSysfsRegistrations ())) { +if ((rc =seclvlfs_register ())) {seclvl_printk (0 ,KERN_ERR ,"Error registering with sysfs\n" ); goto exit; }
@@ -724,12 +697,11 @@*/ static void __exit seclvl_exit(void) { -sysfs_remove_file (&seclvl_subsys.kset.kobj, &sysfs_attr_seclvl.attr); +securityfs_remove (seclvl_ino);if (*passwd || *sha1_passwd) { -sysfs_remove_file (&seclvl_subsys.kset.kobj, - &sysfs_attr_passwd.attr); +securityfs_remove (passwd_ino); } -subsystem_unregister (&seclvl_subsys); +securityfs_remove (dir_ino);if (secondary ==1 ) {mod_unreg_security (MY_NAME , &seclvl_ops); }else if (unregister_security (&seclvl_ops)) {
Re: [PATCH] securityfs
Quoted 9 lines · On Mon, Jul 04, 2005 at 10:53:21AM -0500, [email protected] wrote:
Quoted 9 lines · James Morris
Quoted 7 lines · Tony Jones
Quoted 2 lines
There just isn't enough content to justify a stacker specific filesystem IMHO.
It might be worth thinking about a more general securityfs as part of LSM, to be used by stacker and LSM modules. SELinux could use this instead of managing its own selinuxfs.
Quoted 5 lines
Quoted 3 lines
Good idea. Here's a patch to do just that (compile tested only...)
Comments?
Tested without a hitch.
Thanks for testing.
Quoted 8 lines
In addition, the attached patch converts seclvl to use the securityfs. Also tested without any problems. (Only meant as proof of concept:
Mike, you'll probably want to at least add thepasswd_read_filefunction back in, I assume?)--
seclvl.c| 226 > +++++++++++++++++++++++++++------------------------------------1 files changed, 99 insertions(+), 127 deletions(-)
Nice, glad to see this makes your code smaller and simpler. Although I think it could be made even smaller if you use the default read and write file type functions in libfs (look at the debugfs wrappers of them for u8, u16, etc, for examples of how to use them.)
thanks,
greg k-h
[email protected]
maintainerRe: [PATCH] securityfs
Quoted 4 lines · Greg KH
Nice, glad to see this makes your code smaller and simpler. Although I think it could be made even smaller if you use the default read and write file type functions in libfs (look at the debugfs wrappers of them for u8, u16, etc, for examples of how to use them.)
Hmm, I looked around at libfs and debugfs yesterday... it seems that the simple_attr_read as used by fops_u8 would have been great for seclvl - except that -1 is a valid input for seclvl :)
A more specialized per-type API in security/security.c in the line of debugfs/file.c might be good,simple_attr_read as used by fops_u8 would have been great for
seclvl - except that -1 is a valid input for seclvl :)
The general type of API provided by debugfs/file.c might be useful in security/security.c, though, provided that the securityfs_create_int() and friends also took a function pointer to an update() or validate() function. I'll try to do something like that later today or tomorrow.
thanks,
-serge
Re: [PATCH] securityfs
In reply to Greg KHQuoted 3 lines · Greg KH
Good idea. Here's a patch to do just that (compile tested only...)
Comments?
Looks promising so far.
I'm currently porting selinuxfs funtionality to securityfs, although I'm not sure if we'll be ok during early initialization. selinuxfs is currently kern_mounted via an initcall. We may need an initcall kern_mount() of securityfs before SELinux kicks in.
Stephen: opinions on this?
Otherwise, it looks like it'll allow SELinux to drop some code. Generally it will mean that other LSM components won't have to create their own filesystems, and their subdirectories will be hanging off /security (or wherever selinuxfs is mounted), rather than scattered across /
Some of the SELinux code may be useful as part of securityfs later, as well.
Quoted 19 lines
security/inode.c new file +19
-0+struct dentry *securityfs_create_file (const char *name,mode_t mode, +struct dentry *parent,void *data, +struct file_operations *fops) +{ +struct dentry *dentry =NULL ; +int error; + +pr_debug ("securityfs: creating file '%s'\n" ,name); + + error =simple_pin_fs ("securityfs" , &mount, &mount_count); +if (error) + goto exit; + + error =create_by_name (name, mode, parent, &dentry); +if (error) { + dentry =NULL ; + goto exit; + } +
security/inode.c line 238
Quoted 10 lines
security/inode.c new file +10
-0+if (dentry->d_inode) { +if (data) + dentry->d_inode->u.generic_ip = data; +if (fops) + dentry->d_inode->i_fop = fops; + } +exit: +return dentry; +} +EXPORT_SYMBOL_GPL (securityfs_create_file);
How about having all API functions which return a pointer be converted to use ERR_PTR() ?
This will allow errors to be propagated to the calling code.
- James
Signature · 2 lines
James Morris <[email protected]>
Re: [PATCH] securityfs
Quoted 4 lines · James Morris
Quoted 2 lines · Greg KH
Good idea. Here's a patch to do just that (compile tested only...)
Quoted 8 lines
Quoted 1 line
Comments?
Looks promising so far.
I'm currently porting selinuxfs funtionality to securityfs, although I'm not sure if we'll be ok during early initialization. selinuxfs is currently
kern_mountedvia an initcall. We may need an initcallkern_mount()of securityfs before SELinux kicks in.
Sure, I don't mind moving this if needed.
Quoted 4 lines
Otherwise, it looks like it'll allow SELinux to drop some code. Generally it will mean that other LSM components won't have to create their own filesystems, and their subdirectories will be hanging off /security (or wherever selinuxfs is mounted), rather than scattered across /
The code creates /sys/kernel/security as a mount point for securityfs. This will make the LSB people happy that every LSM does not create a new fs in / :)
Quoted 2 lines
Some of the SELinux code may be useful as part of securityfs later, as well.
That would be fine.
Quoted 4 lines
How about having all API functions which return a pointer be converted to use
ERR_PTR()?This will allow errors to be propagated to the calling code.
Good point, will change that.
thanks,
greg k-h
Re: [PATCH] securityfs
In reply to James MorrisQuoted 6 lines · James Morris
Quoted 3 lines · Greg KH
Good idea. Here's a patch to do just that (compile tested only...)
Comments?
Quoted 8 lines
Looks promising so far.
I'm currently porting selinuxfs funtionality to securityfs, although I'm not sure if we'll be ok during early initialization. selinuxfs is currently
kern_mountedvia an initcall. We may need an initcallkern_mount()of securityfs before SELinux kicks in.Stephen: opinions on this?
The reason for creating a kernel mount of selinuxfs at that point is so that the selinuxfs_mount vfsmount and selinux_null dentry are available for flush_unauthorized_files to use.
Quoted 7 lines
Otherwise, it looks like it'll allow SELinux to drop some code. Generally it will mean that other LSM components won't have to create their own filesystems, and their subdirectories will be hanging off /security (or wherever selinuxfs is mounted), rather than scattered across /
Some of the SELinux code may be useful as part of securityfs later, as well.
We need to be able to assign specific security labels to specific inodes in selinuxfs, particularly for the booleans, but ideally for any of them.
Userspace compatibility is obviously a concern for such a change. libselinux determines where selinuxfs is mounted during library initialization by checking /proc/mounts for selinuxfs, and rc.sysinit does likewise. /sbin/init performs the initial mount of selinuxfs prior to initial policy load. Further, the existence of selinuxfs in /proc/filesystems is used as a test of whether SELinux was enabled in the kernel (e.g. is_selinux_enabled in libselinux).
I'm not sure such a change is worthwhile for SELinux; large amount of disruption for little real gain.
Signature · 2 lines
Stephen Smalley National Security Agency
Re: [PATCH] securityfs
Quoted 5 lines · Stephen Smalley
Quoted 1 line
Stephen: opinions on this?
The reason for creating a kernel mount of selinuxfs at that point is so that the
selinuxfs_mountvfsmount andselinux_nulldentry are available forflush_unauthorized_filesto use.
When exactly is this needed? The securityfs mountpoint will be available via a core_initcall, after which we can initialize the selinux subtree.
Quoted 7 lines
Userspace compatibility is obviously a concern for such a change. libselinux determines where selinuxfs is mounted during library initialization by checking
/proc/mountsfor selinuxfs, and rc.sysinit does likewise.
/sbin/initperforms the initial mount of selinuxfs prior
to initial policy load.
With securityfs, we'd have /sys/kernel/security/selinux configured during kernel initialization.
Quoted 3 lines
Further, the existence of selinuxfs
in/proc/filesystemsis used as a test of whether SELinux was enabled in the kernel (e.g.is_selinux_enabledin libselinux).
Could be a simple change to look for the presence of /sys/kernel/security/selinux
Quoted 2 lines
I'm not sure such a change is worthwhile for SELinux; large amount of disruption for little real gain.
I think it should reduce and simplify the SELinux kernel code, with less filesystems in the kernel, consolidating several potential projects into the same security filesystem.
- James
Signature · 2 lines
James Morris <[email protected]>
Re: [PATCH] securityfs
Quoted 2 lines · James Morris
When exactly is this needed? The securityfs mountpoint will be available via a
core_initcall, after which we can initialize the selinux subtree.
As long as it occurs prior to initial policy load, so that should be fine.
Quoted 2 lines
With securityfs, we'd have
/sys/kernel/security/selinuxconfigured during kernel initialization.
It still has to be mounted by userspace, right? So /sbin/init still needs to know to mount securityfs, and where the selinux nodes live under it, so you are still talking about changing it (and libselinux and rc.sysinit), and risking compatibility breakage for existing systems when they update their kernels.
Quoted 2 lines
Could be a simple change to look for the presence of
/sys/kernel/security/selinux
Slightly different. That would correspond to checking for the presence of selinuxfs in /proc/mounts (i.e. has it been mounted), vs. the current check of selinuxfs in /proc/filesystems (i.e. has it been registered). The latter allows testing whether SELinux is enabled at all in the kernel, regardless of whether selinuxfs has been mounted in the process' namespace. In practice, the difference likely only matters for init and you can deal with distinction there. But again, this requires code change to libselinux, /sbin/init, and rc.sysinit at least, with coordinated update with the kernel. Certainly possible, but experience suggests it isn't likely to go smoothly.
Quoted 3 lines
I think it should reduce and simplify the SELinux kernel code, with less filesystems in the kernel, consolidating several potential projects into the same security filesystem.
If there are several such projects in the first place...
Signature · 2 lines
Stephen Smalley National Security Agency
Re: [PATCH] securityfs
Quoted 5 lines · * Stephen Smalley ([email protected]) wrote:
It still has to be mounted by userspace, right? So
/sbin/initstill needs to know to mount securityfs, and where the selinux nodes live under it, so you are still talking about changing it (and libselinux and rc.sysinit), and risking compatibility breakage for existing systems when they update their kernels.
initrd, and proper dependency during kernel upgrade?
Re: [PATCH] securityfs
In reply to Stephen SmalleyQuoted 5 lines · Stephen Smalley
Quoted 3 lines
I think it should reduce and simplify the SELinux kernel code, with less filesystems in the kernel, consolidating several potential projects into the same security filesystem.
If there are several such projects in the first place...
Serge has already posted a patch converting the sysfs usage over to it, and I know the subdomain people are going to also use this code, for when they submit their patches to mainline (they are currently working on it, honestly, I've seen them doing it...)
thanks,
greg k-h
Re: [PATCH] securityfs
In reply to Greg KHQuoted 3 lines · Greg KH
think it could be made even smaller if you use the default read and write file type functions in libfs (look at the debugfs wrappers of them for u8, u16, etc, for examples of how to use them.)
The attached patch cleans up the securelevel code for the seclvl file. Is this a reasonable way to go about this? Or is there a better way to do this? Should these be in libfs instead? Really I guess it would only take very minor changes to the _attr code in libfs to forego the need for these functions in security/inode.c. It's mainly allowing signed arguments, and a return value from the __set function.
But if this is ok, then it should be quick to come up with the same kind of thing for string arguments, so that all files for both stacker and seclvl should be very simple to code.
thanks,
-serge
--
include/linux/security.h | 24 ++++++++++ security/inode.c | 110 +++++++++++++++++++++++++++++++++++++++++++++++ security/seclvl.c | 84 +++-------------------------------- 3 files changed, 143 insertions(+), 75 deletions(-)
security/inode.c +110 -0
@@ -330,6 +330,116 @@ static void __exit securityfs_exit(void)subsystem_unregister (&security_subsys); } +/* mostly copied from fs/libfs.c:simple_attr */ +struct secfs_int_attr { +int (*get)(void *); +int (*set)(void *,int ); +char get_buf[24 ];/* enough to store an int and "\n\0" */ +char set_buf[24 ]; +void *data; +const char *fmt;/* format for read operation */ +struct semaphore sem;/* protects access to these buffers */ +}; + +int open_file_int (struct inode *inode,struct file *file, +int (*get)(void *),int (*set)(void *,int ), +const char *fmt) +{ +struct secfs_int_attr *attr; + + attr =kmalloc (sizeof (*attr),GFP_KERNEL ); +if (!attr) +return -ENOMEM ; + + attr->get = get; + attr->set = set; + attr->data = inode->u.generic_ip; + attr->fmt = fmt; +init_MUTEX (&attr->sem); + + file->private_data = attr; + +return nonseekable_open (inode, file); +} + +int close_file_int (struct inode *inode,struct file *file) +{ +kfree (file->private_data); +return 0 ; +} + +ssize_t read_file_int (struct file *file,char __user *user_buf, +size_t count,loff_t *ppos) +{ +struct secfs_int_attr *attr; +size_t size; +ssize_t ret; + + attr = file->private_data; + +if (!attr->get) +return -EACCES ; + +down (&attr->sem); +if (*ppos)/* continued read */ + size =strlen (attr->get_buf); +else /* first read */ + size =scnprintf (attr->get_buf,sizeof (attr->get_buf), + attr->fmt, + (unsigned long long )attr->get (attr->data)); + + ret =simple_read_from_buffer (user_buf, count, ppos, attr->get_buf, size); +up (&attr->sem); +return ret; +} + +ssize_t write_file_int (struct file *file,const char __user *user_buf, +size_t count,loff_t *ppos) +{ +struct secfs_int_attr *attr; +int val; +size_t size; +ssize_t ret; + + attr = file->private_data; + +if (!attr->set) +return -EACCES ; + +down (&attr->sem); + ret = -EFAULT ; + size =min (sizeof (attr->set_buf) -1 , count); +if (copy_from_user (attr->set_buf, user_buf, size)) + goto out; + + attr->set_buf[size] ='\0' ; + val =simple_strtol (attr->set_buf,NULL ,0 ); + ret = attr->set (attr->data, val); +if (ret) + goto out; + ret = count;/* claim we got the whole input */ +out: +up (&attr->sem); +return ret; +} + +void secfs_int_set (void *data,int val) +{ + *(int *)data = val; +} + +int secfs_int_get (void *data) +{ +return *(int *)data; +} + +EXPORT_SYMBOL_GPL (read_file_int); +EXPORT_SYMBOL_GPL (close_file_int); +EXPORT_SYMBOL_GPL (open_file_int); +EXPORT_SYMBOL_GPL (write_file_int); +EXPORT_SYMBOL_GPL (secfs_int_set); +EXPORT_SYMBOL_GPL (secfs_int_get); +core_initcall (securityfs_init);module_exit (securityfs_exit);MODULE_LICENSE ("GPL" );
include/linux/security.h +24 -0
@@ -1977,6 +1977,30 @@ static inline int security_netlink_recv(return security_ops->netlink_recv (skb); } +#define SECFS_DEFINE_INT_FILE (__fops, __get, __set, __fmt) \ +static int __fops ## _open(struct inode *inode, struct file *file) \ +{ \ + return open_file_int(inode, file, __get, __set, __fmt); \ +} \ +static struct file_operations __fops = { \ + .owner = THIS_MODULE, \ + .open = __fops ## _open, \ + .release = close_file_int, \ + .read = read_file_int, \ + .write = write_file_int, \ +}; + +int open_file_int (struct inode *inode,struct file *file, +int (*get)(void *),int (*set)(void *,int ), +const char *fmt); +int close_file_int (struct inode *inode,struct file *file); +ssize_t read_file_int (struct file *file,char __user *user_buf, +size_t count,loff_t *ppos); +ssize_t write_file_int (struct file *file,const char __user *user_buf, +size_t count,loff_t *ppos); +void secfs_int_set (void *data,int val); +int secfs_int_get (void *data); +/* prototypes */ extern int security_init (void );extern int register_security (struct security_operations *ops);
security/seclvl.c +9 -75
108 lines not on this page · raw message
Re: [PATCH] securityfs
Quoted 7 lines · On Wed, Jul 06, 2005 at 05:08:35PM -0500, [email protected] wrote:
Quoted 3 lines · Greg KH
think it could be made even smaller if you use the default read and write file type functions in libfs (look at the debugfs wrappers of them for u8, u16, etc, for examples of how to use them.)
The attached patch cleans up the securelevel code for the seclvl file. Is this a reasonable way to go about this?
No.
Quoted 1 line
Or is there a better way to do this?
Look at how debugfs uses the libfs code. We should not need to add these handlers to securityfs.
thanks,
greg k-h
[email protected]
maintainerRe: [PATCH] securityfs
Quoted 4 lines · Greg KH
Quoted 1 line
Or is there a better way to do this?
Look at how debugfs uses the libfs code. We should not need to add these handlers to securityfs.
Ah, ok, thanks. I think I've got it - will send out a new patch tomorrow.
thanks,
-serge
[email protected]
maintainerRe: [PATCH] securityfs
In reply to Greg KHQuoted 9 lines · Greg KH
Quoted 7 lines · On Wed, Jul 06, 2005 at 05:08:35PM -0500, [email protected] wrote:
Quoted 3 lines · Greg KH
think it could be made even smaller if you use the default read and write file type functions in libfs (look at the debugfs wrappers of them for u8, u16, etc, for examples of how to use them.)
The attached patch cleans up the securelevel code for the seclvl file. Is this a reasonable way to go about this?
Quoted 6 lines
No.
Quoted 1 line
Or is there a better way to do this?
Look at how debugfs uses the libfs code. We should not need to add these handlers to securityfs.
Unfortunately the simple_attr code from libfs really doesn't seem to be usable for int args. However the below patch follows some of the examples in debugfs and comes out cleaner than my original patch.
This patch against seclvl moves the filesystem interface from sysfs to the securityfs proposed by Greg KH.
thanks,
-serge
--
seclvl.c | 251 +++++++++++++++++++++++---------------------------------------- 1 files changed, 93 insertions(+), 158 deletions(-)
security/seclvl.c +93 -158
@@ -119,69 +119,6 @@ MODULE_PARM_DESC(hideHash, "When set to }while (0 )/** -* kobject stuff -*/ - -struct subsystem seclvl_subsys; - -struct seclvl_obj { -char *name; -struct list_head slot_list; -struct kobject kobj; -}; - -/** -* There is a seclvl_attribute struct for each file in sysfs. -* -* In our case, we have one of these structs for "passwd" and another -* for "seclvl". -*/ -struct seclvl_attribute { -struct attribute attr; -ssize_t (*show) (struct seclvl_obj *,char *); -ssize_t (*store) (struct seclvl_obj *,const char *,size_t ); -}; - -/** -* When this function is called, one of the files in sysfs is being -* written to. attribute->store is a function pointer to whatever the -* struct seclvl_attribute store function pointer points to. It is -* unique for "passwd" and "seclvl". -*/ -static ssize_t -seclvl_attr_store (struct kobject *kobj, -struct attribute *attr,const char *buf,size_t len) -{ - struct seclvl_obj *obj = container_of(kobj, struct seclvl_obj, kobj); -struct seclvl_attribute *attribute = - container_of(attr, struct seclvl_attribute, attr); -return attribute->store ? attribute->store (obj, buf, len) : -EIO ; -} - -static ssize_t -seclvl_attr_show (struct kobject *kobj,struct attribute *attr,char *buf) -{ - struct seclvl_obj *obj = container_of(kobj, struct seclvl_obj, kobj); -struct seclvl_attribute *attribute = - container_of(attr, struct seclvl_attribute, attr); -return attribute->show ? attribute->show (obj, buf) : -EIO ; -} - -/** -* Callback function pointers for show and store -*/ -static struct sysfs_ops seclvlfs_sysfs_ops = { - .show = seclvl_attr_show, - .store = seclvl_attr_store, -}; - -static struct kobj_type seclvl_ktype = { - .sysfs_ops = &seclvlfs_sysfs_ops -}; - -decl_subsys (seclvl, &seclvl_ktype,NULL ); - -/** * The actual security level. Ranges between -1 and 2 inclusive. */ static int seclvl;
@@ -194,6 +131,11 @@ static int secondary;/** * Verifies that the requested secure level is valid, given the current * secure level. +* +* security level advancement rules: +* Valid levels are -1 through 2, inclusive. +* From -1, stuck. [ in case compiled into kernel ] +* From 0 or above, can only increment. */ static int seclvl_sanity (int reqlvl) {
@@ -202,6 +144,11 @@ static int seclvl_sanity(int reqlvl) "range: [%d]\n", reqlvl);return -EINVAL ; } +if (seclvl ==-1 ) { +seclvl_printk (1 ,KERN_WARNING ,"Not allowed to switch from " +"seclvl [%d]\n" , seclvl); +return -EPERM ; + }if ((seclvl ==0 ) && (reqlvl ==-1 ))return 0 ;if (reqlvl < seclvl) {
@@ -216,36 +163,15 @@ static int seclvl_sanity(int reqlvl)* Called whenever the user reads the sysfs handle to this kernel * object */ -static ssize_t seclvl_read_file (struct seclvl_obj *obj,char *buff) +#define TMPBUFLEN 12 +static ssize_t seclvl_read_file (struct file *filp,char __user *buf, +size_t count,loff_t *ppos) { -return snprintf (buff,PAGE_SIZE ,"%d\n" , seclvl); -} +char tmpbuf[TMPBUFLEN ]; +ssize_t length; -/** -* security level advancement rules: -* Valid levels are -1 through 2, inclusive. -* From -1, stuck. [ in case compiled into kernel ] -* From 0 or above, can only increment. -*/ -static int do_seclvl_advance (int newlvl) -{ -if (newlvl <= seclvl) { -seclvl_printk (1 ,KERN_WARNING ,"Cannot advance to seclvl " -"[%d]\n" , newlvl); -return -EINVAL ; - } -if (newlvl >2 ) { -seclvl_printk (1 ,KERN_WARNING ,"Cannot advance to seclvl " -"[%d]\n" , newlvl); -return -EINVAL ; - } -if (seclvl ==-1 ) { -seclvl_printk (1 ,KERN_WARNING ,"Not allowed to advance to " -"seclvl [%d]\n" , seclvl); -return -EPERM ; - } - seclvl = newlvl; -return 0 ; + length =scnprintf (tmpbuf,TMPBUFLEN ,"%d\n" , seclvl); +return simple_read_from_buffer (buf, count, ppos, tmpbuf, length); }/**
@@ -253,57 +179,38 @@ static int do_seclvl_advance(int newlvl)* object (seclvl/seclvl). It expects a single-digit number. */ static ssize_t -seclvl_write_file (struct seclvl_obj *obj,const char *buff,size_t count) +seclvl_write_file (struct file * file,const char __user * user_buf, +size_t count,loff_t *ppos) { -unsigned long val; -if (count >2 || (count ==2 && buff[1 ] !='\n' )) { -seclvl_printk (1 ,KERN_WARNING ,"Invalid value passed to " -"seclvl: [%s]\n" , buff); +int newlvl; +int buf_size; +char buf[32 ]; + + buf_size =min (count, (sizeof (buf)-1 )); +if (copy_from_user (buf, user_buf, buf_size)) +return -EFAULT ; + +if (sscanf (buf,"%d\n" , &newlvl) !=1 )return -EINVAL ; - } - val = buff[0 ] -48 ; -if (seclvl_sanity (val)) { + +if (seclvl_sanity (newlvl)) {seclvl_printk (1 ,KERN_WARNING ,"Illegal secure level " -"requested: [%d]\n" , (int )val); -return -EPERM ; - } -if (do_seclvl_advance (val)) { -seclvl_printk (0 ,KERN_ERR ,"Failure advancing security level " -"to %lu\n" , val); +"requested: [%d]\n" , newlvl); +return -EINVAL ; } + + seclvl = newlvl;return count; } -/* Generate sysfs_attr_seclvl */ -static struct seclvl_attribute sysfs_attr_seclvl = -__ATTR (seclvl, (S_IFREG |S_IRUGO |S_IWUSR ), seclvl_read_file, - seclvl_write_file); +static struct file_operations seclvl_file_ops = { + .read = seclvl_read_file, + .write = seclvl_write_file, +};static unsigned char hashedPassword[SHA1_DIGEST_SIZE ];/** -* Called whenever the user reads the sysfs passwd handle. -*/ -static ssize_t seclvl_read_passwd (struct seclvl_obj *obj,char *buff) -{ -/* So just how good *is* your password? :-) */ -char tmp[3 ]; -int i =0 ; - buff[0 ] ='\0' ; -if (hideHash) { -/* Security through obscurity */ -return 0 ; - } -while (i <SHA1_DIGEST_SIZE ) { -snprintf (tmp,3 ,"%02x" , hashedPassword[i]); -strncat (buff, tmp,2 ); - i++; - } -strcat (buff,"\n" ); -return ((SHA1_DIGEST_SIZE *2 ) +1 ); -} - -/** * Converts a block of plaintext of into its SHA1 hashed value. * * It would be nice if crypto had a wrapper to do this for us linear
@@ -347,12 +254,15 @@ plaintext_to_sha1(unsigned char *hash, c* object. It hashes the password and compares the hashed results. */ static ssize_t -seclvl_write_passwd (struct seclvl_obj *obj,const char *buff,size_t count) +passwd_write_file (struct file * file,const char __user * buf, +size_t count,loff_t *ppos) {int i;unsigned char tmp[SHA1_DIGEST_SIZE ]; +char *page;int rc;int len; +if (!*passwd && !*sha1_passwd) {seclvl_printk (0 ,KERN_ERR ,"Attempt to password-unlock the " "seclvl module, but neither a plain text "
@@ -363,13 +273,26 @@ seclvl_write_passwd(struct seclvl_obj *o "maintainer about this event.\n");return -EINVAL ; } - len =strlen (buff); + +if (count <0 || count >=PAGE_SIZE ) +return -ENOMEM ; +if (*ppos !=0 ) { +return -EINVAL ; + } + page = (char *)get_zeroed_page (GFP_KERNEL ); +if (!page) +return -ENOMEM ; + len = -EFAULT ; +if (copy_from_user (page, buf, count)) + goto out; + + len =strlen (page);/* ``echo "secret" > seclvl/passwd'' includes a newline */ -if (buff[len -1 ] =='\n' ) { +if (page[len -1 ] =='\n' ) { len--; }/* Hash the password, then compare the hashed values */ -if ((rc =plaintext_to_sha1 (tmp, buff, len))) { +if ((rc =plaintext_to_sha1 (tmp, page, len))) {seclvl_printk (0 ,KERN_ERR ,"Error hashing password: rc = " "[%d]\n" , rc);return rc;
@@ -382,13 +305,16 @@ seclvl_write_passwd(struct seclvl_obj *oseclvl_printk (0 ,KERN_INFO ,"Password accepted; seclvl reduced to 0.\n" ); seclvl =0 ; -return count; + len = count; + +out: +free_page ((unsigned long )page); +return len; } -/* Generate sysfs_attr_passwd */ -static struct seclvl_attribute sysfs_attr_passwd = -__ATTR (passwd, (S_IFREG |S_IRUGO |S_IWUSR ), seclvl_read_passwd, - seclvl_write_passwd); +static struct file_operations passwd_file_ops = { + .write = passwd_write_file, +};/** * Explicitely disallow ptrace'ing the init process.
@@ -647,22 +573,34 @@ static int processPassword(void) }/** -* Sysfs registrations +* securityfs registrations */ -static int doSysfsRegistrations (void ) +struct dentry *dir_ino, *seclvl_ino, *passwd_ino; + +static int seclvlfs_register (void ) { -int rc =0 ; -if ((rc =subsystem_register (&seclvl_subsys))) { -seclvl_printk (0 ,KERN_WARNING , -"Error [%d] registering seclvl subsystem\n" , rc); -return rc; - } -sysfs_create_file (&seclvl_subsys.kset.kobj, &sysfs_attr_seclvl.attr); + dir_ino =securityfs_create_dir ("seclvl" ,NULL ); +if (!dir_ino) +return -EFAULT ; + + seclvl_ino =securityfs_create_file ("seclvl" ,S_IRUGO |S_IWUSR , + dir_ino,NULL , &seclvl_file_ops); +if (!seclvl_ino) + goto out_deldir;if (*passwd || *sha1_passwd) { -sysfs_create_file (&seclvl_subsys.kset.kobj, - &sysfs_attr_passwd.attr); + passwd_ino =securityfs_create_file ("passwd" ,S_IRUGO |S_IWUSR , + dir_ino,NULL , &passwd_file_ops); +if (!passwd_ino) + goto out_delf; }return 0 ; + +out_deldir: +securityfs_remove (dir_ino); +out_delf: +securityfs_remove (seclvl_ino); + +return -EFAULT ; }/**
@@ -677,8 +615,6 @@ static int __init seclvl_init(void) rc = -EINVAL ; goto exit; } - sysfs_attr_seclvl.attr.owner =THIS_MODULE ; - sysfs_attr_passwd.attr.owner =THIS_MODULE ;if (initlvl <-1 || initlvl >2 ) {seclvl_printk (0 ,KERN_ERR ,"Error: bad initial securelevel " "[%d].\n" , initlvl);
@@ -706,7 +642,7 @@ static int __init seclvl_init(void) }/* if primary module registered */ secondary =1 ; }/* if we registered ourselves with the security framework */ -if ((rc =doSysfsRegistrations ())) { +if ((rc =seclvlfs_register ())) {seclvl_printk (0 ,KERN_ERR ,"Error registering with sysfs\n" ); goto exit; }
@@ -724,12 +660,11 @@ static int __init seclvl_init(void)*/ static void __exit seclvl_exit(void) { -sysfs_remove_file (&seclvl_subsys.kset.kobj, &sysfs_attr_seclvl.attr); +securityfs_remove (seclvl_ino);if (*passwd || *sha1_passwd) { -sysfs_remove_file (&seclvl_subsys.kset.kobj, - &sysfs_attr_passwd.attr); +securityfs_remove (passwd_ino); } -subsystem_unregister (&seclvl_subsys); +securityfs_remove (dir_ino);if (secondary ==1 ) {mod_unreg_security (MY_NAME , &seclvl_ops); }else if (unregister_security (&seclvl_ops)) {
Re: [PATCH] securityfs
Quoted 12 lines · On Thu, Jul 07, 2005 at 12:30:35PM -0500, [email protected] wrote:
Quoted 11 lines · Greg KH
Quoted 7 lines · On Wed, Jul 06, 2005 at 05:08:35PM -0500, [email protected] wrote:
Quoted 3 lines · Greg KH
think it could be made even smaller if you use the default read and write file type functions in libfs (look at the debugfs wrappers of them for u8, u16, etc, for examples of how to use them.)
The attached patch cleans up the securelevel code for the seclvl file. Is this a reasonable way to go about this?
No.
Quoted 7 lines
Quoted 4 lines
Quoted 1 line
Or is there a better way to do this?
Look at how debugfs uses the libfs code. We should not need to add these handlers to securityfs.
Unfortunately the
simple_attrcode from libfs really doesn't seem to be usable for int args.
Why not? You want a negative number? Just cast the u64 to a signed int then. Will that not work? If not we can tweak the libfs interface to work properly for you.
Quoted 2 lines
However the below patch follows some of the
examples in debugfs and comes out cleaner than my original patch.
That is nicer. But I think you can get it smaller with the libfs stuff :)
thanks,
greg k-h
Re: [PATCH] securityfs
Quoted 6 lines · Greg KH
Quoted 2 lines
Unfortunately the
simple_attrcode from libfs really doesn't seem to be usable for int args.Why not? You want a negative number? Just cast the u64 to a signed int then. Will that not work? If not we can tweak the libfs interface to work properly for you.
Hmm, I ran into two problems:
1, the __simple_attr_check_format seems to complain about a "%d" format.
2, when I try just doing the typecasting, I get an oops...
The patch below is my attempt. The oops follows, but I'll look at it some more tomorrow. It seems like it has to be something obvious...
Jul 7 18:14:42 serge-hv4 kernel: Oops: Kernel access of bad area, sig: 11 [#2] Jul 7 18:14:42 serge-hv4 kernel: SMP NR_CPUS=128 NUMA PSERIES LPAR Jul 7 18:14:42 serge-hv4 kernel: Modules linked in: seclvl ipv6 sg binfmt_misc dm_mod Jul 7 18:14:42 serge-hv4 kernel: NIP: D00000000002F1DC XER: 20000001 LR: C0000000000E3A58 CTR: D00000000002F1DC Jul 7 18:14:42 serge-hv4 kernel: REGS: c00000004256f9c0 TRAP: 0300 Not tainted (2.6.13-rc1-seclvl) Jul 7 18:14:42 serge-hv4 kernel: MSR: 8000000000009032 EE: 1 PR: 0 FP: 0 ME: 1 IR/DR: 11 CR: 24040482 Jul 7 18:14:42 serge-hv4 kernel: DAR: 0000000000000000 DSISR: 0000000040000000 Jul 7 18:14:42 serge-hv4 kernel: TASK: c000000043858030[4707] 'cat' THREAD: c00000004256c000 CPU: 3 Jul 7 18:14:42 serge-hv4 kernel: GPR00: D00000000002F1DC C00000004256FC40 D000000000040888 0000000000000000 Jul 7 18:14:42 serge-hv4 kernel: GPR04: 0000000010015858 0000000000001000 C00000004256FE08 0000000000001000 Jul 7 18:14:42 serge-hv4 kernel: GPR08: 0000000010015858 D0000000000387B8 C000000000538D78 D00000000002F1E4 Jul 7 18:14:42 serge-hv4 kernel: GPR12: 0000000000000000 C000000000435400 00000000100F3458 0000000000000001 Jul 7 18:14:42 serge-hv4 kernel: GPR16: 0000000000001000 00000000FFFFFFFF 0000000000000000 0000000000000000 Jul 7 18:14:42 serge-hv4 kernel: GPR20: 0000000010015858 00000000FFEF4D14 0000000000000002 0000000000000000 Jul 7 18:14:42 serge-hv4 kernel: GPR24: 0000000044222442 0000000000001000 0000000010015858 C00000004256FE08 Jul 7 18:14:42 serge-hv4 kernel: GPR28: C000000047C00F10 C000000047C00F50 C0000000004AC920 C000000047C00F00 Jul 7 18:14:42 serge-hv4 kernel: NIP [d00000000002f1dc] .seclvl_int_get+0x0/0x8 [seclvl] Jul 7 18:14:42 serge-hv4 kernel: LR [c0000000000e3a58] .simple_attr_read+0xb8/0x168 Jul 7 18:14:42 serge-hv4 kernel: Call Trace: Jul 7 18:14:42 serge-hv4 kernel: [c00000004256fc40] [000000000ffca938] 0xffca938 (unreliable) Jul 7 18:14:42 serge-hv4 kernel: [c00000004256fcf0] [c0000000000b13bc] .vfs_read+0x1c0/0x1c8 Jul 7 18:14:42 serge-hv4 kernel: [c00000004256fd90] [c0000000000b1740] .sys_read+0x4c/0x90 Jul 7 18:14:42 serge-hv4 kernel: [c00000004256fe30] [c00000000000d600] syscall_exit+0x0/0x18 Jul 7 18:14:42 serge-hv4 kernel: Instruction dump: Jul 7 18:14:42 serge-hv4 kernel: e93e8008 ebbe8060 ebe90000 e81d0000 7c00f850 2ba003e8 409dfe94 e8be8058 Jul 7 18:14:42 serge-hv4 kernel: e87e8068 e89e8020 38c0ffff 4bffff94 <e8630000> 4e800020 7c0802a6 fbc1fff0
thanks,
-serge
include/linux/fs.h +0 -1
@@ -1717,7 +1717,6 @@ static inline void simple_transaction_se#define DEFINE_SIMPLE_ATTRIBUTE (__fops, __get, __set, __fmt) \ static int __fops ## _open(struct inode *inode, struct file *file) \ { \ - __simple_attr_check_format(__fmt, 0ull); \ return simple_attr_open(inode, file, __get, __set, __fmt); \ } \ static struct file_operations __fops = { \
security/seclvl.c +70 -158
323 lines not on this page · raw message
[email protected]
maintainerRe: [PATCH] securityfs
Quoted 4 lines · Quoting [email protected] ([email protected]):
Quoted 3 lines · Greg KH
Quoted 2 lines
Unfortunately the
simple_attrcode from libfs really doesn't seem to be usable for int args.
Quoted 8 lines
Quoted 3 lines
Why not? You want a negative number? Just cast the u64 to a signed int then. Will that not work? If not we can tweak the libfs interface to work properly for you.
Hmm, I ran into two problems:
1, the__simple_attr_check_formatseems to complain about a "%d" format.
2, when I try just doing the typecasting, I get an oops...
Uh, never mind...
please don't look at that patch :)
With the obvious fix, that does in fact work (patch appended). The __simple_attr_check_format problem remains however. I assume we don't really want to just take it out, though, like this patch does? The error I get without the fs.h patch is:
security/seclvl.c: In function `seclvl_file_ops_open':security/seclvl.c:186: warning: int format, different type arg (arg 2)
thanks,
-serge
--
include/linux/fs.h | 1 security/seclvl.c | 228 ++++++++++++++++------------------------------------- 2 files changed, 70 insertions(+), 159 deletions(-)
include/linux/fs.h +0 -1
@@ -1717,7 +1717,6 @@ static inline void simple_transaction_se#define DEFINE_SIMPLE_ATTRIBUTE (__fops, __get, __set, __fmt) \ static int __fops ## _open(struct inode *inode, struct file *file) \ { \ - __simple_attr_check_format(__fmt, 0ull); \ return simple_attr_open(inode, file, __get, __set, __fmt); \ } \ static struct file_operations __fops = { \
security/seclvl.c +70 -158
323 lines not on this page · raw message
Re: [PATCH] securityfs
Quoted 2 lines · On Thu, Jul 07, 2005 at 05:46:04PM -0500, [email protected] wrote:
With the obvious fix, that does in fact work (patch appended).
Good.
Quoted 2 lines
The
__simple_attr_check_formatproblem remains however. I assume we don't really want to just take it out, though, like this patch does?
No we do not.
Quoted 4 lines
The error I get without the
fs.hpatch is:
security/seclvl.c: In function `seclvl_file_ops_open':security/seclvl.c:186: warning: int format, different type arg (arg 2)
Care to work to try to fix it up?
thanks,
greg k-h
Re: [PATCH] securityfs
Quoted 9 lines · Greg KH
Quoted 2 lines · On Thu, Jul 07, 2005 at 05:46:04PM -0500, [email protected] wrote:
With the obvious fix, that does in fact work (patch appended).
Good.
Quoted 2 lines
The
__simple_attr_check_formatproblem remains however. I assume we don't really want to just take it out, though, like this patch does?
Quoted 8 lines
No we do not.
Quoted 4 lines
The error I get without the
fs.hpatch is:
security/seclvl.c: In function `seclvl_file_ops_open':security/seclvl.c:186: warning: int format, different type arg (arg 2)Care to work to try to fix it up?
Yes I do, thanks :)
-serge
Re: [PATCH] securityfs
In reply to Greg KHQuoted 9 lines · Greg KH
Quoted 2 lines · On Thu, Jul 07, 2005 at 05:46:04PM -0500, [email protected] wrote:
With the obvious fix, that does in fact work (patch appended).
Good.
Quoted 2 lines
The
__simple_attr_check_formatproblem remains however. I assume we don't really want to just take it out, though, like this patch does?
Quoted 8 lines
No we do not.
Quoted 4 lines
The error I get without the
fs.hpatch is:
security/seclvl.c: In function `seclvl_file_ops_open':security/seclvl.c:186: warning: int format, different type arg (arg 2)Care to work to try to fix it up?
Once again, the simple_attr in libfs was actually sufficient - I'd thought the __attribute__(format(printk(1,2))) was more mysterious than it really is.
At last, here is the full patch to make seclvl use securityfs.
thanks,
-serge
--
seclvl.c | 228 +++++++++++++++++++-------------------------------------------- 1 files changed, 70 insertions(+), 158 deletions(-)
security/seclvl.c +70 -158
@@ -119,69 +119,6 @@ MODULE_PARM_DESC(hideHash, "When set to }while (0 )/** -* kobject stuff -*/ - -struct subsystem seclvl_subsys; - -struct seclvl_obj { -char *name; -struct list_head slot_list; -struct kobject kobj; -}; - -/** -* There is a seclvl_attribute struct for each file in sysfs. -* -* In our case, we have one of these structs for "passwd" and another -* for "seclvl". -*/ -struct seclvl_attribute { -struct attribute attr; -ssize_t (*show) (struct seclvl_obj *,char *); -ssize_t (*store) (struct seclvl_obj *,const char *,size_t ); -}; - -/** -* When this function is called, one of the files in sysfs is being -* written to. attribute->store is a function pointer to whatever the -* struct seclvl_attribute store function pointer points to. It is -* unique for "passwd" and "seclvl". -*/ -static ssize_t -seclvl_attr_store (struct kobject *kobj, -struct attribute *attr,const char *buf,size_t len) -{ - struct seclvl_obj *obj = container_of(kobj, struct seclvl_obj, kobj); -struct seclvl_attribute *attribute = - container_of(attr, struct seclvl_attribute, attr); -return attribute->store ? attribute->store (obj, buf, len) : -EIO ; -} - -static ssize_t -seclvl_attr_show (struct kobject *kobj,struct attribute *attr,char *buf) -{ - struct seclvl_obj *obj = container_of(kobj, struct seclvl_obj, kobj); -struct seclvl_attribute *attribute = - container_of(attr, struct seclvl_attribute, attr); -return attribute->show ? attribute->show (obj, buf) : -EIO ; -} - -/** -* Callback function pointers for show and store -*/ -static struct sysfs_ops seclvlfs_sysfs_ops = { - .show = seclvl_attr_show, - .store = seclvl_attr_store, -}; - -static struct kobj_type seclvl_ktype = { - .sysfs_ops = &seclvlfs_sysfs_ops -}; - -decl_subsys (seclvl, &seclvl_ktype,NULL ); - -/** * The actual security level. Ranges between -1 and 2 inclusive. */ static int seclvl;
@@ -213,97 +150,44 @@ static int seclvl_sanity(int reqlvl) }/** -* Called whenever the user reads the sysfs handle to this kernel -* object -*/ -static ssize_t seclvl_read_file (struct seclvl_obj *obj,char *buff) -{ -return snprintf (buff,PAGE_SIZE ,"%d\n" , seclvl); -} - -/** * security level advancement rules: * Valid levels are -1 through 2, inclusive. * From -1, stuck. [ in case compiled into kernel ] * From 0 or above, can only increment. */ -static int do_seclvl_advance (int newlvl) +static void do_seclvl_advance (void *data,u64 val) { -if (newlvl <= seclvl) { -seclvl_printk (1 ,KERN_WARNING ,"Cannot advance to seclvl " -"[%d]\n" , newlvl); -return -EINVAL ; - } +int ret; +int newlvl = (int )val; + + ret =seclvl_sanity (newlvl); +if (ret) +return ; +if (newlvl >2 ) {seclvl_printk (1 ,KERN_WARNING ,"Cannot advance to seclvl " "[%d]\n" , newlvl); -return -EINVAL ; +return ; }if (seclvl ==-1 ) {seclvl_printk (1 ,KERN_WARNING ,"Not allowed to advance to " "seclvl [%d]\n" , seclvl); -return -EPERM ; +return ; } - seclvl = newlvl; -return 0 ; + seclvl = newlvl;/* would it be more "correct" to set *data? */ +return ; } -/** -* Called whenever the user writes to the sysfs handle to this kernel -* object (seclvl/seclvl). It expects a single-digit number. -*/ -static ssize_t -seclvl_write_file (struct seclvl_obj *obj,const char *buff,size_t count) +static u64 seclvl_int_get (void *data) { -unsigned long val; -if (count >2 || (count ==2 && buff[1 ] !='\n' )) { -seclvl_printk (1 ,KERN_WARNING ,"Invalid value passed to " -"seclvl: [%s]\n" , buff); -return -EINVAL ; - } - val = buff[0 ] -48 ; -if (seclvl_sanity (val)) { -seclvl_printk (1 ,KERN_WARNING ,"Illegal secure level " -"requested: [%d]\n" , (int )val); -return -EPERM ; - } -if (do_seclvl_advance (val)) { -seclvl_printk (0 ,KERN_ERR ,"Failure advancing security level " -"to %lu\n" , val); - } -return count; +return *(int *)data; } -/* Generate sysfs_attr_seclvl */ -static struct seclvl_attribute sysfs_attr_seclvl = -__ATTR (seclvl, (S_IFREG |S_IRUGO |S_IWUSR ), seclvl_read_file, - seclvl_write_file); +DEFINE_SIMPLE_ATTRIBUTE (seclvl_file_ops, seclvl_int_get, do_seclvl_advance,"%lld\n" );static unsigned char hashedPassword[SHA1_DIGEST_SIZE ];/** -* Called whenever the user reads the sysfs passwd handle. -*/ -static ssize_t seclvl_read_passwd (struct seclvl_obj *obj,char *buff) -{ -/* So just how good *is* your password? :-) */ -char tmp[3 ]; -int i =0 ; - buff[0 ] ='\0' ; -if (hideHash) { -/* Security through obscurity */ -return 0 ; - } -while (i <SHA1_DIGEST_SIZE ) { -snprintf (tmp,3 ,"%02x" , hashedPassword[i]); -strncat (buff, tmp,2 ); - i++; - } -strcat (buff,"\n" ); -return ((SHA1_DIGEST_SIZE *2 ) +1 ); -} - -/** * Converts a block of plaintext of into its SHA1 hashed value. * * It would be nice if crypto had a wrapper to do this for us linear
@@ -347,12 +231,15 @@ plaintext_to_sha1(unsigned char *hash, c* object. It hashes the password and compares the hashed results. */ static ssize_t -seclvl_write_passwd (struct seclvl_obj *obj,const char *buff,size_t count) +passwd_write_file (struct file * file,const char __user * buf, +size_t count,loff_t *ppos) {int i;unsigned char tmp[SHA1_DIGEST_SIZE ]; +char *page;int rc;int len; +if (!*passwd && !*sha1_passwd) {seclvl_printk (0 ,KERN_ERR ,"Attempt to password-unlock the " "seclvl module, but neither a plain text "
@@ -363,13 +250,26 @@ seclvl_write_passwd(struct seclvl_obj *o "maintainer about this event.\n");return -EINVAL ; } - len =strlen (buff); + +if (count <0 || count >=PAGE_SIZE ) +return -ENOMEM ; +if (*ppos !=0 ) { +return -EINVAL ; + } + page = (char *)get_zeroed_page (GFP_KERNEL ); +if (!page) +return -ENOMEM ; + len = -EFAULT ; +if (copy_from_user (page, buf, count)) + goto out; + + len =strlen (page);/* ``echo "secret" > seclvl/passwd'' includes a newline */ -if (buff[len -1 ] =='\n' ) { +if (page[len -1 ] =='\n' ) { len--; }/* Hash the password, then compare the hashed values */ -if ((rc =plaintext_to_sha1 (tmp, buff, len))) { +if ((rc =plaintext_to_sha1 (tmp, page, len))) {seclvl_printk (0 ,KERN_ERR ,"Error hashing password: rc = " "[%d]\n" , rc);return rc;
@@ -382,13 +282,16 @@ seclvl_write_passwd(struct seclvl_obj *oseclvl_printk (0 ,KERN_INFO ,"Password accepted; seclvl reduced to 0.\n" ); seclvl =0 ; -return count; + len = count; + +out: +free_page ((unsigned long )page); +return len; } -/* Generate sysfs_attr_passwd */ -static struct seclvl_attribute sysfs_attr_passwd = -__ATTR (passwd, (S_IFREG |S_IRUGO |S_IWUSR ), seclvl_read_passwd, - seclvl_write_passwd); +static struct file_operations passwd_file_ops = { + .write = passwd_write_file, +};/** * Explicitely disallow ptrace'ing the init process.
@@ -647,22 +550,34 @@ static int processPassword(void) }/** -* Sysfs registrations +* securityfs registrations */ -static int doSysfsRegistrations (void ) +struct dentry *dir_ino, *seclvl_ino, *passwd_ino; + +static int seclvlfs_register (void ) { -int rc =0 ; -if ((rc =subsystem_register (&seclvl_subsys))) { -seclvl_printk (0 ,KERN_WARNING , -"Error [%d] registering seclvl subsystem\n" , rc); -return rc; - } -sysfs_create_file (&seclvl_subsys.kset.kobj, &sysfs_attr_seclvl.attr); + dir_ino =securityfs_create_dir ("seclvl" ,NULL ); +if (!dir_ino) +return -EFAULT ; + + seclvl_ino =securityfs_create_file ("seclvl" ,S_IRUGO |S_IWUSR , + dir_ino, &seclvl, &seclvl_file_ops); +if (!seclvl_ino) + goto out_deldir;if (*passwd || *sha1_passwd) { -sysfs_create_file (&seclvl_subsys.kset.kobj, - &sysfs_attr_passwd.attr); + passwd_ino =securityfs_create_file ("passwd" ,S_IRUGO |S_IWUSR , + dir_ino,NULL , &passwd_file_ops); +if (!passwd_ino) + goto out_delf; }return 0 ; + +out_deldir: +securityfs_remove (dir_ino); +out_delf: +securityfs_remove (seclvl_ino); + +return -EFAULT ; }/**
@@ -677,8 +592,6 @@ static int __init seclvl_init(void) rc = -EINVAL ; goto exit; } - sysfs_attr_seclvl.attr.owner =THIS_MODULE ; - sysfs_attr_passwd.attr.owner =THIS_MODULE ;if (initlvl <-1 || initlvl >2 ) {seclvl_printk (0 ,KERN_ERR ,"Error: bad initial securelevel " "[%d].\n" , initlvl);
@@ -706,7 +619,7 @@ static int __init seclvl_init(void) }/* if primary module registered */ secondary =1 ; }/* if we registered ourselves with the security framework */ -if ((rc =doSysfsRegistrations ())) { +if ((rc =seclvlfs_register ())) {seclvl_printk (0 ,KERN_ERR ,"Error registering with sysfs\n" ); goto exit; }
@@ -724,12 +637,11 @@ static int __init seclvl_init(void)*/ static void __exit seclvl_exit(void) { -sysfs_remove_file (&seclvl_subsys.kset.kobj, &sysfs_attr_seclvl.attr); +securityfs_remove (seclvl_ino);if (*passwd || *sha1_passwd) { -sysfs_remove_file (&seclvl_subsys.kset.kobj, - &sysfs_attr_passwd.attr); +securityfs_remove (passwd_ino); } -subsystem_unregister (&seclvl_subsys); +securityfs_remove (dir_ino);if (secondary ==1 ) {mod_unreg_security (MY_NAME , &seclvl_ops); }else if (unregister_security (&seclvl_ops)) {
Re: [PATCH] securityfs
Quoted 25 lines · On Fri, Jul 08, 2005 at 03:44:19PM -0500, [email protected] wrote:
Quoted 9 lines · Greg KH
Quoted 2 lines · On Thu, Jul 07, 2005 at 05:46:04PM -0500, [email protected] wrote:
With the obvious fix, that does in fact work (patch appended).
Good.
Quoted 2 lines
The
__simple_attr_check_formatproblem remains however. I assume we don't really want to just take it out, though, like this patch does?Quoted 8 lines
No we do not.
Quoted 4 lines
The error I get without the
fs.hpatch is:
security/seclvl.c: In function `seclvl_file_ops_open':security/seclvl.c:186: warning: int format, different type arg (arg 2)Care to work to try to fix it up?
Once again, the
simple_attrin libfs was actually sufficient - I'd thought the __attribute__(format(printk(1,2))) was more mysterious than it really is.At last, here is the full patch to make seclvl use securityfs.
Quoted 7 lines
thanks,
-sergeSigned-off-by Serge Hallyn <[email protected]>--
seclvl.c | 228 +++++++++++++++++++-------------------------------------------- 1 files changed, 70 insertions(+), 158 deletions(-)
Very nice, it's always good to end up removing lines of code :)
thanks for verifying that it all works properly.
Chris, care to forward the securityfs patch to Linus?
thanks,
greg k-h
Re: [PATCH] securityfs
Quoted 1 line · * Greg KH ([email protected]) wrote:
Chris, care to forward the securityfs patch to Linus?
Yeah, I've got it queued up right now, and I'm playing with it a bit. As well as this one. Thanks guys.
-chris
Re: [patch 5/12] lsm stacking v0.2: actual stacker module
In reply to [email protected]Hey Serge,
I don't think your symbol_get() is doing what you think it is ;-)
Quoted 6 lines
+ * Add the stacked module (as specified by name and ops).
+ * If the module is not compiled in, thesymbol_getat the end will
+ * prevent the the module from being unloaded.(quoted diff) +3
-0+*/ +static int stacker_register (const char *name, struct security_operations *ops) +{
...
Review
Quoted 6 lines
(quoted diff) +6
-0+ symbol_get(ops); + +out: + spin_unlock(&stacker_lock); + return ret; +}
Seemed useful to be able to view which modules had been unloaded. Easier to maintain them on their own list than to compute the difference of <stacked_modules> and <all_modules>. Patch attached, not sure if you are cool with reusing the 'unload' file.
Review
Quoted 4 lines
(quoted diff) +4
-0+static struct stacker_attribute stacker_attr_unload = { + .attr = {.name = "unload", .mode = S_IFREG | S_IRUGO | S_IWUSR}, + .store = stacker_unload_write, +};
Apart from this, looks good. I ran it against our regression tests using AppArmor (SubDomain) composed with Capability and everything was functionally
as expected. I still need to run it through our SMP stress tests.
Thanks
Tony
stacker.c renamed from stacker.c.orig +20 -0
@@ -39,6 +39,7 @@struct security_operations module_operations; };static struct list_head stacked_modules;/* list of stacked modules */ +static struct list_head unloaded_modules;/* list of unloaded modules */ static struct list_head all_modules;/* list of all modules, including freed */ static short sysfsfiles_registered;
@@ -1439,6 +1440,7 @@rcu_read_lock ();list_del_rcu (&m->lsm_list); +list_add_tail_rcu (&m->lsm_list, &unloaded_modules);if (list_empty (&stacked_modules)) {INIT_LIST_HEAD (&default_module.lsm_list);list_add_tail_rcu (&default_module.lsm_list, &stacked_modules);
@@ -1452,9 +1454,26 @@return ret; } +/* list unloaded modules */ +static ssize_t stacker_unload_read (struct stacker_kobj *obj,char *buff) +{ +ssize_t len =0 ; +struct module_entry *m; + +rcu_read_lock (); +stack_for_each_entry (m, &unloaded_modules, lsm_list) { + len +=snprintf (buff+len,PAGE_SIZE - len,"%s\n" , + m->module_name); + } +rcu_read_unlock (); + +return len; +} +static struct stacker_attribute stacker_attr_unload = { .attr = {.name ="unload" , .mode =S_IFREG |S_IRUGO |S_IWUSR }, .store = stacker_unload_write, + .show = stacker_unload_read, };
@@ -1525,6 +1544,7 @@INIT_LIST_HEAD (&stacked_modules);INIT_LIST_HEAD (&all_modules); +INIT_LIST_HEAD (&unloaded_modules);spin_lock_init (&stacker_lock); default_module.module_name =DEFAULT_MODULE_NAME ; default_module.namelen =strlen (DEFAULT_MODULE_NAME );
[email protected]
maintainerRe: [patch 5/12] lsm stacking v0.2: actual stacker module
Quoted 3 lines · Tony Jones
Hey Serge,
I don't think your
symbol_get()is doing what you think it is ;-)
Hmm, I wonder whether something changed. It shouldn't be possible to rmmod module b if module a has done a symbol_get on it... This may mean more stringent locking will be required after all to support unloading. That, or a rmmod lsm hook.
Quoted 7 lines
Quoted 6 lines
+ * Add the stacked module (as specified by name and ops).
+ * If the module is not compiled in, thesymbol_getat the end will
+ * prevent the the module from being unloaded.(quoted diff) +3
-0+*/ +static int stacker_register (const char *name, struct security_operations *ops) +{...
Quoted 12 lines
Review
Quoted 6 lines
(quoted diff) +6
-0+ symbol_get(ops); + +out: + spin_unlock(&stacker_lock); + return ret; +}Seemed useful to be able to view which modules had been unloaded. Easier to maintain them on their own list than to compute the difference of <
stacked_modules> and <all_modules>. Patch attached, not sure if you are cool with reusing the 'unload' file.
No, that's good, thanks. Though I guess "unloading" of this type won't be needed if true module deletion has to be supported.
Quoted 3 lines
Apart from this, looks good. I ran it against our regression tests using AppArmor (SubDomain) composed with Capability and everything was functionally
as expected. I still need to run it through our SMP stress tests.
Excellent :)
thanks,
-serge
Re: [patch 5/12] lsm stacking v0.2: actual stacker module
Quoted 4 lines · On Mon, Jul 04, 2005 at 06:51:35AM -0500, [email protected] wrote:
Quoted 1 line
I don't think your
symbol_get()is doing what you think it is ;-)Hmm, I wonder whether something changed. It shouldn't be possible to rmmod module b if module a has done a
symbol_geton it...
Are you thinking of resolve_symbol rather than get_symbol?
You are calling __symbol_get("ops").
Maybe (/probably :-)) I'm totally misunderstanding what you are doing but:
a) I would have thought you would need to call symbol_get on the name the caller was passing, i.e symbol_get(capability_security_ops)
b) The module registering these ops would need to EXPORT_SYMBOL this name.
c) mod->state is MODULE_STATE_COMING right before the call to mod->init in sys_init_module which causes any symbol_gets() to return 0 (not that you actually care about the return value, only it's side effect)
d) I don't see anything in this code path that would incr a ref on the registering module as a side effect of returning the sym.
Quoted 2 lines
more stringent locking will be required after all to support unloading. That, or a rmmod lsm hook.
Yep. I was able to rmmod subdomain and capability, the former with unpleasant results.
Tony
[email protected]
maintainerRe: [patch 5/12] lsm stacking v0.2: actual stacker module
Quoted 11 lines · Tony Jones
Quoted 4 lines · On Mon, Jul 04, 2005 at 06:51:35AM -0500, [email protected] wrote:
Quoted 1 line
I don't think your
symbol_get()is doing what you think it is ;-)Hmm, I wonder whether something changed. It shouldn't be possible to rmmod module b if module a has done a
symbol_geton it...Are you thinking of
resolve_symbolrather thanget_symbol?You are calling
__symbol_get("ops").
Quoted 9 lines
Maybe (/probably :-)) I'm totally misunderstanding what you are doing but:
a) I would have thought you would need to callsymbol_geton the name the caller was passing, i.esymbol_get(capability_security_ops)
b) The module registering these ops would need toEXPORT_SYMBOLthis name.
c)mod->stateisMODULE_STATE_COMINGright before the call tomod->initinsys_init_modulewhich causes anysymbol_gets()to return 0 (not that you actually care about the return value, only it's side effect)
d) I don't see anything in this code path that would incr a ref on the registering module as a side effect of returning the sym.
__symbol_get should eventually call try_module_get, which increments the use count, right?
But I'm completely misusing symbol_get - as you say, that is supposed to be "symbol_name", not a pointer to the symbol.
Any suggestions on a good way to do what I wanted to do? Frankly a new LSM hook seems the cleanest solution. Or, I could ramp up the locking and permit module deletion, probably at a bit of performance cost. Or I could just count on modules doing a symbol_get on themselves?
thanks,
-serge
Re: [patch 5/12] lsm stacking v0.2: actual stacker module
Quoted 12 lines · On Mon, Jul 04, 2005 at 03:06:46PM -0500, [email protected] wrote:
Quoted 11 lines
You are calling
__symbol_get("ops").Maybe (/probably :-)) I'm totally misunderstanding what you are doing but:
a) I would have thought you would need to callsymbol_geton the name the caller was passing, i.esymbol_get(capability_security_ops)
b) The module registering these ops would need toEXPORT_SYMBOLthis name.
c)mod->stateisMODULE_STATE_COMINGright before the call tomod->initinsys_init_modulewhich causes anysymbol_gets()to return 0 (not that you actually care about the return value, only it's side effect)
d) I don't see anything in this code path that would incr a ref on the registering module as a side effect of returning the sym.
Quoted 2 lines
__symbol_getshould eventually calltry_module_get, which increments the use count, right?
Duh, I missed the call to try_module_get, probably because it's right below the 'if (mod && mod->state == MODULE_STATE_COMING) return 0;' :-) in strong_try_module_get (2.6.13-rc1)
mod->state is MODULE_STATE_COMING until after mod->init returns and since you are calling __symbol_get indirectly from the modules init routine, bammo.
Quoted 5 lines
Any suggestions on a good way to do what I wanted to do? Frankly a new LSM hook seems the cleanest solution. Or, I could ramp up the locking and permit module deletion, probably at a bit of performance cost. Or I could just count on modules doing a
symbol_geton themselves?
I think any symbol_get is problematic given the above. I was thinking you could wrap mod_reg_security but it would still need to be called from within the modules init fn.
I'm going to have to give it some thought, but a new rmmod hook does seem a good solution off the top of my head.
Tony
[email protected]
maintainerRe: [patch 5/12] lsm stacking v0.2: actual stacker module
Quoted 2 lines · Tony Jones
I'm going to have to give it some thought, but a new rmmod hook does seem a good solution off the top of my head.
In reponse to some prodding by Tony, here is a summary of the current locking scheme in stacker, sprinkled with some notes about one way lsm removal could be supported.
This will likely be added to the Documentation/stacker.txt file.
thanks,
-serge
The following describes the locking used by the lsm stacker as of July 1, 2005:
Things which require locking include:
1. module list
2. per-kernel-object security lists
The module list is protected as follows:
Walking the list is done under a partial rcu_read_lock. In particular, we cannot hold the rcu_read_lock while calling a module_entry->lsm_hook(), as these are very likely to sleep. Therefore we call rcu_read_lock() only when we rcu_dereference module_entry->next.
module_entries are not to be deleted. By using the stacker_unload() function, they may be removed from the stacked_modules list. The forward pointer is not changed, so that any stacker hook which is currently on module_entry can safely and correctly dereference module_entry->next. The module_entry remains on the all_modules list, which is used when kernel objects are freed. In this way, any memory allocated by module_entry can still be freed.
In the past, module deletion was supported in this scheme as
follows: we added a reference count to the module_entry, which was incremented (under the rcu_read_lock) whenever a stacker hook was going to execute module_entry->lsm_hook(). Module deletion was then done from a call_rcu(). If the refcount was not null after an rcu cycle, the del_func could delete the module. Otherwise, it decremented the usage count, so that when the stacker hook returned from lsm_hook() it would find the refcount at 1, and delete the module.
Re-enabling module deletion in this way should have a performance impact, and would require all modules to delete all their allocated kernel memory during module_exit().
The kernel object security lists are protected as follows:
The security_set_value and security_del_value are only to be called during security_alloc_object and security_del_object, respectively. Since these are automatically safe from concurrent accesses, no locking is required here.
The security_add_value() function is protected from concurrent access using the stacker_value_spinlock. security_get_value() is protected from security_add_value() using rcu.
To allow module deletion, it would be desirable for modules to be able to delete kernel object security entries at any time. This should be safe to do using RCU. Modules would use security_unlink_value(), which would use hlist_del_rcu() to free the value, and LSMs would have to use call_rcu() to free the data in order to protect racing security_get_value()s. This would happen as follows:
1. security_unlink_value() would basically be security_del_value protected using the stacker_value_spinlock().
2. An LSM would delete a value using:
my_struct = security_unlink_value_type(&inode->i_security,
MY_LSM_ID, struct my_struct);
< do any necessary freeing of LSM data> security_free_value_type(my_struct);
3. security_free_value_type would use call_rcu to kfree my_struct.
Re: [patch 5/12] lsm stacking v0.2: actual stacker module
In reply to Tony JonesQuoted 5 lines · Tony Jones
Hey Serge,
Seemed useful to be able to view which modules had been unloaded. Easier to maintain them on their own list than to compute the difference of <stacked_modules> and <all_modules>. Patch attached, not sure if you are cool with reusing the 'unload' file.
Attached is a patch to re-introduce the necessary locking to allow unloading of LSMs. I don't have any performance results nor hardcore stability tests yet.
This version does not support dynamic removal of ->security data, though - that still has to be done when the object is deleted. So while unloading an LSM is safe, it is also likely to leak memory. If we decide this patch is the way to go, then we can tackle ->security data next.
Hopefully I'll have performance data to send out next week.
thanks,
-serge
--
stacker.c | 255 ++++++++++++++++++++++++++++++++++++++------------------------ 1 files changed, 160 insertions(+), 95 deletions(-)
security/stacker.c +160 -95
@@ -33,13 +33,13 @@struct module_entry {struct list_head lsm_list;/* list of active lsms */ -struct list_head all_lsms;/* list of all lsms */ char *module_name;int namelen;struct security_operations module_operations; +struct rcu_head m_rcu; +atomic_t use; };static struct list_head stacked_modules;/* list of stacked modules */ -static struct list_head all_modules;/* list of all modules, including freed */ static short sysfsfiles_registered;
@@ -84,6 +84,32 @@ MODULE_PARM_DESC(debug, "Debug enabled o* We return as soon as an error is returned. */ +static inline void stacker_free_module (struct module_entry *m) +{ +kfree (m->module_name); +kfree (m); +} + +/* +* Version of stacker_free_module called from call_rcu +*/ +static void free_mod_fromrcu (struct rcu_head *head) +{ +struct module_entry *m; + + m = container_of(head, struct module_entry, m_rcu); +stacker_free_module (m); +} + +static void stacker_del_module (struct rcu_head *head) +{ +struct module_entry *m; + + m = container_of(head, struct module_entry, m_rcu); +if (atomic_dec_and_test (&m->use)) +stacker_free_module (m); +} +#define stack_for_each_entry (pos, head, member) \ for (pos = list_entry((head)->next, typeof(*pos), member); \ &pos->member != (head); \
@@ -93,16 +119,27 @@ MODULE_PARM_DESC(debug, "Debug enabled o/* to make this safe for module deletion, we would need to * add a reference count to m as we had before */ +/* +* XXX We can't quite do this - we delete the module before we grab +* m->next? +* We could just do a call_rcu. Then the call_rcu happens in same +* rcu cycle has dereference, so module won't be deleted until the +* next cycle. +* That's what I'm going to do. +*/ #define RETURN_ERROR_IF_ANY_ERROR (BASE_FUNC ,FUNC_WITH_ARGS ) do { \ int result = 0; \ struct module_entry *m; \ rcu_read_lock(); \ stack_for_each_entry(m, &stacked_modules, lsm_list) { \ - if (!m->module_operations.BASE_FUNC) \ - continue; \ - rcu_read_unlock(); \ - result = m->module_operations.FUNC_WITH_ARGS; \ - rcu_read_lock(); \ + if (m->module_operations.BASE_FUNC) { \ + atomic_inc(&m->use); \ + rcu_read_unlock(); \ + result = m->module_operations.FUNC_WITH_ARGS; \ + rcu_read_lock(); \ + if (unlikely(atomic_dec_and_test(&m->use))) \ + call_rcu(&m->m_rcu, free_mod_fromrcu); \ + } \ if (result) \ break; \ } \
@@ -116,9 +153,12 @@ MODULE_PARM_DESC(debug, "Debug enabled orcu_read_lock (); \ stack_for_each_entry(m, &stacked_modules, lsm_list) { \if (m->module_operations.BASE_FUNC) { \ +atomic_inc (&m->use); \rcu_read_unlock (); \ m->module_operations.FUNC_WITH_ARGS; \rcu_read_lock (); \ +if (unlikely (atomic_dec_and_test (&m->use))) \ +call_rcu (&m->m_rcu, free_mod_fromrcu); \ } \ } \rcu_read_unlock (); \
@@ -129,38 +169,47 @@ MODULE_PARM_DESC(debug, "Debug enabled orcu_read_lock (); \ stack_for_each_entry(m, &stacked_modules, lsm_list ) { \if (m->module_operations.BASE_FREE) { \ +atomic_inc (&m->use); \rcu_read_unlock (); \ m->module_operations.FREE_WITH_ARGS; \rcu_read_lock (); \ +if (unlikely (atomic_dec_and_test (&m->use))) \ +call_rcu (&m->m_rcu, free_mod_fromrcu); \ } \ } \rcu_read_unlock (); \ } while (0)#define ALLOC_SECURITY (BASE_FUNC ,FUNC_WITH_ARGS ,BASE_FREE ,FREE_WITH_ARGS ) do { \ - int result; \ + int result = 0; \ struct module_entry *m, *m2; \ rcu_read_lock(); \ stack_for_each_entry(m, &stacked_modules, lsm_list) { \ - if (!m->module_operations.BASE_FUNC) \ - continue; \ - rcu_read_unlock(); \ - result = m->module_operations.FUNC_WITH_ARGS; \ - rcu_read_lock(); \ + if (m->module_operations.BASE_FUNC) { \ + atomic_inc(&m->use); \ + rcu_read_unlock(); \ + result = m->module_operations.FUNC_WITH_ARGS; \ + rcu_read_lock(); \ + if (unlikely(atomic_dec_and_test(&m->use))) \ + call_rcu(&m->m_rcu, free_mod_fromrcu); \ + } \ if (result) \ goto bad; \ } \ rcu_read_unlock(); \ return 0; \ bad: \ - stack_for_each_entry(m2, &all_modules, all_lsms) { \ + stack_for_each_entry(m2, &stacked_modules, lsm_list) { \ if (m == m2) \ break; \ if (!m2->module_operations.BASE_FREE) \ continue; \ + atomic_inc(&m2->use); \ rcu_read_unlock(); \ m2->module_operations.FREE_WITH_ARGS; \ rcu_read_lock(); \ + if (unlikely(atomic_dec_and_test(&m2->use))) \ + call_rcu(&m2->m_rcu, free_mod_fromrcu); \ } \ rcu_read_unlock(); \ return result; \
@@ -251,10 +300,16 @@ static int stacker_vm_enough_memory(longrcu_read_lock ();stack_for_each_entry (m, &stacked_modules, lsm_list) { -if (!m->module_operations.vm_enough_memory) +if (!m->module_operations.vm_enough_memory) {continue ; + } +atomic_inc (&m->use);rcu_read_unlock (); result = m->module_operations.vm_enough_memory (pages); +rcu_read_lock (); +if (unlikely (atomic_dec_and_test (&m->use))) +stacker_free_module (m); +rcu_read_unlock ();return result; }rcu_read_unlock ();
@@ -281,9 +336,12 @@ static int stacker_netlink_send (structif (!m->module_operations.netlink_send)continue ;NETLINK_CB (skb).eff_cap = ~0 ; +atomic_inc (&m->use);rcu_read_unlock (); result = m->module_operations.netlink_send (sk, skb);rcu_read_lock (); +if (unlikely (atomic_dec_and_test (&m->use))) +call_rcu (&m->m_rcu, free_mod_fromrcu); tmpcap &=NETLINK_CB (skb).eff_cap;if (result)break ;
@@ -987,33 +1045,42 @@ stacker_getprocattr(struct task_struct *stack_for_each_entry (m, &stacked_modules, lsm_list) {if (!m->module_operations.getprocattr)continue ; +atomic_inc (&m->use);rcu_read_unlock (); ret = m->module_operations.getprocattr (p, name, value+len, size-len);rcu_read_lock (); -if (ret == -EINVAL ) -continue ; - found_noneinval =1 ; -if (ret <0 ) { +if (ret >0 ) { + found_noneinval =1 ; + len += ret; +if (len+m->namelen+4 < size) { +char *v = value; +if (v[len-1 ]=='\n' ) + len--; + len +=sprintf (value+len," (%s)\n" , + m->module_name); + } + }else if (ret != -EINVAL ) { + found_noneinval =1 ;memset (value,0 , len); len = ret; + }else + ret =0 ; + +if (unlikely (atomic_dec_and_test (&m->use))) +call_rcu (&m->m_rcu, free_mod_fromrcu); + +if (ret <0 )break ; - } -if (ret ==0 ) -continue ; - len += ret; -if (len+m->namelen+4 < size) { -char *v = value; -if (v[len-1 ]=='\n' ) - len--; - len +=sprintf (value+len," (%s)\n" , m->module_name); - } }rcu_read_unlock ();return found_noneinval ? len : -EINVAL ; } +/* +* find an lsm by name. If found, increment its use count and return it +*/ static struct module_entry *find_active_lsm (const char *name,int len) {
@@ -1022,6 +1089,7 @@ find_active_lsm(const char *name, int lercu_read_lock ();stack_for_each_entry (m, &stacked_modules, lsm_list) {if (m->namelen == len && !strncmp (m->module_name, name, len)) { +atomic_inc (&m->use); ret = m;break ; }
@@ -1043,6 +1111,7 @@ stacker_setprocattr(struct task_struct *char *realv = (char *)value;size_t dsize = size;int loc =0 , end_data = size; +int ret, free_module =0 ;if (list_empty (&stacked_modules))return -EINVAL ;
@@ -1063,7 +1132,7 @@ stacker_setprocattr(struct task_struct * callm =find_active_lsm (realv+loc+1 , dsize-loc-1 );if (!callm) goto call; - + free_module =1 ; loc--;while (loc && realv[loc]==' ' )
@@ -1074,8 +1143,14 @@ call:if (!callm || !callm->module_operations.setprocattr)return -EINVAL ; -return callm->module_operations.setprocattr (p, name, value, end_data) + + ret = callm->module_operations.setprocattr (p, name, value, end_data) + (size-end_data); + +if (free_module &&atomic_dec_and_test (&callm->use)) +stacker_free_module (callm); + +return ret; + }/*
@@ -1116,15 +1191,15 @@ static int stacker_register (const char new_module_entry->module_name = new_module_name; new_module_entry->namelen = namelen; +atomic_set (&new_module_entry->use,1 ); +INIT_LIST_HEAD (&new_module_entry->lsm_list); -INIT_LIST_HEAD (&new_module_entry->all_lsms);rcu_read_lock ();if (!modules_registered) { modules_registered++;list_del_rcu (&default_module.lsm_list); } -list_add_tail_rcu (&new_module_entry->all_lsms, &all_modules);list_add_tail_rcu (&new_module_entry->lsm_list, &stacked_modules);if (strcmp (name,"selinux" ) ==0 ) selinux_module = new_module_entry;
@@ -1141,16 +1216,60 @@ out: }/* -* Currently this version of stacker does not allow for module -* unregistering. -* Easy way to allow for this is using rcu ref counting like an older -* version of stacker did. -* Another way would be to force stacker_unregister to sleep between -* removing the module from all_modules and free_modules and unloading it. +* find_lsm_module_by_name: +* Find a module by name. Used by stacker_unregister. Called with +* stacker spinlock held. +*/ +static struct module_entry * +find_lsm_with_namelen (const char *name,int len) +{ +struct module_entry *m, *ret =NULL ; + +rcu_read_lock (); +list_for_each_entry_rcu (m, &stacked_modules, lsm_list) { +atomic_inc (&m->use); +rcu_read_unlock (); +if (m->namelen == len && !strncmp (m->module_name, name, len)) + ret = m; +rcu_read_lock (); +if (unlikely (atomic_dec_and_test (&m->use))) +call_rcu (&m->m_rcu, free_mod_fromrcu); +if (ret) +break ; + } +rcu_read_unlock (); + +return ret; +} + +/* */ static int stacker_unregister (const char *name,struct security_operations *ops) { -return -EPERM ; +struct module_entry *m; +int len =strnlen (name,MAX_MODULE_NAME_LEN ); +int ret =0 ; + +spin_lock (&stacker_lock); + m =find_lsm_with_namelen (name, len); + +if (!m) { +printk (KERN_INFO "%s: could not find module %s.\n" , + __FUNCTION__, name); + ret = -ENOENT ; + goto out; + } + +list_del_rcu (&m->lsm_list); + +if (strcmp (m->module_name,"selinux" ) ==0 ) + selinux_module =NULL ; +call_rcu (&m->m_rcu, stacker_del_module); + +out: +spin_unlock (&stacker_lock); + +return ret; }static struct security_operations stacker_ops = {
@@ -1407,57 +1526,6 @@ static struct stacker_attribute stacker_ .show = listmodules_read, }; -/* respond to a request to unload a module */ -static ssize_t stacker_unload_write (struct stacker_kobj *obj,const char *name, -size_t count) -{ -struct module_entry *m; -int len =strnlen (name,MAX_MODULE_NAME_LEN ); -int ret = count; - -if (!capable (CAP_SYS_ADMIN )) -return -EPERM ; - -if (count <=0 ) -return -EINVAL ; - -if (!modules_registered) -return -EINVAL ; - -spin_lock (&stacker_lock); - m =find_active_lsm (name, len); - -if (!m) { -printk (KERN_INFO "%s: could not find module %s.\n" , - __FUNCTION__, name); - ret = -ENOENT ; - goto out; - } - -if (strcmp (m->module_name,"selinux" ) ==0 ) - selinux_module =NULL ; - -rcu_read_lock (); -list_del_rcu (&m->lsm_list); -if (list_empty (&stacked_modules)) { -INIT_LIST_HEAD (&default_module.lsm_list); -list_add_tail_rcu (&default_module.lsm_list, &stacked_modules); - modules_registered =0 ; - } -rcu_read_unlock (); - -out: -spin_unlock (&stacker_lock); - -return ret; -} - -static struct stacker_attribute stacker_attr_unload = { - .attr = {.name ="unload" , .mode =S_IFREG |S_IRUGO |S_IWUSR }, - .store = stacker_unload_write, -}; - -/* stop responding to sysfs */ static ssize_t stop_responding_write (struct stacker_kobj *obj,const char *buff,size_t count)
@@ -1483,7 +1551,6 @@ static void unregister_sysfs_files(void)sysfs_remove_file (kobj, &stacker_attr_lockdown.attr);sysfs_remove_file (kobj, &stacker_attr_listmodules.attr);sysfs_remove_file (kobj, &stacker_attr_stop_responding.attr); -sysfs_remove_file (kobj, &stacker_attr_unload.attr); sysfsfiles_registered =0 ; }
@@ -1506,8 +1573,6 @@ static int register_sysfs_files(void) &stacker_attr_listmodules.attr);sysfs_create_file (&stacker_subsys.kset.kobj, &stacker_attr_stop_responding.attr); -sysfs_create_file (&stacker_subsys.kset.kobj, - &stacker_attr_unload.attr); sysfsfiles_registered =1 ;stacker_dbg ("sysfs files registered\n" );return 0 ;
@@ -1524,13 +1589,13 @@ static int __init stacker_init (void) sysfsfiles_registered =0 ;INIT_LIST_HEAD (&stacked_modules); -INIT_LIST_HEAD (&all_modules);spin_lock_init (&stacker_lock); default_module.module_name =DEFAULT_MODULE_NAME ; default_module.namelen =strlen (DEFAULT_MODULE_NAME );memcpy (&default_module.module_operations, &dummy_security_ops,sizeof (struct security_operations ));INIT_LIST_HEAD (&default_module.lsm_list); +atomic_set (&default_module.use,1 );list_add_tail (&default_module.lsm_list, &stacked_modules);if (register_security (&stacker_ops)) {
Re: [patch 5/12] lsm stacking v0.2: actual stacker module
Quoted 4 lines · Quoting [email protected] ([email protected]):
Quoting Tony Jones ([email protected]):
Attached is a patch to re-introduce the necessary locking to allow unloading of LSMs. I don't have any performance results nor hardcore stability tests yet.
And here is a patch on top of that to use securityfs.
thanks,
-serge
--
stacker.c | 169 +++++++++++++++++++------------------------------------------- 1 files changed, 53 insertions(+), 116 deletions(-)
security/stacker.c +53 -116
@@ -41,8 +41,6 @@ struct module_entry { };static struct list_head stacked_modules;/* list of stacked modules */ -static short sysfsfiles_registered; -/* * when !modules_registered, the default_module, defined * below, will be stacked
@@ -104,7 +102,7 @@ static void free_mod_fromrcu(struct rcu_static void stacker_del_module (struct rcu_head *head) {struct module_entry *m; - + m = container_of(head, struct module_entry, m_rcu);if (atomic_dec_and_test (&m->use))stacker_free_module (m);
@@ -1430,155 +1428,95 @@ static struct security_operations stacke#endif }; - -/* -* Functions to provide the sysfs interface -*/ - -/* A structure to pass into sysfs through kobjects */ -struct stacker_kobj { -struct list_head slot_list; -struct kobject kobj; -}; - -struct stacker_attribute { -struct attribute attr; -ssize_t (*show)(struct stacker_kobj *,char *); -ssize_t (*store)(struct stacker_kobj *,const char *,size_t ); -}; - -/* variables to hold kobject/sysfs data */ -static struct subsystem stacker_subsys; - -static void unregister_sysfs_files (void ); - -static ssize_t stacker_attr_store (struct kobject *kobj, -struct attribute *attr,const char *buf,size_t len) -{ -struct stacker_kobj *obj =container_of (kobj, - struct stacker_kobj, kobj); -struct stacker_attribute *attribute =container_of (attr, - struct stacker_attribute, attr); - -return attribute->store ? attribute->store (obj, buf, len) :0 ; -} - -static ssize_t stacker_attr_show (struct kobject *kobj, -struct attribute *attr,char *buf) +static u64 stacker_u8_get (void *data) { -struct stacker_kobj *obj =container_of (kobj, - struct stacker_kobj, kobj); -struct stacker_attribute *attribute =container_of (attr, - struct stacker_attribute, attr); - -return attribute->show ? attribute->show (obj, buf) :0 ; +return *(u8 *)data; } -static struct sysfs_ops stacker_sysfs_ops = { - .show = stacker_attr_show, - .store = stacker_attr_store, -}; - -static struct kobj_type stacker_ktype = { - .sysfs_ops = &stacker_sysfs_ops -}; - -static decl_subsys(stacker, &stacker_ktype, NULL); -/* Set lockdown */ -static ssize_t lockdown_read (struct stacker_kobj *obj,char *buff) -{ -return sprintf (buff,"%d" , forbid_stacker_register); -} - -static ssize_t lockdown_write (struct stacker_kobj *obj,const char *buff,size_t count) +static void lockdown_write (void *data,u64 val) { -if (count>0 ) - forbid_stacker_register =1 ; - -return count; + forbid_stacker_register =1 ; } -static struct stacker_attribute stacker_attr_lockdown = { - .attr = {.name ="lockdown" , .mode =S_IFREG |S_IRUGO |S_IWUSR }, - .show = lockdown_read, - .store = lockdown_write -}; +DEFINE_SIMPLE_ATTRIBUTE (lockdown_fops, stacker_u8_get, lockdown_write,"%llu\n" );/* list modules */ -static ssize_t listmodules_read (struct stacker_kobj *obj,char *buff) +static ssize_t listmodules_read (struct file *filp,char __user *user_buf, +size_t count,loff_t *ppos) {ssize_t len =0 ;struct module_entry *m; +char *page; + + page = (char *)__get_free_page (GFP_KERNEL ); +if (!page) +return -ENOMEM ;rcu_read_lock ();stack_for_each_entry (m, &stacked_modules, lsm_list) { - len +=snprintf (buff+len,PAGE_SIZE - len,"%s\n" , + len +=snprintf (page+len,PAGE_SIZE - len,"%s\n" , m->module_name); }rcu_read_unlock (); +if (len >=0 ) + len =simple_read_from_buffer (user_buf, count, ppos, page, len); +free_page ((unsigned long )page); +return len; } -static struct stacker_attribute stacker_attr_listmodules = { - .attr = {.name ="list_modules" , .mode =S_IFREG |S_IRUGO |S_IWUSR }, - .show = listmodules_read, +static struct file_operations listmodules_fops = { + .read = listmodules_read, }; +static void unregister_stacker_files (void ); +/* stop responding to sysfs */ -static ssize_t stop_responding_write (struct stacker_kobj *obj, -const char *buff,size_t count) +static void stop_responding_write (void *data,u64 val) { -if (count>0 ) -unregister_sysfs_files (); -return count; +unregister_stacker_files (); } -static struct stacker_attribute stacker_attr_stop_responding = { - .attr = {.name ="stop_responding" , .mode =S_IFREG |S_IRUGO |S_IWUSR }, - .store = stop_responding_write -}; - -static void unregister_sysfs_files (void ) -{ -struct kobject *kobj; +DEFINE_SIMPLE_ATTRIBUTE (stopresp_fops,NULL , stop_responding_write,"%llu\n" ); -if (!sysfsfiles_registered) -return ; +struct dentry * stacker_dir_ino, + * lockdown_ino, + * listmodules_ino, + * stopresp_ino, + * modunload_ino; - kobj = &stacker_subsys.kset.kobj; -sysfs_remove_file (kobj, &stacker_attr_lockdown.attr); -sysfs_remove_file (kobj, &stacker_attr_listmodules.attr); -sysfs_remove_file (kobj, &stacker_attr_stop_responding.attr); - - sysfsfiles_registered =0 ; +static void unregister_stacker_files (void ) +{ +securityfs_remove (stacker_dir_ino); +securityfs_remove (lockdown_ino); +securityfs_remove (listmodules_ino); +securityfs_remove (stopresp_ino); } -static int register_sysfs_files (void ) +static int register_stacker_files (void ) { -int result; + stacker_dir_ino =securityfs_create_dir ("stacker" ,NULL ); +if (!stacker_dir_ino) +return -EFAULT ; - result =subsystem_register (&stacker_subsys); -if (result) { -printk (KERN_WARNING -"Error (%d) registering stacker sysfs subsystem\n" , - result); -return result; - } + lockdown_ino =securityfs_create_file ("lockdown" ,S_IRUGO |S_IWUSR , + stacker_dir_ino, &forbid_stacker_register, + &lockdown_fops); + listmodules_ino =securityfs_create_file ("listmodules" ,S_IRUGO , + stacker_dir_ino,NULL , &listmodules_fops); + stopresp_ino =securityfs_create_file ("stop_responding" ,S_IWUSR , + stacker_dir_ino,NULL , &stopresp_fops); -sysfs_create_file (&stacker_subsys.kset.kobj, - &stacker_attr_lockdown.attr); -sysfs_create_file (&stacker_subsys.kset.kobj, - &stacker_attr_listmodules.attr); -sysfs_create_file (&stacker_subsys.kset.kobj, - &stacker_attr_stop_responding.attr); - sysfsfiles_registered =1 ; -stacker_dbg ("sysfs files registered\n" ); +if (!lockdown_ino || !listmodules_ino || !stopresp_ino) { +unregister_stacker_files (); +return -EFAULT ; + }return 0 ; } -module_init (register_sysfs_files); +module_init (register_stacker_files);extern struct security_operations dummy_security_ops;#define DEFAULT_MODULE_NAME "dummy"
@@ -1586,7 +1524,6 @@ extern struct security_operations dummy_static int __init stacker_init (void ) { forbid_stacker_register =0 ; - sysfsfiles_registered =0 ;INIT_LIST_HEAD (&stacked_modules);spin_lock_init (&stacker_lock);
@@ -1620,7 +1557,7 @@ static void __exit stacker_exit (void)* Should probably force all child modules to exit somehow... */ -unregister_sysfs_files (); +unregister_stacker_files ();if (unregister_security (&stacker_ops))printk (KERN_WARNING "Error unregistering LSM stacker.\n" );else
Re: [patch 5/12] lsm stacking v0.2: actual stacker module
In reply to [email protected]Quoted 1 line · On Thu, 2005-06-30 at 14:50 -0500, [email protected] wrote:
Adds the actual stacker LSM.
<snip>
Quoted 4 lines
security/stacker.c new file +4
-0+static int stacker_inode_getsecurity (struct inode *inode,const char *name,void *buffer,size_t size) +{ +RETURN_ERROR_IF_ANY_ERROR (inode_getsecurity,inode_getsecurity (inode,name,buffer,size)); +}
security/stacker.c line 588
Quoted 10 lines
security/stacker.c new file +10
-0+ +static int stacker_inode_setsecurity (struct inode *inode,const char *name,const void *value,size_t size,int flags) +{ +RETURN_ERROR_IF_ANY_ERROR (inode_setsecurity,inode_setsecurity (inode,name,value,size,flags)); +} + +static int stacker_inode_listsecurity (struct inode *inode,char *buffer,size_t buffer_size) +{ +RETURN_ERROR_IF_ANY_ERROR (inode_listsecurity,inode_listsecurity (inode,buffer, buffer_size)); +}
These hooks pose a similar problem for stacking as with the [gs]etprocattr hooks, although [gs]etsecurity have the benefit of already taking a distinguishing name suffix (the part after the security. prefix). Note also that inode_getsecurity returns the number of bytes used/required on success.
The proposed inode_init_security hook will likewise have an issue for stacking.
Signature · 2 lines
Stephen Smalley National Security Agency
Re: [patch 5/12] lsm stacking v0.2: actual stacker module
Thanks Stephen.
More comments below. This finally proves that I need to provide some documentation for each hook under stacker showing how modules are expected to interact. This hopefully will help me catch things like this. Hopefully it would also be useful to module writers in general.
Quoted 24 lines · Stephen Smalley
Quoted 1 line · On Thu, 2005-06-30 at 14:50 -0500, [email protected] wrote:
Adds the actual stacker LSM.
<snip>
Quoted 4 lines
security/stacker.c new file +4
-0+static int stacker_inode_getsecurity (struct inode *inode,const char *name,void *buffer,size_t size) +{ +RETURN_ERROR_IF_ANY_ERROR (inode_getsecurity,inode_getsecurity (inode,name,buffer,size)); +}security/stacker.c line 588
Quoted 10 lines
security/stacker.c new file +10
-0+ +static int stacker_inode_setsecurity (struct inode *inode,const char *name,const void *value,size_t size,int flags) +{ +RETURN_ERROR_IF_ANY_ERROR (inode_setsecurity,inode_setsecurity (inode,name,value,size,flags)); +} + +static int stacker_inode_listsecurity (struct inode *inode,char *buffer,size_t buffer_size) +{ +RETURN_ERROR_IF_ANY_ERROR (inode_listsecurity,inode_listsecurity (inode,buffer, buffer_size)); +}These hooks pose a similar problem for stacking as with the [gs]etprocattr hooks, although [gs]etsecurity have the benefit of already taking a distinguishing name suffix (the part after the security. prefix). Note also that
inode_getsecurityreturns the number of bytes used/required on success.
Quoted 2 lines
The proposed
inode_init_securityhook will likewise have an issue for stacking.
I can imagine a few ways of fixing this:
1. We simply expect that only one module use xattrs. This
is probably unacceptable, as we will want both EVM and selinux to store xattrs.
2. A module registers an xattr name when it registers
itself. Then only the registered module is consulted on one of these calls. If no module is registered, all are consulted as they are now.
This prevents a module like capability from deciding
based on its own credentials whether another module's hook should be called. Is that a good or bad thing?
This might have the added bonus of obviating the need
for a separate cap_stack module.
3. We return an error <0 only if all modules return <0.
Otherwise we do the obvious thing: setxattr, return 0.
getxattr: do we return the first nonzero and stop there, or do we return a concatenation of the results? I assume the former...
thanks,
-serge
Re: [patch 5/12] lsm stacking v0.2: actual stacker module
Quoted 5 lines · On Mon, 2005-07-11 at 12:51 -0500, [email protected] wrote:
I can imagine a few ways of fixing this:
1. We simply expect that only one module use xattrs. This
is probably unacceptable, as we will want both EVM and selinux to store xattrs.
Note that these particular hooks are only used for filesystems like devpts and tmpfs where there is no underlying storage for the security xattrs but we still need a way to [gs]et the incore inode security label from userspace.
Quoted 4 lines
2. A module registers an xattr name when it registers
itself. Then only the registered module is consulted on one of these calls. If no module is registered, all are consulted as they are now.
SELinux already checks the name suffix in inode_getsecurity and inode_setsecurity, and returns -EOPNOTSUPP if it isn't selinux. Hence, stacker could just iterate through the modules until it gets a result other than -EOPNOTSUPP, relying on the modules to check the name.
listsecurity is different, as it is supposed to yield the list of attribute names concatenated together, but that shouldn't be difficult for stacker to construct, similar to your getprocattr logic but without the need to add tags.
Quoted 3 lines
This prevents a module like capability from deciding
based on its own credentials whether another module's hook should be called. Is that a good or bad thing?
These hooks aren't supposed to be doing permission checking; that is handled by the separate security_inode_*xattr hooks. They are just for getting/setting the incore inode security label.
Quoted 2 lines
This might have the added bonus of obviating the need
for a separatecap_stackmodule.
I don't think so - different hooks are involved (inode_setxattr vs. inode_setsecurity).
Signature · 2 lines
Stephen Smalley National Security Agency
Re: [patch 5/12] lsm stacking v0.2: actual stacker module
In reply to Stephen SmalleyQuoted 5 lines · Stephen Smalley
These hooks pose a similar problem for stacking as with the [gs]etprocattr hooks, although [gs]etsecurity have the benefit of already taking a distinguishing name suffix (the part after the security. prefix). Note also that
inode_getsecurityreturns the number of bytes used/required on success.
The attached patch tries to handle the get,set, and listsecurity hooks.
Quoted 2 lines
The proposed
inode_init_securityhook will likewise have an issue for stacking.
I guess I'll wait to patch that until the hook shows up in 2.6.13-rc?, since my patches are generally against that tree.
thanks,
-serge
--
stacker.c | 79 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 files changed, 76 insertions(+), 3 deletions(-)
security/stacker.c +76 -3
@@ -569,19 +569,92 @@ static int stacker_inode_removexattr (stRETURN_ERROR_IF_ANY_ERROR (inode_removexattr,inode_removexattr (dentry,name)); } +/* +* inode_getsecurity: We loop through all modules until one does not return +* -EOPNOTSUPP. +* Note that if some LSM returns -EPERM, stacker assumes the LSM knows what +* it's doing. If you don't want to control the name, then return +* -EOPNOTSUPP! +*/ static int stacker_inode_getsecurity (struct inode *inode,const char *name,void *buffer,size_t size) { -RETURN_ERROR_IF_ANY_ERROR (inode_getsecurity,inode_getsecurity (inode,name,buffer,size)); +struct module_entry *m; +int ret = -EOPNOTSUPP ; + +rcu_read_lock (); +stack_for_each_entry (m, &stacked_modules, lsm_list) { +if (!m->module_operations.inode_getsecurity) +continue ; +rcu_read_unlock (); + ret = m->module_operations.inode_getsecurity (inode,name,buffer,size); +rcu_read_lock (); +if (ret != -EOPNOTSUPP ) +break ; + } +rcu_read_unlock (); + +return ret; } +/* +* inode_setsecurity: We loop through all modules until one does not return +* -EOPNOTSUPP. +* Note that if some LSM returns -EPERM, stacker assumes the LSM knows what +* it's doing. If you don't want to control the name, then return +* -EOPNOTSUPP! +*/ static int stacker_inode_setsecurity (struct inode *inode,const char *name,const void *value,size_t size,int flags) { -RETURN_ERROR_IF_ANY_ERROR (inode_setsecurity,inode_setsecurity (inode,name,value,size,flags)); +struct module_entry *m; +int ret = -EOPNOTSUPP ; + +rcu_read_lock (); +stack_for_each_entry (m, &stacked_modules, lsm_list) { +if (!m->module_operations.inode_setsecurity) +continue ; +rcu_read_unlock (); + ret = m->module_operations.inode_setsecurity (inode, name, + value, size, flags); +rcu_read_lock (); +if (ret != -EOPNOTSUPP ) +break ; + } +rcu_read_unlock (); + +return ret; } +/* +* inode_listsecurity: We loop through all modules appending to buffer, and return +* the newline-separated list of security names defined for this inode. +*/ static int stacker_inode_listsecurity (struct inode *inode,char *buffer,size_t buffer_size) { -RETURN_ERROR_IF_ANY_ERROR (inode_listsecurity,inode_listsecurity (inode,buffer, buffer_size)); +int ret =0 ; +struct module_entry *m; + +rcu_read_lock (); +stack_for_each_entry (m, &stacked_modules, lsm_list) { +int thislen; + +if (!m->module_operations.inode_listsecurity) +continue ; +rcu_read_unlock (); + thislen = m->module_operations.inode_listsecurity (inode, + buffer+ret, buffer_size-ret); +rcu_read_lock (); +if (thislen <0 ) +continue ; + ret += thislen; +if (ret >= buffer_size) { + ret = -ERANGE ; +break ; + } + buffer[ret++] ='\n' ; + } +rcu_read_unlock (); + +return ret; }static int stacker_file_permission (struct file *file,int mask)
Re: [patch 5/12] lsm stacking v0.2: actual stacker module
Stephen points out listsecurity results should simply be separated by the \0 which modules already append. New patch appended.
Thanks, Stephen.
-serge
--
stacker.c | 78 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 files changed, 75 insertions(+), 3 deletions(-)
security/stacker.c +75 -3
@@ -569,19 +569,91 @@ static int stacker_inode_removexattr (stRETURN_ERROR_IF_ANY_ERROR (inode_removexattr,inode_removexattr (dentry,name)); } +/* +* inode_getsecurity: We loop through all modules until one does not return +* -EOPNOTSUPP. +* Note that if some LSM returns -EPERM, stacker assumes the LSM knows what +* it's doing. If you don't want to control the name, then return +* -EOPNOTSUPP! +*/ static int stacker_inode_getsecurity (struct inode *inode,const char *name,void *buffer,size_t size) { -RETURN_ERROR_IF_ANY_ERROR (inode_getsecurity,inode_getsecurity (inode,name,buffer,size)); +struct module_entry *m; +int ret = -EOPNOTSUPP ; + +rcu_read_lock (); +stack_for_each_entry (m, &stacked_modules, lsm_list) { +if (!m->module_operations.inode_getsecurity) +continue ; +rcu_read_unlock (); + ret = m->module_operations.inode_getsecurity (inode,name,buffer,size); +rcu_read_lock (); +if (ret != -EOPNOTSUPP ) +break ; + } +rcu_read_unlock (); + +return ret; } +/* +* inode_setsecurity: We loop through all modules until one does not return +* -EOPNOTSUPP. +* Note that if some LSM returns -EPERM, stacker assumes the LSM knows what +* it's doing. If you don't want to control the name, then return +* -EOPNOTSUPP! +*/ static int stacker_inode_setsecurity (struct inode *inode,const char *name,const void *value,size_t size,int flags) { -RETURN_ERROR_IF_ANY_ERROR (inode_setsecurity,inode_setsecurity (inode,name,value,size,flags)); +struct module_entry *m; +int ret = -EOPNOTSUPP ; + +rcu_read_lock (); +stack_for_each_entry (m, &stacked_modules, lsm_list) { +if (!m->module_operations.inode_setsecurity) +continue ; +rcu_read_unlock (); + ret = m->module_operations.inode_setsecurity (inode, name, + value, size, flags); +rcu_read_lock (); +if (ret != -EOPNOTSUPP ) +break ; + } +rcu_read_unlock (); + +return ret; } +/* +* inode_listsecurity: We loop through all modules appending to buffer, and return +* the \0-separated list of security names defined for this inode. +*/ static int stacker_inode_listsecurity (struct inode *inode,char *buffer,size_t buffer_size) { -RETURN_ERROR_IF_ANY_ERROR (inode_listsecurity,inode_listsecurity (inode,buffer, buffer_size)); +int ret =0 ; +struct module_entry *m; + +rcu_read_lock (); +stack_for_each_entry (m, &stacked_modules, lsm_list) { +int thislen; + +if (!m->module_operations.inode_listsecurity) +continue ; +rcu_read_unlock (); + thislen = m->module_operations.inode_listsecurity (inode, + buffer+ret, buffer_size-ret); +rcu_read_lock (); +if (thislen <0 ) +continue ; + ret += thislen; +if (ret >= buffer_size) { + ret = -ERANGE ; +break ; + } + } +rcu_read_unlock (); + +return ret; }static int stacker_file_permission (struct file *file,int mask)
PATCH 6/12 lsm stacking v0.2: stackable capability lsm
In reply to [email protected]This patch adds a version of the capability module which is safe to stack with SELinux. It notably does not define the inode_setxattr and inode_removexattr hooks, as these otherwise prevent selinux from saving file types to disk.
--- Kconfig | 21 +++++++++++ Makefile | 1 cap_stack.c | 101 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ selinux/Kconfig | 2 + 4 files changed, 124 insertions(+), 1 deletion(-)
security/Kconfig +20 -1
@@ -56,10 +56,29 @@ config SECURITY_NETWORK config SECURITY_CAPABILITIES tristate "Default Linux Capabilities" depends on SECURITY + depends on SECURITY_SELINUX=n && SECURITY_CAP_STACK=n help - This enables the "default" Linux capabilities functionality. + This enables the default Linux capabilities functionality. + This module may not be used in conjunction with the stackable + capabilities or SELinux modules. + If you are unsure how to answer this question, answer Y. + If you are using SELinux, answer N here and look at the + Stackable Linux Capabilities instead. + +config SECURITY_CAP_STACK + tristate "Stackable Linux Capabilities" + depends on SECURITY + help + This enables the "stackable" Linux capabilities functionality. + + If you are using SELinux, this option will be automatically + enabled. + + If you are not using any other LSMs, answer N here and see above + for the Default Linux Capabilities. + config SECURITY_ROOTPLUG tristate "Root Plug Support" depends on USB && SECURITY
security/Makefile +1 -0
@@ -16,5 +16,6 @@ obj-$(CONFIG_SECURITY) += security.o d # Must precede capability.o in order to stack properly. obj-$(CONFIG_SECURITY_SELINUX) += selinux/built-in.o obj-$(CONFIG_SECURITY_CAPABILITIES) += commoncap.o capability.o +obj-$(CONFIG_SECURITY_CAP_STACK) += commoncap.o cap_stack.o obj-$(CONFIG_SECURITY_ROOTPLUG) += commoncap.o root_plug.o obj-$(CONFIG_SECURITY_SECLVL) += seclvl.o
security/cap_stack.c new file +101 -0
101 lines not on this page · raw message
security/selinux/Kconfig +2 -0
@@ -2,6 +2,8 @@ config SECURITY_SELINUX bool "NSA SELinux Support" depends on SECURITY && NET && INET default n + select SECURITY_CAP_STACK + select SECURITY_STACKER help This selects NSA Security-Enhanced Linux (SELinux). You will also need a policy configuration and a labeled filesystem.
PATCH 7/12 lsm stacking v0.2: selinux: update security structs
In reply to [email protected]Add the struct security_list lsm_list; to each structure which SELinux will be appending to a kernel object.
--- objsec.h | 19 +++++++++++-------- 1 files changed, 11 insertions(+), 8 deletions(-)
security/selinux/include/objsec.h +11 -8
@@ -23,11 +23,14 @@#include <linux/fs.h> #include <linux/binfmts.h> #include <linux/in.h> +#include <linux/security.h> #include "flask.h" #include "avc.h" +#define SELINUX_LSM_ID 0xB65 +struct task_security_struct { -unsigned long magic;/* magic number for this module */ +struct security_list lsm_list;/* chained security objects */ struct task_struct *task;/* back pointer to task object */ u32 osid;/* SID prior to last execve */ u32 sid;/* current SID */
@@ -37,7 +40,7 @@ struct task_security_struct { };struct inode_security_struct { -unsigned long magic;/* magic number for this module */ +struct security_list lsm_list;/* chained security objects */ struct inode *inode;/* back pointer to inode object */ struct list_head list;/* list of inode_security_struct */ u32 task_sid;/* SID of creating task */
@@ -49,14 +52,14 @@ struct inode_security_struct { };struct file_security_struct { -unsigned long magic;/* magic number for this module */ +struct security_list lsm_list;/* chained security objects */ struct file *file;/* back pointer to file object */ u32 sid;/* SID of open file description */ u32 fown_sid;/* SID of file owner (for SIGIO) */ };struct superblock_security_struct { -unsigned long magic;/* magic number for this module */ +struct security_list lsm_list;/* chained security objects */ struct super_block *sb;/* back pointer to sb object */ struct list_head list;/* list of superblock_security_struct */ u32 sid;/* SID of file system */
@@ -70,20 +73,20 @@ struct superblock_security_struct { };struct msg_security_struct { -unsigned long magic;/* magic number for this module */ +struct security_list lsm_list;/* chained security objects */ struct msg_msg *msg;/* back pointer */ u32 sid;/* SID of message */ };struct ipc_security_struct { -unsigned long magic;/* magic number for this module */ +struct security_list lsm_list;/* chained security objects */ struct kern_ipc_perm *ipc_perm;/* back pointer */ u16 sclass;/* security class of this object */ u32 sid;/* SID of IPC resource */ };struct bprm_security_struct { -unsigned long magic;/* magic number for this module */ +struct security_list lsm_list;/* chained security objects */ struct linux_binprm *bprm;/* back pointer to bprm object */ u32 sid;/* SID for transformed process */ unsigned char set;
@@ -102,7 +105,7 @@ struct netif_security_struct { };struct sk_security_struct { -unsigned long magic;/* magic number for this module */ +struct security_list lsm_list;/* chained security objects */ struct sock *sk;/* back pointer to sk object */ u32 peer_sid;/* SID of peer */ };
PATCH 8/12 lsm stacking v0.2: selinux: use security_*_value API
In reply to [email protected]Convert SELinux to use the security_*_value_type API for storing and using information appended to kernel objects, instead of directly using the void*.
--- hooks.c | 446 +++++++++++++++++++++++++++++++++++++++--------------------- selinuxfs.c | 10 - 2 files changed, 300 insertions(+), 156 deletions(-)
security/selinux/hooks.c +293 -153
@@ -26,6 +26,7 @@#include <linux/errno.h> #include <linux/sched.h> #include <linux/security.h> +#include <linux/security-stack.h> #include <linux/xattr.h> #include <linux/capability.h> #include <linux/unistd.h>
@@ -126,30 +127,30 @@ static int task_alloc_security(struct tareturn -ENOMEM ;memset (tsec,0 ,sizeof (struct task_security_struct )); - tsec->magic =SELINUX_MAGIC ; tsec->task = task; tsec->osid = tsec->sid = tsec->ptrace_sid =SECINITSID_UNLABELED ; - task->security = tsec; +security_set_value_type (&task->security,SELINUX_LSM_ID , tsec);return 0 ; }static void task_free_security (struct task_struct *task) { -struct task_security_struct *tsec = task->security; - -if (!tsec || tsec->magic !=SELINUX_MAGIC ) -return ; +struct task_security_struct *tsec; + + tsec =security_del_value_type (&task->security,SELINUX_LSM_ID , + struct task_security_struct); - task->security =NULL ;kfree (tsec); }static int inode_alloc_security (struct inode *inode) { -struct task_security_struct *tsec = current->security; +struct task_security_struct *tsec;struct inode_security_struct *isec; + tsec =security_get_value_type (¤t->security,SELINUX_LSM_ID , + struct task_security_struct); isec =kmalloc (sizeof (struct inode_security_struct ),GFP_KERNEL );if (!isec)return -ENOMEM ;
@@ -157,68 +158,71 @@ static int inode_alloc_security(struct imemset (isec,0 ,sizeof (struct inode_security_struct ));init_MUTEX (&isec->sem);INIT_LIST_HEAD (&isec->list); - isec->magic =SELINUX_MAGIC ; isec->inode = inode; isec->sid =SECINITSID_UNLABELED ; isec->sclass =SECCLASS_FILE ; -if (tsec && tsec->magic ==SELINUX_MAGIC ) +if (tsec) isec->task_sid = tsec->sid;else isec->task_sid =SECINITSID_UNLABELED ; - inode->i_security = isec; +security_set_value_type (&inode->i_security,SELINUX_LSM_ID , isec);return 0 ; }static void inode_free_security (struct inode *inode) { -struct inode_security_struct *isec = inode->i_security; -struct superblock_security_struct *sbsec = inode->i_sb->s_security; +struct inode_security_struct *isec; +struct superblock_security_struct *sbsec; -if (!isec || isec->magic !=SELINUX_MAGIC ) + isec =security_del_value_type (&inode->i_security,SELINUX_LSM_ID , + struct inode_security_struct); +if (!isec)return ; + sbsec =security_get_value_type (&inode->i_sb->s_security, + SELINUX_LSM_ID, struct superblock_security_struct); +spin_lock (&sbsec->isec_lock);if (!list_empty (&isec->list))list_del_init (&isec->list);spin_unlock (&sbsec->isec_lock); - inode->i_security =NULL ;kfree (isec); }static int file_alloc_security (struct file *file) { -struct task_security_struct *tsec = current->security; +struct task_security_struct *tsec;struct file_security_struct *fsec; + tsec =security_get_value_type (¤t->security,SELINUX_LSM_ID , + struct task_security_struct); fsec =kmalloc (sizeof (struct file_security_struct ),GFP_ATOMIC );if (!fsec)return -ENOMEM ;memset (fsec,0 ,sizeof (struct file_security_struct )); - fsec->magic =SELINUX_MAGIC ; fsec->file = file; -if (tsec && tsec->magic ==SELINUX_MAGIC ) { +if (tsec) { fsec->sid = tsec->sid; fsec->fown_sid = tsec->sid; }else { fsec->sid =SECINITSID_UNLABELED ; fsec->fown_sid =SECINITSID_UNLABELED ; } - file->f_security = fsec; +security_set_value_type (&file->f_security,SELINUX_LSM_ID , fsec);return 0 ; }static void file_free_security (struct file *file) { -struct file_security_struct *fsec = file->f_security; +struct file_security_struct *fsec; -if (!fsec || fsec->magic !=SELINUX_MAGIC ) -return ; + fsec =security_del_value_type (&file->f_security,SELINUX_LSM_ID , + struct file_security_struct); - file->f_security =NULL ;kfree (fsec); }
@@ -235,20 +239,21 @@ static int superblock_alloc_security(strINIT_LIST_HEAD (&sbsec->list);INIT_LIST_HEAD (&sbsec->isec_head);spin_lock_init (&sbsec->isec_lock); - sbsec->magic =SELINUX_MAGIC ; sbsec->sb = sb; sbsec->sid =SECINITSID_UNLABELED ; sbsec->def_sid =SECINITSID_FILE ; - sb->s_security = sbsec; +security_set_value_type (&sb->s_security,SELINUX_LSM_ID , sbsec);return 0 ; }static void superblock_free_security (struct super_block *sb) { -struct superblock_security_struct *sbsec = sb->s_security; +struct superblock_security_struct *sbsec; -if (!sbsec || sbsec->magic !=SELINUX_MAGIC ) + sbsec =security_del_value_type (&sb->s_security,SELINUX_LSM_ID , + struct superblock_security_struct); +if (!sbsec)return ;spin_lock (&sb_security_lock);
@@ -256,7 +261,6 @@ static void superblock_free_security(strlist_del_init (&sbsec->list);spin_unlock (&sb_security_lock); - sb->s_security =NULL ;kfree (sbsec); }
@@ -273,22 +277,23 @@ static int sk_alloc_security(struct sockreturn -ENOMEM ;memset (ssec,0 ,sizeof (*ssec)); - ssec->magic =SELINUX_MAGIC ; ssec->sk = sk; ssec->peer_sid =SECINITSID_UNLABELED ; - sk->sk_security = ssec; +security_set_value_type (&sk->sk_security,SELINUX_LSM_ID , ssec);return 0 ; }static void sk_free_security (struct sock *sk) { -struct sk_security_struct *ssec = sk->sk_security; +struct sk_security_struct *ssec; -if (sk->sk_family !=PF_UNIX || ssec->magic !=SELINUX_MAGIC ) +if (sk->sk_family !=PF_UNIX )return ; - sk->sk_security =NULL ; + ssec =security_del_value_type (&sk->sk_security,SELINUX_LSM_ID , + struct sk_security_struct); +kfree (ssec); }#endif /* CONFIG_SECURITY_NETWORK */
@@ -335,8 +340,13 @@ static int try_context_mount(struct supeconst char *name;u32 sid;int alloc =0 , rc =0 , seen =0 ; -struct task_security_struct *tsec = current->security; -struct superblock_security_struct *sbsec = sb->s_security; +struct task_security_struct *tsec; +struct superblock_security_struct *sbsec; + + tsec =security_get_value_type (¤t->security,SELINUX_LSM_ID , + struct task_security_struct); + sbsec =security_get_value_type (&sb->s_security,SELINUX_LSM_ID , + struct superblock_security_struct);if (!data) goto out;
@@ -502,11 +512,14 @@ out:static int superblock_doinit (struct super_block *sb,void *data) { -struct superblock_security_struct *sbsec = sb->s_security; +struct superblock_security_struct *sbsec;struct dentry *root = sb->s_root;struct inode *inode = root->d_inode;int rc =0 ; + sbsec =security_get_value_type (&sb->s_security,SELINUX_LSM_ID , + struct superblock_security_struct); +down (&sbsec->sem);if (sbsec->initialized) goto out;
@@ -731,7 +744,7 @@ static int selinux_proc_get_sid(struct pstatic int inode_doinit_with_dentry (struct inode *inode,struct dentry *opt_dentry) {struct superblock_security_struct *sbsec =NULL ; -struct inode_security_struct *isec = inode->i_security; +struct inode_security_struct *isec;u32 sid;struct dentry *dentry;#define INITCONTEXTLEN 255
@@ -740,6 +753,9 @@ static int inode_doinit_with_dentry(struint rc =0 ;int hold_sem =0 ; + isec =security_get_value_type (&inode->i_security,SELINUX_LSM_ID , + struct inode_security_struct); +if (isec->initialized) goto out;
@@ -748,7 +764,8 @@ static int inode_doinit_with_dentry(struif (isec->initialized) goto out; - sbsec = inode->i_sb->s_security; + sbsec =security_get_value_type (&inode->i_sb->s_security, + SELINUX_LSM_ID, struct superblock_security_struct);if (!sbsec->initialized) {/* Defer initialization until selinux_complete_init, after the initial policy is loaded and the security
@@ -922,8 +939,10 @@ static int task_has_perm(struct task_str {struct task_security_struct *tsec1, *tsec2; - tsec1 = tsk1->security; - tsec2 = tsk2->security; + tsec1 =security_get_value_type (&tsk1->security,SELINUX_LSM_ID , + struct task_security_struct); + tsec2 =security_get_value_type (&tsk2->security,SELINUX_LSM_ID , + struct task_security_struct);return avc_has_perm (tsec1->sid, tsec2->sid,SECCLASS_PROCESS , perms,NULL ); }
@@ -935,7 +954,8 @@ static int task_has_capability(struct tastruct task_security_struct *tsec;struct avc_audit_data ad; - tsec = tsk->security; + tsec =security_get_value_type (&tsk->security,SELINUX_LSM_ID , + struct task_security_struct);AVC_AUDIT_DATA_INIT (&ad,CAP ); ad.tsk = tsk;
@@ -951,7 +971,8 @@ static int task_has_system(struct task_s {struct task_security_struct *tsec; - tsec = tsk->security; + tsec =security_get_value_type (&tsk->security,SELINUX_LSM_ID , + struct task_security_struct);return avc_has_perm (tsec->sid,SECINITSID_KERNEL ,SECCLASS_SYSTEM , perms,NULL );
@@ -969,8 +990,10 @@ static int inode_has_perm(struct task_ststruct inode_security_struct *isec;struct avc_audit_data ad; - tsec = tsk->security; - isec = inode->i_security; + tsec =security_get_value_type (&tsk->security,SELINUX_LSM_ID , + struct task_security_struct); + isec =security_get_value_type (&inode->i_security,SELINUX_LSM_ID , + struct inode_security_struct);if (!adp) { adp = &ad;
@@ -1009,14 +1032,19 @@ static inline int file_has_perm(struct t struct file *file, u32 av) { -struct task_security_struct *tsec = tsk->security; -struct file_security_struct *fsec = file->f_security; +struct task_security_struct *tsec; +struct file_security_struct *fsec;struct vfsmount *mnt = file->f_vfsmnt;struct dentry *dentry = file->f_dentry;struct inode *inode = dentry->d_inode;struct avc_audit_data ad;int rc; + tsec =security_get_value_type (&tsk->security,SELINUX_LSM_ID , + struct task_security_struct); + fsec =security_get_value_type (&file->f_security,SELINUX_LSM_ID , + struct file_security_struct); +AVC_AUDIT_DATA_INIT (&ad,FS ); ad.u.fs.mnt = mnt; ad.u.fs.dentry = dentry;
@@ -1049,9 +1077,12 @@ static int may_create(struct inode *dir,struct avc_audit_data ad;int rc; - tsec = current->security; - dsec = dir->i_security; - sbsec = dir->i_sb->s_security; + tsec =security_get_value_type (¤t->security,SELINUX_LSM_ID , + struct task_security_struct); + dsec =security_get_value_type (&dir->i_security,SELINUX_LSM_ID , + struct inode_security_struct); + sbsec =security_get_value_type (&dir->i_sb->s_security,SELINUX_LSM_ID , + struct superblock_security_struct);AVC_AUDIT_DATA_INIT (&ad,FS ); ad.u.fs.dentry = dentry;
@@ -1096,9 +1127,12 @@ static int may_link(struct inode *dir,u32 av;int rc; - tsec = current->security; - dsec = dir->i_security; - isec = dentry->d_inode->i_security; + tsec =security_get_value_type (¤t->security,SELINUX_LSM_ID , + struct task_security_struct); + dsec =security_get_value_type (&dir->i_security,SELINUX_LSM_ID , + struct inode_security_struct); + isec =security_get_value_type (&dentry->d_inode->i_security, + SELINUX_LSM_ID, struct inode_security_struct);AVC_AUDIT_DATA_INIT (&ad,FS ); ad.u.fs.dentry = dentry;
@@ -1140,11 +1174,15 @@ static inline int may_rename(struct inodint old_is_dir, new_is_dir;int rc; - tsec = current->security; - old_dsec = old_dir->i_security; - old_isec = old_dentry->d_inode->i_security; + tsec =security_get_value_type (¤t->security,SELINUX_LSM_ID , + struct task_security_struct); + old_dsec =security_get_value_type (&old_dir->i_security,SELINUX_LSM_ID , + struct inode_security_struct); + old_isec =security_get_value_type (&old_dentry->d_inode->i_security, + SELINUX_LSM_ID, struct inode_security_struct); old_is_dir =S_ISDIR (old_dentry->d_inode->i_mode); - new_dsec = new_dir->i_security; + new_dsec =security_get_value_type (&new_dir->i_security,SELINUX_LSM_ID , + struct inode_security_struct);AVC_AUDIT_DATA_INIT (&ad,FS );
@@ -1172,7 +1210,8 @@ static inline int may_rename(struct inodif (rc)return rc;if (new_dentry->d_inode) { - new_isec = new_dentry->d_inode->i_security; + new_isec =security_get_value_type (&new_dentry->d_inode->i_security, + SELINUX_LSM_ID, struct inode_security_struct); new_is_dir =S_ISDIR (new_dentry->d_inode->i_mode); rc = avc_has_perm(tsec->sid, new_isec->sid, new_isec->sclass,
@@ -1193,8 +1232,10 @@ static int superblock_has_perm(struct tastruct task_security_struct *tsec;struct superblock_security_struct *sbsec; - tsec = tsk->security; - sbsec = sb->s_security; + tsec =security_get_value_type (&tsk->security,SELINUX_LSM_ID , + struct task_security_struct); + sbsec =security_get_value_type (&sb->s_security,SELINUX_LSM_ID , + struct superblock_security_struct);return avc_has_perm (tsec->sid, sbsec->sid,SECCLASS_FILESYSTEM , perms, ad); }
@@ -1247,8 +1288,13 @@ static inline u32 file_to_av(struct file/* Set an inode's SID to a specified value. */ static int inode_security_set_sid (struct inode *inode,u32 sid) { -struct inode_security_struct *isec = inode->i_security; -struct superblock_security_struct *sbsec = inode->i_sb->s_security; +struct inode_security_struct *isec; +struct superblock_security_struct *sbsec; + + isec =security_get_value_type (&inode->i_security,SELINUX_LSM_ID , + struct inode_security_struct); + sbsec =security_get_value_type (&inode->i_sb->s_security, + SELINUX_LSM_ID, struct superblock_security_struct);if (!sbsec->initialized) {/* Defer initialization to selinux_complete_init. */
@@ -1277,9 +1323,12 @@ static int post_create(struct inode *dirunsigned int len;int rc; - tsec = current->security; - dsec = dir->i_security; - sbsec = dir->i_sb->s_security; + tsec =security_get_value_type (¤t->security,SELINUX_LSM_ID , + struct task_security_struct); + dsec =security_get_value_type (&dir->i_security,SELINUX_LSM_ID , + struct inode_security_struct); + sbsec =security_get_value_type (&dir->i_sb->s_security,SELINUX_LSM_ID , + struct superblock_security_struct); inode = dentry->d_inode;if (!inode) {
@@ -1346,13 +1395,17 @@ static int post_create(struct inode *dirstatic int selinux_ptrace (struct task_struct *parent,struct task_struct *child) { -struct task_security_struct *psec = parent->security; -struct task_security_struct *csec = child->security; +struct task_security_struct *psec; +struct task_security_struct *csec;int rc; rc = secondary_ops->ptrace (parent,child);if (rc)return rc; + psec =security_get_value_type (&parent->security,SELINUX_LSM_ID , + struct task_security_struct); + csec =security_get_value_type (&child->security,SELINUX_LSM_ID , + struct task_security_struct); rc =task_has_perm (parent, child,PROCESS__PTRACE );/* Save the SID of the tracing process for later use in apply_creds. */
@@ -1414,7 +1467,8 @@ static int selinux_sysctl(ctl_table *tabif (rc)return rc; - tsec = current->security; + tsec =security_get_value_type (¤t->security,SELINUX_LSM_ID , + struct task_security_struct); rc =selinux_proc_get_sid (table->de, (op ==001 ) ?SECCLASS_DIR :SECCLASS_FILE , &tsid);
@@ -1549,12 +1603,11 @@ static int selinux_bprm_alloc_security(sreturn -ENOMEM ;memset (bsec,0 ,sizeof *bsec); - bsec->magic =SELINUX_MAGIC ; bsec->bprm = bprm; bsec->sid =SECINITSID_UNLABELED ; bsec->set =0 ; - bprm->security = bsec; +security_set_value_type (&bprm->security,SELINUX_LSM_ID , bsec);return 0 ; }
@@ -1572,13 +1625,16 @@ static int selinux_bprm_set_security(strif (rc)return rc; - bsec = bprm->security; + bsec =security_get_value_type (&bprm->security,SELINUX_LSM_ID , + struct bprm_security_struct);if (bsec->set)return 0 ; - tsec = current->security; - isec = inode->i_security; + tsec =security_get_value_type (¤t->security,SELINUX_LSM_ID , + struct task_security_struct); + isec =security_get_value_type (&inode->i_security,SELINUX_LSM_ID , + struct inode_security_struct);/* Default to the current task SID. */ bsec->sid = tsec->sid;
@@ -1641,9 +1697,11 @@ static int selinux_bprm_check_security (static int selinux_bprm_secureexec (struct linux_binprm *bprm) { -struct task_security_struct *tsec = current->security; +struct task_security_struct *tsec;int atsecure =0 ; + tsec =security_get_value_type (¤t->security,SELINUX_LSM_ID , + struct task_security_struct);if (tsec->osid != tsec->sid) {/* Enable secure mode for SIDs transitions unless the noatsecure permission is granted between
@@ -1658,8 +1716,11 @@ static int selinux_bprm_secureexec (strustatic void selinux_bprm_free_security (struct linux_binprm *bprm) { -kfree (bprm->security); - bprm->security =NULL ; +struct bprm_security_struct *bsec; + + bsec =security_del_value_type (&bprm->security,SELINUX_LSM_ID , + struct bprm_security_struct); +kfree (bsec); }extern struct vfsmount *selinuxfs_mount;
@@ -1756,9 +1817,10 @@ static void selinux_bprm_apply_creds(str secondary_ops->bprm_apply_creds (bprm, unsafe); - tsec = current->security; - - bsec = bprm->security; + tsec =security_get_value_type (¤t->security,SELINUX_LSM_ID , + struct task_security_struct); + bsec =security_get_value_type (&bprm->security,SELINUX_LSM_ID , + struct bprm_security_struct); sid = bsec->sid; tsec->osid = tsec->sid;
@@ -1801,8 +1863,10 @@ static void selinux_bprm_post_apply_credstruct bprm_security_struct *bsec;int rc, i; - tsec = current->security; - bsec = bprm->security; + tsec =security_get_value_type (¤t->security,SELINUX_LSM_ID , + struct task_security_struct); + bsec =security_get_value_type (&bprm->security,SELINUX_LSM_ID , + struct bprm_security_struct);if (bsec->unsafe) {force_sig_specific (SIGKILL , current);
@@ -2162,9 +2226,9 @@ static int selinux_inode_getattr(structstatic int selinux_inode_setxattr (struct dentry *dentry,char *name,void *value,size_t size,int flags) { -struct task_security_struct *tsec = current->security; +struct task_security_struct *tsec;struct inode *inode = dentry->d_inode; -struct inode_security_struct *isec = inode->i_security; +struct inode_security_struct *isec;struct superblock_security_struct *sbsec;struct avc_audit_data ad;u32 newsid;
@@ -2184,7 +2248,8 @@ static int selinux_inode_setxattr(structreturn dentry_has_perm (current,NULL , dentry,FILE__SETATTR ); } - sbsec = inode->i_sb->s_security; + sbsec =security_get_value_type (&inode->i_sb->s_security, + SELINUX_LSM_ID, struct superblock_security_struct);if (sbsec->behavior ==SECURITY_FS_USE_MNTPOINT )return -EOPNOTSUPP ;
@@ -2194,6 +2259,10 @@ static int selinux_inode_setxattr(structAVC_AUDIT_DATA_INIT (&ad,FS ); ad.u.fs.dentry = dentry; + tsec =security_get_value_type (¤t->security,SELINUX_LSM_ID , + struct task_security_struct); + isec =security_get_value_type (&inode->i_security,SELINUX_LSM_ID , + struct inode_security_struct); rc =avc_has_perm (tsec->sid, isec->sid, isec->sclass,FILE__RELABELFROM , &ad);if (rc)
@@ -2224,10 +2293,13 @@ static void selinux_inode_post_setxattr( void *value, size_t size, int flags) {struct inode *inode = dentry->d_inode; -struct inode_security_struct *isec = inode->i_security; +struct inode_security_struct *isec;u32 newsid;int rc; + isec =security_get_value_type (&inode->i_security,SELINUX_LSM_ID , + struct inode_security_struct); +if (strcmp (name,XATTR_NAME_SELINUX )) {/* Not an attribute we recognize, so nothing to do. */ return ;
@@ -2247,7 +2319,10 @@ static void selinux_inode_post_setxattr(static int selinux_inode_getxattr (struct dentry *dentry,char *name) {struct inode *inode = dentry->d_inode; -struct superblock_security_struct *sbsec = inode->i_sb->s_security; +struct superblock_security_struct *sbsec; + + sbsec =security_get_value_type (&inode->i_sb->s_security, + SELINUX_LSM_ID, struct superblock_security_struct);if (sbsec->behavior ==SECURITY_FS_USE_MNTPOINT )return -EOPNOTSUPP ;
@@ -2284,7 +2359,7 @@ static int selinux_inode_removexattr (ststatic int selinux_inode_getsecurity (struct inode *inode,const char *name,void *buffer,size_t size) { -struct inode_security_struct *isec = inode->i_security; +struct inode_security_struct *isec;char *context;unsigned len;int rc;
@@ -2294,6 +2369,9 @@ static int selinux_inode_getsecurity(strif (strcmp (name,XATTR_SELINUX_SUFFIX ))return -EOPNOTSUPP ; + isec =security_get_value_type (&inode->i_security,SELINUX_LSM_ID , + struct inode_security_struct); + rc =security_sid_to_context (isec->sid, &context, &len);if (rc)return rc;
@@ -2314,13 +2392,16 @@ static int selinux_inode_getsecurity(strstatic int selinux_inode_setsecurity (struct inode *inode,const char *name,const void *value,size_t size,int flags) { -struct inode_security_struct *isec = inode->i_security; +struct inode_security_struct *isec;u32 newsid;int rc;if (strcmp (name,XATTR_SELINUX_SUFFIX ))return -EOPNOTSUPP ; + isec =security_get_value_type (&inode->i_security,SELINUX_LSM_ID , + struct inode_security_struct); +if (!value || !size)return -EACCES ;
@@ -2567,8 +2648,10 @@ static int selinux_file_set_fowner(strucstruct task_security_struct *tsec;struct file_security_struct *fsec; - tsec = current->security; - fsec = file->f_security; + tsec =security_get_value_type (¤t->security,SELINUX_LSM_ID , + struct task_security_struct); + fsec =security_get_value_type (&file->f_security,SELINUX_LSM_ID , + struct file_security_struct); fsec->fown_sid = tsec->sid;return 0 ;
@@ -2585,8 +2668,10 @@ static int selinux_file_send_sigiotask(s/* struct fown_struct is never outside the context of a struct file */ file = (struct file *)((long )fown - offsetof(struct file ,f_owner)); - tsec = tsk->security; - fsec = file->f_security; + tsec =security_get_value_type (&tsk->security,SELINUX_LSM_ID , + struct task_security_struct); + fsec =security_get_value_type (&file->f_security,SELINUX_LSM_ID , + struct file_security_struct);if (!signum) perm =signal_to_av (SIGIO );/* as per send_sigio_to_task */
@@ -2620,12 +2705,14 @@ static int selinux_task_alloc_security(sstruct task_security_struct *tsec1, *tsec2;int rc; - tsec1 = current->security; + tsec1 =security_get_value_type (¤t->security,SELINUX_LSM_ID , + struct task_security_struct); rc =task_alloc_security (tsk);if (rc)return rc; - tsec2 = tsk->security; + tsec2 =security_get_value_type (&tsk->security,SELINUX_LSM_ID , + struct task_security_struct); tsec2->osid = tsec1->osid; tsec2->sid = tsec1->sid;
@@ -2778,7 +2865,8 @@ static void selinux_task_reparent_to_ini secondary_ops->task_reparent_to_init (p); - tsec = p->security; + tsec =security_get_value_type (&p->security,SELINUX_LSM_ID , + struct task_security_struct); tsec->osid = tsec->sid; tsec->sid =SECINITSID_KERNEL ;return ;
@@ -2787,8 +2875,13 @@ static void selinux_task_reparent_to_inistatic void selinux_task_to_inode (struct task_struct *p,struct inode *inode) { -struct task_security_struct *tsec = p->security; -struct inode_security_struct *isec = inode->i_security; +struct task_security_struct *tsec; +struct inode_security_struct *isec; + + tsec =security_get_value_type (&p->security,SELINUX_LSM_ID , + struct task_security_struct); + isec =security_get_value_type (&inode->i_security,SELINUX_LSM_ID , + struct inode_security_struct); isec->sid = tsec->sid; isec->initialized =1 ;
@@ -2956,8 +3049,10 @@ static int socket_has_perm(struct task_sstruct avc_audit_data ad;int err =0 ; - tsec = task->security; - isec =SOCK_INODE (sock)->i_security; + tsec =security_get_value_type (&task->security,SELINUX_LSM_ID , + struct task_security_struct); + isec =security_get_value_type (&SOCK_INODE (sock)->i_security,SELINUX_LSM_ID , + struct inode_security_struct);if (isec->sid ==SECINITSID_KERNEL ) goto out;
@@ -2979,7 +3074,8 @@ static int selinux_socket_create(int famif (kern) goto out; - tsec = current->security; + tsec =security_get_value_type (¤t->security,SELINUX_LSM_ID , + struct task_security_struct); err =avc_has_perm (tsec->sid, tsec->sid,socket_type_to_security_class (family, type, protocol),SOCKET__CREATE ,NULL );
@@ -2994,9 +3090,11 @@ static void selinux_socket_post_create(sstruct inode_security_struct *isec;struct task_security_struct *tsec; - isec =SOCK_INODE (sock)->i_security; + isec =security_get_value_type (&SOCK_INODE (sock)->i_security, + SELINUX_LSM_ID, struct inode_security_struct); - tsec = current->security; + tsec =security_get_value_type (¤t->security,SELINUX_LSM_ID , + struct task_security_struct); isec->sclass =socket_type_to_security_class (family, type, protocol); isec->sid = kern ?SECINITSID_KERNEL : tsec->sid; isec->initialized =1 ;
@@ -3034,8 +3132,10 @@ static int selinux_socket_bind(struct sostruct sock *sk = sock->sk;u32 sid, node_perm, addrlen; - tsec = current->security; - isec =SOCK_INODE (sock)->i_security; + tsec =security_get_value_type (¤t->security, + SELINUX_LSM_ID, struct task_security_struct); + isec =security_get_value_type (&SOCK_INODE (sock)->i_security, + SELINUX_LSM_ID, struct inode_security_struct);if (family ==PF_INET ) { addr4 = (struct sockaddr_in *)address;
@@ -3113,7 +3213,8 @@ static int selinux_socket_connect(struct/* * If a TCP socket, check name_connect permission for the port. */ - isec =SOCK_INODE (sock)->i_security; + isec =security_get_value_type (&SOCK_INODE (sock)->i_security, + SELINUX_LSM_ID, struct inode_security_struct);if (isec->sclass ==SECCLASS_TCP_SOCKET ) {struct sock *sk = sock->sk;struct avc_audit_data ad;
@@ -3167,9 +3268,11 @@ static int selinux_socket_accept(structif (err)return err; - newisec =SOCK_INODE (newsock)->i_security; + newisec =security_get_value_type (&SOCK_INODE (newsock)->i_security, + SELINUX_LSM_ID, struct inode_security_struct); - isec =SOCK_INODE (sock)->i_security; + isec =security_get_value_type (&SOCK_INODE (sock)->i_security, + SELINUX_LSM_ID, struct inode_security_struct); newisec->sclass = isec->sclass; newisec->sid = isec->sid; newisec->initialized =1 ;
@@ -3229,8 +3332,10 @@ static int selinux_socket_unix_stream_coif (err)return err; - isec =SOCK_INODE (sock)->i_security; - other_isec =SOCK_INODE (other)->i_security; + isec =security_get_value_type (&SOCK_INODE (sock)->i_security, + SELINUX_LSM_ID, struct inode_security_struct); + other_isec =security_get_value_type (&SOCK_INODE (other)->i_security, + SELINUX_LSM_ID, struct inode_security_struct);AVC_AUDIT_DATA_INIT (&ad,NET ); ad.u.net.sk = other->sk;
@@ -3242,11 +3347,13 @@ static int selinux_socket_unix_stream_coreturn err;/* connecting socket */ - ssec = sock->sk->sk_security; + ssec =security_get_value_type (&sock->sk->sk_security,SELINUX_LSM_ID , + struct sk_security_struct); ssec->peer_sid = other_isec->sid;/* server child socket */ - ssec = newsk->sk_security; + ssec =security_get_value_type (&newsk->sk_security,SELINUX_LSM_ID , + struct sk_security_struct); ssec->peer_sid = isec->sid;return 0 ;
@@ -3260,8 +3367,10 @@ static int selinux_socket_unix_may_send(struct avc_audit_data ad;int err; - isec =SOCK_INODE (sock)->i_security; - other_isec =SOCK_INODE (other)->i_security; + isec =security_get_value_type (&SOCK_INODE (sock)->i_security, + SELINUX_LSM_ID, struct inode_security_struct); + other_isec =security_get_value_type (&SOCK_INODE (other)->i_security, + SELINUX_LSM_ID, struct inode_security_struct);AVC_AUDIT_DATA_INIT (&ad,NET ); ad.u.net.sk = other->sk;
@@ -3301,7 +3410,8 @@ static int selinux_socket_sock_rcv_skb(s inode =SOCK_INODE (sock);if (inode) {struct inode_security_struct *isec; - isec = inode->i_security; + isec =security_get_value_type (&inode->i_security, + SELINUX_LSM_ID, struct inode_security_struct); sock_sid = isec->sid; sock_class = isec->sclass; }
@@ -3384,13 +3494,15 @@ static int selinux_socket_getpeersec(strstruct sk_security_struct *ssec;struct inode_security_struct *isec; - isec =SOCK_INODE (sock)->i_security; + isec =security_get_value_type (&SOCK_INODE (sock)->i_security, + SELINUX_LSM_ID, struct inode_security_struct);if (isec->sclass !=SECCLASS_UNIX_STREAM_SOCKET ) { err = -ENOPROTOOPT ; goto out; } - ssec = sock->sk->sk_security; + ssec =security_get_value_type (&sock->sk->sk_security,SELINUX_LSM_ID , + struct sk_security_struct); err =security_sid_to_context (ssec->peer_sid, &scontext, &scontext_len);if (err)
@@ -3429,7 +3541,10 @@ static int selinux_nlmsg_perm(struct socu32 perm;struct nlmsghdr *nlh;struct socket *sock = sk->sk_socket; -struct inode_security_struct *isec =SOCK_INODE (sock)->i_security; +struct inode_security_struct *isec; + + isec =security_get_value_type (&SOCK_INODE (sock)->i_security, + SELINUX_LSM_ID, struct inode_security_struct);if (skb->len <NLMSG_SPACE (0 )) { err = -EINVAL ;
@@ -3495,7 +3610,8 @@ static unsigned int selinux_ip_postrouteif (err) goto out; - isec = inode->i_security; + isec =security_get_value_type (&inode->i_security,SELINUX_LSM_ID , + struct inode_security_struct);switch (isec->sclass) {case SECCLASS_UDP_SOCKET :
@@ -3605,7 +3721,8 @@ static int selinux_netlink_send(struct sif (err)return err; - tsec = current->security; + tsec =security_get_value_type (¤t->security, + SELINUX_LSM_ID, struct task_security_struct); avd.allowed =0 ; avc_has_perm_noaudit(tsec->sid, tsec->sid,
@@ -3629,15 +3746,17 @@ static int ipc_alloc_security(struct tas struct kern_ipc_perm *perm, u16 sclass) { -struct task_security_struct *tsec = task->security; +struct task_security_struct *tsec;struct ipc_security_struct *isec; + tsec =security_get_value_type (&task->security,SELINUX_LSM_ID , + struct task_security_struct); + isec =kmalloc (sizeof (struct ipc_security_struct ),GFP_KERNEL );if (!isec)return -ENOMEM ;memset (isec,0 ,sizeof (struct ipc_security_struct )); - isec->magic =SELINUX_MAGIC ; isec->sclass = sclass; isec->ipc_perm = perm;if (tsec) {
@@ -3645,18 +3764,18 @@ static int ipc_alloc_security(struct tas }else { isec->sid =SECINITSID_UNLABELED ; } - perm->security = isec; +security_set_value_type (&perm->security,SELINUX_LSM_ID , isec);return 0 ; }static void ipc_free_security (struct kern_ipc_perm *perm) { -struct ipc_security_struct *isec = perm->security; -if (!isec || isec->magic !=SELINUX_MAGIC ) -return ; +struct ipc_security_struct *isec; + + isec =security_del_value_type (&perm->security,SELINUX_LSM_ID , + struct ipc_security_struct); - perm->security =NULL ;kfree (isec); }
@@ -3669,21 +3788,20 @@ static int msg_msg_alloc_security(structreturn -ENOMEM ;memset (msec,0 ,sizeof (struct msg_security_struct )); - msec->magic =SELINUX_MAGIC ; msec->msg = msg; msec->sid =SECINITSID_UNLABELED ; - msg->security = msec; +security_set_value_type (&msg->security,SELINUX_LSM_ID , msec);return 0 ; }static void msg_msg_free_security (struct msg_msg *msg) { -struct msg_security_struct *msec = msg->security; -if (!msec || msec->magic !=SELINUX_MAGIC ) -return ; +struct msg_security_struct *msec; + + msec =security_del_value_type (&msg->security,SELINUX_LSM_ID , + struct msg_security_struct); - msg->security =NULL ;kfree (msec); }
@@ -3694,8 +3812,10 @@ static int ipc_has_perm(struct kern_ipc_struct ipc_security_struct *isec;struct avc_audit_data ad; - tsec = current->security; - isec = ipc_perms->security; + tsec =security_get_value_type (¤t->security,SELINUX_LSM_ID , + struct task_security_struct); + isec =security_get_value_type (&ipc_perms->security,SELINUX_LSM_ID , + struct ipc_security_struct);AVC_AUDIT_DATA_INIT (&ad,IPC ); ad.u.ipc_id = ipc_perms->key;
@@ -3725,8 +3845,10 @@ static int selinux_msg_queue_alloc_securif (rc)return rc; - tsec = current->security; - isec = msq->q_perm.security; + tsec =security_get_value_type (¤t->security,SELINUX_LSM_ID , + struct task_security_struct); + isec =security_get_value_type (&msq->q_perm.security,SELINUX_LSM_ID , + struct ipc_security_struct);AVC_AUDIT_DATA_INIT (&ad,IPC ); ad.u.ipc_id = msq->q_perm.key;
@@ -3751,8 +3873,10 @@ static int selinux_msg_queue_associate(sstruct ipc_security_struct *isec;struct avc_audit_data ad; - tsec = current->security; - isec = msq->q_perm.security; + tsec =security_get_value_type (¤t->security,SELINUX_LSM_ID , + struct task_security_struct); + isec =security_get_value_type (&msq->q_perm.security,SELINUX_LSM_ID , + struct ipc_security_struct);AVC_AUDIT_DATA_INIT (&ad,IPC ); ad.u.ipc_id = msq->q_perm.key;
@@ -3797,9 +3921,12 @@ static int selinux_msg_queue_msgsnd(strustruct avc_audit_data ad;int rc; - tsec = current->security; - isec = msq->q_perm.security; - msec = msg->security; + tsec =security_get_value_type (¤t->security,SELINUX_LSM_ID , + struct task_security_struct); + isec =security_get_value_type (&msq->q_perm.security,SELINUX_LSM_ID , + struct ipc_security_struct); + msec =security_get_value_type (&msg->security,SELINUX_LSM_ID , + struct msg_security_struct);/* * First time through, need to assign label to the message
@@ -3845,9 +3972,12 @@ static int selinux_msg_queue_msgrcv(strustruct avc_audit_data ad;int rc; - tsec = target->security; - isec = msq->q_perm.security; - msec = msg->security; + tsec =security_get_value_type (&target->security,SELINUX_LSM_ID , + struct task_security_struct); + isec =security_get_value_type (&msq->q_perm.security,SELINUX_LSM_ID , + struct ipc_security_struct); + msec =security_get_value_type (&msg->security,SELINUX_LSM_ID , + struct msg_security_struct);AVC_AUDIT_DATA_INIT (&ad,IPC ); ad.u.ipc_id = msq->q_perm.key;
@@ -3872,8 +4002,10 @@ static int selinux_shm_alloc_security(stif (rc)return rc; - tsec = current->security; - isec = shp->shm_perm.security; + tsec =security_get_value_type (¤t->security,SELINUX_LSM_ID , + struct task_security_struct); + isec =security_get_value_type (&shp->shm_perm.security,SELINUX_LSM_ID , + struct ipc_security_struct);AVC_AUDIT_DATA_INIT (&ad,IPC ); ad.u.ipc_id = shp->shm_perm.key;
@@ -3898,8 +4030,10 @@ static int selinux_shm_associate(structstruct ipc_security_struct *isec;struct avc_audit_data ad; - tsec = current->security; - isec = shp->shm_perm.security; + tsec =security_get_value_type (¤t->security,SELINUX_LSM_ID , + struct task_security_struct); + isec =security_get_value_type (&shp->shm_perm.security,SELINUX_LSM_ID , + struct ipc_security_struct);AVC_AUDIT_DATA_INIT (&ad,IPC ); ad.u.ipc_id = shp->shm_perm.key;
@@ -3971,8 +4105,10 @@ static int selinux_sem_alloc_security(stif (rc)return rc; - tsec = current->security; - isec = sma->sem_perm.security; + tsec =security_get_value_type (¤t->security,SELINUX_LSM_ID , + struct task_security_struct); + isec =security_get_value_type (&sma->sem_perm.security,SELINUX_LSM_ID , + struct ipc_security_struct);AVC_AUDIT_DATA_INIT (&ad,IPC ); ad.u.ipc_id = sma->sem_perm.key;
@@ -3997,8 +4133,10 @@ static int selinux_sem_associate(structstruct ipc_security_struct *isec;struct avc_audit_data ad; - tsec = current->security; - isec = sma->sem_perm.security; + tsec =security_get_value_type (¤t->security,SELINUX_LSM_ID , + struct task_security_struct); + isec =security_get_value_type (&sma->sem_perm.security,SELINUX_LSM_ID , + struct ipc_security_struct);AVC_AUDIT_DATA_INIT (&ad,IPC ); ad.u.ipc_id = sma->sem_perm.key;
@@ -4132,7 +4270,8 @@ static int selinux_getprocattr(struct taif (!size)return -ERANGE ; - tsec = p->security; + tsec =security_get_value_type (&p->security,SELINUX_LSM_ID , + struct task_security_struct);if (!strcmp (name,"current" )) sid = tsec->sid;
@@ -4207,7 +4346,8 @@ static int selinux_setprocattr(struct taoperation. See selinux_bprm_set_security for the execve checks and may_create for the file creation checks. The operation will then fail if the context is not permitted. */ - tsec = p->security; + tsec =security_get_value_type (&p->security,SELINUX_LSM_ID , + struct task_security_struct);if (!strcmp (name,"exec" )) tsec->exec_sid = sid;else if (!strcmp (name,"fscreate" ))
security/selinux/selinuxfs.c +7 -3
@@ -18,6 +18,7 @@#include <linux/init.h> #include <linux/string.h> #include <linux/security.h> +#include <linux/security-stack.h> #include <linux/major.h> #include <linux/seq_file.h> #include <linux/percpu.h>
@@ -59,7 +60,8 @@ static int task_has_security(struct task {struct task_security_struct *tsec; - tsec = tsk->security; + tsec =security_get_value_type (&tsk->security,SELINUX_LSM_ID , + struct task_security_struct);if (!tsec)return -EACCES ;
@@ -982,7 +984,8 @@ static int sel_make_bools(void) ret = -ENAMETOOLONG ; goto err; } - isec = (struct inode_security_struct *)inode->i_security; + isec =security_get_value_type (&inode->i_security, + SELINUX_LSM_ID, struct inode_security_struct);if ((ret =security_genfs_sid ("selinuxfs" , page,SECCLASS_FILE , &sid))) goto err; isec->sid = sid;
@@ -1267,7 +1270,8 @@ static int sel_fill_super(struct super_b inode =sel_make_inode (sb,S_IFCHR |S_IRUGO |S_IWUGO );if (!inode) goto out; - isec = (struct inode_security_struct *)inode->i_security; + isec =security_get_value_type (&inode->i_security,SELINUX_LSM_ID , + struct inode_security_struct); isec->sid =SECINITSID_DEVNULL ; isec->sclass =SECCLASS_CHR_FILE ; isec->initialized =1 ;
PATCH 9/12 lsm stacking v0.2: selinux: remove secondary support
In reply to [email protected]Remove the SELinux support for secondary modules. This is no longer necessary as SELinux can now be simply stacked with the cap-stack module.
--- hooks.c | 266 ++++++++-------------------------------------------------------- 1 files changed, 35 insertions(+), 231 deletions(-)
security/selinux/hooks.c +35 -231
@@ -80,6 +80,8 @@extern unsigned int policydb_loaded_version;extern int selinux_nlmsg_lookup (u16 sclass,u16 nlmsg_type,u32 *perm); +static int secondary;/* how were we registered? */ +#ifdef CONFIG_SECURITY_SELINUX_DEVELOP int selinux_enforcing =0 ;
@@ -102,15 +104,6 @@ static int __init selinux_enabled_setup(__setup ("selinux=" , selinux_enabled_setup);#endif -/* Original (dummy) security module. */ -static struct security_operations *original_ops =NULL ; - -/* Minimal support for a secondary security module, -just to allow the use of the dummy or capability modules. -The owlsm module can alternatively be used as a secondary -module as long as CONFIG_OWLSM_FD is not enabled. */ -static struct security_operations *secondary_ops =NULL ; -/* Lists of inode and superblock security structures initialized before the policy was loaded. */ static LIST_HEAD (superblock_security_head);
@@ -1399,9 +1392,6 @@ static int selinux_ptrace(struct task_ststruct task_security_struct *csec;int rc; - rc = secondary_ops->ptrace (parent,child); -if (rc) -return rc; psec =security_get_value_type (&parent->security,SELINUX_LSM_ID , struct task_security_struct); csec = security_get_value_type(&child->security, SELINUX_LSM_ID,
@@ -1417,41 +1407,17 @@ static int selinux_ptrace(struct task_ststatic int selinux_capget (struct task_struct *target,kernel_cap_t *effective,kernel_cap_t *inheritable,kernel_cap_t *permitted) { -int error; - - error =task_has_perm (current, target,PROCESS__GETCAP ); -if (error) -return error; - -return secondary_ops->capget (target, effective, inheritable, permitted); +return task_has_perm (current, target,PROCESS__GETCAP ); }static int selinux_capset_check (struct task_struct *target,kernel_cap_t *effective,kernel_cap_t *inheritable,kernel_cap_t *permitted) { -int error; - - error = secondary_ops->capset_check (target, effective, inheritable, permitted); -if (error) -return error; -return task_has_perm (current, target,PROCESS__SETCAP ); } -static void selinux_capset_set (struct task_struct *target,kernel_cap_t *effective, -kernel_cap_t *inheritable,kernel_cap_t *permitted) -{ - secondary_ops->capset_set (target, effective, inheritable, permitted); -} -static int selinux_capable (struct task_struct *tsk,int cap) { -int rc; - - rc = secondary_ops->capable (tsk, cap); -if (rc) -return rc; -return task_has_capability (tsk,cap); }
@@ -1463,10 +1429,6 @@ static int selinux_sysctl(ctl_table *tabu32 tsid;int rc; - rc = secondary_ops->sysctl (table, op); -if (rc) -return rc; - tsec =security_get_value_type (¤t->security,SELINUX_LSM_ID , struct task_security_struct);
@@ -1534,11 +1496,7 @@ static int selinux_quota_on(struct dentrstatic int selinux_syslog (int type) { -int rc; - - rc = secondary_ops->syslog (type); -if (rc) -return rc; +int rc =0 ;switch (type) {case 3 :/* Read last kernel messages */
@@ -1562,36 +1520,6 @@ static int selinux_syslog(int type)return rc; } -/* -* Check that a process has enough memory to allocate a new virtual -* mapping. 0 means there is enough memory for the allocation to -* succeed and -ENOMEM implies there is not. -* -* Note that secondary_ops->capable and task_has_perm_noaudit return 0 -* if the capability is granted, but __vm_enough_memory requires 1 if -* the capability is granted. -* -* Do not audit the selinux permission check, as this is applied to all -* processes that allocate mappings. -*/ -static int selinux_vm_enough_memory (long pages) -{ -int rc, cap_sys_admin =0 ; -struct task_security_struct *tsec = current->security; - - rc = secondary_ops->capable (current,CAP_SYS_ADMIN ); -if (rc ==0 ) - rc =avc_has_perm_noaudit (tsec->sid, tsec->sid, -SECCLASS_CAPABILITY , -CAP_TO_MASK (CAP_SYS_ADMIN ), -NULL ); - -if (rc ==0 ) - cap_sys_admin =1 ; - -return __vm_enough_memory (pages, cap_sys_admin); -} -/* binprm security operations */ static int selinux_bprm_alloc_security (struct linux_binprm *bprm)
@@ -1621,10 +1549,6 @@ static int selinux_bprm_set_security(strstruct avc_audit_data ad;int rc; - rc = secondary_ops->bprm_set_security (bprm); -if (rc) -return rc; - bsec =security_get_value_type (&bprm->security,SELINUX_LSM_ID , struct bprm_security_struct);
@@ -1689,12 +1613,6 @@ static int selinux_bprm_set_security(strreturn 0 ; } -static int selinux_bprm_check_security (struct linux_binprm *bprm) -{ -return secondary_ops->bprm_check_security (bprm); -} - -static int selinux_bprm_secureexec (struct linux_binprm *bprm) {struct task_security_struct *tsec;
@@ -1711,7 +1629,7 @@ static int selinux_bprm_secureexec (stru PROCESS__NOATSECURE, NULL); } -return (atsecure || secondary_ops->bprm_secureexec (bprm)); +return atsecure; }static void selinux_bprm_free_security (struct linux_binprm *bprm)
@@ -1815,8 +1733,6 @@ static void selinux_bprm_apply_creds(stru32 sid;int rc; - secondary_ops->bprm_apply_creds (bprm, unsafe); - tsec =security_get_value_type (¤t->security,SELINUX_LSM_ID , struct task_security_struct); bsec = security_get_value_type(&bprm->security, SELINUX_LSM_ID,
@@ -2042,12 +1958,6 @@ static int selinux_mount(char * dev_name unsigned long flags, void * data) { - int rc; - - rc = secondary_ops->sb_mount (dev_name, nd, type, flags, data); -if (rc) -return rc; -if (flags &MS_REMOUNT )return superblock_has_perm (current, nd->mnt->mnt_sb,FILESYSTEM__REMOUNT ,NULL );
@@ -2058,12 +1968,6 @@ static int selinux_mount(char * dev_namestatic int selinux_umount (struct vfsmount *mnt,int flags) { -int rc; - - rc = secondary_ops->sb_umount (mnt, flags); -if (rc) -return rc; -return superblock_has_perm (current,mnt->mnt_sb,FILESYSTEM__UNMOUNT ,NULL ); }
@@ -2092,11 +1996,6 @@ static void selinux_inode_post_create(ststatic int selinux_inode_link (struct dentry *old_dentry,struct inode *dir,struct dentry *new_dentry) { -int rc; - - rc = secondary_ops->inode_link (old_dentry,dir,new_dentry); -if (rc) -return rc;return may_link (dir, old_dentry,MAY_LINK ); }
@@ -2107,11 +2006,6 @@ static void selinux_inode_post_link(strustatic int selinux_inode_unlink (struct inode *dir,struct dentry *dentry) { -int rc; - - rc = secondary_ops->inode_unlink (dir, dentry); -if (rc) -return rc;return may_link (dir, dentry,MAY_UNLINK ); }
@@ -2142,12 +2036,6 @@ static int selinux_inode_rmdir(struct instatic int selinux_inode_mknod (struct inode *dir,struct dentry *dentry,int mode,dev_t dev) { -int rc; - - rc = secondary_ops->inode_mknod (dir, dentry, mode, dev); -if (rc) -return rc; -return may_create (dir, dentry,inode_mode_to_security_class (mode)); }
@@ -2175,23 +2063,12 @@ static int selinux_inode_readlink(structstatic int selinux_inode_follow_link (struct dentry *dentry,struct nameidata *nameidata) { -int rc; - - rc = secondary_ops->inode_follow_link (dentry,nameidata); -if (rc) -return rc;return dentry_has_perm (current,NULL , dentry,FILE__READ ); }static int selinux_inode_permission (struct inode *inode,int mask,struct nameidata *nd) { -int rc; - - rc = secondary_ops->inode_permission (inode, mask, nd); -if (rc) -return rc; -if (!mask) {/* No permission to check. Existence test. */ return 0 ;
@@ -2203,12 +2080,6 @@ static int selinux_inode_permission(strustatic int selinux_inode_setattr (struct dentry *dentry,struct iattr *iattr) { -int rc; - - rc = secondary_ops->inode_setattr (dentry, iattr); -if (rc) -return rc; -if (iattr->ia_valid &ATTR_FORCE )return 0 ;
@@ -2530,12 +2401,6 @@ static int file_map_prot_check(struct fistatic int selinux_file_mmap (struct file *file,unsigned long reqprot,unsigned long prot,unsigned long flags) { -int rc; - - rc = secondary_ops->file_mmap (file, reqprot, prot, flags); -if (rc) -return rc; -if (selinux_checkreqprot) prot = reqprot;
@@ -2549,10 +2414,6 @@ static int selinux_file_mprotect(struct {int rc; - rc = secondary_ops->file_mprotect (vma, reqprot, prot); -if (rc) -return rc; -if (selinux_checkreqprot) prot = reqprot;
@@ -2575,7 +2436,7 @@ static int selinux_file_mprotect(struct* check ability to execute the possibly modified content. * This typically should only occur for text relocations. */ -int rc =file_has_perm (current, vma->vm_file,FILE__EXECMOD ); + rc =file_has_perm (current, vma->vm_file,FILE__EXECMOD );if (rc)return rc; }
@@ -2691,12 +2552,6 @@ static int selinux_file_receive(struct fstatic int selinux_task_create (unsigned long clone_flags) { -int rc; - - rc = secondary_ops->task_create (clone_flags); -if (rc) -return rc; -return task_has_perm (current, current,PROCESS__FORK ); }
@@ -2745,11 +2600,6 @@ static int selinux_task_setuid(uid_t id0return 0 ; } -static int selinux_task_post_setuid (uid_t id0,uid_t id1,uid_t id2,int flags) -{ -return secondary_ops->task_post_setuid (id0,id1,id2,flags); -} -static int selinux_task_setgid (gid_t id0,gid_t id1,gid_t id2,int flags) {/* See the comment for setuid above. */
@@ -2779,24 +2629,12 @@ static int selinux_task_setgroups(structstatic int selinux_task_setnice (struct task_struct *p,int nice) { -int rc; - - rc = secondary_ops->task_setnice (p, nice); -if (rc) -return rc; -return task_has_perm (current,p,PROCESS__SETSCHED ); }static int selinux_task_setrlimit (unsigned int resource,struct rlimit *new_rlim) {struct rlimit *old_rlim = current->signal->rlim + resource; -int rc; - - rc = secondary_ops->task_setrlimit (resource, new_rlim); -if (rc) -return rc; -/* Control the ability to change the hard limit (whether lowering or raising it), so that the hard limit can later be used as a safe reset point for the soft limit
@@ -2820,11 +2658,6 @@ static int selinux_task_getscheduler(strstatic int selinux_task_kill (struct task_struct *p,struct siginfo *info,int sig) {u32 perm; -int rc; - - rc = secondary_ops->task_kill (p, info, sig); -if (rc) -return rc;if (info && ((unsigned long )info ==1 || (unsigned long )info ==2 ||SI_FROMKERNEL (info)))
@@ -2863,8 +2696,6 @@ static void selinux_task_reparent_to_ini {struct task_security_struct *tsec; - secondary_ops->task_reparent_to_init (p); - tsec =security_get_value_type (&p->security,SELINUX_LSM_ID , struct task_security_struct); tsec->osid = tsec->sid;
@@ -3328,10 +3159,6 @@ static int selinux_socket_unix_stream_costruct avc_audit_data ad;int err; - err = secondary_ops->unix_stream_connect (sock, other, newsk); -if (err) -return err; - isec =security_get_value_type (&SOCK_INODE (sock)->i_security, SELINUX_LSM_ID, struct inode_security_struct); other_isec = security_get_value_type(&SOCK_INODE(other)->i_security,
@@ -3715,11 +3542,7 @@ static int selinux_netlink_send(struct s {struct task_security_struct *tsec;struct av_decision avd; -int err; - - err = secondary_ops->netlink_send (sk, skb); -if (err) -return err; +int err =0 ; tsec =security_get_value_type (¤t->security, SELINUX_LSM_ID, struct task_security_struct);
@@ -3735,13 +3558,6 @@ static int selinux_netlink_send(struct sreturn err; } -static int selinux_netlink_recv (struct sk_buff *skb) -{ -if (!cap_raised (NETLINK_CB (skb).eff_cap,CAP_NET_ADMIN )) -return -EPERM ; -return 0 ; -} -static int ipc_alloc_security (struct task_struct *task,struct kern_ipc_perm *perm,u16 sclass)
@@ -4079,11 +3895,6 @@ static int selinux_shm_shmat(struct shmi char __user *shmaddr, int shmflg) {u32 perms; -int rc; - - rc = secondary_ops->shm_shmat (shp, shmaddr, shmflg); -if (rc) -return rc;if (shmflg &SHM_RDONLY ) perms =SHM__READ ;
@@ -4219,32 +4030,12 @@ static int selinux_ipc_permission(struct/* module stacking operations */ static int selinux_register_security (const char *name,struct security_operations *ops) { -if (secondary_ops != original_ops) { -printk (KERN_INFO "%s: There is already a secondary security " -"module registered.\n" , __FUNCTION__); -return -EINVAL ; - } - - secondary_ops = ops; - -printk (KERN_INFO "%s: Registering secondary module %s\n" , - __FUNCTION__, - name); - -return 0 ; +return -EINVAL ; }static int selinux_unregister_security (const char *name,struct security_operations *ops) { -if (ops != secondary_ops) { -printk (KERN_INFO "%s: trying to unregister a security module " -"that is not registered.\n" , __FUNCTION__); -return -EINVAL ; - } - - secondary_ops = original_ops; - -return 0 ; +return -EINVAL ; }static void selinux_d_instantiate (struct dentry *dentry,struct inode *inode)
@@ -4407,23 +4198,19 @@ static struct security_operations selinu .ptrace = selinux_ptrace, .capget = selinux_capget, .capset_check = selinux_capset_check, - .capset_set = selinux_capset_set, .sysctl = selinux_sysctl, .capable = selinux_capable, .quotactl = selinux_quotactl, .quota_on = selinux_quota_on, .syslog = selinux_syslog, - .vm_enough_memory = selinux_vm_enough_memory, .netlink_send = selinux_netlink_send, - .netlink_recv = selinux_netlink_recv, .bprm_alloc_security = selinux_bprm_alloc_security, .bprm_free_security = selinux_bprm_free_security, .bprm_apply_creds = selinux_bprm_apply_creds, .bprm_post_apply_creds = selinux_bprm_post_apply_creds, .bprm_set_security = selinux_bprm_set_security, - .bprm_check_security = selinux_bprm_check_security, .bprm_secureexec = selinux_bprm_secureexec, .sb_alloc_security = selinux_sb_alloc_security,
@@ -4480,7 +4267,6 @@ static struct security_operations selinu .task_alloc_security = selinux_task_alloc_security, .task_free_security = selinux_task_free_security, .task_setuid = selinux_task_setuid, - .task_post_setuid = selinux_task_post_setuid, .task_setgid = selinux_task_setgid, .task_setpgid = selinux_task_setpgid, .task_getpgid = selinux_task_getpgid,
@@ -4552,10 +4338,12 @@ static struct security_operations selinu#endif }; +#define MY_NAME "selinux"static __init int selinux_init (void ) {struct task_security_struct *tsec; + secondary =0 ;if (!selinux_enabled) {printk (KERN_INFO "SELinux: Disabled at boot.\n" );return 0 ;
@@ -4566,22 +4354,30 @@ static __init int selinux_init(void)/* Set the security state for the initial task. */ if (task_alloc_security (current))panic ("SELinux: Failed to initialize initial task.\n" ); - tsec = current->security; + tsec =security_get_value_type (¤t->security,SELINUX_LSM_ID , + struct task_security_struct); tsec->osid = tsec->sid =SECINITSID_KERNEL ;avc_init (); - original_ops = secondary_ops = security_ops; -if (!secondary_ops) -panic ("SELinux: No initial security operations\n" ); -if (register_security (&selinux_ops)) -panic ("SELinux: Unable to register with kernel.\n" ); +if (register_security (&selinux_ops)) { +if (mod_reg_security (MY_NAME , &selinux_ops)) { +printk (KERN_ERR "%s: Failed to register with primary LSM.\n" , + __FUNCTION__); +panic ("SELinux: Unable to register with kernel.\n" ); + }else { +printk (KERN_ERR "%s: registered with primary LSM.\n" , + __FUNCTION__); + } + secondary =1 ; + }if (selinux_enforcing) {printk (KERN_INFO "SELinux: Starting in enforcing mode\n" ); }else {printk (KERN_INFO "SELinux: Starting in permissive mode\n" ); } +return 0 ; }
@@ -4691,6 +4487,7 @@ int selinux_disable(void) {extern void exit_sel_fs (void );static int selinux_disabled =0 ; +int ret;if (ss_initialized) {/* Not permitted after initial policy load. */
@@ -4706,8 +4503,15 @@ int selinux_disable(void) selinux_disabled =1 ; -/* Reset security_ops to the secondary module, dummy or capability. */ - security_ops = secondary_ops; +if (secondary) + ret =mod_unreg_security (MY_NAME , &selinux_ops); +else + ret =unregister_security (&selinux_ops); + +if (ret) +printk (KERN_INFO "Failure unregistering selinux.\n" ); +else +printk (KERN_INFO "Unregistered selinux.\n" );/* Unregister netfilter hooks. */ selinux_nf_ip_exit ();
PATCH 10/12 lsm stacking v0.2: hook completeness verification
In reply to [email protected]Add a script to check whether all security_operations hooks are defined in both dummy_security_ops (through security_fixup_ops) and in stacker_ops. Also adds a note in security.h to remind developers that all hooks must be defined in these two modules, and to verify this using the lsm_verify_hooks.sh script.
--- include/linux/security.h | 4 ++++ scripts/lsm_verify_hooks.sh | 44 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+)
include/linux/security.h +4 -0
@@ -121,6 +121,10 @@ struct swap_info_struct;/** * struct security_operations - main security structure * +* When adding functions to this structure, please add them to +* dummy.c and stacker.c, and run linux/scripts/lsm_verify_hooks.sh +* to verify their inclusion in these modules. +* * Security hooks for program execution operations. * * @bprm_alloc_security:
scripts/lsm_verify_hooks.sh new file +44 -0
44 lines not on this page · raw message
PATCH 11/12 lsm stacking v0.2: /proc/$$/attr/ sharing
In reply to [email protected]This patch enables sharing of the /proc/<pid>/attr files. Input and output now takes the form of
"whatever_data_is_expected (module_name)"
For writes, the data section (minus " (module_name)") is sent to the module identified as "module_name". For reads, stacker appends the " (module_name)" to whatever modules send. If any module returns an error other than -EINVAL, that error and no data is returned.
If data is written to a procattr file without " (module_name)" the data is sent to the selinux module.
--- stacker.c | 125 +++++++++++++++++++++++++++++++++++++++++++++++++------------- 1 files changed, 100 insertions(+), 25 deletions(-)
security/stacker.c +100 -25
@@ -966,24 +966,116 @@ static void stacker_d_instantiate (strucCALL_ALL (d_instantiate,d_instantiate (dentry,inode)); } +/* +* Query all LSMs. +* If all return EINVAL, we return EINVAL. If any returns any other +* error, then we return that error. Otherwise, we concatenate all +* modules' results. +*/ static int stacker_getprocattr (struct task_struct *p,char *name,void *value,size_t size) { -if (!selinux_module) -return -EINVAL ; -if (!selinux_module->module_operations.getprocattr) +struct module_entry *m; +int len =0 , ret; +int found_noneinval =0 ; + + +if (list_empty (&stacked_modules))return -EINVAL ; -return selinux_module->module_operations.getprocattr (p, name, value, size); + +rcu_read_lock (); +stack_for_each_entry (m, &stacked_modules, lsm_list) { +if (!m->module_operations.getprocattr) +continue ; +rcu_read_unlock (); + ret = m->module_operations.getprocattr (p, name, + value+len, size-len); +rcu_read_lock (); +if (ret == -EINVAL ) +continue ; + found_noneinval =1 ; +if (ret <0 ) { +memset (value,0 , len); + len = ret; +break ; + } +if (ret ==0 ) +continue ; + len += ret; +if (len+m->namelen+4 < size) { +char *v = value; +if (v[len-1 ]=='\n' ) + len--; + len +=sprintf (value+len," (%s)\n" , m->module_name); + } + } +rcu_read_unlock (); + +return found_noneinval ? len : -EINVAL ; +} + +static struct module_entry * +find_active_lsm (const char *name,int len) +{ +struct module_entry *m, *ret =NULL ; + +rcu_read_lock (); +stack_for_each_entry (m, &stacked_modules, lsm_list) { +if (m->namelen == len && !strncmp (m->module_name, name, len)) { + ret = m; +break ; + } + } + +rcu_read_unlock (); +return ret; } -static int stacker_setprocattr (struct task_struct *p,char *name,void *value,size_t size) +/* +* We assume input will be either +* "data" - in which case it goes to selinux, or +* "data (mod_name)" in which case the data goes to module mod_name. +*/ +static int +stacker_setprocattr (struct task_struct *p,char *name,void *value,size_t size) { +struct module_entry *callm = selinux_module; +char *realv = (char *)value; +size_t dsize = size; +int loc =0 , end_data = size; -if (!selinux_module) +if (list_empty (&stacked_modules))return -EINVAL ; -if (!selinux_module->module_operations.setprocattr) + +if (dsize && realv[dsize-1 ] =='\n' ) + dsize--; + +if (!dsize || realv[dsize-1 ]!=')' ) + goto call; + + dsize--; + loc = dsize-1 ; +while (loc && realv[loc]!='(' ) + loc--; +if (!loc) + goto call; + + callm =find_active_lsm (realv+loc+1 , dsize-loc-1 ); +if (!callm) + goto call; + + + loc--; +while (loc && realv[loc]==' ' ) + loc--; + + end_data = loc+1 ; +call: +if (!callm || !callm->module_operations.setprocattr)return -EINVAL ; -return selinux_module->module_operations.setprocattr (p, name, value, size); + +return callm->module_operations.setprocattr (p, name, value, end_data) + + (size-end_data); }/*
@@ -1048,23 +1140,6 @@ out:return ret; } -static struct module_entry * -find_active_lsm (const char *name,int len) -{ -struct module_entry *m, *ret =NULL ; - -rcu_read_lock (); -stack_for_each_entry (m, &stacked_modules, lsm_list) { -if (m->namelen == len && !strncmp (m->module_name, name, len)) { - ret = m; -break ; - } - } - -rcu_read_unlock (); -return ret; -} -/* * Currently this version of stacker does not allow for module * unregistering.
PATCH 12/12 lsm stacking v0.2: update seclvl for stacking
In reply to [email protected]Add stacking support to the seclvl module.
--- seclvl.c | 101 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 files changed, 91 insertions(+), 10 deletions(-)
security/seclvl.c +91 -10
@@ -21,6 +21,7 @@#include <linux/kernel.h> #include <linux/init.h> #include <linux/security.h> +#include <linux/security-stack.h> #include <linux/netlink.h> #include <linux/fs.h> #include <linux/namei.h>
@@ -35,6 +36,7 @@#include <linux/sysfs.h> #define SHA1_DIGEST_SIZE 20 +#define SECLVL_LSM_ID 0xF45/** * Module parameter that defines the initial secure level.
@@ -485,12 +487,39 @@ static int seclvl_settime(struct timespereturn 0 ; } +/* +* A structure which is stored with the inode when a process +* has a unmounted block device open for writing. +*/ +struct seclvl_i_sec { +struct security_list lsm_list; +struct task_struct *task; +spinlock_t spinlock; +}; + +static void seclvl_inode_free (struct inode *inode) +{ +struct seclvl_i_sec *isec; + + isec =security_del_value_type (&inode->i_security,SECLVL_LSM_ID , + struct seclvl_i_sec); +if (isec) { +if (isec->task == current) + isec->task =NULL ; +kfree (isec); + } +} +/* claim the blockdev to exclude mounters, release on file close */ -static int seclvl_bd_claim (struct inode *inode) +static int seclvl_bd_claim (struct inode *inode,struct seclvl_i_sec *isec) {int holder;struct block_device *bdev =NULL ;dev_t dev = inode->i_rdev; + +if (isec->task && isec->task != current) +return -EPERM ; + bdev =open_by_devnum (dev,FMODE_WRITE );if (bdev) {if (bd_claim (bdev, &holder)) {
@@ -498,7 +527,7 @@ static int seclvl_bd_claim(struct inodereturn -EPERM ; }/* claimed, mark it to release on close */ - inode->i_security = current; + isec->task = current; }return 0 ; }
@@ -506,16 +535,59 @@ static int seclvl_bd_claim(struct inode/* release the blockdev if you claimed it */ static void seclvl_bd_release (struct inode *inode) { -if (inode &&S_ISBLK (inode->i_mode) && inode->i_security == current) { -struct block_device *bdev = inode->i_bdev; -if (bdev) { -bd_release (bdev); -blkdev_put (bdev); - inode->i_security =NULL ; - } +struct seclvl_i_sec *isec; + +if (inode &&S_ISBLK (inode->i_mode)) { + isec =security_get_value_type (&inode->i_security, + SECLVL_LSM_ID, struct seclvl_i_sec); +if (!isec) +return ; +spin_lock (&isec->spinlock); +if (isec->task == current) { +struct block_device *bdev = inode->i_bdev; +if (bdev) { +bd_release (bdev); +blkdev_put (bdev); + isec->task =NULL ; + } + } +spin_unlock (&isec->spinlock); } } +static DEFINE_SPINLOCK (seclvl_new_isec_lock); + +/** +* Either returns the existing inode isec, or creates a new +* isec, places it on the inode->i_security list, and returns +* it. +* On error, return NULL. +*/ +static struct seclvl_i_sec * +seclvl_inode_get_or_alloc (struct inode *inode) +{ +struct seclvl_i_sec *isec; + + isec =security_get_value_type (&inode->i_security, + SECLVL_LSM_ID, struct seclvl_i_sec); +if (isec) +return isec; +spin_lock (&seclvl_new_isec_lock); + isec =security_get_value_type (&inode->i_security, + SECLVL_LSM_ID, struct seclvl_i_sec); +if (isec) + goto out; + isec =kmalloc (sizeof (struct seclvl_i_sec ),GFP_KERNEL ); +if (!isec) + goto out; +spin_lock_init (&isec->spinlock); +security_add_value_type (&inode->i_security,SECLVL_LSM_ID , isec); + +out: +spin_unlock (&seclvl_new_isec_lock); +return isec; +} +/** * Security for writes to block devices is regulated by this seclvl * function. Deny all writes to block devices in seclvl 2. In
@@ -524,6 +596,8 @@ static void seclvl_bd_release(struct inostatic int seclvl_inode_permission (struct inode *inode,int mask,struct nameidata *nd) { +struct seclvl_i_sec *isec; +if (current->pid !=1 &&S_ISBLK (inode->i_mode) && (mask &MAY_WRITE )) {switch (seclvl) {case 2 :
@@ -531,13 +605,19 @@ seclvl_inode_permission(struct inode *in "denied in secure level [%d]\n", seclvl);return -EPERM ;case 1 : -if (seclvl_bd_claim (inode)) { + isec =seclvl_inode_get_or_alloc (inode); +if (!isec) +return -ENOMEM ; +spin_lock (&isec->spinlock); +if (seclvl_bd_claim (inode, isec)) {seclvl_printk (1 ,KERN_WARNING ,"Write to mounted block device " "denied in secure level [%d]\n" , seclvl); +spin_unlock (&isec->spinlock);return -EPERM ; } +spin_unlock (&isec->spinlock); } }return 0 ;
@@ -595,6 +675,7 @@ static struct security_operations seclvl .capable = seclvl_capable, .inode_permission = seclvl_inode_permission, .inode_setattr = seclvl_inode_setattr, + .inode_free_security = seclvl_inode_free, .file_free_security = seclvl_file_free_security, .settime = seclvl_settime, .sb_umount = seclvl_umount,