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

Dustin Kirkland dustin.kirkland at us.ibm.com
Tue Oct 18 22:24:41 UTC 2005


On Fri, 2005-10-07 at 14:43 -0700, Chris Wright wrote: 
> (Note: as mentioned on IRC, patch inline as well please).

My bad.  I knew better...  ;)


> > 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.
> 
> Boy i don't like these kind of interfaces...it's racy, etc..

Agreed. There is a chance of a race condition in that the size could
conceivably change between subsequent calls.  But as discussed on IRC,
this is a limitation levied upon us of using the present xattr
interfaces.  For now, I propose documenting the theoretically potential
race condition, but pointing to the other existing xattr interfaces
implemented in the same manner.

> > 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;
> > +	}
> > +
> 
> OK, some issues here.  First, the checkid is to ensure it's valid object
> still, so this shouldn't be above that.  Second, I assume it's some
> requirement to log attempted updates?   Because adding a third test for
> IPC_SET is not a good idea...too many special case logics.  Third, this
> thing is asking for some real trouble by doing kmalloc with spinlock
> held.  That's a no go.

[1,2,3] all true.  This call has been moved into the existing
switch (cmd) {
        case IPC_SET:
code block a few lines below.  And the kmalloc is now atomic.


> > 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;
> > +	}
> > +
> 
> Ditto

Fixed as above.

> > 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;
> 
> Ditto

Fixed as above.

> > 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);
> 
> Here object is valid, but lock is still held, so no sleeping (aka
> kmalloc(GFP_KERNEL).  Alos, this has some 'sprinkling' effect, but I
> probably missed all the discussion looking for proper hooking locations.
> Is that information written down somehwere to justify the locations?

True.  The kmalloc() inside of audit_ipc_security_context() is now
GFP_ATOMIC.  

> > 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
> > @@ -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);
> 
> Stack var is cheap, and might be easier to read ...

Agreed.  Using char *ctx until end, in which case if everything is
good, context->names[idx].security_context = ctx.

Did the same in audit_ipc_security_context().


> > +	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,
> 
> Why the cast?  Undermines the const interface.

Not sure why that was there.  Cast removed.

> > +			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;
> > +}
> 
> -ETOOMANY audit_panics

Changed to a goto label "error_path" for readability.

> > @@ -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;
> 
> Leaks ax.

Thanks.  Good catch.  Fixed in new patch.

> > +	}
> > +
> > +	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;
> > +}
> 
> -ETOOMANY audit_panics.

Fixed with "error_path" goto label.

