| From: |
| Serge Hallyn <serue@us.ibm.com> |
| To: |
| Chris Wright <chrisw@osdl.org>,
Stephen Smalley <sds@epoch.ncsc.mil>,
James Morris <jmorris@redhat.com> |
| Subject: |
| [RFC] [Stacking v4 1/3] New lsm chaining patch |
| Date: |
| Fri, 03 Dec 2004 12:03:59 -0600 |
| Cc: |
| LSM Mailing List <linux-security-module@wirex.com> |
Attached is a new version of lsm-chain.patch. It moves
CONFIG_SECURITY_STACKER out of security.h, changing the
security_get_value and friends in the case of no CONFIG_SECURITY_STACKER
from #defines in security.h to brief static inlines in security.c.
thanks,
-serge
--
=======================================================
Serge Hallyn
Security Software Engineer, IBM Linux Technology Center
serue@us.ibm.com
Index: linux-2.6.9/fs/exec.c
===================================================================
--- linux-2.6.9.orig/fs/exec.c 2004-11-25 09:55:31.655895608 -0600
+++ linux-2.6.9/fs/exec.c 2004-11-25 09:57:12.615547408 -0600
@@ -1116,6 +1116,7 @@
bprm->file = file;
bprm->filename = filename;
bprm->interp = filename;
+ INIT_HLIST_HEAD(&bprm->security);
bprm->mm = mm_alloc();
if (!bprm->mm)
goto out_file;
@@ -1171,8 +1172,7 @@
__free_page(page);
}
- if (bprm->security)
- security_bprm_free(bprm);
+ security_bprm_free(bprm);
out_mm:
if (bprm->mm)
Index: linux-2.6.9/fs/inode.c
===================================================================
--- linux-2.6.9.orig/fs/inode.c 2004-11-25 09:53:49.150478800 -0600
+++ linux-2.6.9/fs/inode.c 2004-11-25 09:57:12.616547256 -0600
@@ -134,7 +134,7 @@
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.9/include/linux/binfmts.h
===================================================================
--- linux-2.6.9.orig/include/linux/binfmts.h 2004-10-18 16:54:30.000000000
-0500
+++ linux-2.6.9/include/linux/binfmts.h 2004-11-25 09:57:12.624546040 -0600
@@ -29,7 +29,7 @@
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.9/include/linux/fs.h
===================================================================
--- linux-2.6.9.orig/include/linux/fs.h 2004-11-25 09:53:52.144023712 -0600
+++ linux-2.6.9/include/linux/fs.h 2004-11-25 09:57:12.625545888 -0600
@@ -479,7 +479,7 @@
unsigned int i_flags;
atomic_t i_writecount;
- void *i_security;
+ struct hlist_head i_security;
union {
void *generic_ip;
} u;
@@ -553,7 +553,7 @@
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_ra_state f_ra;
unsigned long f_version;
- void *f_security;
+ struct hlist_head f_security;
/* needed for tty driver, and maybe others */
void *private_data;
@@ -773,7 +773,7 @@
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_dirty; /* dirty inodes */
Index: linux-2.6.9/include/linux/ipc.h
===================================================================
--- linux-2.6.9.orig/include/linux/ipc.h 2004-10-18 16:53:05.000000000 -0500
+++ linux-2.6.9/include/linux/ipc.h 2004-11-25 09:57:12.632544824 -0600
@@ -65,7 +65,7 @@
gid_t cgid;
mode_t mode;
unsigned long seq;
- void *security;
+ struct hlist_head security;
};
#endif /* __KERNEL__ */
Index: linux-2.6.9/include/linux/msg.h
===================================================================
--- linux-2.6.9.orig/include/linux/msg.h 2004-10-18 16:54:31.000000000 -0500
+++ linux-2.6.9/include/linux/msg.h 2004-11-25 09:57:12.633544672 -0600
@@ -70,7 +70,7 @@
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.9/include/linux/sched.h
===================================================================
--- linux-2.6.9.orig/include/linux/sched.h 2004-11-25 09:53:52.644947560 -0600
+++ linux-2.6.9/include/linux/sched.h 2004-11-25 09:57:12.633544672 -0600
@@ -627,7 +627,7 @@
void *notifier_data;
sigset_t *notifier_mask;
- void *security;
+ struct hlist_head security;
struct audit_context *audit_context;
/* Thread group tracking */
Index: linux-2.6.9/include/linux/security.h
===================================================================
--- linux-2.6.9.orig/include/linux/security.h 2004-11-25 09:53:52.660945128
-0600
+++ linux-2.6.9/include/linux/security.h 2004-11-25 14:18:04.943031944 -0600
@@ -34,6 +34,55 @@
struct ctl_table;
/*
+ * structure to be embedded at top of each LSM's security
+ * objects.
+ *
+ * XXX If performance is still bad, then I guess start
+ * ifdefing this out again...
+ */
+struct security_list {
+ struct hlist_node list;
+ int security_id;
+};
+
+/*
+ * How to use:
+ *
+ * In any object which you wish to chain onto a kernel security object
+ * such as inode->i_security, add the following:
+ * struct security_list lsm_list;
+ *
+ * The function prototypes are as follows:
+ */
+
+extern rwlock_t security_list_rwlock;
+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 void security_set_value_nocheck(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);
+
+#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, type) ( { \
+ struct security_list *v; \
+ v = security_set_value(head, id, &value->lsm_list); \
+ v ? hlist_entry(v, type, lsm_list) : NULL; } )
+
+#define security_set_value_nocheck_type(head, id, value) \
+ security_set_value_nocheck(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.9/include/net/sock.h
===================================================================
--- linux-2.6.9.orig/include/net/sock.h 2004-11-25 09:55:31.848866272 -0600
+++ linux-2.6.9/include/net/sock.h 2004-11-25 09:57:12.636544216 -0600
@@ -254,7 +254,7 @@
__u32 sk_sndmsg_off;
struct sk_buff *sk_send_head;
int sk_write_pending;
- void *sk_security;
+ struct hlist_head sk_security;
__u8 sk_queue_shrunk;
/* three bytes hole, try to pack */
void (*sk_state_change)(struct sock *sk);
Index: linux-2.6.9/ipc/msg.c
===================================================================
--- linux-2.6.9.orig/ipc/msg.c 2004-11-25 09:53:53.040887368 -0600
+++ linux-2.6.9/ipc/msg.c 2004-11-25 09:57:12.637544064 -0600
@@ -98,7 +98,7 @@
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.9/ipc/msgutil.c
===================================================================
--- linux-2.6.9.orig/ipc/msgutil.c 2004-10-18 16:54:07.000000000 -0500
+++ linux-2.6.9/ipc/msgutil.c 2004-11-25 09:57:12.644543000 -0600
@@ -41,7 +41,7 @@
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.9/ipc/sem.c
===================================================================
--- linux-2.6.9.orig/ipc/sem.c 2004-11-25 09:53:53.041887216 -0600
+++ linux-2.6.9/ipc/sem.c 2004-11-25 09:57:12.645542848 -0600
@@ -177,7 +177,7 @@
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.9/ipc/shm.c
===================================================================
--- linux-2.6.9.orig/ipc/shm.c 2004-11-25 09:53:53.042887064 -0600
+++ linux-2.6.9/ipc/shm.c 2004-11-25 09:57:12.645542848 -0600
@@ -196,7 +196,7 @@
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.9/kernel/fork.c
===================================================================
--- linux-2.6.9.orig/kernel/fork.c 2004-11-25 09:55:31.858864752 -0600
+++ linux-2.6.9/kernel/fork.c 2004-11-25 09:57:12.646542696 -0600
@@ -872,7 +872,7 @@
p->utime = p->stime = 0;
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;
Index: linux-2.6.9/security/dummy.c
===================================================================
--- linux-2.6.9.orig/security/dummy.c 2004-11-25 09:53:53.534812280 -0600
+++ linux-2.6.9/security/dummy.c 2004-11-25 09:57:12.647542544 -0600
@@ -1036,3 +1036,5 @@
#endif /* CONFIG_SECURITY_NETWORK */
}
+EXPORT_SYMBOL_GPL(security_fixup_ops);
+
Index: linux-2.6.9/security/security.c
===================================================================
--- linux-2.6.9.orig/security/security.c 2004-11-25 09:53:53.545810608 -0600
+++ linux-2.6.9/security/security.c 2004-11-25 14:34:54.160607552 -0600
@@ -20,6 +20,128 @@
#define SECURITY_FRAMEWORK_VERSION "1.0.0"
+rwlock_t security_list_rwlock = RW_LOCK_UNLOCKED;
+
+#ifdef CONFIG_SECURITY_STACKER
+struct security_list *
+security_get_value(struct hlist_head *head, int security_id)
+{
+ unsigned long flags;
+ struct security_list *e, *ret = NULL;
+ struct hlist_node *tmp;
+
+ read_lock_irqsave(&security_list_rwlock, flags);
+ hlist_for_each_entry(e, tmp, head, list) {
+ if (e->security_id == security_id) {
+ ret = e;
+ goto out;
+ }
+ }
+
+out:
+ read_unlock_irqrestore(&security_list_rwlock, flags);
+ return ret;
+}
+
+void
+security_set_value_nocheck(struct hlist_head *head, int security_id,
+ struct security_list *obj_node)
+{
+ unsigned long flags;
+
+ write_lock_irqsave(&security_list_rwlock, flags);
+
+ INIT_HLIST_NODE(&obj_node->list);
+ obj_node->security_id = security_id;
+ hlist_add_head(&obj_node->list, head);
+
+ write_unlock_irqrestore(&security_list_rwlock, flags);
+}
+
+struct security_list *
+security_set_value(struct hlist_head *head, int security_id,
+ struct security_list *obj_node)
+{
+ unsigned long flags;
+ struct security_list *e, *ret = NULL;
+ struct hlist_node *tmp;
+
+ write_lock_irqsave(&security_list_rwlock, flags);
+ hlist_for_each_entry(e, tmp, head, list) {
+ if (e->security_id == security_id) {
+ ret = e;
+ hlist_del(&e->list);
+ break;
+ }
+ }
+
+ INIT_HLIST_NODE(&obj_node->list);
+ obj_node->security_id = security_id;
+ hlist_add_head(&obj_node->list, head);
+
+ write_unlock_irqrestore(&security_list_rwlock, flags);
+ return ret;
+}
+
+struct security_list *
+security_del_value(struct hlist_head *head, int security_id)
+{
+ unsigned long flags;
+ struct security_list *e, *ret = NULL;
+ struct hlist_node *tmp;
+
+ write_lock_irqsave(&security_list_rwlock, flags);
+ hlist_for_each_entry(e, tmp, head, list) {
+ if (e->security_id == security_id) {
+ ret = e;
+ hlist_del(&e->list);
+ goto out;
+ }
+ }
+
+out:
+ write_unlock_irqrestore(&security_list_rwlock, flags);
+ return ret;
+}
+
+#else
+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;
+}
+
+struct security_list *
+security_set_value(struct hlist_head *head, int security_id,
+ struct security_list *obj_node)
+{
+ struct hlist_node *tmp = head->first;
+ head->first = &obj_node->list;
+ return tmp ? hlist_entry(tmp, struct security_list, list) : NULL;
+}
+
+void
+security_set_value_nocheck(struct hlist_head *head, int security_id,
+ struct security_list *obj_node)
+{
+ head->first = &obj_node->list;
+}
+
+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
+
+EXPORT_SYMBOL_GPL(security_get_value);
+EXPORT_SYMBOL_GPL(security_set_value);
+EXPORT_SYMBOL_GPL(security_set_value_nocheck);
+EXPORT_SYMBOL_GPL(security_del_value);
+
/* things that live in dummy.c */
extern struct security_operations dummy_security_ops;
extern void security_fixup_ops(struct security_operations *ops);