* [patch 1/11] lsm stacking: don't default to dummy_##hook
2005-06-08 23:55 patch 0/11] lsm stacking: intro serue
@ 2005-06-08 23:56 ` serue
2005-06-08 23:57 ` [patch 2/11] lsm stacking: replace void* security with hlist serue
` (9 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: serue @ 2005-06-08 23:56 UTC (permalink / raw)
To: lkml; +Cc: Chris Wright, Stephen Smalley, James Morris
When stacking multiple LSMs, we do not want hooks which are undefined to
be substituted with the dummy_##hook.
Signed-off-by: Serge Hallyn <serue@us.ibm.com>
---
security/security.c | 12 ++++++------
1 files changed, 6 insertions(+), 6 deletions(-)
Index: linux-2.6.12-rc6/security/security.c
===================================================================
--- linux-2.6.12-rc6.orig/security/security.c
+++ linux-2.6.12-rc6/security/security.c
@@ -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;
}
^ permalink raw reply [flat|nested] 12+ messages in thread* [patch 2/11] lsm stacking: replace void* security with hlist
2005-06-08 23:55 patch 0/11] lsm stacking: intro serue
2005-06-08 23:56 ` [patch 1/11] lsm stacking: don't default to dummy_##hook serue
@ 2005-06-08 23:57 ` serue
2005-06-08 23:58 ` [patch 3/11] lsm stacking: introduce security_*_value API serue
` (8 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: serue @ 2005-06-08 23:57 UTC (permalink / raw)
To: lkml; +Cc: Chris Wright, Stephen Smalley, James Morris
Replace kernel object ->security void*'s with hlists. This will permit
multiple LSMs to each store information under one kernel object.
Signed-off-by: Serge Hallyn <serue@us.ibm.com>
---
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(-)
Index: linux-2.6.12-rc6/fs/compat.c
===================================================================
--- linux-2.6.12-rc6.orig/fs/compat.c
+++ linux-2.6.12-rc6/fs/compat.c
@@ -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)
Index: linux-2.6.12-rc6/fs/exec.c
===================================================================
--- linux-2.6.12-rc6.orig/fs/exec.c
+++ linux-2.6.12-rc6/fs/exec.c
@@ -1152,6 +1152,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)
@@ -1210,8 +1211,7 @@ out:
__free_page(page);
}
- if (bprm->security)
- security_bprm_free(bprm);
+ security_bprm_free(bprm);
out_mm:
if (bprm->mm)
Index: linux-2.6.12-rc6/fs/inode.c
===================================================================
--- linux-2.6.12-rc6.orig/fs/inode.c
+++ linux-2.6.12-rc6/fs/inode.c
@@ -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)
Index: linux-2.6.12-rc6/include/linux/binfmts.h
===================================================================
--- linux-2.6.12-rc6.orig/include/linux/binfmts.h
+++ linux-2.6.12-rc6/include/linux/binfmts.h
@@ -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
Index: linux-2.6.12-rc6/include/linux/fs.h
===================================================================
--- linux-2.6.12-rc6.orig/include/linux/fs.h
+++ linux-2.6.12-rc6/include/linux/fs.h
@@ -477,7 +477,7 @@ struct inode {
unsigned int i_flags;
atomic_t i_writecount;
- void *i_security;
+ struct hlist_head i_security;
union {
void *generic_ip;
} u;
@@ -551,7 +551,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 */
};
@@ -589,7 +589,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;
@@ -775,7 +775,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 */
Index: linux-2.6.12-rc6/include/linux/ipc.h
===================================================================
--- linux-2.6.12-rc6.orig/include/linux/ipc.h
+++ linux-2.6.12-rc6/include/linux/ipc.h
@@ -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_perm
gid_t cgid;
mode_t mode;
unsigned long seq;
- void *security;
+ struct hlist_head security;
};
#endif /* __KERNEL__ */
Index: linux-2.6.12-rc6/include/linux/msg.h
===================================================================
--- linux-2.6.12-rc6.orig/include/linux/msg.h
+++ linux-2.6.12-rc6/include/linux/msg.h
@@ -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 */
};
Index: linux-2.6.12-rc6/include/linux/sched.h
===================================================================
--- linux-2.6.12-rc6.orig/include/linux/sched.h
+++ linux-2.6.12-rc6/include/linux/sched.h
@@ -690,7 +690,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;
Index: linux-2.6.12-rc6/include/net/sock.h
===================================================================
--- linux-2.6.12-rc6.orig/include/net/sock.h
+++ linux-2.6.12-rc6/include/net/sock.h
@@ -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);
Index: linux-2.6.12-rc6/ipc/msg.c
===================================================================
--- linux-2.6.12-rc6.orig/ipc/msg.c
+++ linux-2.6.12-rc6/ipc/msg.c
@@ -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);
Index: linux-2.6.12-rc6/ipc/msgutil.c
===================================================================
--- linux-2.6.12-rc6.orig/ipc/msgutil.c
+++ linux-2.6.12-rc6/ipc/msgutil.c
@@ -41,7 +41,7 @@ struct msg_msg *load_msg(const void __us
return ERR_PTR(-ENOMEM);
msg->next = NULL;
- msg->security = NULL;
+ INIT_HLIST_HEAD(&msg->security);
if (copy_from_user(msg + 1, src, alen)) {
err = -EFAULT;
Index: linux-2.6.12-rc6/ipc/sem.c
===================================================================
--- linux-2.6.12-rc6.orig/ipc/sem.c
+++ linux-2.6.12-rc6/ipc/sem.c
@@ -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);
Index: linux-2.6.12-rc6/ipc/shm.c
===================================================================
--- linux-2.6.12-rc6.orig/ipc/shm.c
+++ linux-2.6.12-rc6/ipc/shm.c
@@ -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);
Index: linux-2.6.12-rc6/kernel/fork.c
===================================================================
--- linux-2.6.12-rc6.orig/kernel/fork.c
+++ linux-2.6.12-rc6/kernel/fork.c
@@ -936,7 +936,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;
^ permalink raw reply [flat|nested] 12+ messages in thread* [patch 3/11] lsm stacking: introduce security_*_value API
2005-06-08 23:55 patch 0/11] lsm stacking: intro serue
2005-06-08 23:56 ` [patch 1/11] lsm stacking: don't default to dummy_##hook serue
2005-06-08 23:57 ` [patch 2/11] lsm stacking: replace void* security with hlist serue
@ 2005-06-08 23:58 ` serue
2005-06-08 23:59 ` [patch 4/11] lsm stacking: stacker documentation serue
` (7 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: serue @ 2005-06-08 23:58 UTC (permalink / raw)
To: lkml; +Cc: Chris Wright, Stephen Smalley, James Morris
Define the functions to be used by LSMs to add, retrieve, and remove
elements to the kernel object ->security hlists.
Signed-off-by: Serge Hallyn <serue@us.ibm.com>
---
include/linux/security-stack.h | 51 +++++++++++++++++++++++++++
include/linux/security.h | 29 +++++++++++++++
security/security.c | 75 +++++++++++++++++++++++++++++++++++++++++
3 files changed, 155 insertions(+)
Index: linux-2.6.12-rc6/include/linux/security-stack.h
===================================================================
--- /dev/null
+++ linux-2.6.12-rc6/include/linux/security-stack.h
@@ -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
Index: linux-2.6.12-rc6/include/linux/security.h
===================================================================
--- linux-2.6.12-rc6.orig/include/linux/security.h
+++ linux-2.6.12-rc6/include/linux/security.h
@@ -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
*/
Index: linux-2.6.12-rc6/security/security.c
===================================================================
--- linux-2.6.12-rc6.orig/security/security.c
+++ linux-2.6.12-rc6/security/security.c
@@ -20,6 +20,81 @@
#define SECURITY_FRAMEWORK_VERSION "1.0.0"
+#ifdef CONFIG_SECURITY_STACKER
+fastcall struct security_list *
+security_get_value(struct hlist_head *head, int security_id)
+{
+ struct security_list *e, *ret = NULL;
+ struct hlist_node *tmp;
+
+ rcu_read_lock();
+ for (tmp = head->first; tmp;
+ tmp = rcu_dereference(tmp->next)) {
+ e = hlist_entry(tmp, struct security_list, list);
+ if (e->security_id == security_id) {
+ ret = e;
+ goto out;
+ }
+ }
+
+out:
+ rcu_read_unlock();
+ return ret;
+}
+
+fastcall void
+security_set_value(struct hlist_head *head, int security_id,
+ struct security_list *obj_node)
+{
+
+ obj_node->security_id = security_id;
+ hlist_add_head(&obj_node->list, head);
+}
+
+static DEFINE_SPINLOCK(stacker_value_spinlock);
+
+fastcall void
+security_add_value(struct hlist_head *head, int security_id,
+ struct security_list *obj_node)
+{
+
+ spin_lock(&stacker_value_spinlock);
+ obj_node->security_id = security_id;
+ hlist_add_head_rcu(&obj_node->list, head);
+ spin_unlock(&stacker_value_spinlock);
+}
+
+/*
+ * XXX Serge: is it possible to add a security_del_value_locked(),
+ * which waits for a full rcu read cycle before returning an object
+ * to be deleted, so that it would be safe to use along with racing
+ * security_get_value()?
+ */
+
+/* No locking needed: only called during object_destroy */
+fastcall struct security_list *
+security_del_value(struct hlist_head *head, int security_id)
+{
+ struct security_list *e;
+ struct hlist_node *tmp;
+
+ for (tmp = head->first; tmp; tmp = tmp->next) {
+ e = hlist_entry(tmp, struct security_list, list);
+ if (e->security_id == security_id) {
+ hlist_del(&e->list);
+ return e;
+ }
+ }
+
+ return NULL;
+}
+
+EXPORT_SYMBOL_GPL(security_get_value);
+EXPORT_SYMBOL_GPL(security_set_value);
+EXPORT_SYMBOL_GPL(security_add_value);
+EXPORT_SYMBOL_GPL(security_del_value);
+#endif
+
/* things that live in dummy.c */
extern struct security_operations dummy_security_ops;
extern void security_fixup_ops(struct security_operations *ops);
^ permalink raw reply [flat|nested] 12+ messages in thread* [patch 4/11] lsm stacking: stacker documentation
2005-06-08 23:55 patch 0/11] lsm stacking: intro serue
` (2 preceding siblings ...)
2005-06-08 23:58 ` [patch 3/11] lsm stacking: introduce security_*_value API serue
@ 2005-06-08 23:59 ` serue
2005-06-09 0:00 ` [patch 5/11] lsm stacking: actual stacker module serue
` (6 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: serue @ 2005-06-08 23:59 UTC (permalink / raw)
To: lkml; +Cc: Chris Wright, Stephen Smalley, James Morris
Add documentation about stacker and its usage.
Signed-off-by: Serge Hallyn <serue@us.ibm.com>
---
Documentation/LSM-stacking.txt | 157 +++++++++++++++++++++++++++++++++++++++++
1 files changed, 157 insertions(+)
Index: linux-2.6.12-rc6/Documentation/LSM-stacking.txt
===================================================================
--- /dev/null
+++ linux-2.6.12-rc6/Documentation/LSM-stacking.txt
@@ -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,
+linux-security-module@wirex.com. 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.
^ permalink raw reply [flat|nested] 12+ messages in thread* [patch 5/11] lsm stacking: actual stacker module
2005-06-08 23:55 patch 0/11] lsm stacking: intro serue
` (3 preceding siblings ...)
2005-06-08 23:59 ` [patch 4/11] lsm stacking: stacker documentation serue
@ 2005-06-09 0:00 ` serue
2005-06-09 0:00 ` [patch 6/11] lsm stacking: introduce stackable capabilities lsm serue
` (5 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: serue @ 2005-06-09 0:00 UTC (permalink / raw)
To: lkml; +Cc: Chris Wright, Stephen Smalley, James Morris
Adds the actual stacker LSM.
Signed-off-by: Serge Hallyn <serue@us.ibm.com>
---
security/Kconfig | 6
security/Makefile | 1
security/stacker.c | 1455 +++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 1462 insertions(+)
Index: linux-2.6.12-rc2/security/Kconfig
===================================================================
--- linux-2.6.12-rc2.orig/security/Kconfig 2005-05-23 09:55:11.000000000 -0500
+++ linux-2.6.12-rc2/security/Kconfig 2005-05-23 15:25:45.000000000 -0500
@@ -87,5 +87,11 @@
source security/selinux/Kconfig
+config SECURITY_STACKER
+ boolean "LSM Stacking"
+ depends on SECURITY
+ help
+ Stack multiple LSMs.
+
endmenu
Index: linux-2.6.12-rc2/security/Makefile
===================================================================
--- linux-2.6.12-rc2.orig/security/Makefile 2005-05-23 09:55:11.000000000 -0500
+++ linux-2.6.12-rc2/security/Makefile 2005-05-23 15:25:45.000000000 -0500
@@ -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
Index: linux-2.6.12-rc2/security/stacker.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.12-rc2/security/stacker.c 2005-05-23 15:25:39.000000000 -0500
@@ -0,0 +1,1455 @@
+/* "Stacker" Linux security module (LSM).
+ *
+ * Allows you to load (stack) multiple (additional) security modules.
+ *
+ * Copyright (C) 2002,2003,2004,2005 Serge E. Hallyn <serue@us.ibm.com>
+ * Copyright (C) 2002 David A. Wheeler <dwheeler@dwheeler.com>.
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/security.h>
+#include <linux/skbuff.h>
+#include <linux/netlink.h>
+#include <linux/capability.h>
+#include <linux/rwsem.h>
+#include <linux/kobject.h>
+#include <linux/sysfs.h>
+#include <linux/netdevice.h>
+#include <linux/string.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <asm/system.h>
+
+/* A module entry keeps track of one of the stacked modules
+ * Note that module_operations is aggregated instead of being pointed to -
+ * it's one less allocation and one less pointer to follow. */
+
+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;
+};
+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;
+
+static spinlock_t stacker_lock;
+static int forbid_stacker_register; /* = 0; if 1, can't register */
+
+
+/*
+ * Workarounds for the fact that get and setprocattr are used only by
+ * selinux. (Maybe)
+ */
+static struct module_entry *selinux_module;
+
+/* Maximum number of characters in a stacked LSM module name */
+#define MAX_MODULE_NAME_LEN 128
+
+static int debug = 0;
+
+module_param(debug, bool, 0600);
+MODULE_PARM_DESC(debug, "Debug enabled or not");
+#define MY_NAME "stacker"
+#define stacker_dbg(fmt, arg...) \
+ do { \
+ if (debug) \
+ printk(KERN_DEBUG "%s: %s: " fmt , \
+ MY_NAME , __FUNCTION__ , \
+ ## arg); \
+ } while (0)
+
+/* Walk through the list of modules in stacked_modules
+ * and ask each (in turn) for their results, then return the
+ * results. If more than one module reports an error, return
+ * the FIRST error code.
+ *
+ * We return as soon as an error is returned.
+ */
+
+#define stack_for_each_entry(pos, head, member) \
+ for (pos = list_entry((head)->next, typeof(*pos), member); \
+ &pos->member != (head); \
+ pos = rcu_dereference(list_entry(pos->member.next, \
+ typeof(*pos), member)))
+
+/* to make this safe for module deletion, we would need to
+ * add a reference count to m as we had before
+ */
+#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 (result) \
+ break; \
+ } \
+ rcu_read_unlock(); \
+ return result; \
+} while (0)
+
+/* Call all modules in stacked_modules' routine */
+#define CALL_ALL(BASE_FUNC, FUNC_WITH_ARGS) do { \
+ struct module_entry *m; \
+ rcu_read_lock(); \
+ stack_for_each_entry(m, &stacked_modules, lsm_list) { \
+ if (m->module_operations.BASE_FUNC) { \
+ rcu_read_unlock(); \
+ m->module_operations.FUNC_WITH_ARGS; \
+ rcu_read_lock(); \
+ } \
+ } \
+ rcu_read_unlock(); \
+} while (0)
+
+#define FREE_ALL(BASE_FREE,FREE_WITH_ARGS) do { \
+ struct module_entry *m; \
+ rcu_read_lock(); \
+ stack_for_each_entry(m, &stacked_modules, lsm_list ) { \
+ if (m->module_operations.BASE_FREE) { \
+ rcu_read_unlock(); \
+ m->module_operations.FREE_WITH_ARGS; \
+ rcu_read_lock(); \
+ } \
+ } \
+ rcu_read_unlock(); \
+} while (0)
+
+#define ALLOC_SECURITY(BASE_FUNC,FUNC_WITH_ARGS,BASE_FREE,FREE_WITH_ARGS) do { \
+ int result; \
+ 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 (result) \
+ goto bad; \
+ } \
+ rcu_read_unlock(); \
+ return 0; \
+bad: \
+ stack_for_each_entry(m2, &all_modules, all_lsms) { \
+ if (m == m2) \
+ break; \
+ if (!m2->module_operations.BASE_FREE) \
+ continue; \
+ rcu_read_unlock(); \
+ m2->module_operations.FREE_WITH_ARGS; \
+ rcu_read_lock(); \
+ } \
+ rcu_read_unlock(); \
+ return result; \
+} while (0)
+
+/*
+ * The list of functions for stacker_ops
+ */
+static int stacker_ptrace (struct task_struct *parent, struct task_struct *child)
+{
+ RETURN_ERROR_IF_ANY_ERROR(ptrace,ptrace(parent, child));
+}
+
+static int stacker_capget (struct task_struct *target, kernel_cap_t * effective,
+ kernel_cap_t * inheritable, kernel_cap_t * permitted)
+{
+ RETURN_ERROR_IF_ANY_ERROR(capget,capget(target, effective, inheritable, permitted));
+}
+
+static int stacker_capset_check (struct task_struct *target,
+ kernel_cap_t * effective,
+ kernel_cap_t * inheritable,
+ kernel_cap_t * permitted)
+{
+ RETURN_ERROR_IF_ANY_ERROR(capset_check,capset_check(target, effective, inheritable, permitted));
+}
+
+static void stacker_capset_set (struct task_struct *target,
+ kernel_cap_t * effective,
+ kernel_cap_t * inheritable,
+ kernel_cap_t * permitted)
+{
+ CALL_ALL(capset_set,capset_set(target, effective, inheritable, permitted));
+}
+
+static int stacker_acct (struct file *file)
+{
+ RETURN_ERROR_IF_ANY_ERROR(acct,acct(file));
+}
+
+static int stacker_capable (struct task_struct *tsk, int cap)
+{
+ RETURN_ERROR_IF_ANY_ERROR(capable,capable(tsk,cap));
+}
+
+
+static int stacker_sysctl (struct ctl_table * table, int op)
+{
+ RETURN_ERROR_IF_ANY_ERROR(sysctl,sysctl(table, op));
+}
+
+static int stacker_quotactl (int cmds, int type, int id, struct super_block *sb)
+{
+ RETURN_ERROR_IF_ANY_ERROR(quotactl,quotactl(cmds,type,id,sb));
+}
+
+static int stacker_quota_on (struct dentry *dentry)
+{
+ RETURN_ERROR_IF_ANY_ERROR(quota_on,quota_on(dentry));
+}
+
+static int stacker_syslog (int type)
+{
+ RETURN_ERROR_IF_ANY_ERROR(syslog,syslog(type));
+}
+
+static int stacker_settime(struct timespec *ts, struct timezone *tz)
+{
+ RETURN_ERROR_IF_ANY_ERROR(settime,settime(ts,tz));
+}
+
+/*
+ * vm_enough_memory performs actual updates of vm state. Most
+ * modules, including dummy, use the __vm_enough_memory helper
+ * to do this for them.
+ * This means we can't call more than one module's vm_enough.
+ * So we call the first module's, or if no modules are loaded,
+ * we call dummy_vm_enough_memory.
+ */
+static int stacker_vm_enough_memory(long pages)
+{
+ int result;
+ struct module_entry *m;
+
+ if (unlikely(list_empty(&stacked_modules)))
+ goto no_module_vmenough;
+
+ rcu_read_lock();
+ stack_for_each_entry(m, &stacked_modules, lsm_list) {
+ if (!m->module_operations.vm_enough_memory)
+ continue;
+ rcu_read_unlock();
+ result = m->module_operations.vm_enough_memory(pages);
+ return result;
+ }
+ rcu_read_unlock();
+
+no_module_vmenough:
+ result = __vm_enough_memory(pages, capable(CAP_SYS_ADMIN));
+ return result;
+}
+
+/*
+ * Each module may have it's own idea of how to set netlink perms.
+ * We use the intersection of all as the final alloted perms.
+ */
+static int stacker_netlink_send (struct sock *sk, struct sk_buff *skb)
+{
+ kernel_cap_t tmpcap = ~0;
+ int result = 0;
+ struct module_entry *m;
+
+ rcu_read_lock();
+ stack_for_each_entry(m, &stacked_modules, lsm_list) {
+ if (!m->module_operations.netlink_send)
+ continue;
+ NETLINK_CB(skb).eff_cap = ~0;
+ rcu_read_unlock();
+ result = m->module_operations.netlink_send(sk, skb);
+ rcu_read_lock();
+ tmpcap &= NETLINK_CB(skb).eff_cap;
+ if (result)
+ break;
+ }
+ rcu_read_unlock();
+
+ NETLINK_CB(skb).eff_cap = tmpcap;
+ return result;
+}
+
+
+static int stacker_netlink_recv (struct sk_buff *skb)
+{
+ RETURN_ERROR_IF_ANY_ERROR(netlink_recv,netlink_recv(skb));
+}
+
+static int stacker_bprm_alloc_security (struct linux_binprm *bprm)
+{
+ ALLOC_SECURITY(bprm_alloc_security,bprm_alloc_security(bprm),bprm_free_security,bprm_free_security(bprm));
+}
+
+static void stacker_bprm_free_security (struct linux_binprm *bprm)
+{
+ FREE_ALL(bprm_free_security,bprm_free_security(bprm));
+}
+
+static void stacker_bprm_apply_creds (struct linux_binprm *bprm, int unsafe)
+{
+ CALL_ALL(bprm_apply_creds,bprm_apply_creds(bprm, unsafe));
+}
+
+static void stacker_bprm_post_apply_creds (struct linux_binprm * bprm)
+{
+ CALL_ALL(bprm_post_apply_creds,bprm_post_apply_creds(bprm));
+}
+
+static int stacker_bprm_set_security (struct linux_binprm *bprm)
+{
+ RETURN_ERROR_IF_ANY_ERROR(bprm_set_security,bprm_set_security(bprm));
+}
+
+static int stacker_bprm_check_security (struct linux_binprm *bprm)
+{
+ RETURN_ERROR_IF_ANY_ERROR(bprm_check_security,bprm_check_security(bprm));
+}
+
+static int stacker_bprm_secureexec (struct linux_binprm *bprm)
+{
+ RETURN_ERROR_IF_ANY_ERROR(bprm_secureexec,bprm_secureexec(bprm));
+}
+
+static int stacker_sb_alloc_security (struct super_block *sb)
+{
+ ALLOC_SECURITY(sb_alloc_security,sb_alloc_security(sb),sb_free_security,sb_free_security(sb));
+}
+
+static void stacker_sb_free_security (struct super_block *sb)
+{
+ FREE_ALL(sb_free_security,sb_free_security(sb));
+}
+
+static int stacker_sb_copy_data (struct file_system_type *type,
+ void *orig, void *copy)
+{
+ RETURN_ERROR_IF_ANY_ERROR(sb_copy_data,sb_copy_data(type,orig,copy));
+}
+
+static int stacker_sb_kern_mount (struct super_block *sb, void *data)
+{
+ RETURN_ERROR_IF_ANY_ERROR(sb_kern_mount,sb_kern_mount(sb, data));
+}
+
+static int stacker_sb_statfs (struct super_block *sb)
+{
+ RETURN_ERROR_IF_ANY_ERROR(sb_statfs,sb_statfs(sb));
+}
+
+static int stacker_mount (char *dev_name, struct nameidata *nd, char *type,
+ unsigned long flags, void *data)
+{
+ RETURN_ERROR_IF_ANY_ERROR(sb_mount,sb_mount(dev_name, nd, type, flags, data));
+}
+
+static int stacker_check_sb (struct vfsmount *mnt, struct nameidata *nd)
+{
+ RETURN_ERROR_IF_ANY_ERROR(sb_check_sb,sb_check_sb(mnt, nd));
+}
+
+static int stacker_umount (struct vfsmount *mnt, int flags)
+{
+ RETURN_ERROR_IF_ANY_ERROR(sb_umount,sb_umount(mnt, flags));
+}
+
+static void stacker_umount_close (struct vfsmount *mnt)
+{
+ CALL_ALL(sb_umount_close,sb_umount_close(mnt));
+}
+
+static void stacker_umount_busy (struct vfsmount *mnt)
+{
+ CALL_ALL(sb_umount_busy,sb_umount_busy(mnt));
+}
+
+static void stacker_post_remount (struct vfsmount *mnt, unsigned long flags,
+ void *data)
+{
+ CALL_ALL(sb_post_remount,sb_post_remount(mnt, flags, data));
+}
+
+
+static void stacker_post_mountroot (void)
+{
+ CALL_ALL(sb_post_mountroot,sb_post_mountroot());
+}
+
+static void stacker_post_addmount (struct vfsmount *mnt, struct nameidata *nd)
+{
+ CALL_ALL(sb_post_addmount,sb_post_addmount(mnt, nd));
+}
+
+static int stacker_pivotroot (struct nameidata *old_nd, struct nameidata *new_nd)
+{
+ RETURN_ERROR_IF_ANY_ERROR(sb_pivotroot,sb_pivotroot(old_nd, new_nd));
+}
+
+static void stacker_post_pivotroot (struct nameidata *old_nd, struct nameidata *new_nd)
+{
+ CALL_ALL(sb_post_pivotroot,sb_post_pivotroot(old_nd, new_nd));
+}
+
+static int stacker_inode_alloc_security (struct inode *inode)
+{
+ ALLOC_SECURITY(inode_alloc_security,inode_alloc_security(inode),inode_free_security,inode_free_security(inode));
+}
+
+static void stacker_inode_free_security (struct inode *inode)
+{
+ FREE_ALL(inode_free_security,inode_free_security(inode));
+}
+
+static int stacker_inode_create (struct inode *inode, struct dentry *dentry,
+ int mask)
+{
+ RETURN_ERROR_IF_ANY_ERROR(inode_create,inode_create(inode, dentry, mask));
+}
+
+static void stacker_inode_post_create (struct inode *inode,
+ struct dentry *dentry, int mask)
+{
+ CALL_ALL(inode_post_create,inode_post_create(inode, dentry, mask));
+}
+
+static int stacker_inode_link (struct dentry *old_dentry, struct inode *inode,
+ struct dentry *new_dentry)
+{
+ RETURN_ERROR_IF_ANY_ERROR(inode_link,inode_link(old_dentry, inode, new_dentry));
+}
+
+static void stacker_inode_post_link (struct dentry *old_dentry,
+ struct inode *inode,
+ struct dentry *new_dentry)
+{
+ CALL_ALL(inode_post_link,inode_post_link(old_dentry, inode, new_dentry));
+}
+
+static int stacker_inode_unlink (struct inode *inode, struct dentry *dentry)
+{
+ RETURN_ERROR_IF_ANY_ERROR(inode_unlink,inode_unlink(inode, dentry));
+}
+
+static int stacker_inode_symlink (struct inode *inode, struct dentry *dentry,
+ const char *name)
+{
+ RETURN_ERROR_IF_ANY_ERROR(inode_symlink,inode_symlink(inode, dentry, name));
+}
+
+static void stacker_inode_post_symlink (struct inode *inode,
+ struct dentry *dentry, const char *name)
+{
+ CALL_ALL(inode_post_symlink,inode_post_symlink(inode, dentry, name));
+}
+
+static int stacker_inode_mkdir (struct inode *inode, struct dentry *dentry,
+ int mask)
+{
+ RETURN_ERROR_IF_ANY_ERROR(inode_mkdir,inode_mkdir(inode, dentry, mask));
+}
+
+static void stacker_inode_post_mkdir (struct inode *inode,
+ struct dentry *dentry, int mask)
+{
+ CALL_ALL(inode_post_mkdir,inode_post_mkdir(inode, dentry, mask));
+}
+
+static int stacker_inode_rmdir (struct inode *inode, struct dentry *dentry)
+{
+ RETURN_ERROR_IF_ANY_ERROR(inode_rmdir,inode_rmdir(inode, dentry));
+}
+
+static int stacker_inode_mknod (struct inode *inode, struct dentry *dentry,
+ int major, dev_t minor)
+{
+ RETURN_ERROR_IF_ANY_ERROR(inode_mknod,inode_mknod(inode, dentry, major, minor));
+}
+
+static void stacker_inode_post_mknod (struct inode *inode,
+ struct dentry *dentry, int major, dev_t minor)
+{
+ CALL_ALL(inode_post_mknod,inode_post_mknod(inode, dentry, major, minor));
+}
+
+static int stacker_inode_rename (struct inode *old_inode,
+ struct dentry *old_dentry,
+ struct inode *new_inode,
+ struct dentry *new_dentry)
+{
+ RETURN_ERROR_IF_ANY_ERROR(inode_rename,inode_rename(old_inode, old_dentry,
+ new_inode, new_dentry));
+}
+
+static void stacker_inode_post_rename (struct inode *old_inode,
+ struct dentry *old_dentry,
+ struct inode *new_inode,
+ struct dentry *new_dentry)
+{
+ CALL_ALL(inode_post_rename,inode_post_rename(old_inode, old_dentry,
+ new_inode, new_dentry));
+}
+
+static int stacker_inode_readlink (struct dentry *dentry)
+{
+ RETURN_ERROR_IF_ANY_ERROR(inode_readlink,inode_readlink(dentry));
+}
+
+static int stacker_inode_follow_link (struct dentry *dentry,
+ struct nameidata *nameidata)
+{
+ RETURN_ERROR_IF_ANY_ERROR(inode_follow_link,inode_follow_link(dentry, nameidata));
+}
+
+static int stacker_inode_permission (struct inode *inode, int mask,
+ struct nameidata *nd)
+{
+ RETURN_ERROR_IF_ANY_ERROR(inode_permission,inode_permission(inode, mask, nd));
+}
+
+static int stacker_inode_setattr (struct dentry *dentry, struct iattr *iattr)
+{
+ RETURN_ERROR_IF_ANY_ERROR(inode_setattr,inode_setattr(dentry, iattr));
+}
+
+static int stacker_inode_getattr (struct vfsmount *mnt, struct dentry *dentry)
+{
+ RETURN_ERROR_IF_ANY_ERROR(inode_getattr,inode_getattr(mnt,dentry));
+}
+
+static void stacker_inode_delete (struct inode *ino)
+{
+ CALL_ALL(inode_delete,inode_delete(ino));
+}
+
+static int stacker_inode_setxattr (struct dentry *dentry, char *name,
+ void *value, size_t size, int flags)
+{
+ RETURN_ERROR_IF_ANY_ERROR(inode_setxattr,inode_setxattr(dentry,name,value,size,flags));
+}
+
+static void stacker_inode_post_setxattr (struct dentry *dentry, char *name, void *value,
+ size_t size, int flags)
+{
+ CALL_ALL(inode_post_setxattr,inode_post_setxattr(dentry,name,value,size,flags));
+}
+
+static int stacker_inode_getxattr (struct dentry *dentry, char *name)
+{
+ RETURN_ERROR_IF_ANY_ERROR(inode_getxattr,inode_getxattr(dentry,name));
+}
+
+static int stacker_inode_listxattr (struct dentry *dentry)
+{
+ RETURN_ERROR_IF_ANY_ERROR(inode_listxattr,inode_listxattr(dentry));
+}
+
+static int stacker_inode_removexattr (struct dentry *dentry, char *name)
+{
+ RETURN_ERROR_IF_ANY_ERROR(inode_removexattr,inode_removexattr(dentry,name));
+}
+
+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));
+}
+
+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));
+}
+
+static int stacker_file_permission (struct file *file, int mask)
+{
+ RETURN_ERROR_IF_ANY_ERROR(file_permission,file_permission(file,mask));
+}
+
+static int stacker_file_alloc_security (struct file *file)
+{
+ ALLOC_SECURITY(file_alloc_security,file_alloc_security(file),file_free_security,file_free_security(file));
+}
+
+static void stacker_file_free_security (struct file *file)
+{
+ FREE_ALL(file_free_security,file_free_security(file));
+}
+
+static int stacker_file_ioctl (struct file *file, unsigned int command,
+ unsigned long arg)
+{
+ RETURN_ERROR_IF_ANY_ERROR(file_ioctl,file_ioctl(file,command,arg));
+}
+
+static int stacker_file_mmap (struct file *file, unsigned long reqprot,
+ unsigned long prot, unsigned long flags)
+{
+ RETURN_ERROR_IF_ANY_ERROR(file_mmap,file_mmap(file, reqprot, prot, flags));
+}
+
+static int stacker_file_mprotect (struct vm_area_struct *vma,
+ unsigned long reqprot, unsigned long prot)
+{
+ RETURN_ERROR_IF_ANY_ERROR(file_mprotect,file_mprotect(vma,reqprot,prot));
+}
+
+static int stacker_file_lock (struct file *file, unsigned int cmd)
+{
+ RETURN_ERROR_IF_ANY_ERROR(file_lock,file_lock(file,cmd));
+}
+
+static int stacker_file_fcntl (struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ RETURN_ERROR_IF_ANY_ERROR(file_fcntl,file_fcntl(file,cmd,arg));
+}
+
+static int stacker_file_set_fowner (struct file *file)
+{
+ RETURN_ERROR_IF_ANY_ERROR(file_set_fowner,file_set_fowner(file));
+}
+
+static int stacker_file_send_sigiotask (struct task_struct *tsk,
+ struct fown_struct *fown, int sig)
+{
+ RETURN_ERROR_IF_ANY_ERROR(file_send_sigiotask,file_send_sigiotask(tsk,fown,sig));
+}
+
+static int stacker_file_receive (struct file *file)
+{
+ RETURN_ERROR_IF_ANY_ERROR(file_receive,file_receive(file));
+}
+
+static int stacker_task_create (unsigned long clone_flags)
+{
+ RETURN_ERROR_IF_ANY_ERROR(task_create,task_create(clone_flags));
+}
+
+static int stacker_task_alloc_security (struct task_struct *p)
+{
+ ALLOC_SECURITY(task_alloc_security,task_alloc_security(p),task_free_security,task_free_security(p));
+}
+
+static void stacker_task_free_security (struct task_struct *p)
+{
+ FREE_ALL(task_free_security,task_free_security(p));
+}
+
+static int stacker_task_setuid (uid_t id0, uid_t id1, uid_t id2, int flags)
+{
+ RETURN_ERROR_IF_ANY_ERROR(task_setuid,task_setuid(id0,id1,id2,flags));
+}
+
+static int stacker_task_post_setuid (uid_t id0, uid_t id1, uid_t id2, int flags)
+{
+ RETURN_ERROR_IF_ANY_ERROR(task_post_setuid,task_post_setuid(id0,id1,id2,flags));
+}
+
+static int stacker_task_setgid (gid_t id0, gid_t id1, gid_t id2, int flags)
+{
+ RETURN_ERROR_IF_ANY_ERROR(task_setgid,task_setgid(id0,id1,id2,flags));
+}
+
+static int stacker_task_setpgid (struct task_struct *p, pid_t pgid)
+{
+ RETURN_ERROR_IF_ANY_ERROR(task_setpgid,task_setpgid(p,pgid));
+}
+
+static int stacker_task_getpgid (struct task_struct *p)
+{
+ RETURN_ERROR_IF_ANY_ERROR(task_getpgid,task_getpgid(p));
+}
+
+static int stacker_task_getsid (struct task_struct *p)
+{
+ RETURN_ERROR_IF_ANY_ERROR(task_getsid,task_getsid(p));
+}
+
+static int stacker_task_setgroups (struct group_info *group_info)
+{
+ RETURN_ERROR_IF_ANY_ERROR(task_setgroups,task_setgroups(group_info));
+}
+
+static int stacker_task_setnice (struct task_struct *p, int nice)
+{
+ RETURN_ERROR_IF_ANY_ERROR(task_setnice,task_setnice(p,nice));
+}
+
+static int stacker_task_setrlimit (unsigned int resource, struct rlimit *new_rlim)
+{
+ RETURN_ERROR_IF_ANY_ERROR(task_setrlimit,task_setrlimit(resource,new_rlim));
+}
+
+static int stacker_task_setscheduler (struct task_struct *p, int policy,
+ struct sched_param *lp)
+{
+ RETURN_ERROR_IF_ANY_ERROR(task_setscheduler,task_setscheduler(p,policy,lp));
+}
+
+static int stacker_task_getscheduler (struct task_struct *p)
+{
+ RETURN_ERROR_IF_ANY_ERROR(task_getscheduler,task_getscheduler(p));
+}
+
+static int stacker_task_wait (struct task_struct *p)
+{
+ RETURN_ERROR_IF_ANY_ERROR(task_wait,task_wait(p));
+}
+
+static int stacker_task_kill (struct task_struct *p, struct siginfo *info,
+ int sig)
+{
+ RETURN_ERROR_IF_ANY_ERROR(task_kill,task_kill(p,info,sig));
+}
+
+static int stacker_task_prctl (int option, unsigned long arg2, unsigned long arg3,
+ unsigned long arg4, unsigned long arg5)
+{
+ RETURN_ERROR_IF_ANY_ERROR(task_prctl,task_prctl(option,arg2,arg3,arg4,arg5));
+}
+
+static void stacker_task_reparent_to_init (struct task_struct *p)
+{
+ /* Note that the dummy version of this hook would call:
+ * p->euid = p->fsuid = 0; */
+
+ CALL_ALL(task_reparent_to_init,task_reparent_to_init(p));
+}
+
+static void stacker_task_to_inode(struct task_struct *p, struct inode *inode)
+{
+ CALL_ALL(task_to_inode,task_to_inode(p, inode));
+}
+
+#ifdef CONFIG_SECURITY_NETWORK
+static int stacker_socket_create (int family, int type, int protocol, int kern)
+{
+ RETURN_ERROR_IF_ANY_ERROR(socket_create,socket_create(family,type,protocol,kern));
+}
+
+static void stacker_socket_post_create (struct socket *sock, int family,
+ int type, int protocol, int kern)
+{
+ CALL_ALL(socket_post_create,socket_post_create(sock,family,type,protocol,kern));
+}
+
+static int stacker_socket_bind (struct socket *sock, struct sockaddr *address,
+ int addrlen)
+{
+ RETURN_ERROR_IF_ANY_ERROR(socket_bind,socket_bind(sock,address,addrlen));
+}
+
+static int stacker_socket_connect (struct socket *sock,
+ struct sockaddr *address, int addrlen)
+{
+ RETURN_ERROR_IF_ANY_ERROR(socket_connect,socket_connect(sock,address,addrlen));
+}
+
+static int stacker_socket_listen (struct socket *sock, int backlog)
+{
+ RETURN_ERROR_IF_ANY_ERROR(socket_listen,socket_listen(sock,backlog));
+}
+
+static int stacker_socket_accept (struct socket *sock, struct socket *newsock)
+{
+ RETURN_ERROR_IF_ANY_ERROR(socket_accept,socket_accept(sock,newsock));
+}
+
+static void stacker_socket_post_accept (struct socket *sock,
+ struct socket *newsock)
+{
+ CALL_ALL(socket_post_accept,socket_post_accept(sock,newsock));
+}
+
+static int stacker_socket_sendmsg (struct socket *sock, struct msghdr *msg,
+ int size)
+{
+ RETURN_ERROR_IF_ANY_ERROR(socket_sendmsg,socket_sendmsg(sock,msg,size));
+}
+
+static int stacker_socket_recvmsg (struct socket *sock, struct msghdr *msg,
+ int size, int flags)
+{
+ RETURN_ERROR_IF_ANY_ERROR(socket_recvmsg,socket_recvmsg(sock,msg,size,flags));
+}
+
+static int stacker_socket_getsockname (struct socket *sock)
+{
+ RETURN_ERROR_IF_ANY_ERROR(socket_getsockname,socket_getsockname(sock));
+}
+
+static int stacker_socket_getpeername (struct socket *sock)
+{
+ RETURN_ERROR_IF_ANY_ERROR(socket_getpeername,socket_getpeername(sock));
+}
+
+static int stacker_socket_setsockopt (struct socket *sock, int level, int optname)
+{
+ RETURN_ERROR_IF_ANY_ERROR(socket_setsockopt,socket_setsockopt(sock,level,optname));
+}
+
+static int stacker_socket_getsockopt (struct socket *sock, int level, int optname)
+{
+ RETURN_ERROR_IF_ANY_ERROR(socket_getsockopt,socket_getsockopt(sock,level,optname));
+}
+
+static int stacker_socket_shutdown (struct socket *sock, int how)
+{
+ RETURN_ERROR_IF_ANY_ERROR(socket_shutdown,socket_shutdown(sock,how));
+}
+
+static int stacker_socket_sock_rcv_skb (struct sock *sk, struct sk_buff *skb)
+{
+ RETURN_ERROR_IF_ANY_ERROR(socket_sock_rcv_skb,socket_sock_rcv_skb(sk,skb));
+}
+
+static int stacker_unix_stream_connect (struct socket *sock,
+ struct socket *other, struct sock *newsk)
+{
+ RETURN_ERROR_IF_ANY_ERROR(unix_stream_connect,unix_stream_connect(sock,other,newsk));
+}
+
+static int stacker_unix_may_send (struct socket *sock,
+ struct socket *other)
+{
+ RETURN_ERROR_IF_ANY_ERROR(unix_may_send,unix_may_send(sock,other));
+}
+
+static int stacker_socket_getpeersec(struct socket *sock,
+ char __user *optval, int __user *optlen, unsigned len)
+{
+ RETURN_ERROR_IF_ANY_ERROR(socket_getpeersec,socket_getpeersec(sock,optval,optlen,len));
+}
+
+static int stacker_sk_alloc_security(struct sock *sk, int family,
+ int priority)
+{
+ ALLOC_SECURITY(sk_alloc_security,sk_alloc_security(sk,family,priority),sk_free_security,sk_free_security(sk));
+}
+
+static void stacker_sk_free_security (struct sock *sk)
+{
+ FREE_ALL(sk_free_security,sk_free_security(sk));
+}
+
+#endif
+
+static int stacker_ipc_permission (struct kern_ipc_perm *ipcp, short flag)
+{
+ RETURN_ERROR_IF_ANY_ERROR(ipc_permission,ipc_permission(ipcp,flag));
+}
+
+static int stacker_msg_msg_alloc_security (struct msg_msg *msg)
+{
+ ALLOC_SECURITY(msg_msg_alloc_security,msg_msg_alloc_security(msg),msg_msg_free_security,msg_msg_free_security(msg));
+}
+
+static void stacker_msg_msg_free_security (struct msg_msg *msg)
+{
+ FREE_ALL(msg_msg_free_security,msg_msg_free_security(msg));
+}
+
+static int stacker_msg_queue_alloc_security (struct msg_queue *msq)
+{
+ ALLOC_SECURITY(msg_queue_alloc_security,msg_queue_alloc_security(msq),msg_queue_free_security,msg_queue_free_security(msq));
+}
+
+static void stacker_msg_queue_free_security (struct msg_queue *msq)
+{
+ FREE_ALL(msg_queue_free_security,msg_queue_free_security(msq));
+}
+
+static int stacker_msg_queue_associate (struct msg_queue *msq, int msqflg)
+{
+ RETURN_ERROR_IF_ANY_ERROR(msg_queue_associate,msg_queue_associate(msq,msqflg));
+}
+
+static int stacker_msg_queue_msgctl (struct msg_queue *msq, int cmd)
+{
+ RETURN_ERROR_IF_ANY_ERROR(msg_queue_msgctl,msg_queue_msgctl(msq,cmd));
+}
+
+static int stacker_msg_queue_msgsnd (struct msg_queue *msq, struct msg_msg *msg,
+ int msgflg)
+{
+ RETURN_ERROR_IF_ANY_ERROR(msg_queue_msgsnd,msg_queue_msgsnd(msq,msg,msgflg));
+}
+
+static int stacker_msg_queue_msgrcv (struct msg_queue *msq, struct msg_msg *msg,
+ struct task_struct *target, long type,
+ int mode)
+{
+ RETURN_ERROR_IF_ANY_ERROR(msg_queue_msgrcv,msg_queue_msgrcv(msq,msg,target,type,mode));
+}
+
+static int stacker_shm_alloc_security (struct shmid_kernel *shp)
+{
+ ALLOC_SECURITY(shm_alloc_security,shm_alloc_security(shp),shm_free_security,shm_free_security(shp));
+}
+
+static void stacker_shm_free_security (struct shmid_kernel *shp)
+{
+ FREE_ALL(shm_free_security,shm_free_security(shp));
+}
+
+static int stacker_shm_associate (struct shmid_kernel *shp, int shmflg)
+{
+ RETURN_ERROR_IF_ANY_ERROR(shm_associate,shm_associate(shp,shmflg));
+}
+
+static int stacker_shm_shmctl (struct shmid_kernel *shp, int cmd)
+{
+ RETURN_ERROR_IF_ANY_ERROR(shm_shmctl,shm_shmctl(shp,cmd));
+}
+
+static int stacker_shm_shmat (struct shmid_kernel *shp, char *shmaddr,
+ int shmflg)
+{
+ RETURN_ERROR_IF_ANY_ERROR(shm_shmat,shm_shmat(shp,shmaddr,shmflg));
+}
+
+static int stacker_sem_alloc_security (struct sem_array *sma)
+{
+ ALLOC_SECURITY(sem_alloc_security,sem_alloc_security(sma),sem_free_security,sem_free_security(sma));
+}
+
+static void stacker_sem_free_security (struct sem_array *sma)
+{
+ FREE_ALL(sem_free_security,sem_free_security(sma));
+}
+
+static int stacker_sem_associate (struct sem_array *sma, int semflg)
+{
+ RETURN_ERROR_IF_ANY_ERROR(sem_associate,sem_associate(sma,semflg));
+}
+
+static int stacker_sem_semctl (struct sem_array *sma, int cmd)
+{
+ RETURN_ERROR_IF_ANY_ERROR(sem_semctl,sem_semctl(sma,cmd));
+}
+
+static int stacker_sem_semop (struct sem_array *sma,
+ struct sembuf *sops, unsigned nsops, int alter)
+{
+ RETURN_ERROR_IF_ANY_ERROR(sem_semop,sem_semop(sma,sops,nsops,alter));
+}
+
+static void stacker_d_instantiate (struct dentry *dentry, struct inode *inode)
+{
+ CALL_ALL(d_instantiate,d_instantiate(dentry,inode));
+}
+
+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)
+ return -EINVAL;
+ return selinux_module->module_operations.getprocattr(p, name, value, size);
+}
+
+static int stacker_setprocattr(struct task_struct *p, char *name, void *value, size_t size)
+{
+
+ if (!selinux_module)
+ return -EINVAL;
+ if (!selinux_module->module_operations.setprocattr)
+ return -EINVAL;
+ return selinux_module->module_operations.setprocattr(p, name, value, size);
+}
+
+/*
+ * Add the stacked module (as specified by name and ops).
+ * If the module is not compiled in, the symbol_get at the end will
+ * prevent the the module from being unloaded.
+*/
+static int stacker_register (const char *name, struct security_operations *ops)
+{
+ char *new_module_name;
+ struct module_entry *new_module_entry;
+ int namelen = strnlen(name, MAX_MODULE_NAME_LEN);
+ int ret = 0;
+
+ spin_lock(&stacker_lock);
+
+ if (forbid_stacker_register) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ new_module_name = kmalloc(namelen+1, GFP_KERNEL);
+ new_module_entry = kmalloc(sizeof(struct module_entry), GFP_KERNEL);
+ if (!new_module_name || !new_module_entry) {
+ printk(KERN_WARNING
+ "%s: Failure registering module - out of memory\n",
+ __FUNCTION__);
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ memset(new_module_entry, 0, sizeof(struct module_entry));
+ strncpy(new_module_name, name, namelen);
+ new_module_name[namelen] = '\0';
+ memcpy(&new_module_entry->module_operations, ops,
+ sizeof(struct security_operations));
+
+ new_module_entry->module_name = new_module_name;
+ new_module_entry->namelen = namelen;
+
+ INIT_LIST_HEAD(&new_module_entry->lsm_list);
+ INIT_LIST_HEAD(&new_module_entry->all_lsms);
+ list_add_tail(&new_module_entry->all_lsms, &all_modules);
+ list_add_tail(&new_module_entry->lsm_list, &stacked_modules);
+ if (strcmp(name, "selinux") == 0)
+ selinux_module = new_module_entry;
+
+ printk(KERN_INFO "%s: registered %s module\n", __FUNCTION__,
+ new_module_entry->module_name);
+
+ symbol_get(ops);
+
+out:
+ spin_unlock(&stacker_lock);
+ 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.
+ * 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.
+ */
+static int stacker_unregister (const char *name, struct security_operations *ops)
+{
+ return -EPERM;
+}
+
+static struct security_operations stacker_ops = {
+ .ptrace = stacker_ptrace,
+ .capget = stacker_capget,
+ .capset_check = stacker_capset_check,
+ .capset_set = stacker_capset_set,
+ .acct = stacker_acct,
+ .sysctl = stacker_sysctl,
+ .capable = stacker_capable,
+ .quotactl = stacker_quotactl,
+ .quota_on = stacker_quota_on,
+ .syslog = stacker_syslog,
+ .settime = stacker_settime,
+ .vm_enough_memory = stacker_vm_enough_memory,
+
+ .bprm_alloc_security = stacker_bprm_alloc_security,
+ .bprm_free_security = stacker_bprm_free_security,
+ .bprm_apply_creds = stacker_bprm_apply_creds,
+ .bprm_post_apply_creds = stacker_bprm_post_apply_creds,
+ .bprm_set_security = stacker_bprm_set_security,
+ .bprm_check_security = stacker_bprm_check_security,
+ .bprm_secureexec = stacker_bprm_secureexec,
+
+ .sb_alloc_security = stacker_sb_alloc_security,
+ .sb_free_security = stacker_sb_free_security,
+ .sb_copy_data = stacker_sb_copy_data,
+ .sb_kern_mount = stacker_sb_kern_mount,
+ .sb_statfs = stacker_sb_statfs,
+ .sb_mount = stacker_mount,
+ .sb_check_sb = stacker_check_sb,
+ .sb_umount = stacker_umount,
+ .sb_umount_close = stacker_umount_close,
+ .sb_umount_busy = stacker_umount_busy,
+ .sb_post_remount = stacker_post_remount,
+ .sb_post_mountroot = stacker_post_mountroot,
+ .sb_post_addmount = stacker_post_addmount,
+ .sb_pivotroot = stacker_pivotroot,
+ .sb_post_pivotroot = stacker_post_pivotroot,
+
+ .inode_alloc_security = stacker_inode_alloc_security,
+ .inode_free_security = stacker_inode_free_security,
+ .inode_create = stacker_inode_create,
+ .inode_post_create = stacker_inode_post_create,
+ .inode_link = stacker_inode_link,
+ .inode_post_link = stacker_inode_post_link,
+ .inode_unlink = stacker_inode_unlink,
+ .inode_symlink = stacker_inode_symlink,
+ .inode_post_symlink = stacker_inode_post_symlink,
+ .inode_mkdir = stacker_inode_mkdir,
+ .inode_post_mkdir = stacker_inode_post_mkdir,
+ .inode_rmdir = stacker_inode_rmdir,
+ .inode_mknod = stacker_inode_mknod,
+ .inode_post_mknod = stacker_inode_post_mknod,
+ .inode_rename = stacker_inode_rename,
+ .inode_post_rename = stacker_inode_post_rename,
+ .inode_readlink = stacker_inode_readlink,
+ .inode_follow_link = stacker_inode_follow_link,
+ .inode_permission = stacker_inode_permission,
+
+ .inode_setattr = stacker_inode_setattr,
+ .inode_getattr = stacker_inode_getattr,
+ .inode_delete = stacker_inode_delete,
+ .inode_setxattr = stacker_inode_setxattr,
+ .inode_post_setxattr = stacker_inode_post_setxattr,
+ .inode_getxattr = stacker_inode_getxattr,
+ .inode_listxattr = stacker_inode_listxattr,
+ .inode_removexattr = stacker_inode_removexattr,
+ .inode_getsecurity = stacker_inode_getsecurity,
+ .inode_setsecurity = stacker_inode_setsecurity,
+ .inode_listsecurity = stacker_inode_listsecurity,
+
+ .file_permission = stacker_file_permission,
+ .file_alloc_security = stacker_file_alloc_security,
+ .file_free_security = stacker_file_free_security,
+ .file_ioctl = stacker_file_ioctl,
+ .file_mmap = stacker_file_mmap,
+ .file_mprotect = stacker_file_mprotect,
+ .file_lock = stacker_file_lock,
+ .file_fcntl = stacker_file_fcntl,
+ .file_set_fowner = stacker_file_set_fowner,
+ .file_send_sigiotask = stacker_file_send_sigiotask,
+ .file_receive = stacker_file_receive,
+
+ .task_create = stacker_task_create,
+ .task_alloc_security = stacker_task_alloc_security,
+ .task_free_security = stacker_task_free_security,
+ .task_setuid = stacker_task_setuid,
+ .task_post_setuid = stacker_task_post_setuid,
+ .task_setgid = stacker_task_setgid,
+ .task_setpgid = stacker_task_setpgid,
+ .task_getpgid = stacker_task_getpgid,
+ .task_getsid = stacker_task_getsid,
+ .task_setgroups = stacker_task_setgroups,
+ .task_setnice = stacker_task_setnice,
+ .task_setrlimit = stacker_task_setrlimit,
+ .task_setscheduler = stacker_task_setscheduler,
+ .task_getscheduler = stacker_task_getscheduler,
+ .task_kill = stacker_task_kill,
+ .task_wait = stacker_task_wait,
+ .task_prctl = stacker_task_prctl,
+ .task_reparent_to_init = stacker_task_reparent_to_init,
+ .task_to_inode = stacker_task_to_inode,
+
+ .ipc_permission = stacker_ipc_permission,
+
+ .msg_msg_alloc_security = stacker_msg_msg_alloc_security,
+ .msg_msg_free_security = stacker_msg_msg_free_security,
+ .msg_queue_alloc_security = stacker_msg_queue_alloc_security,
+ .msg_queue_free_security = stacker_msg_queue_free_security,
+ .msg_queue_associate = stacker_msg_queue_associate,
+ .msg_queue_msgctl = stacker_msg_queue_msgctl,
+ .msg_queue_msgsnd = stacker_msg_queue_msgsnd,
+ .msg_queue_msgrcv = stacker_msg_queue_msgrcv,
+ .shm_alloc_security = stacker_shm_alloc_security,
+ .shm_free_security = stacker_shm_free_security,
+ .shm_associate = stacker_shm_associate,
+ .shm_shmctl = stacker_shm_shmctl,
+ .shm_shmat = stacker_shm_shmat,
+
+ .sem_alloc_security = stacker_sem_alloc_security,
+ .sem_free_security = stacker_sem_free_security,
+ .sem_associate = stacker_sem_associate,
+ .sem_semctl = stacker_sem_semctl,
+ .sem_semop = stacker_sem_semop,
+
+ .netlink_send = stacker_netlink_send,
+ .netlink_recv = stacker_netlink_recv,
+
+ .register_security = stacker_register,
+ .unregister_security = stacker_unregister,
+
+ .d_instantiate = stacker_d_instantiate,
+ .getprocattr = stacker_getprocattr,
+ .setprocattr = stacker_setprocattr,
+
+#ifdef CONFIG_SECURITY_NETWORK
+ .unix_stream_connect = stacker_unix_stream_connect,
+ .unix_may_send = stacker_unix_may_send,
+ .socket_create = stacker_socket_create,
+ .socket_post_create = stacker_socket_post_create,
+ .socket_bind = stacker_socket_bind,
+ .socket_connect = stacker_socket_connect,
+ .socket_listen = stacker_socket_listen,
+ .socket_accept = stacker_socket_accept,
+ .socket_post_accept = stacker_socket_post_accept,
+ .socket_sendmsg = stacker_socket_sendmsg,
+ .socket_recvmsg = stacker_socket_recvmsg,
+ .socket_getsockname = stacker_socket_getsockname,
+ .socket_getpeername = stacker_socket_getpeername,
+ .socket_getsockopt = stacker_socket_getsockopt,
+ .socket_setsockopt = stacker_socket_setsockopt,
+ .socket_shutdown = stacker_socket_shutdown,
+ .socket_sock_rcv_skb = stacker_socket_sock_rcv_skb,
+ .socket_getpeersec = stacker_socket_getpeersec,
+ .sk_alloc_security = stacker_sk_alloc_security,
+ .sk_free_security = stacker_sk_free_security,
+#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)
+{
+ 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;
+}
+
+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)
+{
+ if (count>0)
+ forbid_stacker_register = 1;
+
+ return count;
+}
+
+static struct stacker_attribute stacker_attr_lockdown = {
+ .attr = {.name = "lockdown", .mode = S_IFREG | S_IRUGO | S_IWUSR},
+ .show = lockdown_read,
+ .store = lockdown_write
+};
+
+/* 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);
+ }
+ rcu_read_unlock();
+
+ return len;
+}
+
+static struct stacker_attribute stacker_attr_listmodules = {
+ .attr = {.name = "list_modules", .mode = S_IFREG | S_IRUGO | S_IWUSR},
+ .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;
+
+ 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;
+ list_del_rcu(&m->lsm_list);
+
+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)
+{
+ if (count>0)
+ unregister_sysfs_files();
+ return count;
+}
+
+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;
+
+ if (!sysfsfiles_registered)
+ return;
+
+ 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);
+ sysfs_remove_file(kobj, &stacker_attr_unload.attr);
+
+ sysfsfiles_registered = 0;
+}
+
+static int register_sysfs_files(void)
+{
+ int result;
+
+ result = subsystem_register(&stacker_subsys);
+ if (result) {
+ printk(KERN_WARNING
+ "Error (%d) registering stacker sysfs subsystem\n",
+ result);
+ return result;
+ }
+
+ 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_unload.attr);
+ sysfsfiles_registered = 1;
+ stacker_dbg("sysfs files registered\n");
+ return 0;
+}
+
+module_init(register_sysfs_files);
+
+static int __init stacker_init (void)
+{
+ forbid_stacker_register = 0;
+ INIT_LIST_HEAD(&stacked_modules);
+ INIT_LIST_HEAD(&all_modules);
+ sysfsfiles_registered = 0;
+ spin_lock_init(&stacker_lock);
+
+ if (register_security (&stacker_ops)) {
+ /*
+ * stacking stacker is just a stupid idea, so don't ask
+ * the current module to load us.
+ */
+ printk (KERN_WARNING "Failure registering stacker module "
+ "as primary security module.\n");
+ return -EINVAL;
+ }
+
+ printk(KERN_NOTICE "LSM stacker registered as the primary "
+ "security module\n");
+ return 0;
+}
+
+static void __exit stacker_exit (void)
+{
+ /*
+ * Since we have no return value, we can't just say no.
+ * Should probably force all child modules to exit somehow...
+ */
+
+ unregister_sysfs_files();
+ if (unregister_security (&stacker_ops))
+ printk(KERN_WARNING "Error unregistering LSM stacker.\n");
+ else
+ printk(KERN_WARNING "LSM stacker removed.\n");
+}
+
+security_initcall (stacker_init);
+module_exit (stacker_exit);
+
+MODULE_DESCRIPTION("LSM stacker - supports multiple simultaneous LSM modules");
+MODULE_AUTHOR("David A. Wheeler, Serge Hallyn");
+MODULE_LICENSE("GPL");
^ permalink raw reply [flat|nested] 12+ messages in thread* [patch 6/11] lsm stacking: introduce stackable capabilities lsm
2005-06-08 23:55 patch 0/11] lsm stacking: intro serue
` (4 preceding siblings ...)
2005-06-09 0:00 ` [patch 5/11] lsm stacking: actual stacker module serue
@ 2005-06-09 0:00 ` serue
2005-06-09 0:01 ` [patch 7/11] lsm stacking: selinux: update ->security structs serue
` (4 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: serue @ 2005-06-09 0:00 UTC (permalink / raw)
To: lkml; +Cc: Chris Wright, Stephen Smalley, James Morris
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.
Signed-off-by: Serge Hallyn <serue@us.ibm.com>
---
security/Kconfig | 21 +++++++++
security/Makefile | 1
security/cap_stack.c | 101 +++++++++++++++++++++++++++++++++++++++++++++++
security/selinux/Kconfig | 2
4 files changed, 124 insertions(+), 1 deletion(-)
Index: linux-2.6.12-rc6/security/Kconfig
===================================================================
--- linux-2.6.12-rc6.orig/security/Kconfig
+++ linux-2.6.12-rc6/security/Kconfig
@@ -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
Index: linux-2.6.12-rc6/security/Makefile
===================================================================
--- linux-2.6.12-rc6.orig/security/Makefile
+++ linux-2.6.12-rc6/security/Makefile
@@ -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
Index: linux-2.6.12-rc6/security/cap_stack.c
===================================================================
--- /dev/null
+++ linux-2.6.12-rc6/security/cap_stack.c
@@ -0,0 +1,101 @@
+/*
+ * Capabilities Linux Security Module
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/security.h>
+#include <linux/file.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/pagemap.h>
+#include <linux/swap.h>
+#include <linux/smp_lock.h>
+#include <linux/skbuff.h>
+#include <linux/netlink.h>
+#include <linux/ptrace.h>
+#include <linux/moduleparam.h>
+
+static struct security_operations capability_ops = {
+ .ptrace = cap_ptrace,
+ .capget = cap_capget,
+ .capset_check = cap_capset_check,
+ .capset_set = cap_capset_set,
+ .capable = cap_capable,
+ .settime = cap_settime,
+ .netlink_send = cap_netlink_send,
+ .netlink_recv = cap_netlink_recv,
+
+ .bprm_apply_creds = cap_bprm_apply_creds,
+ .bprm_set_security = cap_bprm_set_security,
+ .bprm_secureexec = cap_bprm_secureexec,
+
+ .task_post_setuid = cap_task_post_setuid,
+ .task_reparent_to_init = cap_task_reparent_to_init,
+
+ .syslog = cap_syslog,
+
+ .vm_enough_memory = cap_vm_enough_memory,
+};
+
+#define MY_NAME __stringify(KBUILD_MODNAME)
+
+/* flag to keep track of how we were registered */
+static int secondary;
+
+static int capability_disable;
+module_param_named(disable, capability_disable, int, 0);
+MODULE_PARM_DESC(disable, "To disable capabilities module set disable = 1");
+
+static int __init capability_init (void)
+{
+ if (capability_disable) {
+ printk(KERN_INFO "Capabilities disabled at initialization\n");
+ return 0;
+ }
+ /* register ourselves with the security framework */
+ if (register_security (&capability_ops)) {
+ /* try registering with primary module */
+ if (mod_reg_security (MY_NAME, &capability_ops)) {
+ printk (KERN_INFO "Failure registering capabilities "
+ "with primary security module.\n");
+ return -EINVAL;
+ }
+ secondary = 1;
+ }
+ printk (KERN_INFO "Capability LSM initialized%s\n",
+ secondary ? " as secondary" : "");
+ return 0;
+}
+
+static void __exit capability_exit (void)
+{
+ if (capability_disable)
+ return;
+ /* remove ourselves from the security framework */
+ if (secondary) {
+ if (mod_unreg_security (MY_NAME, &capability_ops))
+ printk (KERN_INFO "Failure unregistering capabilities "
+ "with primary module.\n");
+ return;
+ }
+
+ if (unregister_security (&capability_ops)) {
+ printk (KERN_INFO
+ "Failure unregistering capabilities with the kernel\n");
+ }
+}
+
+security_initcall (capability_init);
+module_exit (capability_exit);
+
+MODULE_DESCRIPTION("Standard Linux Capabilities Security Module");
+MODULE_LICENSE("GPL");
Index: linux-2.6.12-rc6/security/selinux/Kconfig
===================================================================
--- linux-2.6.12-rc6.orig/security/selinux/Kconfig
+++ linux-2.6.12-rc6/security/selinux/Kconfig
@@ -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.
^ permalink raw reply [flat|nested] 12+ messages in thread* [patch 7/11] lsm stacking: selinux: update ->security structs
2005-06-08 23:55 patch 0/11] lsm stacking: intro serue
` (5 preceding siblings ...)
2005-06-09 0:00 ` [patch 6/11] lsm stacking: introduce stackable capabilities lsm serue
@ 2005-06-09 0:01 ` serue
2005-06-09 0:02 ` [patch 8/11] lsm stacking: selinux: use security_*_value API serue
` (3 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: serue @ 2005-06-09 0:01 UTC (permalink / raw)
To: lkml; +Cc: Chris Wright, Stephen Smalley, James Morris
Add the struct security_list lsm_list; to each structure which SELinux will be
appending to a kernel object.
Signed-off-by: Serge Hallyn <serue@us.ibm.com>
---
security/selinux/include/objsec.h | 19 +++++++++++--------
1 files changed, 11 insertions(+), 8 deletions(-)
Index: linux-2.6.12-rc2-stack/security/selinux/include/objsec.h
===================================================================
--- linux-2.6.12-rc2-stack.orig/security/selinux/include/objsec.h 2005-04-13 14:17:33.000000000 -0500
+++ linux-2.6.12-rc2-stack/security/selinux/include/objsec.h 2005-04-13 14:38:41.000000000 -0500
@@ -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 */
};
^ permalink raw reply [flat|nested] 12+ messages in thread* [patch 8/11] lsm stacking: selinux: use security_*_value API
2005-06-08 23:55 patch 0/11] lsm stacking: intro serue
` (6 preceding siblings ...)
2005-06-09 0:01 ` [patch 7/11] lsm stacking: selinux: update ->security structs serue
@ 2005-06-09 0:02 ` serue
2005-06-09 0:02 ` [patch 9/11] lsm stacking: selinux: remove secondary support serue
` (2 subsequent siblings)
10 siblings, 0 replies; 12+ messages in thread
From: serue @ 2005-06-09 0:02 UTC (permalink / raw)
To: lkml; +Cc: Chris Wright, Stephen Smalley, James Morris
Convert SELinux to use the security_*_value_type API for storing and using
information appended to kernel objects, instead of directly using the void*.
Signed-off-by: Serge Hallyn <serue@us.ibm.com>
---
security/selinux/hooks.c | 445 ++++++++++++++++++++++++++++---------------
security/selinux/selinuxfs.c | 10
2 files changed, 299 insertions(+), 156 deletions(-)
Index: linux-2.6.12-rc6/security/selinux/hooks.c
===================================================================
--- linux-2.6.12-rc6.orig/security/selinux/hooks.c
+++ linux-2.6.12-rc6/security/selinux/hooks.c
@@ -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 ta
return -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 i
memset(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(str
INIT_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(str
list_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 sock
return -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 supe
const 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 p
static 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(stru
int 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(stru
if (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 ta
struct 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_st
struct 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 inod
int 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 inod
if (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 ta
struct 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 *dir
unsigned 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 *dir
static 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 *tab
if (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(s
return -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(str
if (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,10 @@ static int selinux_bprm_secureexec (stru
static void selinux_bprm_free_security(struct linux_binprm *bprm)
{
- struct bprm_security_struct *bsec = 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);
}
@@ -1757,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;
@@ -1802,8 +1863,10 @@ static void selinux_bprm_post_apply_cred
struct 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 +2225,9 @@ static int selinux_inode_getattr(struct
static 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 +2247,8 @@ static int selinux_inode_setxattr(struct
return 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 +2258,10 @@ static int selinux_inode_setxattr(struct
AVC_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 +2292,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 +2318,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 +2358,7 @@ static int selinux_inode_removexattr (st
static 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 +2368,9 @@ static int selinux_inode_getsecurity(str
if (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 +2391,16 @@ static int selinux_inode_getsecurity(str
static 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;
@@ -2546,8 +2626,10 @@ static int selinux_file_set_fowner(struc
struct 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;
@@ -2564,8 +2646,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 */
@@ -2599,12 +2683,14 @@ static int selinux_task_alloc_security(s
struct 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;
@@ -2757,7 +2843,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;
@@ -2766,8 +2853,13 @@ static void selinux_task_reparent_to_ini
static 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;
@@ -2935,8 +3027,10 @@ static int socket_has_perm(struct task_s
struct 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;
@@ -2958,7 +3052,8 @@ static int selinux_socket_create(int fam
if (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);
@@ -2973,9 +3068,11 @@ static void selinux_socket_post_create(s
struct 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;
@@ -3013,8 +3110,10 @@ static int selinux_socket_bind(struct so
struct 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;
@@ -3092,7 +3191,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;
@@ -3146,9 +3246,11 @@ static int selinux_socket_accept(struct
if (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;
@@ -3208,8 +3310,10 @@ static int selinux_socket_unix_stream_co
if (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;
@@ -3221,11 +3325,13 @@ static int selinux_socket_unix_stream_co
return 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;
@@ -3239,8 +3345,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;
@@ -3280,7 +3388,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;
}
@@ -3363,13 +3472,15 @@ static int selinux_socket_getpeersec(str
struct 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)
@@ -3408,7 +3519,10 @@ static int selinux_nlmsg_perm(struct soc
u32 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;
@@ -3474,7 +3588,8 @@ static unsigned int selinux_ip_postroute
if (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:
@@ -3584,7 +3699,8 @@ static int selinux_netlink_send(struct s
if (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,
@@ -3608,15 +3724,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) {
@@ -3624,18 +3742,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);
}
@@ -3648,21 +3766,20 @@ static int msg_msg_alloc_security(struct
return -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);
}
@@ -3673,8 +3790,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;
@@ -3704,8 +3823,10 @@ static int selinux_msg_queue_alloc_secur
if (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;
@@ -3730,8 +3851,10 @@ static int selinux_msg_queue_associate(s
struct 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;
@@ -3776,9 +3899,12 @@ static int selinux_msg_queue_msgsnd(stru
struct 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
@@ -3824,9 +3950,12 @@ static int selinux_msg_queue_msgrcv(stru
struct 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;
@@ -3851,8 +3980,10 @@ static int selinux_shm_alloc_security(st
if (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;
@@ -3877,8 +4008,10 @@ static int selinux_shm_associate(struct
struct 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;
@@ -3950,8 +4083,10 @@ static int selinux_sem_alloc_security(st
if (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;
@@ -3976,8 +4111,10 @@ static int selinux_sem_associate(struct
struct 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;
@@ -4111,7 +4248,8 @@ static int selinux_getprocattr(struct ta
if (!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;
@@ -4186,7 +4324,8 @@ static int selinux_setprocattr(struct ta
operation. 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"))
Index: linux-2.6.12-rc6/security/selinux/selinuxfs.c
===================================================================
--- linux-2.6.12-rc6.orig/security/selinux/selinuxfs.c
+++ linux-2.6.12-rc6/security/selinux/selinuxfs.c
@@ -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;
@@ -983,7 +985,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;
@@ -1270,7 +1273,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;
^ permalink raw reply [flat|nested] 12+ messages in thread* [patch 9/11] lsm stacking: selinux: remove secondary support
2005-06-08 23:55 patch 0/11] lsm stacking: intro serue
` (7 preceding siblings ...)
2005-06-09 0:02 ` [patch 8/11] lsm stacking: selinux: use security_*_value API serue
@ 2005-06-09 0:02 ` serue
2005-06-09 0:03 ` [patch 10/11] lsm stacking: hook completeness verification serue
2005-06-09 0:04 ` [patch 11/11] lsm stacking: support sharing /proc/$$/attr/* serue
10 siblings, 0 replies; 12+ messages in thread
From: serue @ 2005-06-09 0:02 UTC (permalink / raw)
To: lkml; +Cc: Chris Wright, Stephen Smalley, James Morris
Remove the SELinux support for secondary modules. This is no longer necessary
as SELinux can now be simply stacked with the cap-stack module.
Signed-off-by: Serge Hallyn <serue@us.ibm.com>
---
security/selinux/hooks.c | 266 ++++++-----------------------------------------
1 files changed, 34 insertions(+), 232 deletions(-)
Index: linux-2.6.12-rc6/security/selinux/hooks.c
===================================================================
--- linux-2.6.12-rc6.orig/security/selinux/hooks.c
+++ linux-2.6.12-rc6/security/selinux/hooks.c
@@ -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_st
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,
@@ -1417,41 +1407,17 @@ static int selinux_ptrace(struct task_st
static 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 *tab
u32 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 dentr
static 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(str
struct 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(str
return 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(str
u32 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,
@@ -2041,12 +1957,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);
@@ -2057,12 +1967,6 @@ static int selinux_mount(char * dev_name
static 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);
}
@@ -2091,11 +1995,6 @@ static void selinux_inode_post_create(st
static 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);
}
@@ -2106,11 +2005,6 @@ static void selinux_inode_post_link(stru
static 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);
}
@@ -2141,12 +2035,6 @@ static int selinux_inode_rmdir(struct in
static 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));
}
@@ -2174,23 +2062,12 @@ static int selinux_inode_readlink(struct
static 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;
@@ -2202,12 +2079,6 @@ static int selinux_inode_permission(stru
static 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;
@@ -2529,12 +2400,6 @@ static int file_map_prot_check(struct fi
static 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;
@@ -2546,12 +2411,6 @@ static int selinux_file_mprotect(struct
unsigned long reqprot,
unsigned long prot)
{
- int rc;
-
- rc = secondary_ops->file_mprotect(vma, reqprot, prot);
- if (rc)
- return rc;
-
if (selinux_checkreqprot)
prot = reqprot;
@@ -2669,12 +2528,6 @@ static int selinux_file_receive(struct f
static 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);
}
@@ -2723,11 +2576,6 @@ static int selinux_task_setuid(uid_t id0
return 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. */
@@ -2757,24 +2605,12 @@ static int selinux_task_setgroups(struct
static 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
@@ -2798,11 +2634,6 @@ static int selinux_task_getscheduler(str
static 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)))
@@ -2841,8 +2672,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;
@@ -3306,10 +3135,6 @@ static int selinux_socket_unix_stream_co
struct 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,
@@ -3693,11 +3518,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);
@@ -3713,13 +3534,6 @@ static int selinux_netlink_send(struct s
return 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)
@@ -4057,11 +3871,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;
@@ -4197,32 +4006,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)
@@ -4385,23 +4174,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,
@@ -4458,7 +4243,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,
@@ -4530,10 +4314,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;
@@ -4544,22 +4330,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;
}
@@ -4669,6 +4463,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. */
@@ -4684,8 +4479,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();
^ permalink raw reply [flat|nested] 12+ messages in thread* [patch 10/11] lsm stacking: hook completeness verification
2005-06-08 23:55 patch 0/11] lsm stacking: intro serue
` (8 preceding siblings ...)
2005-06-09 0:02 ` [patch 9/11] lsm stacking: selinux: remove secondary support serue
@ 2005-06-09 0:03 ` serue
2005-06-09 0:04 ` [patch 11/11] lsm stacking: support sharing /proc/$$/attr/* serue
10 siblings, 0 replies; 12+ messages in thread
From: serue @ 2005-06-09 0:03 UTC (permalink / raw)
To: lkml; +Cc: Chris Wright, Stephen Smalley, James Morris
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.
Signed-off-by: Serge Hallyn <serue@us.ibm.com>
---
include/linux/security.h | 4 ++++
scripts/lsm_verify_hooks.sh | 44 ++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 48 insertions(+)
Index: linux-2.6.12-rc2/include/linux/security.h
===================================================================
--- linux-2.6.12-rc2.orig/include/linux/security.h 2005-05-23 15:01:00.000000000 -0500
+++ linux-2.6.12-rc2/include/linux/security.h 2005-05-23 15:01:43.000000000 -0500
@@ -121,6 +121,10 @@
/**
* 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:
Index: linux-2.6.12-rc2/scripts/lsm_verify_hooks.sh
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.12-rc2/scripts/lsm_verify_hooks.sh 2005-05-23 15:01:43.000000000 -0500
@@ -0,0 +1,44 @@
+#!/bin/sh
+
+# Author: Serge E. Hallyn <serue@us.ibm.com>
+
+# Checks that both the dummy and stacker modules define all the
+# security hooks.
+
+# This probably should be done in perl
+
+# Copyright (C) 2002,2003,2004,2005 Serge E. Hallyn <serue@us.ibm.com>
+# Copyright (C) 2002 David A. Wheeler <dwheeler@dwheeler.com>.
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+
+# Grab the relevant pieces of text
+sed -n '/^void security_fixup_ops /,/}/p' dummy.c > dummy.out
+sed -n '/^static struct security_operations/,/}/p' stacker.c > stack.out
+../scripts/Lindent -o tmpsec.h ../include/linux/security.h
+sed -n '/^struct security_operations {/,/}/p' tmpsec.h > sech.out
+rm tmpsec.h
+
+# Get a list of functions in security.h
+cat sech.out | sed -n '/\t[a-z]/p' | sed -e 's/^\t[a-z]* (\*\([^)]*\).*$/\1/' > sech.out
+
+# check dummy.c
+for line in `cat sech.out`; do
+ grep $line dummy.out > /dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ echo "WARNING: $line missing from dummy module!"
+ fi
+done
+
+# check stacker.c
+for line in `cat sech.out`; do
+ grep $line stack.out > /dev/null 2>&1
+ if [ $? -ne 0 ]; then
+ echo "WARNING: $line missing from stacker module!"
+ fi
+done
+
+rm sech.out stack.out dummy.out
+echo "LSM hook verification done."
^ permalink raw reply [flat|nested] 12+ messages in thread* [patch 11/11] lsm stacking: support sharing /proc/$$/attr/*
2005-06-08 23:55 patch 0/11] lsm stacking: intro serue
` (9 preceding siblings ...)
2005-06-09 0:03 ` [patch 10/11] lsm stacking: hook completeness verification serue
@ 2005-06-09 0:04 ` serue
10 siblings, 0 replies; 12+ messages in thread
From: serue @ 2005-06-09 0:04 UTC (permalink / raw)
To: lkml; +Cc: Chris Wright, Stephen Smalley, James Morris
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.
Signed-off-by: Serge Hallyn <serue@us.ibm.com>
---
security/stacker.c | 125 ++++++++++++++++++++++++++++++++++++++++++-----------
1 files changed, 100 insertions(+), 25 deletions(-)
Index: linux-2.6.12-rc2-stack/security/stacker.c
===================================================================
--- linux-2.6.12-rc2-stack.orig/security/stacker.c 2005-05-25 16:01:52.000000000 -0500
+++ linux-2.6.12-rc2-stack/security/stacker.c 2005-05-31 15:52:49.000000000 -0500
@@ -956,24 +956,116 @@ static void stacker_d_instantiate (struc
CALL_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);
}
/*
@@ -1031,23 +1123,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.
^ permalink raw reply [flat|nested] 12+ messages in thread