Discussion:
[PATCH] LSPP audit enablement: storing selinux ocontext and scontext
(too old to reply)
Dustin Kirkland
2005-07-21 15:48:41 UTC
Permalink
The attached patch contains functionality specified by the labeled
security protection profile--basically appending object context and
subject context labels to audit records.

This code was originally written by Dan Jones against a 2.6.9 kernel
tree. I have ported it forward to the 2.6.13-rc3-mm1 tree and tested
it.

I expect at least one section of this code to generate some animated
discussion. This code utilizes "static inline" function definitions
rather than "#define" macros, as per Documentation/SubmittingPatches
lines 328-372 and Documentation/CodingStyle line 358. This is
inconsistent with the rest of the code in include/linux/audit.h, so I
suspect someone will have to give, in the interest of consistency.
Please advise.

Additionally, we've arbitrarily defined AUDIT_SECURITY_CONTEXT = 1350.
We expect this to change to whatever the appropriate value might be.


Signed-off-by: Dustin Kirkland <***@us.ibm.com>



diff -uprN linux-2.6.13-rc3-mm1/include/linux/audit.h
linux-2.6.13-rc3-mm1-lspp_audit/include/linux/audit.h
--- linux-2.6.13-rc3-mm1/include/linux/audit.h 2005-07-18 15:20:34.000000000 -0500
+++ linux-2.6.13-rc3-mm1-lspp_audit/include/linux/audit.h 2005-07-19 11:33:37.000000000 -0500
@@ -68,6 +68,7 @@
#define AUDIT_CONFIG_CHANGE 1305 /* Audit system configuration change */
#define AUDIT_SOCKADDR 1306 /* sockaddr copied as syscall arg */
#define AUDIT_CWD 1307 /* Current working directory */
+#define AUDIT_SECURITY_CONTEXT 1350 /* security context */

#define AUDIT_AVC 1400 /* SE Linux avc denial or grant */
#define AUDIT_SELINUX_ERR 1401 /* Internal SE Linux Errors */
@@ -238,6 +239,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 +258,14 @@ 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; })
+static inline int audit_ipc_security_context(struct kern_ipc_perm *ipcp)
+{
+ return 0;
+}
+static inline int audit_set_macxattr(const char *name)
+{
+ return 0;
+}
#endif

#ifdef CONFIG_AUDIT
@@ -283,6 +294,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 +305,10 @@ 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)
+static inline void audit_panic(const char *message)
+{
+ return;
+}
#endif
#endif
#endif
diff -uprN linux-2.6.13-rc3-mm1/include/linux/security.h linux-2.6.13-rc3-mm1-lspp_audit/include/linux/security.h
--- linux-2.6.13-rc3-mm1/include/linux/security.h 2005-07-18 15:20:35.000000000 -0500
+++ linux-2.6.13-rc3-mm1-lspp_audit/include/linux/security.h 2005-07-18 16:35:02.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-rc3-mm1/ipc/msg.c linux-2.6.13-rc3-mm1-lspp_audit/ipc/msg.c
--- linux-2.6.13-rc3-mm1/ipc/msg.c 2005-06-17 14:48:29.000000000 -0500
+++ linux-2.6.13-rc3-mm1-lspp_audit/ipc/msg.c 2005-07-18 16:35:02.000000000 -0500
@@ -441,6 +441,13 @@ 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;
diff -uprN linux-2.6.13-rc3-mm1/ipc/sem.c linux-2.6.13-rc3-mm1-lspp_audit/ipc/sem.c
--- linux-2.6.13-rc3-mm1/ipc/sem.c 2005-07-18 15:20:05.000000000 -0500
+++ linux-2.6.13-rc3-mm1-lspp_audit/ipc/sem.c 2005-07-18 16:35:02.000000000 -0500
@@ -811,12 +811,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-rc3-mm1/ipc/shm.c linux-2.6.13-rc3-mm1-lspp_audit/ipc/shm.c
--- linux-2.6.13-rc3-mm1/ipc/shm.c 2005-06-17 14:48:29.000000000 -0500
+++ linux-2.6.13-rc3-mm1-lspp_audit/ipc/shm.c 2005-07-18 16:35:02.000000000 -0500
@@ -610,6 +610,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-rc3-mm1/ipc/util.c linux-2.6.13-rc3-mm1-lspp_audit/ipc/util.c
--- linux-2.6.13-rc3-mm1/ipc/util.c 2005-06-17 14:48:29.000000000 -0500
+++ linux-2.6.13-rc3-mm1-lspp_audit/ipc/util.c 2005-07-18 16:35:02.000000000 -0500
@@ -24,6 +24,7 @@
#include <linux/security.h>
#include <linux/rcupdate.h>
#include <linux/workqueue.h>
+#include <linux/audit.h>

#include <asm/unistd.h>

@@ -420,6 +421,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);
+
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-rc3-mm1/kernel/audit.c linux-2.6.13-rc3-mm1-lspp_audit/kernel/audit.c
--- linux-2.6.13-rc3-mm1/kernel/audit.c 2005-07-18 15:20:35.000000000 -0500
+++ linux-2.6.13-rc3-mm1-lspp_audit/kernel/audit.c 2005-07-18 16:35:02.000000000 -0500
@@ -147,7 +147,7 @@ struct audit_entry {
struct audit_rule rule;
};