> You could avoid some overhead by doing it this way (flip allocations
> upside down...psuedo code, probably buggy):
> 
> 	ret = 0
> 	len = security_ipc_getsecurity(NULL)
> 	if len <= 0
> 		goto out;
> 	
> 	ret = -ENOMEM
> 	context = kmalloc(len)
> 	if (!context)
> 		goto out;
> 	  
> 	ret = security_ipc_getsecurity(context)
> 	if ret != len {		/* I still don't like this double call */
> 		ret = -EFOOBAR
> 		goto out_free;
> 	}
> 	
> 	ret = -ENOMEM;
> 	ax = kmalloc(sizeof(struct aud_ctxt)
> 	if (!ax)
> 		goto out_free;
> 	
> 	ax->security_context = context;
> 	ax->security_context_len = len;
> 	ax->...
> 	context->aux = ax;
> 
> 	ret = 0;
> 	goto out;
> 	
> out_free;
> 	kfree(context)
> out:
> 	return ret;

Reworked as such.  Slightly simplified.

> > +
> > +/* 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;
> > +}
> 
> Do this in the security interface.

Per IRC discussion, this function has been dropped, as well as it's call
in security/selinux/hooks.c.  And instead, in
audit_inode_security_context(), call security_inode_xattr_getsuffix().

> >  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);
> 
> No, for two reasons.  One, unreleted change shouldn't be in this.  Two,
> it's wrong because we currently have no such restriction on avc_audit.

Thanks.

> > 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;
> 
> That's an interface change

I see.  Fixed per IRC discussion.  Basically what is needed is:
       if (!buffer || !size)
                goto getsecurity_exit;


> > @@ -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));
> 
> Parens not needed

Changed.

> > @@ -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));
> 
> same here.

Changed.

> > @@ -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));
> 
> Ditto

Changed.

New patch inline below...

:-Dustin


diff -urpN 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-14 12:56:53.000000000 -0500
+++ linux-2.6.13-rc6-mm2-context_labels/include/linux/audit.h	2005-10-13 16:13:03.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 -urpN 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-14 12:56:54.000000000 -0500
+++ linux-2.6.13-rc6-mm2-context_labels/include/linux/security.h	2005-10-18 12:11:06.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:
@@ -1091,6 +1096,7 @@ struct security_operations {
 	int (*inode_getxattr) (struct dentry *dentry, char *name);
 	int (*inode_listxattr) (struct dentry *dentry);
 	int (*inode_removexattr) (struct dentry *dentry, char *name);
+	char *(*inode_xattr_getsuffix) (void);
   	int (*inode_getsecurity)(struct inode *inode, const char *name, void *buffer, size_t size);
   	int (*inode_setsecurity)(struct inode *inode, const char *name, const void *value, size_t size, int flags);
   	int (*inode_listsecurity)(struct inode *inode, char *buffer, size_t buffer_size);
@@ -1140,6 +1146,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);
@@ -1580,6 +1587,11 @@ static inline int security_inode_removex
 	return security_ops->inode_removexattr (dentry, name);
 }
 
+static inline const char *security_inode_xattr_getsuffix(void)
+{
+	return security_ops->inode_xattr_getsuffix();
+} 
+
 static inline int security_inode_getsecurity(struct inode *inode, const char *name, void *buffer, size_t size)
 {
 	if (unlikely (IS_PRIVATE (inode)))
@@ -1775,6 +1787,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);
@@ -2222,6 +2239,11 @@ static inline int security_inode_removex
 	return cap_inode_removexattr(dentry, name);
 }
 
+static inline const char *security_inode_xattr_getsuffix (void)
+{
+	return NULL ;
+}
+
 static inline int security_inode_getsecurity(struct inode *inode, const char *name, void *buffer, size_t size)
 {
 	return -EOPNOTSUPP;
@@ -2405,6 +2427,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 -urpN 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-14 12:56:54.000000000 -0500
+++ linux-2.6.13-rc6-mm2-context_labels/ipc/msg.c	2005-10-13 16:14:55.000000000 -0500
@@ -460,6 +460,9 @@ asmlinkage long sys_msgctl (int msqid, i
 	switch (cmd) {
 	case IPC_SET:
 	{
+		if ((err = audit_ipc_security_context(ipcp)))
+			goto out_unlock_up;
+
 		err = -EPERM;
 		if (setbuf.qbytes > msg_ctlmnb && !capable(CAP_SYS_RESOURCE))
 			goto out_unlock_up;
diff -urpN 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-14 12:56:54.000000000 -0500
+++ linux-2.6.13-rc6-mm2-context_labels/ipc/sem.c	2005-10-13 16:15:27.000000000 -0500
@@ -818,7 +818,6 @@ static int semctl_down(int semid, int se
 		goto out_unlock;
 	}	
 	ipcp = &sma->sem_perm;
-	
 	if (current->euid != ipcp->cuid && 
 	    current->euid != ipcp->uid && !capable(CAP_SYS_ADMIN)) {
 	    	err=-EPERM;
@@ -835,6 +834,8 @@ static int semctl_down(int semid, int se
 		err = 0;
 		break;
 	case IPC_SET:
+		if ((err = audit_ipc_security_context(ipcp)))
+			goto out_unlock;
 		ipcp->uid = setbuf.uid;
 		ipcp->gid = setbuf.gid;
 		ipcp->mode = (ipcp->mode & ~S_IRWXUGO)
diff -urpN 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-14 12:56:54.000000000 -0500
+++ linux-2.6.13-rc6-mm2-context_labels/ipc/shm.c	2005-10-13 16:15:38.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 -urpN 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-14 12:56:54.000000000 -0500
+++ linux-2.6.13-rc6-mm2-context_labels/ipc/util.c	2005-10-13 16:13:03.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 -urpN 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-14 12:56:54.000000000 -0500
+++ linux-2.6.13-rc6-mm2-context_labels/kernel/audit.c	2005-10-13 16:13:03.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 -urpN 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-14 12:56:54.000000000 -0500
+++ linux-2.6.13-rc6-mm2-context_labels/kernel/auditsc.c	2005-10-18 12:02:54.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;
@@ -657,10 +665,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 +702,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 +789,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)
+			goto error_path;
+		return;
+	}
+
+	security_context = kmalloc(len, GFP_KERNEL);
+	if (!security_context) {
+		goto error_path;
+		return;
+	}
+
+	len = security_getprocattr(current, "current", security_context, len);
+	if (len < 0 )
+		goto error_path;
+
+	audit_log_format(ab, " subj=%s", security_context);
+
+error_path:
+	if (security_context)
+		kfree(security_context);
+	audit_panic("security_getprocattr error in audit_log_task_security_context");
+	return;
+}
+
 static void audit_log_task_info(struct audit_buffer *ab)
 {
 	char name[sizeof(current->comm)];
@@ -797,6 +846,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 +919,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 +958,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 +1178,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;
+	char *ctx = NULL;
+	int len = 0;
+
+	if (!security_inode_xattr_getsuffix())
+		return;
+
+	len = security_inode_getsecurity(inode, (char *)security_inode_xattr_getsuffix(), NULL, 0);
+	if (len < 0) 
+		goto error_path;
+
+	ctx = kmalloc(len, GFP_KERNEL);
+	if (!ctx) 
+		goto error_path;
+
+	len = security_inode_getsecurity(inode, (char *)security_inode_xattr_getsuffix(), ctx, len);
+	if (len < 0)
+		goto error_path;
+
+	context->names[idx].security_context = ctx;
+	return;
+
+error_path:
+	if (ctx)
+		kfree(ctx);
+	audit_panic("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 +1244,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 +1258,57 @@ 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 = NULL;
+	struct audit_context *context = current->audit_context;
+	char *ctx = NULL;
+	int len = 0;
+	int err = 0;
+
+	if (likely(!context))
+		return 0;
+
+	len = security_ipc_getsecurity(ipcp, NULL, 0);
+	if (len < 0) {
+		err = len;
+		goto error_path;
+	}
+
+	ax = kmalloc(sizeof(*ax), GFP_ATOMIC);
+	if (!ax) {
+		err = -ENOMEM;
+		goto error_path;
+	}
+
+	ctx = kmalloc(len, GFP_ATOMIC);;
+	if (!ctx) {
+		err = -ENOMEM;
+		goto error_path;
+	}
+
+	len = security_ipc_getsecurity(ipcp, ctx, len);
+	if (len < 0) {
+		err = len;
+		goto error_path;
+	}
+
+	ax->security_context = ctx;
+	ax->security_context_len = len;
+	ax->d.type = AUDIT_OBJECT_CONTEXT;
+	ax->d.next = context->aux;
+	context->aux = (void *)ax;
+	return 0;
+
+error_path:
+	if (ax)
+		kfree(ax);
+	if (ctx)
+		kfree(ctx);
+	audit_panic("error in audit_ipc_security_context");
+	return err;
+}
+
 int audit_set_loginuid(struct task_struct *task, uid_t loginuid)
 {
 	if (task->audit_context) {
@@ -1197,7 +1340,7 @@ int audit_ipc_perms(unsigned long qbytes
 	if (likely(!context))
 		return 0;
 
-	ax = kmalloc(sizeof(*ax), GFP_KERNEL);
+	ax = kmalloc(sizeof(*ax), GFP_ATOMIC);
 	if (!ax)
 		return -ENOMEM;
 
diff -urpN 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-14 12:56:55.000000000 -0500
+++ linux-2.6.13-rc6-mm2-context_labels/security/dummy.c	2005-10-13 16:13:03.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 -urpN 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-14 12:56:56.000000000 -0500
+++ linux-2.6.13-rc6-mm2-context_labels/security/selinux/hooks.c	2005-10-18 12:13:52.000000000 -0500
@@ -116,6 +116,32 @@ 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;
+
+	rc = security_sid_to_context(sid, &context, &len);
+	if (rc)
+		return rc;
+
+	if (!buffer || !size)
+		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)
@@ -2231,33 +2257,21 @@ static int selinux_inode_removexattr (st
 	return -EACCES;
 }
 
+static const char *selinux_inode_xattr_getsuffix(void)
+{
+	return XATTR_SELINUX_SUFFIX;
+}
+
 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 +4041,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 +4089,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 +4098,6 @@ static int selinux_getprocattr(struct ta
 			return error;
 	}
 
-	if (!size)
-		return -ERANGE;
-
 	tsec = p->security;
 
 	if (!strcmp(name, "current"))
@@ -4097,16 +4114,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,
@@ -4264,6 +4272,7 @@ static struct security_operations selinu
 	.inode_getxattr =		selinux_inode_getxattr,
 	.inode_listxattr =		selinux_inode_listxattr,
 	.inode_removexattr =		selinux_inode_removexattr,
+	.inode_xattr_getsuffix =        selinux_inode_xattr_getsuffix,
 	.inode_getsecurity =            selinux_inode_getsecurity,
 	.inode_setsecurity =            selinux_inode_setsecurity,
 	.inode_listsecurity =           selinux_inode_listsecurity,
@@ -4301,6 +4310,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,


-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 189 bytes
Desc: This is a digitally signed message part
URL: <http://listman.redhat.com/archives/linux-audit/attachments/20051018/9c6116b1/attachment.sig>


More information about the Linux-audit mailing list