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,