-static void audit_panic(const char *message)
+void audit_panic(const char *message)
{
switch (audit_failure)
{
@@ -896,3 +896,4 @@ void audit_log(struct audit_context *ctx
audit_log_end(ab);
}
}
+
diff -uprN linux-2.6.13-rc3-mm1/kernel/auditsc.c linux-2.6.13-rc3-mm1-lspp_audit/kernel/auditsc.c
--- linux-2.6.13-rc3-mm1/kernel/auditsc.c 2005-07-18 15:20:35.000000000 -0500
+++ linux-2.6.13-rc3-mm1-lspp_audit/kernel/auditsc.c 2005-07-19 11:50:15.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;
@@ -167,6 +175,8 @@ struct audit_context {
#endif
};

+static const char *audit_macxattr;
+
/* Public API */
/* There are three lists of rules -- one to search at task creation
* time, one to search at syscall entry time, and another to search at
@@ -650,9 +660,11 @@ static inline void audit_free_names(stru
context->ino_count = 0;
#endif

- for (i = 0; i < context->name_count; i++)
+ for (i = 0; i < context->name_count; i++) {
if (context->names[i].name)
__putname(context->names[i].name);
+ kfree(context->names[i].security_context);
+ }
context->name_count = 0;
if (context->pwd)
dput(context->pwd);
@@ -751,6 +763,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, " scontext=%s", security_context);
+
+out:
+ kfree(security_context);
+ return;
+}
+
static void audit_log_task_info(struct audit_buffer *ab)
{
char name[sizeof(current->comm)];
@@ -777,6 +820,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)
@@ -848,6 +892,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);
+ break; }

}
audit_log_end(ab);
@@ -883,6 +932,10 @@ 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, " ocontext=%s",
+ context->names[i].security_context);
+ }
audit_log_end(ab);
}
}
@@ -1098,6 +1151,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)
@@ -1133,6 +1217,8 @@ 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,
@@ -1270,3 +1356,63 @@ 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);
+ 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_ATOMIC);
+ 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_SECURITY_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 = kmalloc(len, GFP_KERNEL);
+ if (!audit_macxattr)
+ return -ENOMEM;
+ memcpy((void *)audit_macxattr, (const void *)name, len);
+ return 0;
+}
diff -uprN linux-2.6.13-rc3-mm1/security/dummy.c linux-2.6.13-rc3-mm1-lspp_audit/security/dummy.c
--- linux-2.6.13-rc3-mm1/security/dummy.c 2005-07-18 15:20:36.000000000 -0500
+++ linux-2.6.13-rc3-mm1-lspp_audit/security/dummy.c 2005-07-18 16:35:02.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-rc3-mm1/security/selinux/hooks.c linux-2.6.13-rc3-mm1-lspp_audit/security/selinux/hooks.c
--- linux-2.6.13-rc3-mm1/security/selinux/hooks.c 2005-07-18 15:20:36.000000000 -0500
+++ linux-2.6.13-rc3-mm1-lspp_audit/security/selinux/hooks.c 2005-07-19 10:56:44.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)
+ goto getsecurity_exit;
+
+ if (size < len) {
+ kfree(context);
+ return -ERANGE;
+ }
+ 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)
@@ -2232,30 +2261,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,
@@ -3360,6 +3372,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));
+}
+
static int selinux_sk_alloc_security(struct sock *sk, int family, int priority)
{
return sk_alloc_security(sk, family, priority);
@@ -4025,6 +4044,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)
{
@@ -4066,8 +4092,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) {
@@ -4076,9 +4101,6 @@ static int selinux_getprocattr(struct ta
return error;
}

- if (!size)
- return -ERANGE;
-
tsec = p->security;

if (!strcmp(name, "current"))
@@ -4095,16 +4117,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,
@@ -4299,6 +4312,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,
@@ -4379,6 +4393,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 {
Dustin Kirkland
2005-07-22 16:20:32 UTC
Permalink
Post by Dustin Kirkland
The attached patch contains functionality specified by the labeled
security protection profile--basically appending object context and
subject context labels to audit records.
Here's a few examples of how the new audit messages look. Notice the
"ocontext" and "scontext" fields appended to the end of the record.

Eventually, the audit FVT test cases would need to change slightly to
account for the additional information.

But in a private conversation with David Woodhouse, he spoke of creating
a newly branched GIT tree containing post-RHEL4u2 changes--of which this
should be one. This functionality is *not* required for CAPP. Rather,
we're proactively working this upstream now in anticipation of LSPP.

:-Dustin



----
# cat /var/log/audit/audit.log | grep context | tail

type=SYSCALL msg=audit(1121807986.280:1091967): arch=40000003 syscall=5
success=yes exit=3 a0=d618c2 a1=8000 a2=0 a3=8000 items=1 pid=2816
auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0
comm="id" exe="/usr/bin/id" scontext=system_u:system_r:initrc_t

type=PATH msg=audit(1121807986.280:1091967): item=0
name="/proc/self/attr/current" flags=101 inode=184549398 dev=00:03
mode=0100666 ouid=0 ogid=0 rdev=00:00
ocontext=system_u:system_r:initrc_t

type=SYSCALL msg=audit(1121807986.280:1092004): arch=40000003 syscall=5
success=yes exit=3 a0=80f81f0 a1=8000 a2=0 a3=8000 items=1 pid=2810
auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0
comm="K87auditd" exe="/bin/bash" scontext=system_u:system_r:initrc_t

type=PATH msg=audit(1121807986.280:1092004): item=0
name="/etc/sysconfig/auditd" flags=101 inode=245774 dev=03:02
mode=0100640 ouid=0 ogid=0 rdev=00:00 ocontext=system_u:object_r:etc_t

type=SYSCALL msg=audit(1121807986.284:1092061): arch=40000003 syscall=5
success=yes exit=3 a0=81113a0 a1=8000 a2=0 a3=8000 items=1 pid=2810
auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0
comm="K87auditd" exe="/bin/bash" scontext=system_u:system_r:initrc_t

type=PATH msg=audit(1121807986.284:1092061): item=0
name="/var/run/auditd.pid" flags=101 inode=2113716 dev=03:02
mode=0100644 ouid=0 ogid=0 rdev=00:00
ocontext=root:object_r:auditd_var_run_t

type=SYSCALL msg=audit(1121807986.284:1092099): arch=40000003 syscall=5
success=yes exit=3 a0=8111c48 a1=8241 a2=1b6 a3=8241 items=1 pid=2810
auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0
comm="K87auditd" exe="/bin/bash" scontext=system_u:system_r:initrc_t

type=PATH msg=audit(1121807986.284:1092099): item=0 name="/dev/null"
flags=310 inode=506 dev=00:0f mode=040755 ouid=0 ogid=0 rdev=00:00
ocontext=system_u:object_r:device_t

...
David Woodhouse
2005-07-22 17:46:56 UTC
Permalink
Post by Dustin Kirkland
I expect at least one section of this code to generate some animated
discussion. This code utilizes "static inline" function definitions
rather than "#define" macros, as per Documentation/SubmittingPatches
lines 328-372 and Documentation/CodingStyle line 358. This is
inconsistent with the rest of the code in include/linux/audit.h, so I
suspect someone will have to give, in the interest of consistency.
Please advise.
In this case the one-line #define is probably nicer. Let's stick with
that.

Please use kstrdup() in audit_set_macxattr().

Other than that it looks sane at first glance. Steve had some comments
to make, I think, but he's at OLS without a laptop so that may be
delayed...
--
dwmw2
Steve Grubb
2005-07-24 15:48:32 UTC
Permalink
Steve had some comments to make, I think, but he's at OLS without a laptop
so that may be delayed...
This is true. There are some bugs in the patch. However, we really haven't
discussed what the design will look like going forward in LSPP, so this is a
little premature.

I want to spend a little time drafting up what we need to do and the order in
which we integrate the pieces. Another thing that I insist on in the next
round of development is to have a config file for LSPP *before* we start
coding. I want to make sure that we all agree on how the config looks and
that it can truly do the job instead of waiting until the end of development
and seeing if we can do what we intended.

For example, in the current CAPP system, there is a serious problem pointed
out by Amy. The problem is that some architectures have socketcall and others
do not. This means that there is the possibility that we have to have per
arch config files. The solution, I believe, is to make auditctl not load
rules for invalid arches. This way one script can be written and auditctl
will be smarter about what it sends to the kernel.

-Steve
Dustin Kirkland
2005-07-25 18:28:23 UTC
Permalink
Post by Steve Grubb
This is true. There are some bugs in the patch. However, we really haven't
discussed what the design will look like going forward in LSPP, so this is a
little premature.
Bugs in the patch? I don't doubt you, I'm just curious... Can you
cite?
Post by Steve Grubb
I want to spend a little time drafting up what we need to do and the order in
which we integrate the pieces. Another thing that I insist on in the next
round of development is to have a config file for LSPP *before* we start
coding. I want to make sure that we all agree on how the config looks and
that it can truly do the job instead of waiting until the end of development
and seeing if we can do what we intended.
Ok, no problem. Are you ready to start talking about LSPP now, or is
CAPP still taking all of your time?


:-Dustin
Steve Grubb
2005-07-27 16:17:22 UTC
Permalink
Post by Dustin Kirkland
Bugs in the patch? I don't doubt you, I'm just curious... Can you
cite?
I don't have lots of time right now. But, I think there should be some checks
for selinux_enabled.

-Steve
Steve Grubb
2005-07-28 14:49:32 UTC
Permalink
Bugs in the patch?  I don't doubt you, I'm just curious...  Can you
cite?
Another issue...the patch is too eager to call audit_panic(). It is more
correct to fail the syscall and let the app handle failure than bring the
machine to its knees.

-Steve
Timothy R. Chavez
2005-07-28 15:27:39 UTC
Permalink
Post by Steve Grubb
Bugs in the patch?  I don't doubt you, I'm just curious...  Can you
cite?
Another issue...the patch is too eager to call audit_panic(). It is more
correct to fail the syscall and let the app handle failure than bring the
machine to its knees.
-Steve
But audit_panic() doesn't just panic the system or it doesn't have to at
least. You're able to set the 'audit_failure' such that when audit_panic()
is called it can fail silently, print to syslog, or panic the system.

-tim
Post by Steve Grubb
--
Linux-audit mailing list
http://www.redhat.com/mailman/listinfo/linux-audit
Steve Grubb
2005-07-28 15:49:52 UTC
Permalink
Post by Timothy R. Chavez
But audit_panic() doesn't just panic the system or it doesn't have to at
least.  You're able to set the 'audit_failure' such that when audit_panic()
is called it can fail silently, print to syslog, or panic the system.
Right, but audit_panic is reserved for use when the backlog overflows or rate
limit is too high. When you wrote the fs watch code, did you call audit_panic
when a buffer alloc failed? No, you failed the syscall. The behavior should
be consistent.

-Steve
Timothy R. Chavez
2005-07-28 16:12:02 UTC
Permalink
Post by Steve Grubb
Post by Timothy R. Chavez
But audit_panic() doesn't just panic the system or it doesn't have to at
least.  You're able to set the 'audit_failure' such that when audit_panic()
is called it can fail silently, print to syslog, or panic the system.
Right, but audit_panic is reserved for use when the backlog overflows or rate
limit is too high. When you wrote the fs watch code, did you call audit_panic
when a buffer alloc failed? No, you failed the syscall. The behavior should
be consistent.
Yeah, I'm thinking I should be calling audit_panic() instead. I think that the
correct way to handle such errors that occur _in_ the audit sub system. Also,
I fail silently if the audit_watch_notify() hook is called and it can not allocate
an memory to place on the audit context... the admin has no control over this.
At least with audit_panic they can specify how they want the system to fail.

Let's say our system is extremely stressed out and we fail a memory
allocation that's nonfatal... that record is missed but the system is still running
when really the system should probably panic (in a CAPP environment at least).
That's not presently doable with the fs watch code (should I be "eeking" right
now).

I suppose in a CAPP environment if a record cannot be generate the system
should be halted, right? Well with audit_panic the administrator has control
over that behavior.

-tim
Post by Steve Grubb
-Steve
--
Linux-audit mailing list
http://www.redhat.com/mailman/listinfo/linux-audit
Steve Grubb
2005-07-28 16:28:13 UTC
Permalink
Post by Timothy R. Chavez
Yeah, I'm thinking I should be calling audit_panic() instead.
I don't think so. There are many places in the kernel where failed memory
alloc results in -ENOMEM.
Post by Timothy R. Chavez
 Also, I fail silently if the audit_watch_notify() hook is called and it
can not allocate an memory to place on the audit context... the admin has
no control over this. At least with audit_panic they can specify how they
want the system to fail.
This is an exceptional condition. I would be very unhappy as an admin if I had
to constantly investigate why my machine had panic'd. I would rather the
machine stay alive and have the syscall fail. The user can retry and if
memory pressure has eased - we'll get the event.
Post by Timothy R. Chavez
Let's say our system is extremely stressed out and we fail a memory
allocation that's nonfatal... that record is missed but the system is still
running when really the system should probably panic (in a CAPP environment
at least). That's not presently doable with the fs watch code (should I be
"eeking" right now).
If the syscall failed due to audit system problem, the auditable event never
occurred. They were prevented. They should retry and hopefully the memory
situation has changed.
Post by Timothy R. Chavez
I suppose in a CAPP environment if a record cannot be generate the system
should be halted, right?
Or the action prevented.

-Steve
Timothy R. Chavez
2005-07-28 18:48:40 UTC
Permalink
Post by Steve Grubb
Post by Timothy R. Chavez
Yeah, I'm thinking I should be calling audit_panic() instead.
I don't think so. There are many places in the kernel where failed memory
alloc results in -ENOMEM.
Post by Timothy R. Chavez
 Also, I fail silently if the audit_watch_notify() hook is called and it
can not allocate an memory to place on the audit context... the admin has
no control over this. At least with audit_panic they can specify how they
want the system to fail.
This is an exceptional condition. I would be very unhappy as an admin if I had
to constantly investigate why my machine had panic'd. I would rather the
machine stay alive and have the syscall fail. The user can retry and if
memory pressure has eased - we'll get the event.
Post by Timothy R. Chavez
Let's say our system is extremely stressed out and we fail a memory
allocation that's nonfatal... that record is missed but the system is still
running when really the system should probably panic (in a CAPP environment
at least). That's not presently doable with the fs watch code (should I be
"eeking" right now).
If the syscall failed due to audit system problem, the auditable event never
occurred. They were prevented. They should retry and hopefully the memory
situation has changed.
How does it "retry"? If you do "mkdir /tmp/foo" and "foo" is being watched
and we failed to allocate the memory to place on the audit context, "foo" gets
created and no record is generated. This is my understanding at least (just
looking at the audit_notify_watch/auditfs_attach_wdata code).

-tim
Post by Steve Grubb
Post by Timothy R. Chavez
I suppose in a CAPP environment if a record cannot be generate the system
should be halted, right?
Or the action prevented.
-Steve
--
Linux-audit mailing list
http://www.redhat.com/mailman/listinfo/linux-audit
Steve Grubb
2005-07-28 19:13:45 UTC
Permalink
Post by Timothy R. Chavez
How does it "retry"?
If there is no memory, the operation should fail.
Post by Timothy R. Chavez
If you do "mkdir /tmp/foo" and "foo" is being watched
and we failed to allocate the memory to place on the audit context, "foo"
gets created and no record is generated.
mkdir should return -ENOMEM and the dir should not be created. You can't let
the directory be created if the intention was to watch for that and you can't
record the requested event. The user should see the operation failed and try
to make the directory again.

-Steve
Timothy R. Chavez
2005-07-28 19:25:52 UTC
Permalink
Post by Steve Grubb
Post by Timothy R. Chavez
How does it "retry"?
If there is no memory, the operation should fail.
Post by Timothy R. Chavez
If you do "mkdir /tmp/foo" and "foo" is being watched
and we failed to allocate the memory to place on the audit context, "foo"
gets created and no record is generated.
mkdir should return -ENOMEM and the dir should not be created. You can't let
the directory be created if the intention was to watch for that and you can't
record the requested event. The user should see the operation failed and try
to make the directory again.
To do this we'd need two hooks. One to allocate the watch info for the context
before the creation of the inode and then one to fill it out upon success or
free it on failure. Or, we can just use audit_panic :)

-tim
Post by Steve Grubb
-Steve
--
Linux-audit mailing list
http://www.redhat.com/mailman/listinfo/linux-audit
Steve Grubb
2005-07-28 19:45:45 UTC
Permalink
To do this we'd need two hooks.  One to allocate the watch info for the
context before the creation of the inode and then one to fill it out upon
success or free it on failure.  
Right sort of like a sql transaction. Create the data structures & commit or
rollback. But you could also handle rolling back any allocations should your
function fail.
Or, we can just use audit_panic :)
No. audit_panic is for when we have overflowed the backlog or hit a rate
limit. This is for when there is no other course of action possible. With the
watches, you could have returned an error. There was a course of action.

-Steve
Dustin Kirkland
2005-08-29 21:18:04 UTC
Permalink
I've combed through the responses to my original patch. Collected below
are a distilled view of the direct criticisms I can address.

Updated patch attached. In-line comments below.
Post by David Woodhouse
Post by Dustin Kirkland
I expect at least one section of this code to generate some animated
discussion. This code utilizes "static inline" function definitions
rather than "#define" macros, as per Documentation/SubmittingPatches
lines 328-372 and Documentation/CodingStyle line 358. This is
inconsistent with the rest of the code in include/linux/audit.h, so I
suspect someone will have to give, in the interest of consistency.
Please advise.
In this case the one-line #define is probably nicer. Let's stick with
that.
Ok, the static-inlines in linux/audit.h are now changed to #defines.
Post by David Woodhouse
Please use kstrdup() in audit_set_macxattr().
Done.
Post by David Woodhouse
Post by Dustin Kirkland
Bugs in the patch? I don't doubt you, I'm just curious... Can you
cite?
I don't have lots of time right now. But, I think there should be some checks
for selinux_enabled.
Hmmm... Steve: Can you point me to some places where you feel this
might be necessary?
Post by David Woodhouse
Another issue...the patch is too eager to call audit_panic(). It is more
correct to fail the syscall and let the app handle failure than bring the
machine to its knees.
audit_panic is reserved for use when the backlog overflows or rate
limit is too high. When you wrote the fs watch code, did you call audit_panic
when a buffer alloc failed? No, you failed the syscall. The behavior should
be consistent.
Ok, so the audit_panic() code seems to still be under discussion. One
thing that's important to realize is that audit_panic() does not
necessarily panic the kernel. Depending on the value of audit_failure,
it can 1) fail silently, 2) fail with only a KERN_ERR printk, or 3) it
can panic the kernel. Let's come to a consensus on how these failures
should be handled...


So have another look at this patch and please make some constructive
suggestions if the audit_panic() situations should be handled
differently. I'd like to push this for inclusion in David's tree as
soon as possible.

Thanks,
:-Dustin
Stephen Smalley
2005-08-29 21:28:01 UTC
Permalink
Post by Dustin Kirkland
Ok, so the audit_panic() code seems to still be under discussion. One
thing that's important to realize is that audit_panic() does not
necessarily panic the kernel. Depending on the value of audit_failure,
it can 1) fail silently, 2) fail with only a KERN_ERR printk, or 3) it
can panic the kernel. Let's come to a consensus on how these failures
should be handled...
As I understand it, Steve G was suggesting that when possible, it should
be propagating an error up the call chain, ultimately leading to an
error returned from the syscall, rather than doing any of the three
options listed above. That makes sense when collecting data for the
audit prior to the operation being performed, e.g.
audit_ipc_security_context. It doesn't make sense when attempting to
audit a completed syscall, e.g. audit_log_task_security_context, as the
operation has already completed.
--
Stephen Smalley
National Security Agency
Steve Grubb
2005-08-29 22:05:59 UTC
Permalink
That makes sense when collecting data for the audit prior to the operation
being performed, e.g. audit_ipc_security_context. It doesn't make sense when
attempting to audit a completed syscall, e.g.
audit_log_task_security_context, as the operation has already completed.
I completely agree.

And it is worthwhile to check the hook placement to see that we can fail the
syscall if needed. Meaning that there may be a hook right after the action is
performed. But all we are doing is collecting information. It might be moved
in front of the action. Not sure if there are any cases like this since I
haven't looked in depth.

-Steve
Timothy R. Chavez
2005-08-29 23:50:23 UTC
Permalink
Post by Stephen Smalley
Post by Dustin Kirkland
Ok, so the audit_panic() code seems to still be under discussion. One
thing that's important to realize is that audit_panic() does not
necessarily panic the kernel. Depending on the value of audit_failure,
it can 1) fail silently, 2) fail with only a KERN_ERR printk, or 3) it
can panic the kernel. Let's come to a consensus on how these failures
should be handled...
As I understand it, Steve G was suggesting that when possible, it should
be propagating an error up the call chain, ultimately leading to an
error returned from the syscall, rather than doing any of the three
options listed above. That makes sense when collecting data for the
audit prior to the operation being performed, e.g.
audit_ipc_security_context. It doesn't make sense when attempting to
audit a completed syscall, e.g. audit_log_task_security_context, as the
operation has already completed.
It gets muddy when collecting information _during_ the operation, however.
Avoiding use of audit_panic in the file system, could get complicated. The
reason we'd want to avoid using audit_panic boils down to the potential
for lost records. If we fail silently on an -ENOMEM when trying to allocate
the audit aux data, the syscall continues on, the file system changes,
and we have no record of that change. If we fail with a panic, the file
system might have already changed before the panic, and when we
reboot and check the log, there'll be no record corresponding to that
change.

Now, what might be possible, is that we allocate the aux audit data before
the syscall can make any changes to the file system. This way, if the audit
subsystem is unable to allocate memory, it can fail without any inconsistent
behavior occurring (ie: failing out of a mkdir with -ENOMEM because of audit,
after the the directory has already been created) and prevent the loss of
an audit record by preventing the action itself.

In terms of audit, pre-allocation seems pretty darn good. If we can't audit,
we prevent the action from occuring. Seems right in line with the various
*PPs. But, I have to wonder if there's not a better solution out there? Any
suggestions?

If we went with audit panic, there's no guarantee that the change ever
makes it to disk before we panic, which means the auditable event is
effectively prevented. This is probably file system specific and an
unreliable assumption at best. But, I have to wonder what the state
of the system would be if we were getting these -ENOMEMs and how
effective pre-allocation would be. Let's say we're heavily loaded and
we're oscillating such that one second we have memory available
and the next we don't. We may get the pre-allocation, but then
what guarantee do we have that it'll get across the netlink into the
log?

Also, with the catch-all hooks in place, there could be multiple watches
collected in the same syscall, making it impossible to predict how much
memory to pre-allocate.

If we're allowed to lose some records under these conditions, then
it seems like panicing is the right solution. But if we're not, the
solution seems pretty muddy.

David and Klaus, I certainly would appreciate your inputs on the matter.

-tim
Steve Grubb
2005-08-29 21:57:24 UTC
Permalink
Post by Dustin Kirkland
Hmmm... Steve: Can you point me to some places where you feel this
might be necessary?
Any function that hooks the main part of the kernel and does auditing. For
example, audit_ipc_security_context. There's more...
Post by Dustin Kirkland
One thing that's important to realize is that audit_panic() does not
necessarily panic the kernel. Depending on the value of audit_failure,
it can 1) fail silently, 2) fail with only a KERN_ERR printk, or 3) it
can panic the kernel.
Which is inadequate - failing the syscall might also be appropriate and its
not an option in the 3 you mentioned. In the case of printk & ignore...the
syscall passes.
Post by Dustin Kirkland
I'd like to push this for inclusion in David's tree as soon as possible.
I need to wait until I'm caught up to really review this patch. I still think
its too early for LSPP discussion since we haven't set out the requirements
for what we are going to do in this round of development. Its likely to be
next week before I can look at this closely.

I still think it calls audit_panic too easy. How does SE Linux AVC messages
get handled when it fails looking up something? Does it call audit_panic or
try to output the number? I think they should both match.

BTW, does audit_set_macxattr need to NULL check after kstrdup?

-Steve
Stephen Smalley
2005-08-30 15:06:08 UTC
Permalink
Post by Steve Grubb
I still think it calls audit_panic too easy. How does SE Linux AVC messages
get handled when it fails looking up something? Does it call audit_panic or
try to output the number? I think they should both match.
Originally, avc_audit was calling printk and assumed that it would
always succeed. Now, avc_audit uses the audit_log* functions and just
returns silently if audit_log_start fails, consistent with the current
audit system interface to the rest of the kernel. Failures upon other
audit_log* functions give no indication that anything went wrong to the
caller. It would take a fairly major reworking of the audit system code
and its interface to propagate errors up the entire call chain to even
reach avc_audit rather than just calling audit_log_lost/audit_panic and
proceeding. If you were going to do that, I'd think you would want a
new failure mode in audit_panic that causes it to optionally printk a
warning message and return an error code, and alter audit_panic and all
callers to propagate error codes up the call chain.

For failures outside of the audit system, avc_audit falls back to
logging numeric values if it cannot map to a string (for both access
vectors in avc_dump_av and for SIDs/contexts in avc_dump_query, although
the latter is problematic as SIDs are private to the kernel and have no
meaning in userspace). For files it always logs the device and inode
information regardless of whether it can log a path, as you want that
information in all cases.

If avc_audit received errors from the audit system, it could also be
changed to return errors to its callers, most of which go through
avc_has_perm. avc_has_perm could then be changed to propagate an error
from either avc_has_perm_noaudit or avc_audit to the caller (the hook
function), which typically propagates errors from avc_has_perm already.
--
Stephen Smalley
National Security Agency
Dustin Kirkland
2005-08-30 15:18:42 UTC
Permalink
Post by Steve Grubb
Post by Dustin Kirkland
Hmmm... Steve: Can you point me to some places where you feel this
might be necessary?
Any function that hooks the main part of the kernel and does auditing. For
example, audit_ipc_security_context. There's more...
Ok, I'll look around.
Post by Steve Grubb
Post by Dustin Kirkland
One thing that's important to realize is that audit_panic() does not
necessarily panic the kernel. Depending on the value of audit_failure,
it can 1) fail silently, 2) fail with only a KERN_ERR printk, or 3) it
can panic the kernel.
Which is inadequate - failing the syscall might also be appropriate and its
not an option in the 3 you mentioned. In the case of printk & ignore...the
syscall passes.
Ok, then anyone who disagrees with failing the syscall speak up now...
If this is the preferred operation, please say so. Klaus--I, too, am
calling for your input.
Post by Steve Grubb
Post by Dustin Kirkland
I'd like to push this for inclusion in David's tree as soon as possible.
I need to wait until I'm caught up to really review this patch.
I still think its too early for LSPP discussion since we haven't set out the requirements
for what we are going to do in this round of development. Its likely to be
next week before I can look at this closely.
Ok, well I'm hoping to show some progress here on my side. I've been in
a holding pattern for a month since I originally sent this before OLS.
Post by Steve Grubb
I still think it calls audit_panic too easy. How does SE Linux AVC messages
get handled when it fails looking up something? Does it call audit_panic or
try to output the number? I think they should both match.
/me defers to Stephen's response...
Post by Steve Grubb
BTW, does audit_set_macxattr need to NULL check after kstrdup?
I've looked at about a dozen calls to kstrdup() around the kernel, most
of which do not perform a NULL check, though some do. David offered the
suggestion of using kstrdup(), perhaps he has a recommendation?


:-Dustin
Stephen Smalley
2005-08-30 16:18:18 UTC
Permalink
Post by Dustin Kirkland
Ok, then anyone who disagrees with failing the syscall speak up now...
If this is the preferred operation, please say so.
I think we need to think through how this would work. There are
multiple options, e.g.
1) Only audit-related interfaces for storing audit context information
that are called during syscall processing prior to any user-visible
state changes will handle failures in this manner. Those functions will
_not_ call audit_panic and will return an error to the caller, and those
errors need to be propagated back to userspace. It may be desirable to
have these functions log a warning (via printk) prior to returning the
error so that there is also a record of the issue for perusal by an
admin. This should likely be configurable via auditctl.
2) All audit interfaces and functions will be reworked down to the
audit_panic level, with audit_panic changed to return a value and
internally changed to check new audit_failure flags to see whether it
should return an error or just 0, and if returning an error, whether it
should return the error silently or also log a message via printk. All
call chains leading to audit_panic will then be changed to propagate
errors from it upward to the original caller.
--
Stephen Smalley
National Security Agency
Dustin Kirkland
2005-08-30 18:21:14 UTC
Permalink
Forwarding a note from Mounir which did not copy linux-audit...
Post by Dustin Kirkland
Ok, then anyone who disagrees with failing the syscall speak up now...
If this is the preferred operation, please say so. Klaus--I, too, am
calling for your input.
While it can be one of the configurable options for panic, failing the
system call is not enough in all cases. Due to the requirement that the
system must not loose audit record, the system must panic, when
resources are exhausted.
Refer to the linux-audit archive of January 2005.
https://www.redhat.com/archives/linux-audit/2005-January/msg00030.html
Similar issue was discussed for what to do when audit log is full and
what to do when kernel resources are exhausted.
Timothy R. Chavez
2005-08-30 18:43:20 UTC
Permalink
Post by Dustin Kirkland
Forwarding a note from Mounir which did not copy linux-audit...
Post by Dustin Kirkland
Ok, then anyone who disagrees with failing the syscall speak up now...
If this is the preferred operation, please say so. Klaus--I, too, am
calling for your input.
While it can be one of the configurable options for panic, failing the
system call is not enough in all cases. Due to the requirement that the
system must not loose audit record, the system must panic, when
resources are exhausted.
But that's just it, if you're not careful when issueing a panic, there _is_ a
potential of record lossage. Take for instance this case:

We're in context of a "mkdir()" system call. We've determined that
this inode is watched, so then we allocate audit_aux_data memory
for it to place on the audit context. The only problem is that we fail
this memory allocation. Since the inode has already been created,
if we panic the system, there will be no record of the transaction.

I have to wonder if the inode even makes it to disk before we panic. But
this assumption is probably a bit shakey.

Refer to: Message-Id: <***@us.ibm.com>

-tim
Post by Dustin Kirkland
Refer to the linux-audit archive of January 2005.
https://www.redhat.com/archives/linux-audit/2005-January/msg00030.html
Similar issue was discussed for what to do when audit log is full and
what to do when kernel resources are exhausted.
Amy Griffis
2005-08-30 20:29:50 UTC
Permalink
Post by Timothy R. Chavez
But that's just it, if you're not careful when issueing a panic, there _is_ a
We're in context of a "mkdir()" system call. We've determined that
this inode is watched, so then we allocate audit_aux_data memory
for it to place on the audit context. The only problem is that we fail
this memory allocation. Since the inode has already been created,
if we panic the system, there will be no record of the transaction.
This situation could be avoided in the current implementation by
making use of the 20 statically allocated audit_names structs included
in the audit_context.

Amy
Amy Griffis
2005-08-30 00:36:31 UTC
Permalink
Post by Dustin Kirkland
I'd like to push this for inclusion in David's tree as soon as
possible.
Have we determined our base kernel for future development? Will
different kernels be used for different project pieces?

For instance, if audit becomes an Inotify consumer, I'd prefer to work
off of an upstream kernel to follow any Inotify changes. I don't know
if that's appropriate for LSPP development.

Amy
Steve Grubb
2005-08-30 01:38:22 UTC
Permalink
Have we determined our base kernel for future development?  Will
different kernels be used for different project pieces?
We'll be working off of rawhide. I think we'll need a loosely synced repo so
that we have some measure of stability.

-Steve
Dustin Kirkland
2005-08-30 14:41:14 UTC
Permalink
Post by Steve Grubb
Post by Amy Griffis
Have we determined our base kernel for future development? Will
different kernels be used for different project pieces?
We'll be working off of rawhide. I think we'll need a loosely synced repo so
that we have some measure of stability.
When I originally asked David about this patch, he asked me to work
against the latest -mm upstream release. I'll port to another tree, but
I agree with Amy: we should agree on a branch to work from.

:-Dustin
Steve Grubb
2005-08-30 15:04:52 UTC
Permalink
Post by Dustin Kirkland
When I originally asked David about this patch, he asked me to work
against the latest -mm upstream release. I'll port to another tree, but
I agree with Amy: we should agree on a branch to work from.
I think the patches should be developed to the -mm tree, but we will need to
test them in something more stable. When we did the audit development, we
picked an "in house" kernel so we could make changes and get everyone to test
it. The pure -mm tree may be too unstable to get people to test with it and
use on a daily basis.

My guess is that there is going to be about 30 people working and testing
various pieces. While some people don't mind being at the cutting edge and
can rescue themselves if something goes wrong...not everyone can. We need
something that is a little more stable for a group that big to be working
with.

Also think about bug reporting. When someone finds a bug, we'll need to be on
the same kernel to reproduce it and make fixes.

Andrew also sent a note to lkml saying that too many of the patches he was
getting were being immediately followed up with a correction to it. This
means the patches did not get enough testing before being sent. I really hope
that we test the patches for a little while and make corrections before
sending it upstream.

Speaking of which, you guys probably have no idea about the amount of problems
userspace has had trying to support broken and buggy old kernels. I want to
see whole units of work get sent upstream as a unit as much as possible. For
example, the netlink comm had 2 major revisions while we worked on it. I now
have 3 different communication techniques to support. What's worse, I have no
way of telling which method is being used.

-Steve
Amy Griffis
2005-09-03 05:19:33 UTC
Permalink
Hi Dustin,
Post by Dustin Kirkland
Updated patch attached.
Some comments inline.
Post by Dustin Kirkland
diff -uprN linux-2.6.13-rc6-mm2/include/linux/audit.h linux-2.6.13-rc6-mm2-lspp_audit/include/linux/audit.h
--- linux-2.6.13-rc6-mm2/include/linux/audit.h 2005-08-29 11:32:14.000000000 -0500
+++ linux-2.6.13-rc6-mm2-lspp_audit/include/linux/audit.h 2005-08-29 10:44:08.000000000 -0500
@@ -68,6 +68,7 @@
#define AUDIT_CONFIG_CHANGE 1305 /* Audit system configuration change */
#define AUDIT_SOCKADDR 1306 /* sockaddr copied as syscall arg */
#define AUDIT_CWD 1307 /* Current working directory */
+#define AUDIT_SECURITY_CONTEXT 1350 /* security context */
#define AUDIT_AVC 1400 /* SE Linux avc denial or grant */
#define AUDIT_SELINUX_ERR 1401 /* Internal SE Linux Errors */
@@ -238,6 +239,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 +258,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(p) ({ 0; })
+#define audit_set_macxattr(n) ({ 0; })
#endif
#ifdef CONFIG_AUDIT
@@ -283,6 +288,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 +299,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-lspp_audit/include/linux/security.h
--- linux-2.6.13-rc6-mm2/include/linux/security.h 2005-08-29 11:32:16.000000000 -0500
+++ linux-2.6.13-rc6-mm2-lspp_audit/include/linux/security.h 2005-08-29 10:37:50.000000000 -0500
@@ -792,6 +792,11 @@ struct swap_info_struct;
* Return 0 if permission is granted.
+ * Copy the security label associated with the ipc object into
+ * number of bytes used/required on success.
*
* Security hooks for individual messages held in System V IPC message queues
@@ -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-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.
Post by Dustin Kirkland
+
+ 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.
Post by Dustin Kirkland
+ goto out_unlock_up;
+ }
+
err = -EIDRM;
if (msg_checkid(msq,msqid))
goto out_unlock_up;
diff -uprN linux-2.6.13-rc6-mm2/ipc/sem.c linux-2.6.13-rc6-mm2-lspp_audit/ipc/sem.c
--- linux-2.6.13-rc6-mm2/ipc/sem.c 2005-08-29 11:32:16.000000000 -0500
+++ linux-2.6.13-rc6-mm2-lspp_audit/ipc/sem.c 2005-08-29 10:37:51.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-lspp_audit/ipc/shm.c
--- linux-2.6.13-rc6-mm2/ipc/shm.c 2005-08-29 11:32:16.000000000 -0500
+++ linux-2.6.13-rc6-mm2-lspp_audit/ipc/shm.c 2005-08-29 10:37:51.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-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
@@ -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,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?

