[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

Re: [PATCH] LSPP audit enablement: storing selinux ocontext and scontext



I'm addressing Amy's concerns and attaching an updated patch with the
editions discussed inline.


On Fri, 2005-09-02 at 23:19 -0600, Amy Griffis wrote: 
> Some comments inline.
> 
> > diff -uprN linux-2.6.13-rc6-mm2/ipc/msg.c linux-2.6.13-rc6-mm2-lspp_audit/ipc/msg.c
> > --- linux-2.6.13-rc6-mm2/ipc/msg.c	2005-08-29 11:32:16.000000000 -0500
> > +++ linux-2.6.13-rc6-mm2-lspp_audit/ipc/msg.c	2005-08-29 10:37:51.000000000 -0500
> > @@ -443,6 +443,13 @@ asmlinkage long sys_msgctl (int msqid, i
> >  	if (msq == NULL)
> >  		goto out_up;
> >  
> > +	ipcp = &msq->q_perm;
> 
> Please double check that ipcp isn't being set twice, as it appears.

I think you're right.  I rearranged these 4 lines to make it a little
clearer.

> > +
> > +	if (cmd == IPC_SET) {
> > +		if ((err = audit_ipc_security_context(ipcp)))
> 
> I think it's desirable to limit the proliferation of audit hooks where
> possible.  In this case, grabbing q_perm could be consolidated with
> /the current audit_ipc_perms hook, although this would mean processing
> under the spinlock more of the time.

I suppose audit_ipc_security_context() and audit_ipc_perms() could be
collapsed into a single function.  But then this ficticious audit_ipc()
would need to wrapped with the spin lock.  I don't think this tradeoff
would be desirable.  I would think that we want only functionality that
needs to be protected bound to a spin lock.

In any case, does the addition of this code really constitute egregious
proliferation of audit hooks?

// existing spinlock just above here...
        ipcp = &msq->q_perm;
        if (cmd == IPC_SET) {
                if ((err = audit_ipc_security_context(ipcp)))
                        goto out_unlock_up;
        }

> > diff -uprN linux-2.6.13-rc6-mm2/ipc/util.c linux-2.6.13-rc6-mm2-lspp_audit/ipc/util.c
> > --- linux-2.6.13-rc6-mm2/ipc/util.c	2005-08-29 11:32:16.000000000 -0500
> > +++ linux-2.6.13-rc6-mm2-lspp_audit/ipc/util.c	2005-08-29 10:39:17.000000000 -0500
> > @@ -466,6 +467,8 @@ int ipcperms (struct kern_ipc_perm *ipcp
> >  {	/* flag will most probably be 0 or S_...UGO from <linux/stat.h> */
> >  	int requested_mode, granted_mode;
> >  
> > +	audit_ipc_security_context(ipcp);
> 
> Why no error check?

Because audit_ipc_security_context() handles its errors internally by
calling audit_panic(), which can fail silently, printk a message, or
under the most strict configuration panic the kernel.  I think this
gives an administrator the flexibility needed to silently ignore such
context auditing failures, receive debug messages, or in super-strict
mode, panic the system.  

It seems there are disagreements with this methodology.  Please respond
with a working patch that handles this behavior better if you still
disagree.  

Some have suggested propagating errno's up to the calling syscalls.
This rippled into other unforeseen places in my efforts to accomplish
this and I never found a clean implementation.

> Does hooking ipcperms cover all the ipc operations where we need the
> security context?

I poked through all of ipc/*.c looking for EPERM and EACCES, which
identify security-relevant error points.  According to our current
interpretation of the LSPP spec, we only need to be concerned with
IPC_SET operations.  And in this case, I think we have the coverage that
we need. 

> > diff -uprN linux-2.6.13-rc6-mm2/kernel/auditsc.c linux-2.6.13-rc6-mm2-lspp_audit/kernel/auditsc.c
> > --- linux-2.6.13-rc6-mm2/kernel/auditsc.c	2005-08-29 11:32:16.000000000 -0500
> > +++ linux-2.6.13-rc6-mm2-lspp_audit/kernel/auditsc.c	2005-08-29 11:09:43.000000000 -0500
> > +struct audit_aux_data_security_context {
> > +	struct			audit_aux_data d;
> > +	char			*security_context;
> > +	size_t			security_context_len;
> > +};
> 
> I'd prefer not to add another aux struct just to hold ipc security
> context.  I don't see any reason why this couldn't be added to
> audit_aux_data_ipcctl below.

Well, audit_aux_data_security_context is a little more generic than
audit_aux_data_ipcctl (which is ipc-specific).  I tend to disagree with
this suggestion, as the security_context information should be across
objects besides just ipc.

> Also, the security_context_len field is unused.

That's true.  It's easily enough removed.  But as is, it's simply
mimmicing the definition of audit_aux_sockaddr.  I'm ambivalent about
this change.  I'm leaving as is, since it mirrors previous struct
definitions.  If the consensus is to eliminate it, I'm not opposed...

Following the standard set forth by the rest of this file, it seems that
the preferred manner in which to create an extension to an audit record
is to create a structure as above to hold the new data.  

> > @@ -868,6 +912,11 @@ static void audit_log_exit(struct audit_
> >  			struct audit_aux_data_path *axi = (void *)aux;
> >  			audit_log_d_path(ab, "path=", axi->dentry, axi->mnt);
> >  			break; }
> > +		case AUDIT_SECURITY_CONTEXT: {
> > +			struct audit_aux_data_security_context *axi = (void *)aux;
> > +			audit_log_format(ab, " ocontext=%s", axi->security_context);
> > +			kfree(axi->security_context);
> 
> Freeing the security context in audit_free_aux() would be more
> consistent with the current code.

Agreed.  Changed in code.  Please review.

> > @@ -1118,6 +1171,37 @@ void audit_putname(const char *name)
> >  #endif
> >  }
> >  
> > +void audit_inode_security_context(int idx, const struct inode *inode)
> > +{
> > +	struct audit_context *context = current->audit_context;
> > +	int len = 0;
> > +
> > +	if (!audit_macxattr)
> > +		return;
> > +
> > +	len = security_inode_getsecurity((struct inode *)inode, audit_macxattr, NULL, 0);
> > +	if (len < 0) {
> > +		if (len != -EOPNOTSUPP) 
> > +			audit_panic("security_inode_getsecurity error in audit_inode_security_context");
> 
> I don't think audit_panic is needed anywhere in this function, as the
> syscall operation hasn't occured yet.

Hmm.  Okay, well I'm open to ideas on how to go about fixing this.  Note
that audit_inode_security_context() is a void function, as is
audit_inode(), and it would be very difficult to propagate this error up
to the calling syscall, as has been suggested.

How then do we guarantee that we won't lose audit records in the case
where some part of audit_inode_security_context() fails?  There isn't a
return mechanism for propagating that information upward to the
path_lookup() function that needs to audit the inode.  

> > @@ -1292,3 +1378,58 @@ void audit_signal_info(int sig, struct t
> >  	}
> >  }
> >  
> > +int audit_ipc_security_context(struct kern_ipc_perm *ipcp)
> > +{
> > +	struct audit_aux_data_security_context *ax;
> > +	struct audit_context *context = current->audit_context;
> > +	int len = 0;
> > +
> > +	if (likely(!context))
> > +		return 0;
> > +
> > +	ax = kmalloc(sizeof(*ax), GFP_ATOMIC);
> 
> Might add a comment as to why you're using GFP_ATOMIC here.

Actually, this should probably be GFP_KERNEL.  We should be able to
sleep at this point without a problem.  

Searching the rest of the file, though I see a similar kmalloc() in
audit_avc_path() that is GFP_ATOMIC...  Anyone know why?  I think I was
just mirroring the behavior there...  I took the liberty to changing
that one to GFP_KERNEL as well.  Correct me if this is not correct.

> > +	if (!ax) {
> > +		audit_panic("memory allocation error in audit_ipc_security_context");
> 
> Again, don't think audit_panic is needed.

Same comment just above...  Open to suggestions...

> > diff -uprN linux-2.6.13-rc6-mm2/security/selinux/hooks.c linux-2.6.13-rc6-mm2-lspp_audit/security/selinux/hooks.c
> > --- linux-2.6.13-rc6-mm2/security/selinux/hooks.c	2005-08-29 11:32:17.000000000 -0500
> > +++ linux-2.6.13-rc6-mm2-lspp_audit/security/selinux/hooks.c	2005-08-29 10:37:51.000000000 -0500
> > @@ -116,6 +116,35 @@ static struct security_operations *secon
> >  static LIST_HEAD(superblock_security_head);
> >  static DEFINE_SPINLOCK(sb_security_lock);
> >  
> > +/* Return security context for a given sid or just the context 
> > +   length if the buffer is null or length is 0 */
> > +static int selinux_getsecurity(u32 sid, void *buffer, size_t size)
> > +{
> > +	char *context;
> > +	unsigned len;
> > +	int rc;
> > +
> > +	if (buffer && !size)
> > +		return -ERANGE;
> > +
> > +	rc = security_sid_to_context(sid, &context, &len);
> > +	if (rc)
> > +		return rc;
> > +
> > +	if (!buffer || !size)
> 
> You don't need to check !size here.  Based on your other conditionals,
> it can only be possible if you have !buffer, which you've already
> checked.

Good catch.  I agree.  Fixed.

> > +		goto getsecurity_exit;
> > +
> > +	if (size < len) {
> > +		kfree(context);
> > +		return -ERANGE;
> 
> Use getsecurity_exit here.

Ok.  getsecurity_exit label will return len, so I'll need to set len =
-ERANGE.  Fixed in new patch.

> > @@ -3362,6 +3374,13 @@ out:	
> >  	return err;
> >  }
> >  
> > +static int selinux_socket_getsecurity(struct socket *sock, void *buffer, size_t size)
> > +{
> > +	struct inode_security_struct *isec = SOCK_INODE(sock)->i_security;
> > +
> > +	return(selinux_getsecurity(isec->sid, buffer, size));
> > +}
> 
> This patch appears to be unfinished (?)  
> I don't see any code using this function.

That's true.  This was a stub for more work that I think will need to be
done.  I've removed this code from this patch.

--

A few other minor changes...  

In include/linux/audit.h, 1500-1599 has been set aside for LSPP use.
The first two entries are AUDIT_SUBJECT_CONTEXT=1500 and
AUDIT_OBJECT_CONTEXT=1501.  (This replaced the temporarily-stubbed-in
definition of AUDIT_SECURITY_CONTEXT=1350).

The audit record now uses "subj" instead of "scontext" and "obj" instead
of "ocontext".  Saved a few bytes space.

Patch is attached.  David: If you want me diff-ed against something else
(your git tree?), let me know and I'll port forward (yet again). 

:-Dustin


diff -uprN linux-2.6.13-rc6-mm2/include/linux/audit.h linux-2.6.13-rc6-mm2-context_labels/include/linux/audit.h
--- linux-2.6.13-rc6-mm2/include/linux/audit.h	2005-10-06 18:26:11.000000000 -0500
+++ linux-2.6.13-rc6-mm2-context_labels/include/linux/audit.h	2005-10-06 17:53:04.000000000 -0500
@@ -33,7 +33,8 @@
  * 1200 - 1299 messages internal to the audit daemon
  * 1300 - 1399 audit event messages
  * 1400 - 1499 SE Linux use
- * 1500 - 1999 future use
+ * 1500 - 1599 labeled security messages (LSPP)
+ * 1600 - 1999 future use
  * 2000 is for otherwise unclassified kernel audit messages
  *
  * Messages from 1000-1199 are bi-directional. 1200-1299 are exclusively user
@@ -73,6 +74,9 @@
 #define AUDIT_SELINUX_ERR	1401	/* Internal SE Linux Errors */
 #define AUDIT_AVC_PATH		1402	/* dentry, vfsmount pair from avc */
 
+#define AUDIT_SUBJECT_CONTEXT	1500	/* subject security context label */
+#define AUDIT_OBJECT_CONTEXT	1501	/* object security context label */
+
 #define AUDIT_KERNEL		2000	/* Asynchronous audit record. NOT A REQUEST. */
 
 /* Rule flags */
@@ -238,6 +242,8 @@ extern int audit_sockaddr(int len, void 
 extern int audit_avc_path(struct dentry *dentry, struct vfsmount *mnt);
 extern void audit_signal_info(int sig, struct task_struct *t);
 extern int audit_filter_user(struct netlink_skb_parms *cb, int type);
+extern int audit_ipc_security_context(struct kern_ipc_perm *ipcp);
+extern int audit_set_macxattr(const char *name);
 #else
 #define audit_alloc(t) ({ 0; })
 #define audit_free(t) do { ; } while (0)
@@ -255,6 +261,8 @@ extern int audit_filter_user(struct netl
 #define audit_avc_path(dentry, mnt) ({ 0; })
 #define audit_signal_info(s,t) do { ; } while (0)
 #define audit_filter_user(cb,t) ({ 1; })
+#define audit_ipc_security_context(i) do { ; } while (0)
+#define audit_set_macxattr(n) do { ; } while (0)
 #endif
 
 #ifdef CONFIG_AUDIT
@@ -283,6 +291,7 @@ extern void		    audit_send_reply(int pi
 					     int done, int multi,
 					     void *payload, int size);
 extern void		    audit_log_lost(const char *message);
+extern void		    audit_panic(const char *message);
 extern struct semaphore audit_netlink_sem;
 #else
 #define audit_log(c,g,t,f,...) do { ; } while (0)
@@ -293,6 +302,7 @@ extern struct semaphore audit_netlink_se
 #define audit_log_hex(a,b,l) do { ; } while (0)
 #define audit_log_untrustedstring(a,s) do { ; } while (0)
 #define audit_log_d_path(b,p,d,v) do { ; } while (0)
+#define audit_panic(m) do { ; } while (0)
 #endif
 #endif
 #endif
diff -uprN linux-2.6.13-rc6-mm2/include/linux/security.h linux-2.6.13-rc6-mm2-context_labels/include/linux/security.h
--- linux-2.6.13-rc6-mm2/include/linux/security.h	2005-10-06 18:26:11.000000000 -0500
+++ linux-2.6.13-rc6-mm2-context_labels/include/linux/security.h	2005-10-05 12:02:01.000000000 -0500
@@ -792,6 +792,11 @@ struct swap_info_struct;
  *	@ipcp contains the kernel IPC permission structure
  *	@flag contains the desired (requested) permission set
  *	Return 0 if permission is granted.
+ * @ipc_getsecurity:
+ *      Copy the security label associated with the ipc object into
+ *      @buffer.  @buffer may be NULL to request the size of the buffer 
+ *      required.  @size indicates the size of @buffer in bytes. Return 
+ *      number of bytes used/required on success.
  *
  * Security hooks for individual messages held in System V IPC message queues
  * @msg_msg_alloc_security:
@@ -1140,6 +1145,7 @@ struct security_operations {
 	void (*task_to_inode)(struct task_struct *p, struct inode *inode);
 
 	int (*ipc_permission) (struct kern_ipc_perm * ipcp, short flag);
+	int (*ipc_getsecurity)(struct kern_ipc_perm *ipcp, void *buffer, size_t size);
 
 	int (*msg_msg_alloc_security) (struct msg_msg * msg);
 	void (*msg_msg_free_security) (struct msg_msg * msg);
@@ -1775,6 +1781,11 @@ static inline int security_ipc_permissio
 	return security_ops->ipc_permission (ipcp, flag);
 }
 
+static inline int security_ipc_getsecurity(struct kern_ipc_perm *ipcp, void *buffer, size_t size)
+{
+	return security_ops->ipc_getsecurity(ipcp, buffer, size);
+}
+
 static inline int security_msg_msg_alloc (struct msg_msg * msg)
 {
 	return security_ops->msg_msg_alloc_security (msg);
@@ -2405,6 +2416,11 @@ static inline int security_ipc_permissio
 	return 0;
 }
 
+static inline int security_ipc_getsecurity(struct kern_ipc_perm *ipcp, void *buffer, size_t size)
+{
+	return -EOPNOTSUPP;
+}
+
 static inline int security_msg_msg_alloc (struct msg_msg * msg)
 {
 	return 0;
diff -uprN linux-2.6.13-rc6-mm2/ipc/msg.c linux-2.6.13-rc6-mm2-context_labels/ipc/msg.c
--- linux-2.6.13-rc6-mm2/ipc/msg.c	2005-10-06 18:26:11.000000000 -0500
+++ linux-2.6.13-rc6-mm2-context_labels/ipc/msg.c	2005-10-05 21:14:39.000000000 -0500
@@ -443,10 +443,17 @@ asmlinkage long sys_msgctl (int msqid, i
 	if (msq == NULL)
 		goto out_up;
 
+	ipcp = &msq->q_perm;
+
+	if (cmd == IPC_SET) {
+		if ((err = audit_ipc_security_context(ipcp)))
+			goto out_unlock_up;
+	}
+
 	err = -EIDRM;
 	if (msg_checkid(msq,msqid))
 		goto out_unlock_up;
-	ipcp = &msq->q_perm;
+
 	err = -EPERM;
 	if (current->euid != ipcp->cuid && 
 	    current->euid != ipcp->uid && !capable(CAP_SYS_ADMIN))
diff -uprN linux-2.6.13-rc6-mm2/ipc/sem.c linux-2.6.13-rc6-mm2-context_labels/ipc/sem.c
--- linux-2.6.13-rc6-mm2/ipc/sem.c	2005-10-06 18:26:11.000000000 -0500
+++ linux-2.6.13-rc6-mm2-context_labels/ipc/sem.c	2005-10-06 11:01:38.000000000 -0500
@@ -813,12 +813,18 @@ static int semctl_down(int semid, int se
 	if(sma==NULL)
 		return -EINVAL;
 
+	ipcp = &sma->sem_perm;
+
+	if(cmd == IPC_SET) {
+		if ((err = audit_ipc_security_context(ipcp)))
+			goto out_unlock;
+	}
+
 	if (sem_checkid(sma,semid)) {
 		err=-EIDRM;
 		goto out_unlock;
 	}	
-	ipcp = &sma->sem_perm;
-	
+
 	if (current->euid != ipcp->cuid && 
 	    current->euid != ipcp->uid && !capable(CAP_SYS_ADMIN)) {
 	    	err=-EPERM;
diff -uprN linux-2.6.13-rc6-mm2/ipc/shm.c linux-2.6.13-rc6-mm2-context_labels/ipc/shm.c
--- linux-2.6.13-rc6-mm2/ipc/shm.c	2005-10-06 18:26:11.000000000 -0500
+++ linux-2.6.13-rc6-mm2-context_labels/ipc/shm.c	2005-10-06 11:02:50.000000000 -0500
@@ -611,6 +611,9 @@ asmlinkage long sys_shmctl (int shmid, i
 		err=-EINVAL;
 		if(shp==NULL)
 			goto out_up;
+		err = audit_ipc_security_context(&(shp->shm_perm));
+		if(err)
+			goto out_unlock_up;
 		err = shm_checkid(shp,shmid);
 		if(err)
 			goto out_unlock_up;
diff -uprN linux-2.6.13-rc6-mm2/ipc/util.c linux-2.6.13-rc6-mm2-context_labels/ipc/util.c
--- linux-2.6.13-rc6-mm2/ipc/util.c	2005-10-06 18:26:11.000000000 -0500
+++ linux-2.6.13-rc6-mm2-context_labels/ipc/util.c	2005-10-05 20:56:44.000000000 -0500
@@ -26,6 +26,7 @@
 #include <linux/workqueue.h>
 #include <linux/seq_file.h>
 #include <linux/proc_fs.h>
+#include <linux/audit.h>
 
 #include <asm/unistd.h>
 
@@ -466,6 +467,7 @@ int ipcperms (struct kern_ipc_perm *ipcp
 {	/* flag will most probably be 0 or S_...UGO from <linux/stat.h> */
 	int requested_mode, granted_mode;
 
+	audit_ipc_security_context(ipcp);
 	requested_mode = (flag >> 6) | (flag >> 3) | flag;
 	granted_mode = ipcp->mode;
 	if (current->euid == ipcp->cuid || current->euid == ipcp->uid)
diff -uprN linux-2.6.13-rc6-mm2/kernel/audit.c linux-2.6.13-rc6-mm2-context_labels/kernel/audit.c
--- linux-2.6.13-rc6-mm2/kernel/audit.c	2005-10-06 18:26:11.000000000 -0500
+++ linux-2.6.13-rc6-mm2-context_labels/kernel/audit.c	2005-10-05 12:05:31.000000000 -0500
@@ -142,7 +142,7 @@ static void audit_set_pid(struct audit_b
 	nlh->nlmsg_pid = pid;
 }
 
-static void audit_panic(const char *message)
+void audit_panic(const char *message)
 {
 	switch (audit_failure)
 	{
diff -uprN linux-2.6.13-rc6-mm2/kernel/auditsc.c linux-2.6.13-rc6-mm2-context_labels/kernel/auditsc.c
--- linux-2.6.13-rc6-mm2/kernel/auditsc.c	2005-10-06 18:26:11.000000000 -0500
+++ linux-2.6.13-rc6-mm2-context_labels/kernel/auditsc.c	2005-10-06 17:56:21.000000000 -0500
@@ -43,6 +43,7 @@
 #include <linux/netlink.h>
 #include <linux/compiler.h>
 #include <asm/unistd.h>
+#include <linux/security.h>
 
 /* 0 = no checking
    1 = put_count checking
@@ -99,6 +100,7 @@ struct audit_names {
 	gid_t		gid;
 	dev_t		rdev;
 	unsigned	flags;
+	char		*security_context;
 };
 
 struct audit_aux_data {
@@ -108,6 +110,12 @@ struct audit_aux_data {
 
 #define AUDIT_AUX_IPCPERM	0
 
+struct audit_aux_data_security_context {
+	struct			audit_aux_data d;
+	char			*security_context;
+	size_t			security_context_len;
+};
+
 struct audit_aux_data_ipcctl {
 	struct audit_aux_data	d;
 	struct ipc_perm		p;
@@ -117,6 +125,8 @@ struct audit_aux_data_ipcctl {
 	mode_t			mode;
 };
 
+static const char *audit_macxattr;
+
 struct audit_aux_data_socketcall {
 	struct audit_aux_data	d;
 	int			nargs;
@@ -657,10 +667,12 @@ static inline void audit_free_names(stru
 		       context->serial, context->major, context->in_syscall,
 		       context->name_count, context->put_count,
 		       context->ino_count);
-		for (i = 0; i < context->name_count; i++)
+		for (i = 0; i < context->name_count; i++) {
 			printk(KERN_ERR "names[%d] = %p = %s\n", i,
 			       context->names[i].name,
 			       context->names[i].name);
+			kfree(context->names[i].security_context);
+		}
 		dump_stack();
 		return;
 	}
@@ -692,6 +704,14 @@ static inline void audit_free_aux(struct
 			dput(axi->dentry);
 			mntput(axi->mnt);
 		}
+		if (
+			(aux->type == AUDIT_SUBJECT_CONTEXT) ||
+			(aux->type == AUDIT_OBJECT_CONTEXT)
+		   ) {
+			struct audit_aux_data_security_context *axi = (void *)aux;
+			kfree(axi->security_context);
+		}
+
 		context->aux = aux->next;
 		kfree(aux);
 	}
@@ -771,6 +791,37 @@ static inline void audit_free_context(st
 		printk(KERN_ERR "audit: freed %d contexts\n", count);
 }
 
+static void audit_log_task_security_context(struct audit_buffer *ab)
+{
+	char *security_context;
+	ssize_t len = 0;
+
+	len = security_getprocattr(current, "current", NULL, 0);
+	if (len < 0) {
+		if (len != -EINVAL)
+			audit_panic("security_getprocattr error in audit_log_task_security_context");
+		return;
+	}
+
+	security_context = kmalloc(len, GFP_KERNEL);
+	if (!security_context) {
+		audit_panic("memory allocation error in audit_log_task_security_context");
+		return;
+	}
+
+	len = security_getprocattr(current, "current", security_context, len);
+	if (len < 0 ) {
+		audit_panic("security_getprocattr error in audit_log_task_security_context");
+		goto out;
+	}
+
+	audit_log_format(ab, " subj=%s", security_context);
+
+out:
+	kfree(security_context);
+	return;
+}
+
 static void audit_log_task_info(struct audit_buffer *ab)
 {
 	char name[sizeof(current->comm)];
@@ -797,6 +848,7 @@ static void audit_log_task_info(struct a
 		vma = vma->vm_next;
 	}
 	up_read(&mm->mmap_sem);
+	audit_log_task_security_context(ab);
 }
 
 static void audit_log_exit(struct audit_context *context, unsigned int gfp_mask)
@@ -869,7 +921,12 @@ static void audit_log_exit(struct audit_
 			audit_log_d_path(ab, "path=", axi->dentry, axi->mnt);
 			break; }
 
+		case AUDIT_OBJECT_CONTEXT: {
+			struct audit_aux_data_security_context *axi = (void *)aux;
+			audit_log_format(ab, " obj=%s", axi->security_context);
+			break; }
 		}
+
 		audit_log_end(ab);
 	}
 
@@ -903,6 +960,11 @@ static void audit_log_exit(struct audit_
 					 context->names[i].gid,
 					 MAJOR(context->names[i].rdev),
 					 MINOR(context->names[i].rdev));
+		if (context->names[i].security_context) {
+			audit_log_format(ab, " obj=%s",
+					context->names[i].security_context);
+		}
+
 		audit_log_end(ab);
 	}
 }
@@ -1118,6 +1180,37 @@ void audit_putname(const char *name)
 #endif
 }
 
+void audit_inode_security_context(int idx, const struct inode *inode)
+{
+	struct audit_context *context = current->audit_context;
+	int len = 0;
+
+	if (!audit_macxattr)
+		return;
+
+	len = security_inode_getsecurity((struct inode *)inode, audit_macxattr, NULL, 0);
+	if (len < 0) {
+		if (len != -EOPNOTSUPP)
+			audit_panic("security_inode_getsecurity error in audit_inode_security_context");
+		return;
+	}
+
+	context->names[idx].security_context = kmalloc(len, GFP_KERNEL);
+	if (!(context->names[idx].security_context)) {
+		audit_panic("memory allocation error in audit_inode_security_context");
+		return;
+	}
+
+	len = security_inode_getsecurity((struct inode *)inode, audit_macxattr,
+			context->names[idx].security_context, len);
+	if (len < 0) {
+		kfree(context->names[idx].security_context);
+		audit_panic("security_inode_getsecurity error in audit_inode_security_context");
+	}
+
+	return;
+}
+
 /* Store the inode and device from a lookup.  Called from
  * fs/namei.c:path_lookup(). */
 void audit_inode(const char *name, const struct inode *inode, unsigned flags)
@@ -1153,6 +1246,7 @@ void audit_inode(const char *name, const
 	context->names[idx].uid   = inode->i_uid;
 	context->names[idx].gid   = inode->i_gid;
 	context->names[idx].rdev  = inode->i_rdev;
+	audit_inode_security_context(idx, inode);
 }
 
 void auditsc_get_stamp(struct audit_context *ctx,
@@ -1166,6 +1260,67 @@ void auditsc_get_stamp(struct audit_cont
 	ctx->auditable = 1;
 }
 
+int audit_ipc_security_context(struct kern_ipc_perm *ipcp)
+{
+	struct audit_aux_data_security_context *ax;
+	struct audit_context *context = current->audit_context;
+	int len = 0;
+
+	if (likely(!context))
+		return 0;
+
+	ax = kmalloc(sizeof(*ax), GFP_KERNEL);
+	if (!ax) {
+		audit_panic("memory allocation error in audit_ipc_security_context");
+		return -ENOMEM;
+	}
+
+	len = security_ipc_getsecurity(ipcp, NULL, 0);
+	if (len < 0) {
+		if (len != -EOPNOTSUPP)
+			audit_panic("security_ipc_getsecurity error in audit_ipc_security_context");
+		return len;
+	}
+
+	ax->security_context = kmalloc(len, GFP_KERNEL);
+	if (!ax->security_context) {
+		audit_panic("memory allocation error in audit_ipc_security_context");
+		kfree(ax);
+		return -ENOMEM;
+	}
+
+	len = security_ipc_getsecurity(ipcp, ax->security_context, len);
+	if (len < 0) {
+		audit_panic("security_ipc_getsecurity error in audit_ipc_security_context");
+		kfree(ax->security_context);
+		kfree(ax);
+		return len;
+	}
+
+	ax->security_context_len = len;
+
+	ax->d.type = AUDIT_OBJECT_CONTEXT;
+	ax->d.next = context->aux;
+	context->aux = (void *)ax;
+	return 0;
+}
+
+/* Set the security XATTR name. This is needed for audit functions
+ * to obtain the security context of file system objects. */
+int audit_set_macxattr(const char *name)
+{
+	size_t len = strlen(name)+1;
+
+	if (audit_macxattr)
+		return -EINVAL;
+
+	audit_macxattr = kstrdup(name, GFP_KERNEL);
+	if (!audit_macxattr)
+		return -ENOMEM;
+
+	return 0;
+}
+
 int audit_set_loginuid(struct task_struct *task, uid_t loginuid)
 {
 	if (task->audit_context) {
@@ -1262,7 +1417,7 @@ int audit_avc_path(struct dentry *dentry
 	if (likely(!context))
 		return 0;
 
-	ax = kmalloc(sizeof(*ax), GFP_ATOMIC);
+	ax = kmalloc(sizeof(*ax), GFP_KERNEL);
 	if (!ax)
 		return -ENOMEM;
 
diff -uprN linux-2.6.13-rc6-mm2/security/dummy.c linux-2.6.13-rc6-mm2-context_labels/security/dummy.c
--- linux-2.6.13-rc6-mm2/security/dummy.c	2005-10-06 18:26:12.000000000 -0500
+++ linux-2.6.13-rc6-mm2-context_labels/security/dummy.c	2005-10-06 11:26:21.000000000 -0500
@@ -557,6 +557,11 @@ static int dummy_ipc_permission (struct 
 	return 0;
 }
 
+static int dummy_ipc_getsecurity(struct kern_ipc_perm *ipcp, void *buffer, size_t size)
+{
+	return -EOPNOTSUPP;
+}
+
 static int dummy_msg_msg_alloc_security (struct msg_msg *msg)
 {
 	return 0;
@@ -907,6 +912,7 @@ void security_fixup_ops (struct security
 	set_to_dummy_if_null(ops, task_reparent_to_init);
  	set_to_dummy_if_null(ops, task_to_inode);
 	set_to_dummy_if_null(ops, ipc_permission);
+	set_to_dummy_if_null(ops, ipc_getsecurity);
 	set_to_dummy_if_null(ops, msg_msg_alloc_security);
 	set_to_dummy_if_null(ops, msg_msg_free_security);
 	set_to_dummy_if_null(ops, msg_queue_alloc_security);
diff -uprN linux-2.6.13-rc6-mm2/security/selinux/hooks.c linux-2.6.13-rc6-mm2-context_labels/security/selinux/hooks.c
--- linux-2.6.13-rc6-mm2/security/selinux/hooks.c	2005-10-06 18:26:12.000000000 -0500
+++ linux-2.6.13-rc6-mm2-context_labels/security/selinux/hooks.c	2005-10-06 17:27:51.000000000 -0500
@@ -116,6 +116,35 @@ static struct security_operations *secon
 static LIST_HEAD(superblock_security_head);
 static DEFINE_SPINLOCK(sb_security_lock);
 
+/* Return security context for a given sid or just the context 
+   length if the buffer is null or length is 0 */
+static int selinux_getsecurity(u32 sid, void *buffer, size_t size)
+{
+	char *context;
+	unsigned len;
+	int rc;
+
+	if (buffer && !size)
+		return -ERANGE;
+
+	rc = security_sid_to_context(sid, &context, &len);
+	if (rc)
+		return rc;
+
+	if (!buffer)
+		goto getsecurity_exit;
+
+	if (size < len) {
+		len = -ERANGE;
+		goto getsecurity_exit;
+	}
+	memcpy(buffer, context, len);
+
+getsecurity_exit:
+	kfree(context);
+	return len;
+}
+
 /* Allocate and free functions for each kind of security blob. */
 
 static int task_alloc_security(struct task_struct *task)
@@ -2234,30 +2263,13 @@ 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;
-	char *context;
-	unsigned len;
-	int rc;
 
 	/* Permission check handled by selinux_inode_getxattr hook.*/
 
 	if (strcmp(name, XATTR_SELINUX_SUFFIX))
 		return -EOPNOTSUPP;
 
-	rc = security_sid_to_context(isec->sid, &context, &len);
-	if (rc)
-		return rc;
-
-	if (!buffer || !size) {
-		kfree(context);
-		return len;
-	}
-	if (size < len) {
-		kfree(context);
-		return -ERANGE;
-	}
-	memcpy(buffer, context, len);
-	kfree(context);
-	return len;
+	return(selinux_getsecurity(isec->sid, buffer, size));
 }
 
 static int selinux_inode_setsecurity(struct inode *inode, const char *name,
@@ -4027,6 +4039,13 @@ static int selinux_ipc_permission(struct
 	return ipc_has_perm(ipcp, av);
 }
 
+static int selinux_ipc_getsecurity(struct kern_ipc_perm *ipcp, void *buffer, size_t size)
+{
+	struct ipc_security_struct *isec = ipcp->security;
+
+	return(selinux_getsecurity(isec->sid, buffer, size));
+}
+
 /* module stacking operations */
 static int selinux_register_security (const char *name, struct security_operations *ops)
 {
@@ -4068,8 +4087,7 @@ static int selinux_getprocattr(struct ta
 			       char *name, void *value, size_t size)
 {
 	struct task_security_struct *tsec;
-	u32 sid, len;
-	char *context;
+	u32 sid;
 	int error;
 
 	if (current != p) {
@@ -4078,9 +4096,6 @@ static int selinux_getprocattr(struct ta
 			return error;
 	}
 
-	if (!size)
-		return -ERANGE;
-
 	tsec = p->security;
 
 	if (!strcmp(name, "current"))
@@ -4097,16 +4112,7 @@ static int selinux_getprocattr(struct ta
 	if (!sid)
 		return 0;
 
-	error = security_sid_to_context(sid, &context, &len);
-	if (error)
-		return error;
-	if (len > size) {
-		kfree(context);
-		return -ERANGE;
-	}
-	memcpy(value, context, len);
-	kfree(context);
-	return len;
+	return(selinux_getsecurity(sid, value, size));
 }
 
 static int selinux_setprocattr(struct task_struct *p,
@@ -4301,6 +4307,7 @@ static struct security_operations selinu
 	.task_to_inode =                selinux_task_to_inode,
 
 	.ipc_permission =		selinux_ipc_permission,
+	.ipc_getsecurity =		selinux_ipc_getsecurity,
 
 	.msg_msg_alloc_security =	selinux_msg_msg_alloc_security,
 	.msg_msg_free_security =	selinux_msg_msg_free_security,
@@ -4381,6 +4388,10 @@ static __init int selinux_init(void)
 	if (register_security (&selinux_ops))
 		panic("SELinux: Unable to register with kernel.\n");
 
+	if (audit_set_macxattr(XATTR_SELINUX_SUFFIX)) {
+		printk(KERN_WARNING "SELinux: Unable to register xattr name with audit.\n");	
+	}
+
 	if (selinux_enforcing) {
 		printk(KERN_INFO "SELinux:  Starting in enforcing mode\n");
 	} else {

Attachment: signature.asc
Description: This is a digitally signed message part


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]