Does hooking ipcperms cover all the ipc operations where we need the
security context?
Post by Dustin Kirkland
+
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-lspp_audit/kernel/audit.c
--- linux-2.6.13-rc6-mm2/kernel/audit.c 2005-08-29 11:32:16.000000000 -0500
+++ linux-2.6.13-rc6-mm2-lspp_audit/kernel/audit.c 2005-08-29 11:29:16.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)
{
@@ -893,3 +893,4 @@ void audit_log(struct audit_context *ctx
audit_log_end(ab);
}
}
+
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
@@ -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;
+};
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. Also, the security_context_len field is
unused.
Post by Dustin Kirkland
+
struct audit_aux_data_ipcctl {
struct audit_aux_data d;
struct ipc_perm p;
@@ -167,6 +175,8 @@ struct audit_context {
#endif
};
+static const char *audit_macxattr;
+
/* Public API */
/* There are three lists of rules -- one to search at task creation
* time, one to search at syscall entry time, and another to search at
@@ -670,9 +680,11 @@ static inline void audit_free_names(stru
context->ino_count = 0;
#endif
- for (i = 0; i < context->name_count; i++)
+ for (i = 0; i < context->name_count; i++) {
if (context->names[i].name)
__putname(context->names[i].name);
+ kfree(context->names[i].security_context);
+ }
context->name_count = 0;
if (context->pwd)
dput(context->pwd);
@@ -771,6 +783,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, " scontext=%s", security_context);
+
+ kfree(security_context);
+ return;
+}
+
static void audit_log_task_info(struct audit_buffer *ab)
{
char name[sizeof(current->comm)];
@@ -797,6 +840,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)
@@ -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.
Post by Dustin Kirkland
+ break; }
}
audit_log_end(ab);
@@ -903,6 +952,10 @@ 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, " ocontext=%s",
+ context->names[i].security_context);
+ }
audit_log_end(ab);
}
}
@@ -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.
Post by Dustin Kirkland
+ 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 +1237,8 @@ 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,
@@ -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.
Post by Dustin Kirkland
+ if (!ax) {
+ audit_panic("memory allocation error in audit_ipc_security_context");
Again, don't think audit_panic is needed.
Post by Dustin Kirkland
+ 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_ATOMIC);
+ 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_SECURITY_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)
+{
+ if (audit_macxattr)
+ return -EINVAL;
+
+ audit_macxattr = kstrdup(name, GFP_KERNEL);
+ return 0;
+}
diff -uprN linux-2.6.13-rc6-mm2/security/dummy.c linux-2.6.13-rc6-mm2-lspp_audit/security/dummy.c
--- linux-2.6.13-rc6-mm2/security/dummy.c 2005-08-29 11:32:17.000000000 -0500
+++ linux-2.6.13-rc6-mm2-lspp_audit/security/dummy.c 2005-08-29 10:37:51.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-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.
Post by Dustin Kirkland
+ goto getsecurity_exit;
+
+ if (size < len) {
+ kfree(context);
+ return -ERANGE;
Use getsecurity_exit here.
Post by Dustin Kirkland
+ }
+ memcpy(buffer, context, len);
+
+ 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,
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.
Post by Dustin Kirkland
+
static int selinux_sk_alloc_security(struct sock *sk, int family, int priority)
{
return sk_alloc_security(sk, family, priority);
@@ -4027,6 +4046,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 +4094,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 +4103,6 @@ static int selinux_getprocattr(struct ta
return error;
}
- if (!size)
- return -ERANGE;
-
tsec = p->security;
if (!strcmp(name, "current"))
@@ -4097,16 +4119,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 +4314,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 +4395,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 {
--
Linux-audit mailing list
http://www.redhat.com/mailman/listinfo/linux-audit
Dustin Kirkland
2005-10-07 18:24:13 UTC
Permalink
I'm addressing Amy's concerns and attaching an updated patch with the
editions discussed inline.
Post by Amy Griffis
Some comments inline.
Post by Dustin Kirkland
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.
Post by Amy Griffis
Post by Dustin Kirkland
+
+ 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;
}
Post by Amy Griffis
Post by Dustin Kirkland
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.
Post by Amy Griffis
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.
Post by Amy Griffis
Post by Dustin Kirkland
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.
Post by Amy Griffis
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.
Post by Amy Griffis
Post by Dustin Kirkland
@@ -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.
Post by Amy Griffis
Post by Dustin Kirkland
@@ -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.
Post by Amy Griffis
Post by Dustin Kirkland
@@ -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.
Post by Amy Griffis
Post by Dustin Kirkland
+ 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...
Post by Amy Griffis
Post by Dustin Kirkland
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.
Post by Amy Griffis
Post by Dustin Kirkland
+ 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.
Post by Amy Griffis
Post by Dustin Kirkland
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
Chris Wright
2005-10-07 21:43:11 UTC
Permalink
Post by Dustin Kirkland
I'm addressing Amy's concerns and attaching an updated patch with the
editions discussed inline.
(Note: as mentioned on IRC, patch inline as well please).
Post by Dustin Kirkland
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;
* Return 0 if permission is granted.
+ * Copy the security label associated with the ipc object into
+ * number of bytes used/required on success.
Boy i don't like these kind of interfaces...it's racy, etc..
Post by Dustin Kirkland
* Security hooks for individual messages held in System V IPC message queues
@@ -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;
+ }
+
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.
Post by Dustin Kirkland
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;
+ }
+
Ditto
Post by Dustin Kirkland
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;
Ditto
Post by Dustin Kirkland
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);
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?
Post by Dustin Kirkland
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);
+
+ 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);
Stack var is cheap, and might be easier to read ...
Post by Dustin Kirkland
+ 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.
Post by Dustin Kirkland
+ 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
Post by Dustin Kirkland
/* 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;
Leaks ax.
Post by Dustin Kirkland
+ }
+
+ 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.

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;
Post by Dustin Kirkland
+
+/* 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.
Post by Dustin Kirkland
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.
Post by Dustin Kirkland
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;
That's an interface change
Post by Dustin Kirkland
+ 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);
+
+ 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));
Parens not needed
Post by Dustin Kirkland
}
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));
same here.
Post by Dustin Kirkland
+}
+
/* 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));
Ditto
Post by Dustin Kirkland
}
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 {
Dustin Kirkland
2005-10-18 22:24:41 UTC
Permalink
Post by Chris Wright
(Note: as mentioned on IRC, patch inline as well please).
My bad. I knew better... ;)
Post by Chris Wright
Post by Dustin Kirkland
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;
* Return 0 if permission is granted.
+ * Copy the security label associated with the ipc object into
+ * 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.
Post by Chris Wright
Post by Dustin Kirkland
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.
Post by Chris Wright
Post by Dustin Kirkland
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.
Post by Chris Wright
Post by Dustin Kirkland
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.
Post by Chris Wright
Post by Dustin Kirkland
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.
Post by Chris Wright
Post by Dustin Kirkland
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().
Post by Chris Wright
Post by Dustin Kirkland
+ 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.
Post by Chris Wright
Post by Dustin Kirkland
+ 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.
Post by Chris Wright
Post by Dustin Kirkland
@@ -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.
Post by Chris Wright
Post by Dustin Kirkland
+ }
+
+ 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.
Post by Chris Wright
You could avoid some overhead by doing it this way (flip allocations
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)
return ret;
Reworked as such. Slightly simplified.
Post by Chris Wright
Post by Dustin Kirkland
+
+/* 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().
Post by Chris Wright
Post by Dustin Kirkland
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.
Post by Chris Wright
Post by Dustin Kirkland
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;
Post by Chris Wright
Post by Dustin Kirkland
@@ -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.
Post by Chris Wright
Post by Dustin Kirkland
@@ -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.
Post by Chris Wright
Post by Dustin Kirkland
@@ -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,
Klaus Weidner
2005-10-12 23:04:56 UTC
Permalink
Post by Dustin Kirkland
I'm addressing Amy's concerns and attaching an updated patch with the
editions discussed inline.
In an IRC discussion about IPC object audit today, Chris Wright mentioned
that he's concerned about multiple or missing records and also general
code aesthetics.

I'm not very familiar with the code, but I think it may be an option to
put the hooks in the *_checkid() and *get() functions instead of hooking
ipcperm(), those seem to be used more consistently. It would mean a
minimal slowdown in non-permission-checking calls as a tradeoff for
a cleaner interface, assuming that this would indeed get rid of
duplication.

-Klaus
Dustin Kirkland
2005-10-13 05:30:14 UTC
Permalink
Post by Klaus Weidner
Post by Dustin Kirkland
I'm addressing Amy's concerns and attaching an updated patch with the
editions discussed inline.
In an IRC discussion about IPC object audit today, Chris Wright mentioned
that he's concerned about multiple or missing records and also general
code aesthetics.
I'm not very familiar with the code, but I think it may be an option to
put the hooks in the *_checkid() and *get() functions instead of hooking
ipcperm(), those seem to be used more consistently. It would mean a
minimal slowdown in non-permission-checking calls as a tradeoff for
a cleaner interface, assuming that this would indeed get rid of
duplication.
Stephen-

I'm curious about your take on this... The code is hooked in
ipcperms() and near the DAC checks mainly because of a discussion on
the (then closed) LSPP list on/around May 19, 2005. Just wondering if
you have any objections.

Thanks,
:-Dustin
Stephen Smalley
2005-10-13 13:05:22 UTC
Permalink
Post by Dustin Kirkland
Post by Klaus Weidner
In an IRC discussion about IPC object audit today, Chris Wright mentioned
that he's concerned about multiple or missing records and also general
code aesthetics.
I'm not very familiar with the code, but I think it may be an option to
put the hooks in the *_checkid() and *get() functions instead of hooking
ipcperm(), those seem to be used more consistently. It would mean a
minimal slowdown in non-permission-checking calls as a tradeoff for
a cleaner interface, assuming that this would indeed get rid of
duplication.
Stephen-
I'm curious about your take on this... The code is hooked in
ipcperms() and near the DAC checks mainly because of a discussion on
the (then closed) LSPP list on/around May 19, 2005. Just wondering if
you have any objections.
Leveraging ipcperms only seemed natural (for both LSM and audit), given
its wide (but admittedly incomplete and coarse-grained) coverage. I'm
not sure why the overlap/duplication is a concern for audit if it isn't
already a concern for the corresponding LSM hooks. In the SELinux case,
we chose to implement a coarse-grained check there even though we had
finer-grained checks in the other hooks just to ensure that all access
was mediated, because we had greater confidence that ipcperms would be
maintained and used in any further System V IPC development, whereas
fine-grained LSM hooks have a way of disappearing from the tree when the
underlying code is rewritten.

You'd have to audit (code audit) the current usage of *checkid to see
whether it is a suitable location for audit (security audit) purposes.
For sem, I see it being used in find_undo and exit_sem, and the latter
doesn't tolerate failure (BUG_ON) from it, so you'd have to adjust for
possible audit failures. For msg, it happens outside of the loop on a
msgsnd and msgrcv, unlike the permission checking, which might be ok for
audit (unless you are concerned about the IPC object being relabeled
during the potential sleep, but no interface exists for relabeling IPC
objects yet).
--
Stephen Smalley
National Security Agency
Chris Wright
2005-10-13 17:29:59 UTC
Permalink
Post by Stephen Smalley
Leveraging ipcperms only seemed natural (for both LSM and audit), given
its wide (but admittedly incomplete and coarse-grained) coverage. I'm
not sure why the overlap/duplication is a concern for audit if it isn't
already a concern for the corresponding LSM hooks.
The one difference is that the audit record is simpler. The LSM hooks are
fine grained enough to show distinction between call contexts. The audit
interface is just grabbing the label, so duplication would be pure waste.
My primary concern is code that looks like this:

msgctl {
case IPC_STAT:
audit...
case IPC_SET:
...
audit...

if (cmd == IPC_SET)
audit...

case IPC_SET:
...
}

So there's duplication (ugly from code POV) on IPC_SET, and there's no
clear rule for what's being audited (why not audit RMID, for example).
Granted, some of the ugliness comes from existing ipc code organization.
But we don't need to make it worse.

thanks,
-chris
Amy Griffis
2005-10-13 20:54:22 UTC
Permalink
Hi Dustin,
Post by Dustin Kirkland
I'm addressing Amy's concerns and attaching an updated patch with the
editions discussed inline.
Thanks.
Post by Dustin Kirkland
Post by Amy Griffis
Post by Dustin Kirkland
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.
If you look at audit_ipc_perms(), it fails the syscall for any audit
failures. I agree with you that we need a design for audit error
handling. But until we have that, we should stay consistent with the
current behavior, which is to fail the syscall when possible.

I see that the ipcperms() callers are throwing away the return code
and setting -EACCES for all failures. Even so, we should return
-ENOMEM, and hopefully they will be updated at some point to propagate
other errors. Of course we've also discussed hooking somewhere other
than ipcperms, so this might be moot.
Post by Dustin Kirkland
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.
Okay, I can take a look at improving the error handling when I get a
chance.
Post by Dustin Kirkland
Post by Amy Griffis
Post by Dustin Kirkland
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.
I can't think of a reason to make it generic other than to save
space. Since the other aux data structs are already allocated
dynamically, this approach is actually taking more space as well as
introducing the overhead of having to walk more elements in the aux
list.
Post by Dustin Kirkland
Post by Amy Griffis
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...
I don't see why we would want to add an unused field just to look
like another structure.
Post by Dustin Kirkland
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.
You added a security_context field to audit_names. So adding a
comparable field to audit_aux_data_ipcctl makes sense.
Post by Dustin Kirkland
Post by Amy Griffis
Post by Dustin Kirkland
@@ -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.
Saw it, thanks.
Post by Dustin Kirkland
Post by Amy Griffis
Post by Dustin Kirkland
+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,
Right, but it doesn't have to be void.
Post by Dustin Kirkland
as is audit_inode(),
audit_inode is void because up to this point, there haven't been any
errors to report. The memory has been pre-allocated.
Post by Dustin Kirkland
and it would be very difficult to propagate this error up to the
calling syscall, as has been suggested.
I don't see why it would be difficult. path_lookup returns an int, so
we could make audit_inode return an int if we need to.

By the way, have you run into any issues with allocating memory during
path_lookup?
Post by Dustin Kirkland
How then do we guarantee that we won't lose audit records in the
case where some part of audit_inode_security_context() fails?
We wouldn't lose records. Theoretically, the syscall would fail and
audit would log any information it had collected. But with -ENOMEM,
the system probably has other issues.
Post by Dustin Kirkland
Post by Amy Griffis
Post by Dustin Kirkland
+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);
<snip comments>
Post by Dustin Kirkland
Post by Amy Griffis
Post by Dustin Kirkland
+ 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...
audit_ipc_security_context returns an int and the calling functions
are propagating errors, so there should be no issue.
Post by Dustin Kirkland
Post by Amy Griffis
Post by Dustin Kirkland
+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.
Thanks. Just make sure to clarify that this patch is for collecting
security label context for inodes and ipc only, and I'll be happy. :-)

Amy
Debora Velarde
2005-07-28 18:34:58 UTC
Permalink
Post by Dustin Kirkland
Post by Dustin Kirkland
The attached patch contains functionality specified by the labeled
security protection profile--basically appending object context and
subject context labels to audit records.
Here's a few examples of how the new audit messages look. Notice the
"ocontext" and "scontext" fields appended to the end of the record.
Eventually, the audit FVT test cases would need to change slightly to
account for the additional information.
But in a private conversation with David Woodhouse, he spoke of creating
a newly branched GIT tree containing post-RHEL4u2 changes--of which this
should be one. This functionality is *not* required for CAPP. Rather,
we're proactively working this upstream now in anticipation of LSPP.
:-Dustin
----
# cat /var/log/audit/audit.log | grep context | tail
type=SYSCALL msg=audit(1121807986.280:1091967): arch=40000003 syscall=5
success=yes exit=3 a0=d618c2 a1=8000 a2=0 a3=8000 items=1 pid=2816
auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0
comm="id" exe="/usr/bin/id" scontext=system_u:system_r:initrc_t
type=PATH msg=audit(1121807986.280:1091967): item=0
name="/proc/self/attr/current" flags=101 inode=184549398 dev=00:03
mode=0100666 ouid=0 ogid=0 rdev=00:00
ocontext=system_u:system_r:initrc_t
type=SYSCALL msg=audit(1121807986.280:1092004): arch=40000003 syscall=5
success=yes exit=3 a0=80f81f0 a1=8000 a2=0 a3=8000 items=1 pid=2810
auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0
comm="K87auditd" exe="/bin/bash" scontext=system_u:system_r:initrc_t
type=PATH msg=audit(1121807986.280:1092004): item=0
name="/etc/sysconfig/auditd" flags=101 inode=245774 dev=03:02
mode=0100640 ouid=0 ogid=0 rdev=00:00 ocontext=system_u:object_r:etc_t
type=SYSCALL msg=audit(1121807986.284:1092061): arch=40000003 syscall=5
success=yes exit=3 a0=81113a0 a1=8000 a2=0 a3=8000 items=1 pid=2810
auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0
comm="K87auditd" exe="/bin/bash" scontext=system_u:system_r:initrc_t
type=PATH msg=audit(1121807986.284:1092061): item=0
name="/var/run/auditd.pid" flags=101 inode=2113716 dev=03:02
mode=0100644 ouid=0 ogid=0 rdev=00:00
ocontext=root:object_r:auditd_var_run_t
type=SYSCALL msg=audit(1121807986.284:1092099): arch=40000003 syscall=5
success=yes exit=3 a0=8111c48 a1=8241 a2=1b6 a3=8241 items=1 pid=2810
auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0
comm="K87auditd" exe="/bin/bash" scontext=system_u:system_r:initrc_t
type=PATH msg=audit(1121807986.284:1092099): item=0 name="/dev/null"
flags=310 inode=506 dev=00:0f mode=040755 ouid=0 ogid=0 rdev=00:00
ocontext=system_u:object_r:device_t
The audit record changes are okay as long as they are made post RHEL4 U2.
Amy Griffis
2005-07-28 19:03:00 UTC
Permalink
Hi Dustin,

I have some comments about this patch as well, but I think I'll
hold them until we discuss the LSPP audit requirements. As Steve
previously mentioned, it's really not appropriate to be looking at
code when we haven't yet discussed what needs to be done.

Dustin Kirkland wrote: [Thu Jul 21 2005, 11:48:41AM EDT]
Post by Dustin Kirkland
The attached patch contains functionality specified by the labeled
security protection profile--basically appending object context and
subject context labels to audit records.
If you have already researched the requirements, please include a
listing with your patch, along with an explanation of how your patch
meets those requirements. There is more to it than "basically
appending object context and subject context labels to audit records".

If you haven't done any investigation, let us know, so someone can
work up a first draft of the requirements for us to discuss.

Thanks,
Amy
Dustin Kirkland
2005-07-28 19:59:49 UTC
Permalink
Post by Amy Griffis
I have some comments about this patch as well, but I think I'll
hold them until we discuss the LSPP audit requirements. As Steve
previously mentioned, it's really not appropriate to be looking at
code when we haven't yet discussed what needs to be done.
I was trying the "release early, release often" approach ;)
Post by Amy Griffis
If you have already researched the requirements, please include a
listing with your patch, along with an explanation of how your patch
meets those requirements. There is more to it than "basically
appending object context and subject context labels to audit records".
If you haven't done any investigation, let us know, so someone can
work up a first draft of the requirements for us to discuss.
This isn't exactly re-designing audit from the ground up... It's adding
information to existing audit records, beyond what CAPP requires.

See the LSPP specification, section 5.1.1.2(b), copied here for your
convenience:

5.1 Security Audit (FAU)
5.1.1 Audit Data Generation (FAU_GEN.1)
5.1.1.1
The TSF shall be able to generate an audit record of the auditable
events listed in column “Event” of Table 1 (Auditable Events). This
includes all auditable events for the basic level of audit, except
FIA_UID.1’s user identity during failures.
5.1.1.2
The TSF shall record within each audit record at least the following
information:
a) Date and time of the event, type of event, subject identity, and the
outcome
b) The sensitivity labels of subjects, objects, or information
involved; and
c) The additional information specified in the “Details” column of
Table 1 (Auditable Events).

The patch submitted attempts to add (b) beyond what CAPP audit already
provides. I was hoping for feedback on where the patch falls short
accomplishing this. If you want to have a design discussion first,
let's begin.



:-Dustin
Amy Griffis
2005-07-28 21:45:26 UTC
Permalink
Dustin Kirkland wrote: [Thu Jul 28 2005, 03:59:49PM EDT]
If you want to have a design discussion first, let's begin.
Let's start with requirements. :-)

I'm doing a first-pass of the requirements based on my reading of the
LSPP spec. I will post it shortly.

Amy
Steve Grubb
2005-09-26 19:00:39 UTC
Permalink
Post by Dustin Kirkland
The attached patch contains functionality specified by the labeled
security protection profile--basically appending object context and
subject context labels to audit records.
Lets use the following audit message number ranges for the next round of
development:

1500 - 1599 kernel LSPP events
1600 - 1699 user space generated LSPP events
1700 - 1799 kernel crypto events
1800 - 1899 user space crypto events
1900 - 1999 future use (maybe integrity labels and related events)
2100 - 2199 user space anomaly records
2200 - 2299 user space actions taken in response to anomalies


I'd also like to suggest that this patch collect 2 kinds of contexts, subject
and object. Subject being the context associated with the caller, object
being whatever system object that is being accessed. There can be more than
one object in the syscall. I'm undecided about whether they should be all in
1 record or each a separate record in the same event. This would mean taking
1500 as subject label and 1501 as object label.

-Steve
Timothy R. Chavez
2005-09-26 19:28:53 UTC
Permalink
Post by Steve Grubb
Post by Dustin Kirkland
The attached patch contains functionality specified by the labeled
security protection profile--basically appending object context and
subject context labels to audit records.
Lets use the following audit message number ranges for the next round of
1500 - 1599 kernel LSPP events
1600 - 1699 user space generated LSPP events
1700 - 1799 kernel crypto events
1800 - 1899 user space crypto events
1900 - 1999 future use (maybe integrity labels and related events)
Maybe I missed it... What's the 2000 - 2099 block reserved for again? I see
AUDIT_KERNEL at 2000, but I'm looking at an audit git tree that's not been
updated for over a month.
Post by Steve Grubb
2100 - 2199 user space anomaly records
2200 - 2299 user space actions taken in response to anomalies
I'd also like to suggest that this patch collect 2 kinds of contexts, subject
and object. Subject being the context associated with the caller, object
being whatever system object that is being accessed. There can be more than
one object in the syscall. I'm undecided about whether they should be all in
1 record or each a separate record in the same event.
In terms of parsing, I'd imagine it'd be easiest if a subrecord had a static format
(and in the case of a binary record, a fixed size) and could not grow arbitrarily
large. I vote to make them seperate subrecords which are then correlated using
a common token=value. In this case, something like: event=<this_event>??
Post by Steve Grubb
This would mean taking
1500 as subject label and 1501 as object label.
-Steve
-tim
Steve Grubb
2005-09-26 19:42:49 UTC
Permalink
Post by Timothy R. Chavez
Maybe I missed it... What's the 2000 - 2099 block reserved for again?
The legacy 2000 KERNEL message kind of messes up giving that block any real
meaning. If anything comes up in development that doesn't fit anywhere else,
I suppose we could put it here.

-Steve
Steve Grubb
2005-09-26 20:28:39 UTC
Permalink
Post by Steve Grubb
Lets use the following audit message number ranges for the next round of
On second thought, maybe better to group the messages between kernel &
userspace better

1500 - 1599 kernel LSPP events
1700 - 1799 kernel crypto events
1800 - 1999 future kernel use (maybe integrity labels and related events)
2001 - 2099 unused (kernel)
2100 - 2199 user space anomaly records
2200 - 2299 user space actions taken in response to anomalies
2300 - 2399 user space generated LSPP events
2400 - 2499 user space crypto events
2500 - 2999 future user space (maybe integrity labels and related events)

This would allow us to cover more numbers in a case statement where we are
trying to just relay messages through the kernel back to userspace.

-Steve
V***@vt.edu
2005-09-27 05:57:21 UTC
Permalink
Post by Steve Grubb
1500 - 1599 kernel LSPP events
1700 - 1799 kernel crypto events
1800 - 1999 future kernel use (maybe integrity labels and related events)
< and so on..>

Am I the only one who thinks "100 entries will be enough" sounds suspiciously
like "640K should be enough for anybody"? Do we either have a way to
guarantee that it will be enough (go with pseudo-fractional entries
a la '1701 subtype 1, 2, 3, 1702 subtype 1..8, 1703 subtype 1..934, etc',
or a way to expand it, keeping in mind forward/backward combatibility issues)?
Steve Grubb
2005-09-27 19:23:39 UTC
Permalink
Post by V***@vt.edu
Post by Steve Grubb
1500 - 1599 kernel LSPP events
1700 - 1799 kernel crypto events
1800 - 1999 future kernel use (maybe integrity labels and related events)
< and so on..>
Am I the only one who thinks "100 entries will be enough" sounds
suspiciously like "640K should be enough for anybody"?
I'm thinking it should be enough unless vendors want to clip their programs
into the audit system and start inventing their own numbers.
Post by V***@vt.edu
Do we either have a way to guarantee that it will be enough (go with
pseudo-fractional entries a la '1701 subtype 1, 2, 3, 1702 subtype 1..8,
1703 subtype 1..934, etc', or a way to expand it, keeping in mind
forward/backward combatibility issues)?
Well, we could easily continue the same kind of messages in another block. So
far, we've only consumed < 20 message types on any block. I really can't see
a 100 different kinds of LSPP kernel message types.

-Steve
V***@vt.edu
2005-09-27 23:02:00 UTC
Permalink
Post by Steve Grubb
Post by V***@vt.edu
Post by Steve Grubb
1500 - 1599 kernel LSPP events
1700 - 1799 kernel crypto events
1800 - 1999 future kernel use (maybe integrity labels and related events)
< and so on..>
Am I the only one who thinks "100 entries will be enough" sounds
suspiciously like "640K should be enough for anybody"?
I'm thinking it should be enough unless vendors want to clip their programs
into the audit system and start inventing their own numbers.
That's basically what I was worried about.
Post by Steve Grubb
Well, we could easily continue the same kind of messages in another block. So
far, we've only consumed < 20 message types on any block. I really can't see
a 100 different kinds of LSPP kernel message types.
That's just waiting for a bug report when somebody's software doesn't play nice
with "2100..2199,2700..2799" type ranges. Agreed the kernel probably won't need
a lot more, but we might want to make sure we have bigger ranges available for
userspace. Maybe make each userspace range 1K wide rather than 100? (Yes,
I know that's just putting the Y2K problem off to 2038 ;)
Dustin Kirkland
2005-09-26 20:57:25 UTC
Permalink
Post by Steve Grubb
Post by Steve Grubb
Lets use the following audit message number ranges for the next
round of
Post by Steve Grubb
On second thought, maybe better to group the messages between kernel &
userspace better
1500 - 1599 kernel LSPP events
1700 - 1799 kernel crypto events
1800 - 1999 future kernel use (maybe integrity labels and related
events)
Post by Steve Grubb
2001 - 2099 unused (kernel)
2100 - 2199 user space anomaly records
2200 - 2299 user space actions taken in response to anomalies
2300 - 2399 user space generated LSPP events
2400 - 2499 user space crypto events
2500 - 2999 future user space (maybe integrity labels and related
events)
Post by Steve Grubb
This would allow us to cover more numbers in a case statement where we
are
Post by Steve Grubb
trying to just relay messages through the kernel back to userspace.
What about 1600-1699? Perhaps crypto -> 1600-1699, and save 1700-1999
for future use?

2000+ for user space seems sensible to me.


:-Dustin
Steve Grubb
2005-09-26 20:59:18 UTC
Permalink
What about 1600-1699?  Perhaps crypto -> 1600-1699, and save 1700-1999
for future use?
Yes. Typo on my part. Thanks for catching it.

-Steve
Dustin Kirkland
2005-10-19 21:39:21 UTC
Permalink
Post by Amy Griffis
Post by Dustin Kirkland
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.
Okay, I can take a look at improving the error handling when I get a
chance.
Would be appreciated. Especially if you can base your work off of this
work that I've already started ;)
Post by Amy Griffis
Post by Dustin Kirkland
Post by Amy Griffis
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.
I can't think of a reason to make it generic other than to save
space. Since the other aux data structs are already allocated
dynamically, this approach is actually taking more space as well as
introducing the overhead of having to walk more elements in the aux
list.
Ok, I've come around to your point of view. Now, the context is char
*ctx within the audit_aux_data_ipc structure.

This may not be the final word, however. I can see reasons for both
approaches, with the context labels simply appended onto existing
records, or with context labels being auxiliary records connected to
existing records. The implementation in this patch, though, behaves as
you suggest, adding the context data to the char *ctx in the data
structure and simply appending subj=... or obj=... to the rest of the
audit record.
Post by Amy Griffis
Post by Dustin Kirkland
Post by Amy Griffis
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...
I don't see why we would want to add an unused field just to look
like another structure.
Ok, I've removed it.
Post by Amy Griffis
Post by Dustin Kirkland
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.
You added a security_context field to audit_names. So adding a
comparable field to audit_aux_data_ipcctl makes sense.
Agreed. Done.
Post by Amy Griffis
By the way, have you run into any issues with allocating memory during
path_lookup?
No, none yet.
Post by Amy Griffis
Thanks. Just make sure to clarify that this patch is for collecting
security label context for inodes and ipc only, and I'll be happy. :-)
You are correct. There is still work to be done to audit the subj/obj
labels for sockets. I should be very clear about that ;)

--

A couple of other comments...

- There's still work to be done if the audit_panic()'s are to be
replaced with mechanisms to propagate up errno's to the launching
syscalls. Amy said in her previous email that she might look into this.
I will as well, but this bothers me less than it bothers other people,
so I'm hoping those offended by the audit_panic()'s within this patch
might post patches that demonstrate their preferred approaches.

- This patch reduced some of the verbage required for several functions
and variables. In several places, "security_context" was replaced with
"context", such as
s/audit_ipc_security_context/audit_ipc_context/g
s/audit_log_task_security_context/audit_log_task_context/g
s/audit_aux_data_security_context/audit_aux_data_context/g
s/audit_inode_security_context/audit_inode_context/g
Additionally, the audit_names data structure uses char *ctx instead of
char *security_context now (which fits in more with gid,rdev,flags,
etc).

- I also ported this patch forward to the 2.6.14-rc4 kernel such that
David might be able to more easily apply it to his tree.

Please let me know if anyone is offended by these unrequested changes.
If this seems good enough to start testing, I'd like to see David merge
into his try by the end of the week. Thanks!

Updated patch attached.

:-Dustin


diff -uprN linux-2.6.14-rc4/include/linux/audit.h
linux-2.6.14-rc4-context_labels/include/linux/audit.h
--- linux-2.6.14-rc4/include/linux/audit.h 2005-10-19 09:40:27.000000000 -0500
+++ linux-2.6.14-rc4-context_labels/include/linux/audit.h 2005-10-19 10:51:34.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
@@ -232,12 +233,14 @@ extern void auditsc_get_stamp(struct aud
struct timespec *t, unsigned int *serial);
extern int audit_set_loginuid(struct task_struct *task, uid_t loginuid);
extern uid_t audit_get_loginuid(struct audit_context *ctx);
-extern int audit_ipc_perms(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode);
+extern int audit_ipc_perms(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode, struct kern_ipc_perm *ipcp);
extern int audit_socketcall(int nargs, unsigned long *args);
extern int audit_sockaddr(int len, void *addr);
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);
+char *audit_ipc_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 +258,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_context(i) do { ; } while (0)
+#define audit_set_macxattr(n) do { ; } while (0)
#endif

#ifdef CONFIG_AUDIT
@@ -283,6 +288,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 +299,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.14-rc4/include/linux/security.h linux-2.6.14-rc4-context_labels/include/linux/security.h
--- linux-2.6.14-rc4/include/linux/security.h 2005-10-19 09:40:28.000000000 -0500
+++ linux-2.6.14-rc4-context_labels/include/linux/security.h 2005-10-19 06:52:20.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 -uprN linux-2.6.14-rc4/ipc/msg.c linux-2.6.14-rc4-context_labels/ipc/msg.c
--- linux-2.6.14-rc4/ipc/msg.c 2005-10-19 09:40:29.000000000 -0500
+++ linux-2.6.14-rc4-context_labels/ipc/msg.c 2005-10-19 06:52:20.000000000 -0500
@@ -428,8 +428,6 @@ asmlinkage long sys_msgctl (int msqid, i
return -EFAULT;
if (copy_msqid_from_user (&setbuf, buf, version))
return -EFAULT;
- if ((err = audit_ipc_perms(setbuf.qbytes, setbuf.uid, setbuf.gid, setbuf.mode)))
- return err;
break;
case IPC_RMID:
break;
@@ -460,6 +458,9 @@ asmlinkage long sys_msgctl (int msqid, i
switch (cmd) {
case IPC_SET:
{
+ if ((err = audit_ipc_perms(setbuf.qbytes, setbuf.uid, setbuf.gid, setbuf.mode, ipcp)))
+ goto out_unlock_up;
+
err = -EPERM;
if (setbuf.qbytes > msg_ctlmnb && !capable(CAP_SYS_RESOURCE))
goto out_unlock_up;
diff -uprN linux-2.6.14-rc4/ipc/sem.c linux-2.6.14-rc4-context_labels/ipc/sem.c
--- linux-2.6.14-rc4/ipc/sem.c 2005-10-19 09:40:29.000000000 -0500
+++ linux-2.6.14-rc4-context_labels/ipc/sem.c 2005-10-19 06:52:20.000000000 -0500
@@ -806,8 +806,6 @@ static int semctl_down(int semid, int se
if(cmd == IPC_SET) {
if(copy_semid_from_user (&setbuf, arg.buf, version))
return -EFAULT;
- if ((err = audit_ipc_perms(0, setbuf.uid, setbuf.gid, setbuf.mode)))
- return err;
}
sma = sem_lock(semid);
if(sma==NULL)
@@ -818,7 +816,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 +832,8 @@ static int semctl_down(int semid, int se
err = 0;
break;
case IPC_SET:
+ if ((err = audit_ipc_perms(0, setbuf.uid, setbuf.gid, setbuf.mode, ipcp)))
+ goto out_unlock;
ipcp->uid = setbuf.uid;
ipcp->gid = setbuf.gid;
ipcp->mode = (ipcp->mode & ~S_IRWXUGO)
diff -uprN linux-2.6.14-rc4/ipc/shm.c linux-2.6.14-rc4-context_labels/ipc/shm.c
--- linux-2.6.14-rc4/ipc/shm.c 2005-10-19 09:40:29.000000000 -0500
+++ linux-2.6.14-rc4-context_labels/ipc/shm.c 2005-10-19 06:52:20.000000000 -0500
@@ -604,13 +604,13 @@ asmlinkage long sys_shmctl (int shmid, i
err = -EFAULT;
goto out;
}
- if ((err = audit_ipc_perms(0, setbuf.uid, setbuf.gid, setbuf.mode)))
- return err;
down(&shm_ids.sem);
shp = shm_lock(shmid);
err=-EINVAL;
if(shp==NULL)
goto out_up;
+ if ((err = audit_ipc_perms(0, setbuf.uid, setbuf.gid, setbuf.mode, &(shp->shm_perm))))
+ goto out_unlock_up;
err = shm_checkid(shp,shmid);
if(err)
goto out_unlock_up;
diff -uprN linux-2.6.14-rc4/ipc/util.c linux-2.6.14-rc4-context_labels/ipc/util.c
--- linux-2.6.14-rc4/ipc/util.c 2005-10-19 09:40:29.000000000 -0500
+++ linux-2.6.14-rc4-context_labels/ipc/util.c 2005-10-19 10:51:12.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_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.14-rc4/kernel/audit.c linux-2.6.14-rc4-context_labels/kernel/audit.c
--- linux-2.6.14-rc4/kernel/audit.c 2005-10-19 09:40:29.000000000 -0500
+++ linux-2.6.14-rc4-context_labels/kernel/audit.c 2005-10-19 06:52:20.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.14-rc4/kernel/auditsc.c linux-2.6.14-rc4-context_labels/kernel/auditsc.c
--- linux-2.6.14-rc4/kernel/auditsc.c 2005-10-19 09:40:29.000000000 -0500
+++ linux-2.6.14-rc4-context_labels/kernel/auditsc.c 2005-10-19 11:19:39.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 *ctx;
};

struct audit_aux_data {
@@ -115,6 +117,7 @@ struct audit_aux_data_ipcctl {
uid_t uid;
gid_t gid;
mode_t mode;
+ char *ctx;
};

struct audit_aux_data_socketcall {
@@ -661,10 +664,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].ctx);
+ }
dump_stack();
return;
}
@@ -696,6 +701,12 @@ static inline void audit_free_aux(struct
dput(axi->dentry);
mntput(axi->mnt);
}
+ if ( aux->type == AUDIT_IPC ) {
+ struct audit_aux_data_ipcctl *axi = (void *)aux;
+ if (axi->ctx)
+ kfree(axi->ctx);
+ }
+
context->aux = aux->next;
kfree(aux);
}
@@ -775,6 +786,37 @@ static inline void audit_free_context(st
printk(KERN_ERR "audit: freed %d contexts\n", count);
}

+static void audit_log_task_context(struct audit_buffer *ab)
+{
+ char *ctx = NULL;
+ ssize_t len = 0;
+
+ len = security_getprocattr(current, "current", NULL, 0);
+ if (len < 0) {
+ if (len != -EINVAL)
+ goto error_path;
+ return;
+ }
+
+ ctx = kmalloc(len, GFP_KERNEL);
+ if (!ctx) {
+ goto error_path;
+ return;
+ }
+
+ len = security_getprocattr(current, "current", ctx, len);
+ if (len < 0 )
+ goto error_path;
+
+ audit_log_format(ab, " subj=%s", ctx);
+
+error_path:
+ if (ctx)
+ kfree(ctx);
+ audit_panic("security_getprocattr error in audit_log_task_context");
+ return;
+}
+
static void audit_log_task_info(struct audit_buffer *ab)
{
char name[sizeof(current->comm)];
@@ -801,6 +843,7 @@ static void audit_log_task_info(struct a
vma = vma->vm_next;
}
up_read(&mm->mmap_sem);
+ audit_log_task_context(ab);
}

static void audit_log_exit(struct audit_context *context, unsigned int gfp_mask)
@@ -849,8 +892,8 @@ static void audit_log_exit(struct audit_
case AUDIT_IPC: {
struct audit_aux_data_ipcctl *axi = (void *)aux;
audit_log_format(ab,
- " qbytes=%lx iuid=%u igid=%u mode=%x",
- axi->qbytes, axi->uid, axi->gid, axi->mode);
+ " qbytes=%lx iuid=%u igid=%u mode=%x obj=%s",
+ axi->qbytes, axi->uid, axi->gid, axi->mode, axi->ctx);
break; }

case AUDIT_SOCKETCALL: {
@@ -907,6 +950,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].ctx) {
+ audit_log_format(ab, " obj=%s",
+ context->names[i].ctx);
+ }
+
audit_log_end(ab);
}
}
@@ -1122,6 +1170,37 @@ void audit_putname(const char *name)
#endif
}

+void audit_inode_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].ctx = ctx;
+ return;
+
+error_path:
+ if (ctx)
+ kfree(ctx);
+ audit_panic("error in audit_inode_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)
@@ -1157,6 +1236,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_context(idx, inode);
}

void auditsc_get_stamp(struct audit_context *ctx,
@@ -1193,7 +1273,7 @@ uid_t audit_get_loginuid(struct audit_co
return ctx ? ctx->loginuid : -1;
}

-int audit_ipc_perms(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode)
+int audit_ipc_perms(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode, struct kern_ipc_perm *ipcp)
{
struct audit_aux_data_ipcctl *ax;
struct audit_context *context = current->audit_context;
@@ -1201,7 +1281,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;

@@ -1209,6 +1289,7 @@ int audit_ipc_perms(unsigned long qbytes
ax->uid = uid;
ax->gid = gid;
ax->mode = mode;
+ ax->ctx = audit_ipc_context(ipcp);

ax->d.type = AUDIT_IPC;
ax->d.next = context->aux;
@@ -1216,6 +1297,36 @@ int audit_ipc_perms(unsigned long qbytes
return 0;
}

+char *audit_ipc_context(struct kern_ipc_perm *ipcp)
+{
+ struct audit_context *context = current->audit_context;
+ char *ctx = NULL;
+ int len = 0;
+
+ if (likely(!context))
+ return NULL;
+
+ len = security_ipc_getsecurity(ipcp, NULL, 0);
+ if (len < 0)
+ goto error_path;
+
+ ctx = kmalloc(len, GFP_ATOMIC);
+ if (!ctx)
+ goto error_path;
+
+ len = security_ipc_getsecurity(ipcp, ctx, len);
+ if (len < 0)
+ goto error_path;
+
+ return ctx;
+
+error_path:
+ if (ctx)
+ kfree(ctx);
+ audit_panic("error in audit_ipc_context");
+ return NULL;
+}
+
int audit_socketcall(int nargs, unsigned long *args)
{
struct audit_aux_data_socketcall *ax;
diff -uprN linux-2.6.14-rc4/security/dummy.c linux-2.6.14-rc4-context_labels/security/dummy.c
--- linux-2.6.14-rc4/security/dummy.c 2005-10-19 09:40:31.000000000 -0500
+++ linux-2.6.14-rc4-context_labels/security/dummy.c 2005-10-19 06:52:20.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.14-rc4/security/selinux/hooks.c linux-2.6.14-rc4-context_labels/security/selinux/hooks.c
--- linux-2.6.14-rc4/security/selinux/hooks.c 2005-10-19 09:40:31.000000000 -0500
+++ linux-2.6.14-rc4-context_labels/security/selinux/hooks.c 2005-10-19 06:52:20.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)
@@ -2247,33 +2273,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,
@@ -4045,6 +4059,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)
{
@@ -4086,8 +4107,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) {
@@ -4096,9 +4116,6 @@ static int selinux_getprocattr(struct ta
return error;
}

- if (!size)
- return -ERANGE;
-
tsec = p->security;

if (!strcmp(name, "current"))
@@ -4115,16 +4132,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,
@@ -4282,6 +4290,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,
@@ -4319,6 +4328,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,
Dustin Kirkland
2005-10-20 16:13:22 UTC
Permalink
With copyright and changelog statements.





diff -uprN linux-2.6.14-rc4/include/linux/audit.h
linux-2.6.14-rc4-context_labels/include/linux/audit.h
--- linux-2.6.14-rc4/include/linux/audit.h 2005-10-19 09:40:27.000000000 -0500
+++ linux-2.6.14-rc4-context_labels/include/linux/audit.h 2005-10-19 10:51:34.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
@@ -232,12 +233,14 @@ extern void auditsc_get_stamp(struct aud
struct timespec *t, unsigned int *serial);
extern int audit_set_loginuid(struct task_struct *task, uid_t loginuid);
extern uid_t audit_get_loginuid(struct audit_context *ctx);
-extern int audit_ipc_perms(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode);
+extern int audit_ipc_perms(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode, struct kern_ipc_perm *ipcp);
extern int audit_socketcall(int nargs, unsigned long *args);
extern int audit_sockaddr(int len, void *addr);
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);
+char *audit_ipc_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 +258,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_context(i) do { ; } while (0)
+#define audit_set_macxattr(n) do { ; } while (0)
#endif

#ifdef CONFIG_AUDIT
@@ -283,6 +288,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 +299,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.14-rc4/include/linux/security.h linux-2.6.14-rc4-context_labels/include/linux/security.h
--- linux-2.6.14-rc4/include/linux/security.h 2005-10-19 09:40:28.000000000 -0500
+++ linux-2.6.14-rc4-context_labels/include/linux/security.h 2005-10-19 06:52:20.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 -uprN linux-2.6.14-rc4/ipc/msg.c linux-2.6.14-rc4-context_labels/ipc/msg.c
--- linux-2.6.14-rc4/ipc/msg.c 2005-10-19 09:40:29.000000000 -0500
+++ linux-2.6.14-rc4-context_labels/ipc/msg.c 2005-10-19 06:52:20.000000000 -0500
@@ -428,8 +428,6 @@ asmlinkage long sys_msgctl (int msqid, i
return -EFAULT;
if (copy_msqid_from_user (&setbuf, buf, version))
return -EFAULT;
- if ((err = audit_ipc_perms(setbuf.qbytes, setbuf.uid, setbuf.gid, setbuf.mode)))
- return err;
break;
case IPC_RMID:
break;
@@ -460,6 +458,9 @@ asmlinkage long sys_msgctl (int msqid, i
switch (cmd) {
case IPC_SET:
{
+ if ((err = audit_ipc_perms(setbuf.qbytes, setbuf.uid, setbuf.gid, setbuf.mode, ipcp)))
+ goto out_unlock_up;
+
err = -EPERM;
if (setbuf.qbytes > msg_ctlmnb && !capable(CAP_SYS_RESOURCE))
goto out_unlock_up;
diff -uprN linux-2.6.14-rc4/ipc/sem.c linux-2.6.14-rc4-context_labels/ipc/sem.c
--- linux-2.6.14-rc4/ipc/sem.c 2005-10-19 09:40:29.000000000 -0500
+++ linux-2.6.14-rc4-context_labels/ipc/sem.c 2005-10-19 06:52:20.000000000 -0500
@@ -806,8 +806,6 @@ static int semctl_down(int semid, int se
if(cmd == IPC_SET) {
if(copy_semid_from_user (&setbuf, arg.buf, version))
return -EFAULT;
- if ((err = audit_ipc_perms(0, setbuf.uid, setbuf.gid, setbuf.mode)))
- return err;
}
sma = sem_lock(semid);
if(sma==NULL)
@@ -818,7 +816,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 +832,8 @@ static int semctl_down(int semid, int se
err = 0;
break;
case IPC_SET:
+ if ((err = audit_ipc_perms(0, setbuf.uid, setbuf.gid, setbuf.mode, ipcp)))
+ goto out_unlock;
ipcp->uid = setbuf.uid;
ipcp->gid = setbuf.gid;
ipcp->mode = (ipcp->mode & ~S_IRWXUGO)
diff -uprN linux-2.6.14-rc4/ipc/shm.c linux-2.6.14-rc4-context_labels/ipc/shm.c
--- linux-2.6.14-rc4/ipc/shm.c 2005-10-19 09:40:29.000000000 -0500
+++ linux-2.6.14-rc4-context_labels/ipc/shm.c 2005-10-19 06:52:20.000000000 -0500
@@ -604,13 +604,13 @@ asmlinkage long sys_shmctl (int shmid, i
err = -EFAULT;
goto out;
}
- if ((err = audit_ipc_perms(0, setbuf.uid, setbuf.gid, setbuf.mode)))
- return err;
down(&shm_ids.sem);
shp = shm_lock(shmid);
err=-EINVAL;
if(shp==NULL)
goto out_up;
+ if ((err = audit_ipc_perms(0, setbuf.uid, setbuf.gid, setbuf.mode, &(shp->shm_perm))))
+ goto out_unlock_up;
err = shm_checkid(shp,shmid);
if(err)
goto out_unlock_up;
diff -uprN linux-2.6.14-rc4/ipc/util.c linux-2.6.14-rc4-context_labels/ipc/util.c
--- linux-2.6.14-rc4/ipc/util.c 2005-10-19 09:40:29.000000000 -0500
+++ linux-2.6.14-rc4-context_labels/ipc/util.c 2005-10-19 10:51:12.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_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.14-rc4/kernel/audit.c linux-2.6.14-rc4-context_labels/kernel/audit.c
--- linux-2.6.14-rc4/kernel/audit.c 2005-10-19 09:40:29.000000000 -0500
+++ linux-2.6.14-rc4-context_labels/kernel/audit.c 2005-10-19 06:52:20.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.14-rc4/kernel/auditsc.c linux-2.6.14-rc4-context_labels/kernel/auditsc.c
--- linux-2.6.14-rc4/kernel/auditsc.c 2005-10-19 09:40:29.000000000 -0500
+++ linux-2.6.14-rc4-context_labels/kernel/auditsc.c 2005-10-20 11:10:24.000000000 -0500
@@ -2,6 +2,7 @@
* Handles all system-call specific auditing features.
*
* Copyright 2003-2004 Red Hat Inc., Durham, North Carolina.
+ * Copyright (C) IBM Corporation, 2005
* All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -27,6 +28,9 @@
* this file -- see entry.S) is based on a GPL'd patch written by
* ***@suse.de and Copyright 2003 SuSE Linux AG.
*
+ * Subject and object context labeling support added by <***@us.ibm.com>
+ * and <***@us.ibm.com> for LSPP certification compliance.
+ *
*/

#include <linux/init.h>
@@ -43,6 +47,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 +104,7 @@ struct audit_names {
gid_t gid;
dev_t rdev;
unsigned flags;
+ char *ctx;
};

struct audit_aux_data {
@@ -115,6 +121,7 @@ struct audit_aux_data_ipcctl {
uid_t uid;
gid_t gid;
mode_t mode;
+ char *ctx;
};

struct audit_aux_data_socketcall {
@@ -661,10 +668,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].ctx);
+ }
dump_stack();
return;
}
@@ -696,6 +705,12 @@ static inline void audit_free_aux(struct
dput(axi->dentry);
mntput(axi->mnt);
}
+ if ( aux->type == AUDIT_IPC ) {
+ struct audit_aux_data_ipcctl *axi = (void *)aux;
+ if (axi->ctx)
+ kfree(axi->ctx);
+ }
+
context->aux = aux->next;
kfree(aux);
}
@@ -775,6 +790,37 @@ static inline void audit_free_context(st
printk(KERN_ERR "audit: freed %d contexts\n", count);
}

+static void audit_log_task_context(struct audit_buffer *ab)
+{
+ char *ctx = NULL;
+ ssize_t len = 0;
+
+ len = security_getprocattr(current, "current", NULL, 0);
+ if (len < 0) {
+ if (len != -EINVAL)
+ goto error_path;
+ return;
+ }
+
+ ctx = kmalloc(len, GFP_KERNEL);
+ if (!ctx) {
+ goto error_path;
+ return;
+ }
+
+ len = security_getprocattr(current, "current", ctx, len);
+ if (len < 0 )
+ goto error_path;
+
+ audit_log_format(ab, " subj=%s", ctx);
+
+error_path:
+ if (ctx)
+ kfree(ctx);
+ audit_panic("security_getprocattr error in audit_log_task_context");
+ return;
+}
+
static void audit_log_task_info(struct audit_buffer *ab)
{
char name[sizeof(current->comm)];
@@ -801,6 +847,7 @@ static void audit_log_task_info(struct a
vma = vma->vm_next;
}
up_read(&mm->mmap_sem);
+ audit_log_task_context(ab);
}

static void audit_log_exit(struct audit_context *context, unsigned int gfp_mask)
@@ -849,8 +896,8 @@ static void audit_log_exit(struct audit_
case AUDIT_IPC: {
struct audit_aux_data_ipcctl *axi = (void *)aux;
audit_log_format(ab,
- " qbytes=%lx iuid=%u igid=%u mode=%x",
- axi->qbytes, axi->uid, axi->gid, axi->mode);
+ " qbytes=%lx iuid=%u igid=%u mode=%x obj=%s",
+ axi->qbytes, axi->uid, axi->gid, axi->mode, axi->ctx);
break; }

case AUDIT_SOCKETCALL: {
@@ -907,6 +954,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].ctx) {
+ audit_log_format(ab, " obj=%s",
+ context->names[i].ctx);
+ }
+
audit_log_end(ab);
}
}
@@ -1122,6 +1174,37 @@ void audit_putname(const char *name)
#endif
}

+void audit_inode_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].ctx = ctx;
+ return;
+
+error_path:
+ if (ctx)
+ kfree(ctx);
+ audit_panic("error in audit_inode_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)
@@ -1157,6 +1240,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_context(idx, inode);
}

void auditsc_get_stamp(struct audit_context *ctx,
@@ -1193,7 +1277,7 @@ uid_t audit_get_loginuid(struct audit_co
return ctx ? ctx->loginuid : -1;
}

-int audit_ipc_perms(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode)
+int audit_ipc_perms(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode, struct kern_ipc_perm *ipcp)
{
struct audit_aux_data_ipcctl *ax;
struct audit_context *context = current->audit_context;
@@ -1201,7 +1285,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;

@@ -1209,6 +1293,7 @@ int audit_ipc_perms(unsigned long qbytes
ax->uid = uid;
ax->gid = gid;
ax->mode = mode;
+ ax->ctx = audit_ipc_context(ipcp);

ax->d.type = AUDIT_IPC;
ax->d.next = context->aux;
@@ -1216,6 +1301,36 @@ int audit_ipc_perms(unsigned long qbytes
return 0;
}

+char *audit_ipc_context(struct kern_ipc_perm *ipcp)
+{
+ struct audit_context *context = current->audit_context;
+ char *ctx = NULL;
+ int len = 0;
+
+ if (likely(!context))
+ return NULL;
+
+ len = security_ipc_getsecurity(ipcp, NULL, 0);
+ if (len < 0)
+ goto error_path;
+
+ ctx = kmalloc(len, GFP_ATOMIC);
+ if (!ctx)
+ goto error_path;
+
+ len = security_ipc_getsecurity(ipcp, ctx, len);
+ if (len < 0)
+ goto error_path;
+
+ return ctx;
+
+error_path:
+ if (ctx)
+ kfree(ctx);
+ audit_panic("error in audit_ipc_context");
+ return NULL;
+}
+
int audit_socketcall(int nargs, unsigned long *args)
{
struct audit_aux_data_socketcall *ax;
diff -uprN linux-2.6.14-rc4/security/dummy.c linux-2.6.14-rc4-context_labels/security/dummy.c
--- linux-2.6.14-rc4/security/dummy.c 2005-10-19 09:40:31.000000000 -0500
+++ linux-2.6.14-rc4-context_labels/security/dummy.c 2005-10-19 06:52:20.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.14-rc4/security/selinux/hooks.c linux-2.6.14-rc4-context_labels/security/selinux/hooks.c
--- linux-2.6.14-rc4/security/selinux/hooks.c 2005-10-19 09:40:31.000000000 -0500
+++ linux-2.6.14-rc4-context_labels/security/selinux/hooks.c 2005-10-19 06:52:20.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)
@@ -2247,33 +2273,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,
@@ -4045,6 +4059,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)
{
@@ -4086,8 +4107,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) {
@@ -4096,9 +4116,6 @@ static int selinux_getprocattr(struct ta
return error;
}

- if (!size)
- return -ERANGE;
-
tsec = p->security;

if (!strcmp(name, "current"))
@@ -4115,16 +4132,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,
@@ -4282,6 +4290,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,
@@ -4319,6 +4328,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,
Dustin Kirkland
2005-10-20 18:50:56 UTC
Permalink
Ok, sorry for the repeated posting of the patch. I'm trying to keep it
in sync with the feedback I'm receiving.

Steve Grubb asked that I remove the parts of the patch that defined the
LSPP message types, as he just posted a patch that did just that.

I'm complying and posting an updated patch here.

Thanks,
:-Dustin




diff -urpN linux-2.6.14-rc4/include/linux/audit.h
linux-2.6.14-rc4-context_labels/include/linux/audit.h
--- linux-2.6.14-rc4/include/linux/audit.h 2005-10-19 09:40:27.000000000 -0500
+++ linux-2.6.14-rc4-context_labels/include/linux/audit.h 2005-10-20 13:46:27.000000000 -0500
@@ -232,12 +232,14 @@ extern void auditsc_get_stamp(struct aud
struct timespec *t, unsigned int *serial);
extern int audit_set_loginuid(struct task_struct *task, uid_t loginuid);
extern uid_t audit_get_loginuid(struct audit_context *ctx);
-extern int audit_ipc_perms(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode);
+extern int audit_ipc_perms(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode, struct kern_ipc_perm *ipcp);
extern int audit_socketcall(int nargs, unsigned long *args);
extern int audit_sockaddr(int len, void *addr);
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);
+char *audit_ipc_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 +257,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_context(i) do { ; } while (0)
+#define audit_set_macxattr(n) do { ; } while (0)
#endif

#ifdef CONFIG_AUDIT
@@ -283,6 +287,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 +298,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.14-rc4/include/linux/security.h linux-2.6.14-rc4-context_labels/include/linux/security.h
--- linux-2.6.14-rc4/include/linux/security.h 2005-10-19 09:40:28.000000000 -0500
+++ linux-2.6.14-rc4-context_labels/include/linux/security.h 2005-10-19 06:52:20.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.14-rc4/ipc/msg.c linux-2.6.14-rc4-context_labels/ipc/msg.c
--- linux-2.6.14-rc4/ipc/msg.c 2005-10-19 09:40:29.000000000 -0500
+++ linux-2.6.14-rc4-context_labels/ipc/msg.c 2005-10-19 06:52:20.000000000 -0500
@@ -428,8 +428,6 @@ asmlinkage long sys_msgctl (int msqid, i
return -EFAULT;
if (copy_msqid_from_user (&setbuf, buf, version))
return -EFAULT;
- if ((err = audit_ipc_perms(setbuf.qbytes, setbuf.uid, setbuf.gid, setbuf.mode)))
- return err;
break;
case IPC_RMID:
break;
@@ -460,6 +458,9 @@ asmlinkage long sys_msgctl (int msqid, i
switch (cmd) {
case IPC_SET:
{
+ if ((err = audit_ipc_perms(setbuf.qbytes, setbuf.uid, setbuf.gid, setbuf.mode, 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.14-rc4/ipc/sem.c linux-2.6.14-rc4-context_labels/ipc/sem.c
--- linux-2.6.14-rc4/ipc/sem.c 2005-10-19 09:40:29.000000000 -0500
+++ linux-2.6.14-rc4-context_labels/ipc/sem.c 2005-10-19 06:52:20.000000000 -0500
@@ -806,8 +806,6 @@ static int semctl_down(int semid, int se
if(cmd == IPC_SET) {
if(copy_semid_from_user (&setbuf, arg.buf, version))
return -EFAULT;
- if ((err = audit_ipc_perms(0, setbuf.uid, setbuf.gid, setbuf.mode)))
- return err;
}
sma = sem_lock(semid);
if(sma==NULL)
@@ -818,7 +816,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 +832,8 @@ static int semctl_down(int semid, int se
err = 0;
break;
case IPC_SET:
+ if ((err = audit_ipc_perms(0, setbuf.uid, setbuf.gid, setbuf.mode, ipcp)))
+ goto out_unlock;
ipcp->uid = setbuf.uid;
ipcp->gid = setbuf.gid;
ipcp->mode = (ipcp->mode & ~S_IRWXUGO)
diff -urpN linux-2.6.14-rc4/ipc/shm.c linux-2.6.14-rc4-context_labels/ipc/shm.c
--- linux-2.6.14-rc4/ipc/shm.c 2005-10-19 09:40:29.000000000 -0500
+++ linux-2.6.14-rc4-context_labels/ipc/shm.c 2005-10-19 06:52:20.000000000 -0500
@@ -604,13 +604,13 @@ asmlinkage long sys_shmctl (int shmid, i
err = -EFAULT;
goto out;
}
- if ((err = audit_ipc_perms(0, setbuf.uid, setbuf.gid, setbuf.mode)))
- return err;
down(&shm_ids.sem);
shp = shm_lock(shmid);
err=-EINVAL;
if(shp==NULL)
goto out_up;
+ if ((err = audit_ipc_perms(0, setbuf.uid, setbuf.gid, setbuf.mode, &(shp->shm_perm))))
+ goto out_unlock_up;
err = shm_checkid(shp,shmid);
if(err)
goto out_unlock_up;
diff -urpN linux-2.6.14-rc4/ipc/util.c linux-2.6.14-rc4-context_labels/ipc/util.c
--- linux-2.6.14-rc4/ipc/util.c 2005-10-19 09:40:29.000000000 -0500
+++ linux-2.6.14-rc4-context_labels/ipc/util.c 2005-10-19 10:51:12.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_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.14-rc4/kernel/audit.c linux-2.6.14-rc4-context_labels/kernel/audit.c
--- linux-2.6.14-rc4/kernel/audit.c 2005-10-19 09:40:29.000000000 -0500
+++ linux-2.6.14-rc4-context_labels/kernel/audit.c 2005-10-19 06:52:20.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.14-rc4/kernel/auditsc.c linux-2.6.14-rc4-context_labels/kernel/auditsc.c
--- linux-2.6.14-rc4/kernel/auditsc.c 2005-10-19 09:40:29.000000000 -0500
+++ linux-2.6.14-rc4-context_labels/kernel/auditsc.c 2005-10-20 11:10:24.000000000 -0500
@@ -2,6 +2,7 @@
* Handles all system-call specific auditing features.
*
* Copyright 2003-2004 Red Hat Inc., Durham, North Carolina.
+ * Copyright (C) IBM Corporation, 2005
* All Rights Reserved.
*
* This program is free software; you can redistribute it and/or modify
@@ -27,6 +28,9 @@
* this file -- see entry.S) is based on a GPL'd patch written by
* ***@suse.de and Copyright 2003 SuSE Linux AG.
*
+ * Subject and object context labeling support added by <***@us.ibm.com>
+ * and <***@us.ibm.com> for LSPP certification compliance.
+ *
*/

#include <linux/init.h>
@@ -43,6 +47,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 +104,7 @@ struct audit_names {
gid_t gid;
dev_t rdev;
unsigned flags;
+ char *ctx;
};

struct audit_aux_data {
@@ -115,6 +121,7 @@ struct audit_aux_data_ipcctl {
uid_t uid;
gid_t gid;
mode_t mode;
+ char *ctx;
};

struct audit_aux_data_socketcall {
@@ -661,10 +668,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].ctx);
+ }
dump_stack();
return;
}
@@ -696,6 +705,12 @@ static inline void audit_free_aux(struct
dput(axi->dentry);
mntput(axi->mnt);
}
+ if ( aux->type == AUDIT_IPC ) {
+ struct audit_aux_data_ipcctl *axi = (void *)aux;
+ if (axi->ctx)
+ kfree(axi->ctx);
+ }
+
context->aux = aux->next;
kfree(aux);
}
@@ -775,6 +790,37 @@ static inline void audit_free_context(st
printk(KERN_ERR "audit: freed %d contexts\n", count);
}

+static void audit_log_task_context(struct audit_buffer *ab)
+{
+ char *ctx = NULL;
+ ssize_t len = 0;
+
+ len = security_getprocattr(current, "current", NULL, 0);
+ if (len < 0) {
+ if (len != -EINVAL)
+ goto error_path;
+ return;
+ }
+
+ ctx = kmalloc(len, GFP_KERNEL);
+ if (!ctx) {
+ goto error_path;
+ return;
+ }
+
+ len = security_getprocattr(current, "current", ctx, len);
+ if (len < 0 )
+ goto error_path;
+
+ audit_log_format(ab, " subj=%s", ctx);
+
+error_path:
+ if (ctx)
+ kfree(ctx);
+ audit_panic("security_getprocattr error in audit_log_task_context");
+ return;
+}
+
static void audit_log_task_info(struct audit_buffer *ab)
{
char name[sizeof(current->comm)];
@@ -801,6 +847,7 @@ static void audit_log_task_info(struct a
vma = vma->vm_next;
}
up_read(&mm->mmap_sem);
+ audit_log_task_context(ab);
}

static void audit_log_exit(struct audit_context *context, unsigned int gfp_mask)
@@ -849,8 +896,8 @@ static void audit_log_exit(struct audit_
case AUDIT_IPC: {
struct audit_aux_data_ipcctl *axi = (void *)aux;
audit_log_format(ab,
- " qbytes=%lx iuid=%u igid=%u mode=%x",
- axi->qbytes, axi->uid, axi->gid, axi->mode);
+ " qbytes=%lx iuid=%u igid=%u mode=%x obj=%s",
+ axi->qbytes, axi->uid, axi->gid, axi->mode, axi->ctx);
break; }

case AUDIT_SOCKETCALL: {
@@ -907,6 +954,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].ctx) {
+ audit_log_format(ab, " obj=%s",
+ context->names[i].ctx);
+ }
+
audit_log_end(ab);
}
}
@@ -1122,6 +1174,37 @@ void audit_putname(const char *name)
#endif
}

+void audit_inode_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].ctx = ctx;
+ return;
+
+error_path:
+ if (ctx)
+ kfree(ctx);
+ audit_panic("error in audit_inode_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)
@@ -1157,6 +1240,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_context(idx, inode);
}

void auditsc_get_stamp(struct audit_context *ctx,
@@ -1193,7 +1277,7 @@ uid_t audit_get_loginuid(struct audit_co
return ctx ? ctx->loginuid : -1;
}

-int audit_ipc_perms(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode)
+int audit_ipc_perms(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode, struct kern_ipc_perm *ipcp)
{
struct audit_aux_data_ipcctl *ax;
struct audit_context *context = current->audit_context;
@@ -1201,7 +1285,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;

@@ -1209,6 +1293,7 @@ int audit_ipc_perms(unsigned long qbytes
ax->uid = uid;
ax->gid = gid;
ax->mode = mode;
+ ax->ctx = audit_ipc_context(ipcp);

ax->d.type = AUDIT_IPC;
ax->d.next = context->aux;
@@ -1216,6 +1301,36 @@ int audit_ipc_perms(unsigned long qbytes
return 0;
}

+char *audit_ipc_context(struct kern_ipc_perm *ipcp)
+{
+ struct audit_context *context = current->audit_context;
+ char *ctx = NULL;
+ int len = 0;
+
+ if (likely(!context))
+ return NULL;
+
+ len = security_ipc_getsecurity(ipcp, NULL, 0);
+ if (len < 0)
+ goto error_path;
+
+ ctx = kmalloc(len, GFP_ATOMIC);
+ if (!ctx)
+ goto error_path;
+
+ len = security_ipc_getsecurity(ipcp, ctx, len);
+ if (len < 0)
+ goto error_path;
+
+ return ctx;
+
+error_path:
+ if (ctx)
+ kfree(ctx);
+ audit_panic("error in audit_ipc_context");
+ return NULL;
+}
+
int audit_socketcall(int nargs, unsigned long *args)
{
struct audit_aux_data_socketcall *ax;
diff -urpN linux-2.6.14-rc4/security/dummy.c linux-2.6.14-rc4-context_labels/security/dummy.c
--- linux-2.6.14-rc4/security/dummy.c 2005-10-19 09:40:31.000000000 -0500
+++ linux-2.6.14-rc4-context_labels/security/dummy.c 2005-10-19 06:52:20.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.14-rc4/security/selinux/hooks.c linux-2.6.14-rc4-context_labels/security/selinux/hooks.c
--- linux-2.6.14-rc4/security/selinux/hooks.c 2005-10-19 09:40:31.000000000 -0500
+++ linux-2.6.14-rc4-context_labels/security/selinux/hooks.c 2005-10-19 06:52:20.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)
@@ -2247,33 +2273,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,
@@ -4045,6 +4059,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)
{
@@ -4086,8 +4107,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) {
@@ -4096,9 +4116,6 @@ static int selinux_getprocattr(struct ta
return error;
}

- if (!size)
- return -ERANGE;
-
tsec = p->security;

if (!strcmp(name, "current"))
@@ -4115,16 +4132,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,
@@ -4282,6 +4290,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,
@@ -4319,6 +4328,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,

Loading...