Linux-audit Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] Audit of POSIX Message Queue Syscalls
@ 2006-05-17  1:40 George C. Wilson
  2006-05-17 13:34 ` Steve Grubb
                   ` (2 more replies)
  0 siblings, 3 replies; 12+ messages in thread
From: George C. Wilson @ 2006-05-17  1:40 UTC (permalink / raw)
  To: linux-audit

This patch adds audit support to POSIX message queues.  It applies cleanly to
the lspp.b12 branch of Al Viro's git tree.  There are new auxiliary data
structures, and collection and emission routines in kernel/auditsc.c.  New hooks
in ipc/mqueue.c collect arguments from the syscalls.

I tested the patch by building the examples from the POSIX MQ library tarball.
Build them -lrt, not against the old MQ library in the tarball.  Here's the URL:
http://www.geocities.com/wronski12/posix_ipc/libmqueue-4.41.tar.gz
Do auditctl -a exit,always -S for mq_open, mq_timedsend, mq_timedreceive,
mq_notify, mq_getsetattr.  mq_unlink has no new hooks.  Please see the
corresponding userspace patch to get correct output from auditd for the new
record types.

Assumptions/Notes:
	- Capturing the name arg is not required for sys_mq_open() sys_mq_open and
	  mq_unlink() as it is already collected in the syscall record.
	- I was collecting more data from the notification struct for mq_notify().
	  However nothing other than the signal number appeared to be useful.
	  I don't like copying the entire sigevent struct just to get the signal
	  number.
	- Because mq_getsetattr() takes both in and out parameters,
	  uninitialized data can show up in the audit records.
	- I don't like having to copy as many parameters as I did from
	  userspace.  The intent is to ensure the in parameters are captured no
	  matter the error path.  Also, in mq_open() the existing copy_from_user()
	  is done in another function.  Multiple hooks to avoid introducing the new
	  copy_from_user() would be messy.
	- I don't like what I did with the return code in mq_getsetattr().
	  But the idea is only to return the audit hook's return code if the
	  code above it did not fail.

 include/linux/audit.h |   15 ++
 ipc/mqueue.c          |   21 +++-
 kernel/auditsc.c      |  254 +++++++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 288 insertions(+), 2 deletions(-)

Signed-off-by: George Wilson <ltcgcw@us.ibm.com>

--

diff --git a/include/linux/audit.h b/include/linux/audit.h
index 3c69de2..60b3119 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -26,6 +26,7 @@
 
 #include <linux/sched.h>
 #include <linux/elf.h>
+#include <linux/mqueue.h>
 
 /* The netlink messages for the audit system is divided into blocks:
  * 1000 - 1099 are for commanding the audit system
@@ -85,6 +86,10 @@
 #define AUDIT_CWD		1307	/* Current working directory */
 #define AUDIT_EXECVE		1309	/* execve arguments */
 #define AUDIT_IPC_SET_PERM	1311	/* IPC new permissions record type */
+#define AUDIT_MQ_OPEN		1312	/* POSIX MQ open record type */
+#define AUDIT_MQ_SENDRECV	1313	/* POSIX MQ send/receive record type */
+#define AUDIT_MQ_NOTIFY		1314	/* POSIX MQ notify record type */
+#define AUDIT_MQ_GETSETATTR	1315	/* POSIX MQ get/set attribute record type */
 
 #define AUDIT_AVC		1400	/* SE Linux avc denial or grant */
 #define AUDIT_SELINUX_ERR	1401	/* Internal SE Linux Errors */
@@ -332,6 +337,11 @@ extern int audit_socketcall(int nargs, u
 extern int audit_sockaddr(int len, void *addr);
 extern int audit_avc_path(struct dentry *dentry, struct vfsmount *mnt);
 extern int audit_set_macxattr(const char *name);
+extern int audit_mq_open(int oflag, mode_t mode, struct mq_attr __user *u_attr);
+extern int audit_mq_timedsend(mqd_t mqdes, size_t msg_len, unsigned int msg_prio, const struct timespec __user *u_abs_timeout);
+extern int audit_mq_timedreceive(mqd_t mqdes, size_t msg_len, unsigned int __user *u_msg_prio, const struct timespec __user *u_abs_timeout);
+extern int audit_mq_notify(mqd_t mqdes, const struct sigevent __user *u_notification);
+extern int audit_mq_getsetattr(mqd_t mqdes, struct mq_attr *mqstat, struct mq_attr *omqstat);
 #else
 #define audit_alloc(t) ({ 0; })
 #define audit_free(t) do { ; } while (0)
@@ -352,6 +362,11 @@ extern int audit_set_macxattr(const char
 #define audit_sockaddr(len, addr) ({ 0; })
 #define audit_avc_path(dentry, mnt) ({ 0; })
 #define audit_set_macxattr(n) do { ; } while (0)
+#define audit_mq_open(n) do { ; } while (0)
+#define audit_mq_timedsend(n) do { ; } while (0)
+#define audit_mq_timedreceive(n) do { ; } while (0)
+#define audit_mq_notify(n) do { ; } while (0)
+#define audit_mq_getsetattr(n) do { ; } while (0)
 #endif
 
 #ifdef CONFIG_AUDIT
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index 41ecbd4..8f6a82d 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -8,6 +8,8 @@
  * Lockless receive & send, fd based notify:
  * 			    Manfred Spraul	    (manfred@colorfullife.com)
  *
+ * Audit:                   George Wilson           (ltcgcw@us.ibm.com)
+ *
  * This file is released under the GPL.
  */
 
@@ -24,6 +26,7 @@
 #include <linux/skbuff.h>
 #include <linux/netlink.h>
 #include <linux/syscalls.h>
+#include <linux/audit.h>
 #include <linux/signal.h>
 #include <linux/mutex.h>
 
@@ -660,6 +663,9 @@ asmlinkage long sys_mq_open(const char _
 	if (IS_ERR(name = getname(u_name)))
 		return PTR_ERR(name);
 
+	if ((error = audit_mq_open(oflag, mode, u_attr)) != 0)
+		return error;
+
 	fd = get_unused_fd();
 	if (fd < 0)
 		goto out_putname;
@@ -814,6 +820,9 @@ asmlinkage long sys_mq_timedsend(mqd_t m
 	long timeout;
 	int ret;
 
+	if ((ret = audit_mq_timedsend(mqdes, msg_len, msg_prio, u_abs_timeout)) != 0)
+		return ret;
+
 	if (unlikely(msg_prio >= (unsigned long) MQ_PRIO_MAX))
 		return -EINVAL;
 
@@ -896,6 +905,9 @@ asmlinkage ssize_t sys_mq_timedreceive(m
 	struct mqueue_inode_info *info;
 	struct ext_wait_queue wait;
 
+	if ((ret = audit_mq_timedreceive(mqdes, msg_len, u_msg_prio, u_abs_timeout)) != 0)
+		return ret;
+
 	timeout = prepare_timeout(u_abs_timeout);
 
 	ret = -EBADF;
@@ -975,6 +987,9 @@ asmlinkage long sys_mq_notify(mqd_t mqde
 	struct mqueue_inode_info *info;
 	struct sk_buff *nc;
 
+	if ((ret = audit_mq_notify(mqdes, u_notification)) != 0)
+		return ret;
+
 	nc = NULL;
 	sock = NULL;
 	if (u_notification != NULL) {
@@ -1087,7 +1102,7 @@ asmlinkage long sys_mq_getsetattr(mqd_t 
 			const struct mq_attr __user *u_mqstat,
 			struct mq_attr __user *u_omqstat)
 {
-	int ret;
+	int ret, audret;
 	struct mq_attr mqstat, omqstat;
 	struct file *filp;
 	struct inode *inode;
@@ -1130,9 +1145,13 @@ asmlinkage long sys_mq_getsetattr(mqd_t 
 						sizeof(struct mq_attr)))
 		ret = -EFAULT;
 
+
 out_fput:
 	fput(filp);
 out:
+	audret = audit_mq_getsetattr(mqdes, &mqstat, &omqstat);
+	if (ret == 0)
+		ret = audret;
 	return ret;
 }
 
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index c30f146..2fdead5 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -3,7 +3,7 @@
  *
  * Copyright 2003-2004 Red Hat Inc., Durham, North Carolina.
  * Copyright 2005 Hewlett-Packard Development Company, L.P.
- * Copyright (C) 2005 IBM Corporation
+ * Copyright (C) 2005, 2006 IBM Corporation
  * All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify
@@ -29,6 +29,9 @@
  * this file -- see entry.S) is based on a GPL'd patch written by
  * okir@suse.de and Copyright 2003 SuSE Linux AG.
  *
+ * POSIX message queue support added by George Wilson <ltcgcw@us.ibm.com>,
+ * 2006.
+ *
  * The support of additional filter rules compares (>, <, >=, <=) was
  * added by Dustin Kirkland <dustin.kirkland@us.ibm.com>, 2005.
  *
@@ -102,6 +105,34 @@ struct audit_aux_data {
 
 #define AUDIT_AUX_IPCPERM	0
 
+struct audit_aux_data_mq_open {
+	struct audit_aux_data	d;
+	int			oflag;
+	mode_t			mode;
+	struct mq_attr		attr;
+};
+
+struct audit_aux_data_mq_sendrecv {
+	struct audit_aux_data	d;
+	mqd_t			mqdes;
+	size_t			msg_len;
+	unsigned int		msg_prio;
+	struct timespec		abs_timeout;
+};
+
+struct audit_aux_data_mq_notify {
+	struct audit_aux_data	d;
+	mqd_t			mqdes;
+	struct sigevent 	notification;
+};
+
+struct audit_aux_data_mq_getsetattr {
+	struct audit_aux_data	d;
+	mqd_t			mqdes;
+	struct mq_attr 		mqstat;
+	struct mq_attr		omqstat;
+};
+
 struct audit_aux_data_ipcctl {
 	struct audit_aux_data	d;
 	struct ipc_perm		p;
@@ -709,6 +740,46 @@ static void audit_log_exit(struct audit_
 			continue; /* audit_panic has been called */
 
 		switch (aux->type) {
+		case AUDIT_MQ_OPEN: {
+			struct audit_aux_data_mq_open *axi = (void *)aux;
+			audit_log_format(ab, 
+				"oflag=0x%x mode=%#o mq_flags=0x%lx mq_maxmsg=%ld "
+				"mq_msgsize=%ld mq_curmsgs=%ld",
+				axi->oflag, axi->mode, axi->attr.mq_flags,
+				axi->attr.mq_maxmsg, axi->attr.mq_msgsize,
+				axi->attr.mq_curmsgs);
+			break; }
+
+		case AUDIT_MQ_SENDRECV: {
+			struct audit_aux_data_mq_sendrecv *axi = (void *)aux;
+			audit_log_format(ab, 
+				"mqdes=%d msg_len=%ld msg_prio=%u "
+				"abs_timeout_sec=%ld abs_timeout_nsec=%ld",
+				axi->mqdes, axi->msg_len, axi->msg_prio,
+				axi->abs_timeout.tv_sec, axi->abs_timeout.tv_nsec);
+			break; }
+
+		case AUDIT_MQ_NOTIFY: {
+			struct audit_aux_data_mq_notify *axi = (void *)aux;
+			audit_log_format(ab, 
+				"mqdes=%d sigev_signo=%d",
+				axi->mqdes,
+				axi->notification.sigev_signo);
+			break; }
+
+		case AUDIT_MQ_GETSETATTR: {
+			struct audit_aux_data_mq_getsetattr *axi = (void *)aux;
+			audit_log_format(ab, 
+				"mqdes=%d mq_flags=0x%lx mq_maxmsg=%ld mq_msgsize=%ld "
+				"mq_curmsgs=%ld omq_flags=0x%lx omq_maxmsg=%ld "
+				"omq_msgsize=%ld omq_curmsgs=%ld",
+				axi->mqdes, 
+				axi->mqstat.mq_flags, axi->mqstat.mq_maxmsg,
+				axi->mqstat.mq_msgsize, axi->mqstat.mq_curmsgs,
+				axi->omqstat.mq_flags, axi->omqstat.mq_maxmsg,
+				axi->omqstat.mq_msgsize, axi->omqstat.mq_curmsgs);
+			break; }
+
 		case AUDIT_IPC: {
 			struct audit_aux_data_ipcctl *axi = (void *)aux;
 			audit_log_format(ab, 
@@ -1242,6 +1313,187 @@ uid_t audit_get_loginuid(struct audit_co
 }
 
 /**
+ * audit_mq_open - record audit data for a POSIX MQ open
+ * @oflag: open flag
+ * @mode: mode bits
+ * @u_attr: queue attributes
+ *
+ * Returns 0 for success or NULL context or < 0 on error.
+ */
+int audit_mq_open(int oflag, mode_t mode, struct mq_attr __user *u_attr)
+{
+	struct audit_aux_data_mq_open *ax;
+	struct audit_context *context = current->audit_context;
+
+	if (likely(!context))
+		return 0;
+
+	ax = kmalloc(sizeof(*ax), GFP_ATOMIC);
+	if (!ax)
+		return -ENOMEM;
+
+	if (u_attr != NULL) {
+		if (copy_from_user(&ax->attr, u_attr, sizeof(ax->attr)))
+			return -EFAULT;
+	} else
+		memset(&ax->attr, 0, sizeof(ax->attr));
+
+	ax->oflag = oflag;
+	ax->mode = mode;
+
+	ax->d.type = AUDIT_MQ_OPEN;
+	ax->d.next = context->aux;
+	context->aux = (void *)ax;
+	return 0;
+}
+
+/**
+ * audit_mq_timedsend - record audit data for a POSIX MQ timed send
+ * @mqdes: MQ descriptor
+ * @msg_len: Message length
+ * @msg_prio: Message priority
+ * @abs_timeout: Message timeout in absolute time
+ *
+ * Returns 0 for success or NULL context or < 0 on error.
+ */
+int audit_mq_timedsend(mqd_t mqdes, size_t msg_len, unsigned int msg_prio,
+			const struct timespec __user *u_abs_timeout)
+{
+	struct audit_aux_data_mq_sendrecv *ax;
+	struct audit_context *context = current->audit_context;
+
+	if (likely(!context))
+		return 0;
+
+	ax = kmalloc(sizeof(*ax), GFP_ATOMIC);
+	if (!ax)
+		return -ENOMEM;
+
+	if (u_abs_timeout != NULL) {
+		if (copy_from_user(&ax->abs_timeout, u_abs_timeout, sizeof(ax->abs_timeout)))
+			return -EFAULT;
+	} else
+		memset(&ax->abs_timeout, 0, sizeof(ax->abs_timeout));
+
+	ax->mqdes = mqdes;
+	ax->msg_len = msg_len;
+	ax->msg_prio = msg_prio;
+
+	ax->d.type = AUDIT_MQ_SENDRECV;
+	ax->d.next = context->aux;
+	context->aux = (void *)ax;
+	return 0;
+}
+
+/**
+ * audit_mq_timedreceive - record audit data for a POSIX MQ timed receive
+ * @mqdes: MQ descriptor
+ * @msg_len: Message length
+ * @msg_prio: Message priority
+ * @abs_timeout: Message timeout in absolute time
+ *
+ * Returns 0 for success or NULL context or < 0 on error.
+ */
+int audit_mq_timedreceive(mqd_t mqdes, size_t msg_len,
+				unsigned int __user *u_msg_prio,
+				const struct timespec __user *u_abs_timeout)
+{
+	struct audit_aux_data_mq_sendrecv *ax;
+	struct audit_context *context = current->audit_context;
+
+	if (likely(!context))
+		return 0;
+
+	ax = kmalloc(sizeof(*ax), GFP_ATOMIC);
+	if (!ax)
+		return -ENOMEM;
+
+	if (u_msg_prio != NULL) {
+		if (get_user(ax->msg_prio, u_msg_prio))
+			return -EFAULT;
+	} else
+		ax->msg_prio = 0;
+
+	if (u_abs_timeout != NULL) {
+		if (copy_from_user(&ax->abs_timeout, u_abs_timeout, sizeof(ax->abs_timeout)))
+			return -EFAULT;
+	} else
+		memset(&ax->abs_timeout, 0, sizeof(ax->abs_timeout));
+
+	ax->mqdes = mqdes;
+	ax->msg_len = msg_len;
+
+	ax->d.type = AUDIT_MQ_SENDRECV;
+	ax->d.next = context->aux;
+	context->aux = (void *)ax;
+	return 0;
+}
+
+/**
+ * audit_mq_notify - record audit data for a POSIX MQ notify
+ * @mqdes: MQ descriptor
+ * @u_notification: Notification event
+ *
+ * Returns 0 for success or NULL context or < 0 on error.
+ */
+
+int audit_mq_notify(mqd_t mqdes, const struct sigevent __user *u_notification)
+{
+	struct audit_aux_data_mq_notify *ax;
+	struct audit_context *context = current->audit_context;
+
+	if (likely(!context))
+		return 0;
+
+	ax = kmalloc(sizeof(*ax), GFP_ATOMIC);
+	if (!ax)
+		return -ENOMEM;
+
+	if (u_notification != NULL) {
+		if (copy_from_user(&ax->notification, u_notification, sizeof(ax->notification)))
+			return -EFAULT;
+	} else
+		memset(&ax->notification, 0, sizeof(ax->notification));
+
+	ax->mqdes = mqdes;
+
+	ax->d.type = AUDIT_MQ_NOTIFY;
+	ax->d.next = context->aux;
+	context->aux = (void *)ax;
+	return 0;
+}
+
+/**
+ * audit_mq_getsetattr - record audit data for a POSIX MQ get/set attribute
+ * @mqdes: MQ descriptor
+ * @mqstat: MQ flags
+ * @omqstat: Old MQ flags
+ *
+ * Returns 0 for success or NULL context or < 0 on error.
+ */
+int audit_mq_getsetattr(mqd_t mqdes, struct mq_attr *mqstat, struct mq_attr *omqstat)
+{
+	struct audit_aux_data_mq_getsetattr *ax;
+	struct audit_context *context = current->audit_context;
+
+	if (likely(!context))
+		return 0;
+
+	ax = kmalloc(sizeof(*ax), GFP_ATOMIC);
+	if (!ax)
+		return -ENOMEM;
+
+	ax->mqdes = mqdes;
+	ax->mqstat = *mqstat;
+	ax->omqstat = *omqstat;
+
+	ax->d.type = AUDIT_MQ_GETSETATTR;
+	ax->d.next = context->aux;
+	context->aux = (void *)ax;
+	return 0;
+}
+
+/**
  * audit_ipc_obj - record audit data for ipc object
  * @ipcp: ipc permissions
  *
-- 
George Wilson <ltcgcw@us.ibm.com>
IBM Linux Technology Center

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH] Audit of POSIX Message Queue Syscalls
  2006-05-17  1:40 [PATCH] Audit of POSIX Message Queue Syscalls George C. Wilson
@ 2006-05-17 13:34 ` Steve Grubb
  2006-05-17 16:39   ` Amy Griffis
  2006-05-17 22:38   ` George C. Wilson
  2006-05-17 14:34 ` Timothy R. Chavez
  2006-05-24 21:09 ` [PATCH] Audit of POSIX Message Queue Syscalls v.2 George C. Wilson
  2 siblings, 2 replies; 12+ messages in thread
From: Steve Grubb @ 2006-05-17 13:34 UTC (permalink / raw)
  To: linux-audit

On Tuesday 16 May 2006 21:40, George C. Wilson wrote:
> +++ b/include/linux/audit.h
> @@ -26,6 +26,7 @@
>
>  #include <linux/sched.h>
>  #include <linux/elf.h>
> +#include <linux/mqueue.h>

Do we really need the header or just a forward declaration for mq structs?

> @@ -85,6 +86,10 @@
>  #define AUDIT_CWD		1307	/* Current working directory */
>  #define AUDIT_EXECVE		1309	/* execve arguments */
>  #define AUDIT_IPC_SET_PERM	1311	/* IPC new permissions record type */
> +#define AUDIT_MQ_OPEN		1312	/* POSIX MQ open record type */
> +#define AUDIT_MQ_SENDRECV	1313	/* POSIX MQ send/receive record type */
> +#define AUDIT_MQ_NOTIFY		1314	/* POSIX MQ notify record type */
> +#define AUDIT_MQ_GETSETATTR	1315	/* POSIX MQ get/set attribute record type

Do we really need 4 message types? IPC was able to get by on 2 of them. Are we 
recording more than IPC?

> --- a/ipc/mqueue.c
> +++ b/ipc/mqueue.c
> @@ -1087,7 +1102,7 @@ asmlinkage long sys_mq_getsetattr(mqd_t
>  			const struct mq_attr __user *u_mqstat,
>  			struct mq_attr __user *u_omqstat)
>  {
> -	int ret;
> +	int ret, audret;
>  	struct mq_attr mqstat, omqstat;
>  	struct file *filp;
>  	struct inode *inode;
> @@ -1130,9 +1145,13 @@ asmlinkage long sys_mq_getsetattr(mqd_t
>  						sizeof(struct mq_attr)))
>  		ret = -EFAULT;
>
> +

Is this additional space really needed?

>  out_fput:
>  	fput(filp);
>  out:
> +	audret = audit_mq_getsetattr(mqdes, &mqstat, &omqstat);
> +	if (ret == 0)
> +		ret = audret;
>  	return ret;
>  }

what if u_mqstat==NULL and the fd was bad upon syscall entry? All the data 
structures are whatever the stack contained, and therefore completely bogus. 
I think there are a couple ways that the structs could be uninitialized.

> diff --git a/kernel/auditsc.c b/kernel/auditsc.c
> index c30f146..2fdead5 100644
> --- a/kernel/auditsc.c
> +++ b/kernel/auditsc.c
> @@ -709,6 +740,46 @@ static void audit_log_exit(struct audit_
>  			continue; /* audit_panic has been called */
>
>  		switch (aux->type) {
> +		case AUDIT_MQ_OPEN: {
> +			struct audit_aux_data_mq_open *axi = (void *)aux;
> +			audit_log_format(ab,
> +				"oflag=0x%x mode=%#o mq_flags=0x%lx mq_maxmsg=%ld "
> +				"mq_msgsize=%ld mq_curmsgs=%ld",
> +				axi->oflag, axi->mode, axi->attr.mq_flags,
> +				axi->attr.mq_maxmsg, axi->attr.mq_msgsize,

Do we really need to record the size? Is there anything here that's not sec 
relevant? The same comment applies to the next 3 message types.

> @@ -1242,6 +1313,187 @@ uid_t audit_get_loginuid(struct audit_co
>  }
>
>  /**
> + * audit_mq_open - record audit data for a POSIX MQ open
> + * @oflag: open flag
> + * @mode: mode bits
> + * @u_attr: queue attributes
> + *
> + * Returns 0 for success or NULL context or < 0 on error.
> + */
> +int audit_mq_open(int oflag, mode_t mode, struct mq_attr __user *u_attr)
> +{
> +	struct audit_aux_data_mq_open *ax;
> +	struct audit_context *context = current->audit_context;
> +
> +	if (likely(!context))
> +		return 0;

What if audit is not enabled? Need to check for it and bail out.

> +
> +	ax = kmalloc(sizeof(*ax), GFP_ATOMIC);
> +	if (!ax)
> +		return -ENOMEM;
> +
> +	if (u_attr != NULL) {
> +		if (copy_from_user(&ax->attr, u_attr, sizeof(ax->attr)))
> +			return -EFAULT;

memory leak from above allocation.

> +int audit_mq_timedsend(mqd_t mqdes, size_t msg_len, unsigned int msg_prio,
> +			const struct timespec __user *u_abs_timeout)
> +{
> +	struct audit_aux_data_mq_sendrecv *ax;
> +	struct audit_context *context = current->audit_context;
> +
> +	if (likely(!context))
> +		return 0;

audit_enabled?

> +	ax = kmalloc(sizeof(*ax), GFP_ATOMIC);
> +	if (!ax)
> +		return -ENOMEM;
> +
> +	if (u_abs_timeout != NULL) {
> +		if (copy_from_user(&ax->abs_timeout, u_abs_timeout,
> sizeof(ax->abs_timeout))) +			return -EFAULT;

memleak

> +int audit_mq_timedreceive(mqd_t mqdes, size_t msg_len,
> +				unsigned int __user *u_msg_prio,
> +				const struct timespec __user *u_abs_timeout)
> +{
> +	struct audit_aux_data_mq_sendrecv *ax;
> +	struct audit_context *context = current->audit_context;
> +
> +	if (likely(!context))
> +		return 0;

audit_enabled?

> +	ax = kmalloc(sizeof(*ax), GFP_ATOMIC);
> +	if (!ax)
> +		return -ENOMEM;
> +
> +	if (u_msg_prio != NULL) {
> +		if (get_user(ax->msg_prio, u_msg_prio))
> +			return -EFAULT;

memleak

> +	} else
> +		ax->msg_prio = 0;
> +
> +	if (u_abs_timeout != NULL) {
> +		if (copy_from_user(&ax->abs_timeout, u_abs_timeout,
> sizeof(ax->abs_timeout))) +			return -EFAULT;

memleak

> +int audit_mq_notify(mqd_t mqdes, const struct sigevent __user
> *u_notification) +{
> +	struct audit_aux_data_mq_notify *ax;
> +	struct audit_context *context = current->audit_context;
> +
> +	if (likely(!context))
> +		return 0;

audit_enabled?

> +	ax = kmalloc(sizeof(*ax), GFP_ATOMIC);
> +	if (!ax)
> +		return -ENOMEM;
> +
> +	if (u_notification != NULL) {
> +		if (copy_from_user(&ax->notification, u_notification,
> sizeof(ax->notification))) +			return -EFAULT;

memleak

> +int audit_mq_getsetattr(mqd_t mqdes, struct mq_attr *mqstat, struct
> mq_attr *omqstat) +{
> +	struct audit_aux_data_mq_getsetattr *ax;
> +	struct audit_context *context = current->audit_context;
> +
> +	if (likely(!context))
> +		return 0;

audit_enabled?

-Steve

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] Audit of POSIX Message Queue Syscalls
  2006-05-17  1:40 [PATCH] Audit of POSIX Message Queue Syscalls George C. Wilson
  2006-05-17 13:34 ` Steve Grubb
@ 2006-05-17 14:34 ` Timothy R. Chavez
  2006-05-17 18:27   ` Steve Grubb
  2006-05-24 21:09 ` [PATCH] Audit of POSIX Message Queue Syscalls v.2 George C. Wilson
  2 siblings, 1 reply; 12+ messages in thread
From: Timothy R. Chavez @ 2006-05-17 14:34 UTC (permalink / raw)
  To: George C. Wilson; +Cc: linux-audit

Hey George,

Just some quick things.  I didn't want to reproduce any of the things
Steve pointed out already... These are just general comments...

-tim

On Tue, 2006-05-16 at 20:40 -0500, George C. Wilson wrote:
<snip>
> @@ -660,6 +663,9 @@ asmlinkage long sys_mq_open(const char _
>  	if (IS_ERR(name = getname(u_name)))
>  		return PTR_ERR(name);
>  
> +	if ((error = audit_mq_open(oflag, mode, u_attr)) != 0)
> +		return error;
> +
>  	fd = get_unused_fd();
>  	if (fd < 0)
>  		goto out_putname;
> @@ -814,6 +820,9 @@ asmlinkage long sys_mq_timedsend(mqd_t m
>  	long timeout;
>  	int ret;
>  
> +	if ((ret = audit_mq_timedsend(mqdes, msg_len, msg_prio, u_abs_timeout)) != 0)
> +		return ret;
> +

Take the assignment out of the dang conditional :)  Besides, you're over
80 characters here aren't ya?  Also, you should probably just follow the
same convention in the function..

ret = audit_mg_timedsend(..);
if (!ret)
	goto out;

[..]
>  	if (unlikely(msg_prio >= (unsigned long) MQ_PRIO_MAX))
>  		return -EINVAL;
>  
> @@ -896,6 +905,9 @@ asmlinkage ssize_t sys_mq_timedreceive(m
>  	struct mqueue_inode_info *info;
>  	struct ext_wait_queue wait;
>  
> +	if ((ret = audit_mq_timedreceive(mqdes, msg_len, u_msg_prio, u_abs_timeout)) != 0)
> +		return ret;
> +
>  	timeout = prepare_timeout(u_abs_timeout);
>  
>  	ret = -EBADF;
> @@ -975,6 +987,9 @@ asmlinkage long sys_mq_notify(mqd_t mqde
>  	struct mqueue_inode_info *info;
>  	struct sk_buff *nc;
>  
> +	if ((ret = audit_mq_notify(mqdes, u_notification)) != 0)
> +		return ret;
> +
>  	nc = NULL;
>  	sock = NULL;
>  	if (u_notification != NULL) {
> @@ -1087,7 +1102,7 @@ asmlinkage long sys_mq_getsetattr(mqd_t 
>  			const struct mq_attr __user *u_mqstat,
>  			struct mq_attr __user *u_omqstat)
>  {
> -	int ret;
> +	int ret, audret;
>  	struct mq_attr mqstat, omqstat;
>  	struct file *filp;
>  	struct inode *inode;
> @@ -1130,9 +1145,13 @@ asmlinkage long sys_mq_getsetattr(mqd_t 
>  						sizeof(struct mq_attr)))
>  		ret = -EFAULT;
>  
> +

Eh, get rid of these...

[..]
>  out_fput:
>  	fput(filp);
>  out:
> +	audret = audit_mq_getsetattr(mqdes, &mqstat, &omqstat);
> +	if (ret == 0)
> +		ret = audret;

At a cursory glance, this looks a little fishy to me...

>  	return ret;
>  }
>  
<snip>

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] Audit of POSIX Message Queue Syscalls
  2006-05-17 13:34 ` Steve Grubb
@ 2006-05-17 16:39   ` Amy Griffis
  2006-05-17 18:11     ` Steve Grubb
  2006-05-17 22:38   ` George C. Wilson
  1 sibling, 1 reply; 12+ messages in thread
From: Amy Griffis @ 2006-05-17 16:39 UTC (permalink / raw)
  To: linux-audit

On Wed, May 17, 2006 at 09:34:46AM -0400, Steve Grubb wrote:
> > @@ -1242,6 +1313,187 @@ uid_t audit_get_loginuid(struct audit_co
> >  }
> >
> >  /**
> > + * audit_mq_open - record audit data for a POSIX MQ open
> > + * @oflag: open flag
> > + * @mode: mode bits
> > + * @u_attr: queue attributes
> > + *
> > + * Returns 0 for success or NULL context or < 0 on error.
> > + */
> > +int audit_mq_open(int oflag, mode_t mode, struct mq_attr __user *u_attr)
> > +{
> > +	struct audit_aux_data_mq_open *ax;
> > +	struct audit_context *context = current->audit_context;
> > +
> > +	if (likely(!context))
> > +		return 0;
> 
> What if audit is not enabled? Need to check for it and bail out.

The audit_enabled flag is only checked once during syscall processing,
in audit_syscall_entry.  Once we've made the decision to audit a
syscall, we don't re-check.

If audit_enabled was 0 in audit_syscall_entry, then
context->in_syscall will be 0.  The latter is what you should check
along with !context.

Looking through the code, I see that audit_getname, audit_inode and
friends do both checks, while the other aux data collectors only check
!context.  Looks like someone should add the second check for those
also (except maybe audit_avc_path).  IIRC, we want the avc path
records even when syscall auditing is disabled.

Amy

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] Audit of POSIX Message Queue Syscalls
  2006-05-17 16:39   ` Amy Griffis
@ 2006-05-17 18:11     ` Steve Grubb
  0 siblings, 0 replies; 12+ messages in thread
From: Steve Grubb @ 2006-05-17 18:11 UTC (permalink / raw)
  To: linux-audit

On Wednesday 17 May 2006 12:39, Amy Griffis wrote:
> Looking through the code, I see that audit_getname, audit_inode and
> friends do both checks, while the other aux data collectors only check
> !context.  Looks like someone should add the second check for those
> also (except maybe audit_avc_path).  

I think this was going to be done when the hook functions were changed to an 
inline function that checks if audit is enabled before doing the real 
function call.

> IIRC, we want the avc path records even when syscall auditing is disabled.

True.

-Steve

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] Audit of POSIX Message Queue Syscalls
  2006-05-17 14:34 ` Timothy R. Chavez
@ 2006-05-17 18:27   ` Steve Grubb
  0 siblings, 0 replies; 12+ messages in thread
From: Steve Grubb @ 2006-05-17 18:27 UTC (permalink / raw)
  To: linux-audit

On Wednesday 17 May 2006 10:34, Timothy R. Chavez wrote:
> >  out_fput:
> >       fput(filp);
> >  out:
> > +     audret = audit_mq_getsetattr(mqdes, &mqstat, &omqstat);
> > +     if (ret == 0)
> > +             ret = audret;
>
> At a cursory glance, this looks a little fishy to me...

I think the intent is OK...but the real problem that I see is that it 
generates a record also when calling mq_getattr(). Seems like the function 
could be put here

1095         if (u_mqstat != NULL) {
1096                 if (copy_from_user(&mqstat, u_mqstat, sizeof(struct 
mq_attr)))
1097                         return -EFAULT;
1098                 if (mqstat.mq_flags & (~O_NONBLOCK))
1099                         return -EINVAL;

-->                    audret = audit_mq_getsetattr(mqdes, &mqstat);
			if (audret)
				return audret;           
1100         }

omqstat does not need to be recorded does it? AFAICT, this is the status 
buffer going back to the user.

-Steve

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] Audit of POSIX Message Queue Syscalls
  2006-05-17 13:34 ` Steve Grubb
  2006-05-17 16:39   ` Amy Griffis
@ 2006-05-17 22:38   ` George C. Wilson
  1 sibling, 0 replies; 12+ messages in thread
From: George C. Wilson @ 2006-05-17 22:38 UTC (permalink / raw)
  To: Steve Grubb; +Cc: Timothy Chavez, linux-audit

Thanks much for the review.  First kernel patch, and it shows :-|  I'll produce
a new patch addresing your and Tim's issues plus some other issues I see.

-- 
George Wilson <ltcgcw@us.ibm.com>
IBM Linux Technology Center

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH] Audit of POSIX Message Queue Syscalls v.2
  2006-05-17  1:40 [PATCH] Audit of POSIX Message Queue Syscalls George C. Wilson
  2006-05-17 13:34 ` Steve Grubb
  2006-05-17 14:34 ` Timothy R. Chavez
@ 2006-05-24 21:09 ` George C. Wilson
  2006-05-24 21:23   ` Linda Knippers
                     ` (2 more replies)
  2 siblings, 3 replies; 12+ messages in thread
From: George C. Wilson @ 2006-05-24 21:09 UTC (permalink / raw)
  To: linux-audit

This patch adds audit support to POSIX message queues.  It applies cleanly to
the lspp.b15 branch of Al Viro's git tree.  There are new auxiliary data
structures, and collection and emission routines in kernel/auditsc.c.  New hooks
in ipc/mqueue.c collect arguments from the syscalls.

I tested the patch by building the examples from the POSIX MQ library tarball.
Build them -lrt, not against the old MQ library in the tarball.  Here's the URL:
http://www.geocities.com/wronski12/posix_ipc/libmqueue-4.41.tar.gz
Do auditctl -a exit,always -S for mq_open, mq_timedsend, mq_timedreceive,
mq_notify, mq_getsetattr.  mq_unlink has no new hooks.  Please see the
corresponding userspace patch to get correct output from auditd for the new
record types.

Notes:
	> Do we really need the header or just a forward declaration for mq
	structs?
	No.  Forward declaration added, #include removed.

	> Do we really need 4 message types? IPC was able to get by on 2 of
	> them. Are we recording more than IPC?
	I don't see an easy easy way around this.  The parameters are
	different for each of the calls.  It is possible to emit empty
	fields or conditionalize the output if we want to go that route.

	> Is this additional space really needed?
	No.  Removed.

	> what if u_mqstat==NULL and the fd was bad upon syscall entry? All
	> the data structures are whatever the stack contained, and therefore
	> completely bogus.  I think there are a couple ways that the structs
	> could be uninitialized.
	Got rid of omqstat, moved collection inside the null check, got rid
	of audret.

	> What if audit is not enabled? Need to check for it and bail out.
	Yes, was doing much unnecessary work in the disabled case.  Added
	checks for audit enabled.

	> memory leak from above allocation.
	These do not appear to be leaks.  They always get freed in
	do_syscall_trace_leave(), both when the syscalls return -EFAULT and
	when audit is disabled.  I verified this with printk's.  With the
	check for audit enabled, they no longer get allocated needlessly.
	Unless a syscall can bypass do_syscall_trace_leave(), these look
	like they don't leak.

	> Do we really need to record the size? Is there anything here that's
	> not sec relevant? The same comment applies to the next 3 message
	> types.
	Relative to LSPP, no.  But if someone is trying to DoS the machine,
	it may be helpful.  These are very good questions.  I'm happy to
	pare it down if consensus is this is too much data.

	> Take the assignment out of the dang conditional :)  Besides, you're
	> over 80 characters here aren't ya?  Also, you should probably just
	> follow the same convention in the function.
	Sage advice taken.

	> At a cursory glance, this looks a little fishy to me.
	Looked fishy to me, too, which I had pointed out in my comments.
	Addressed by 4th item above.

	The dummy function prototypes were grossly wrong.  Corrected these.
	This code now builds with audit turned off in the .config.  I had to
	slightly modify the base lspp.b12 code as it did not build with audit
	compiled out.  Looks like this is OK in lspp.b15, though.

 include/linux/audit.h |   17 +++
 ipc/mqueue.c          |   22 ++++
 kernel/auditsc.c      |  264 +++++++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 302 insertions(+), 1 deletion(-)

Signed-off-by: George Wilson <ltcgcw@us.ibm.com>

--

diff --git a/include/linux/audit.h b/include/linux/audit.h
index d8101d3..aa93091 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -85,6 +85,10 @@
 #define AUDIT_CWD		1307	/* Current working directory */
 #define AUDIT_EXECVE		1309	/* execve arguments */
 #define AUDIT_IPC_SET_PERM	1311	/* IPC new permissions record type */
+#define AUDIT_MQ_OPEN		1312	/* POSIX MQ open record type */
+#define AUDIT_MQ_SENDRECV	1313	/* POSIX MQ send/receive record type */
+#define AUDIT_MQ_NOTIFY		1314	/* POSIX MQ notify record type */
+#define AUDIT_MQ_GETSETATTR	1315	/* POSIX MQ get/set attribute record type */
 
 #define AUDIT_AVC		1400	/* SE Linux avc denial or grant */
 #define AUDIT_SELINUX_ERR	1401	/* Internal SE Linux Errors */
@@ -288,6 +292,8 @@ struct audit_context;
 struct inode;
 struct netlink_skb_parms;
 struct linux_binprm;
+struct mq_attr;
+struct mqstat;
 
 #define AUDITSC_INVALID 0
 #define AUDITSC_SUCCESS 1
@@ -350,6 +356,12 @@ static inline int audit_ipc_set_perm(uns
 		return __audit_ipc_set_perm(qbytes, uid, gid, mode);
 	return 0;
 }
+
+extern int audit_mq_open(int oflag, mode_t mode, struct mq_attr __user *u_attr);
+extern int audit_mq_timedsend(mqd_t mqdes, size_t msg_len, unsigned int msg_prio, const struct timespec __user *u_abs_timeout);
+extern int audit_mq_timedreceive(mqd_t mqdes, size_t msg_len, unsigned int __user *u_msg_prio, const struct timespec __user *u_abs_timeout);
+extern int audit_mq_notify(mqd_t mqdes, const struct sigevent __user *u_notification);
+extern int audit_mq_getsetattr(mqd_t mqdes, struct mq_attr *mqstat);
 #else
 #define audit_alloc(t) ({ 0; })
 #define audit_free(t) do { ; } while (0)
@@ -370,6 +382,11 @@ static inline int audit_ipc_set_perm(uns
 #define audit_sockaddr(len, addr) ({ 0; })
 #define audit_avc_path(dentry, mnt) ({ 0; })
 #define audit_set_macxattr(n) do { ; } while (0)
+#define audit_mq_open(o,m,a) ({ 0; })
+#define audit_mq_timedsend(d,l,p,t) ({ 0; })
+#define audit_mq_timedreceive(d,l,p,t) ({ 0; })
+#define audit_mq_notify(d,n) ({ 0; })
+#define audit_mq_getsetattr(d,s) ({ 0; })
 #endif
 
 #ifdef CONFIG_AUDIT
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index 41ecbd4..1511714 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -8,6 +8,8 @@
  * Lockless receive & send, fd based notify:
  * 			    Manfred Spraul	    (manfred@colorfullife.com)
  *
+ * Audit:                   George Wilson           (ltcgcw@us.ibm.com)
+ *
  * This file is released under the GPL.
  */
 
@@ -24,6 +26,7 @@
 #include <linux/skbuff.h>
 #include <linux/netlink.h>
 #include <linux/syscalls.h>
+#include <linux/audit.h>
 #include <linux/signal.h>
 #include <linux/mutex.h>
 
@@ -657,6 +660,10 @@ asmlinkage long sys_mq_open(const char _
 	char *name;
 	int fd, error;
 
+	error = audit_mq_open(oflag, mode, u_attr);
+	if (error != 0)
+		return error;
+
 	if (IS_ERR(name = getname(u_name)))
 		return PTR_ERR(name);
 
@@ -814,6 +821,10 @@ asmlinkage long sys_mq_timedsend(mqd_t m
 	long timeout;
 	int ret;
 
+	ret = audit_mq_timedsend(mqdes, msg_len, msg_prio, u_abs_timeout);
+	if (ret != 0)
+		return ret;
+
 	if (unlikely(msg_prio >= (unsigned long) MQ_PRIO_MAX))
 		return -EINVAL;
 
@@ -896,6 +907,10 @@ asmlinkage ssize_t sys_mq_timedreceive(m
 	struct mqueue_inode_info *info;
 	struct ext_wait_queue wait;
 
+	ret = audit_mq_timedreceive(mqdes, msg_len, u_msg_prio, u_abs_timeout);
+	if (ret != 0)
+		return ret;
+
 	timeout = prepare_timeout(u_abs_timeout);
 
 	ret = -EBADF;
@@ -975,6 +990,10 @@ asmlinkage long sys_mq_notify(mqd_t mqde
 	struct mqueue_inode_info *info;
 	struct sk_buff *nc;
 
+	ret = audit_mq_notify(mqdes, u_notification);
+	if (ret != 0)
+		return ret;
+
 	nc = NULL;
 	sock = NULL;
 	if (u_notification != NULL) {
@@ -1115,6 +1134,9 @@ asmlinkage long sys_mq_getsetattr(mqd_t 
 	omqstat = info->attr;
 	omqstat.mq_flags = filp->f_flags & O_NONBLOCK;
 	if (u_mqstat) {
+		ret = audit_mq_getsetattr(mqdes, &mqstat);
+		if (ret != 0)
+			goto out;
 		if (mqstat.mq_flags & O_NONBLOCK)
 			filp->f_flags |= O_NONBLOCK;
 		else
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 0d1d9af..a7ab249 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -3,7 +3,7 @@
  *
  * Copyright 2003-2004 Red Hat Inc., Durham, North Carolina.
  * Copyright 2005 Hewlett-Packard Development Company, L.P.
- * Copyright (C) 2005 IBM Corporation
+ * Copyright (C) 2005, 2006 IBM Corporation
  * All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify
@@ -29,6 +29,9 @@
  * this file -- see entry.S) is based on a GPL'd patch written by
  * okir@suse.de and Copyright 2003 SuSE Linux AG.
  *
+ * POSIX message queue support added by George Wilson <ltcgcw@us.ibm.com>,
+ * 2006.
+ *
  * The support of additional filter rules compares (>, <, >=, <=) was
  * added by Dustin Kirkland <dustin.kirkland@us.ibm.com>, 2005.
  *
@@ -49,6 +52,7 @@
 #include <linux/module.h>
 #include <linux/mount.h>
 #include <linux/socket.h>
+#include <linux/mqueue.h>
 #include <linux/audit.h>
 #include <linux/personality.h>
 #include <linux/time.h>
@@ -102,6 +106,33 @@ struct audit_aux_data {
 
 #define AUDIT_AUX_IPCPERM	0
 
+struct audit_aux_data_mq_open {
+	struct audit_aux_data	d;
+	int			oflag;
+	mode_t			mode;
+	struct mq_attr		attr;
+};
+
+struct audit_aux_data_mq_sendrecv {
+	struct audit_aux_data	d;
+	mqd_t			mqdes;
+	size_t			msg_len;
+	unsigned int		msg_prio;
+	struct timespec		abs_timeout;
+};
+
+struct audit_aux_data_mq_notify {
+	struct audit_aux_data	d;
+	mqd_t			mqdes;
+	struct sigevent 	notification;
+};
+
+struct audit_aux_data_mq_getsetattr {
+	struct audit_aux_data	d;
+	mqd_t			mqdes;
+	struct mq_attr 		mqstat;
+};
+
 struct audit_aux_data_ipcctl {
 	struct audit_aux_data	d;
 	struct ipc_perm		p;
@@ -708,6 +739,43 @@ static void audit_log_exit(struct audit_
 			continue; /* audit_panic has been called */
 
 		switch (aux->type) {
+		case AUDIT_MQ_OPEN: {
+			struct audit_aux_data_mq_open *axi = (void *)aux;
+			audit_log_format(ab, 
+				"oflag=0x%x mode=%#o mq_flags=0x%lx mq_maxmsg=%ld "
+				"mq_msgsize=%ld mq_curmsgs=%ld",
+				axi->oflag, axi->mode, axi->attr.mq_flags,
+				axi->attr.mq_maxmsg, axi->attr.mq_msgsize,
+				axi->attr.mq_curmsgs);
+			break; }
+
+		case AUDIT_MQ_SENDRECV: {
+			struct audit_aux_data_mq_sendrecv *axi = (void *)aux;
+			audit_log_format(ab, 
+				"mqdes=%d msg_len=%ld msg_prio=%u "
+				"abs_timeout_sec=%ld abs_timeout_nsec=%ld",
+				axi->mqdes, axi->msg_len, axi->msg_prio,
+				axi->abs_timeout.tv_sec, axi->abs_timeout.tv_nsec);
+			break; }
+
+		case AUDIT_MQ_NOTIFY: {
+			struct audit_aux_data_mq_notify *axi = (void *)aux;
+			audit_log_format(ab, 
+				"mqdes=%d sigev_signo=%d",
+				axi->mqdes,
+				axi->notification.sigev_signo);
+			break; }
+
+		case AUDIT_MQ_GETSETATTR: {
+			struct audit_aux_data_mq_getsetattr *axi = (void *)aux;
+			audit_log_format(ab, 
+				"mqdes=%d mq_flags=0x%lx mq_maxmsg=%ld mq_msgsize=%ld "
+				"mq_curmsgs=%ld ",
+				axi->mqdes, 
+				axi->mqstat.mq_flags, axi->mqstat.mq_maxmsg,
+				axi->mqstat.mq_msgsize, axi->mqstat.mq_curmsgs);
+			break; }
+
 		case AUDIT_IPC: {
 			struct audit_aux_data_ipcctl *axi = (void *)aux;
 			audit_log_format(ab, 
@@ -1230,6 +1298,200 @@ uid_t audit_get_loginuid(struct audit_co
 }
 
 /**
+ * audit_mq_open - record audit data for a POSIX MQ open
+ * @oflag: open flag
+ * @mode: mode bits
+ * @u_attr: queue attributes
+ *
+ * Returns 0 for success or NULL context or < 0 on error.
+ */
+int audit_mq_open(int oflag, mode_t mode, struct mq_attr __user *u_attr)
+{
+	struct audit_aux_data_mq_open *ax;
+	struct audit_context *context = current->audit_context;
+
+	if (!audit_enabled)
+		return 0;
+
+	if (likely(!context))
+		return 0;
+
+	ax = kmalloc(sizeof(*ax), GFP_ATOMIC);
+	if (!ax)
+		return -ENOMEM;
+
+	if (u_attr != NULL) {
+		if (copy_from_user(&ax->attr, u_attr, sizeof(ax->attr)))
+			return -EFAULT;
+	} else
+		memset(&ax->attr, 0, sizeof(ax->attr));
+
+	ax->oflag = oflag;
+	ax->mode = mode;
+
+	ax->d.type = AUDIT_MQ_OPEN;
+	ax->d.next = context->aux;
+	context->aux = (void *)ax;
+	return 0;
+}
+
+/**
+ * audit_mq_timedsend - record audit data for a POSIX MQ timed send
+ * @mqdes: MQ descriptor
+ * @msg_len: Message length
+ * @msg_prio: Message priority
+ * @abs_timeout: Message timeout in absolute time
+ *
+ * Returns 0 for success or NULL context or < 0 on error.
+ */
+int audit_mq_timedsend(mqd_t mqdes, size_t msg_len, unsigned int msg_prio,
+			const struct timespec __user *u_abs_timeout)
+{
+	struct audit_aux_data_mq_sendrecv *ax;
+	struct audit_context *context = current->audit_context;
+
+	if (!audit_enabled)
+		return 0;
+
+	if (likely(!context))
+		return 0;
+
+	ax = kmalloc(sizeof(*ax), GFP_ATOMIC);
+	if (!ax)
+		return -ENOMEM;
+
+	if (u_abs_timeout != NULL) {
+		if (copy_from_user(&ax->abs_timeout, u_abs_timeout, sizeof(ax->abs_timeout)))
+			return -EFAULT;
+	} else
+		memset(&ax->abs_timeout, 0, sizeof(ax->abs_timeout));
+
+	ax->mqdes = mqdes;
+	ax->msg_len = msg_len;
+	ax->msg_prio = msg_prio;
+
+	ax->d.type = AUDIT_MQ_SENDRECV;
+	ax->d.next = context->aux;
+	context->aux = (void *)ax;
+	return 0;
+}
+
+/**
+ * audit_mq_timedreceive - record audit data for a POSIX MQ timed receive
+ * @mqdes: MQ descriptor
+ * @msg_len: Message length
+ * @msg_prio: Message priority
+ * @abs_timeout: Message timeout in absolute time
+ *
+ * Returns 0 for success or NULL context or < 0 on error.
+ */
+int audit_mq_timedreceive(mqd_t mqdes, size_t msg_len,
+				unsigned int __user *u_msg_prio,
+				const struct timespec __user *u_abs_timeout)
+{
+	struct audit_aux_data_mq_sendrecv *ax;
+	struct audit_context *context = current->audit_context;
+
+	if (!audit_enabled)
+		return 0;
+
+	if (likely(!context))
+		return 0;
+
+	ax = kmalloc(sizeof(*ax), GFP_ATOMIC);
+	if (!ax)
+		return -ENOMEM;
+
+	if (u_msg_prio != NULL) {
+		if (get_user(ax->msg_prio, u_msg_prio))
+			return -EFAULT;
+	} else
+		ax->msg_prio = 0;
+
+	if (u_abs_timeout != NULL) {
+		if (copy_from_user(&ax->abs_timeout, u_abs_timeout, sizeof(ax->abs_timeout)))
+			return -EFAULT;
+	} else
+		memset(&ax->abs_timeout, 0, sizeof(ax->abs_timeout));
+
+	ax->mqdes = mqdes;
+	ax->msg_len = msg_len;
+
+	ax->d.type = AUDIT_MQ_SENDRECV;
+	ax->d.next = context->aux;
+	context->aux = (void *)ax;
+	return 0;
+}
+
+/**
+ * audit_mq_notify - record audit data for a POSIX MQ notify
+ * @mqdes: MQ descriptor
+ * @u_notification: Notification event
+ *
+ * Returns 0 for success or NULL context or < 0 on error.
+ */
+
+int audit_mq_notify(mqd_t mqdes, const struct sigevent __user *u_notification)
+{
+	struct audit_aux_data_mq_notify *ax;
+	struct audit_context *context = current->audit_context;
+
+	if (!audit_enabled)
+		return 0;
+
+	if (likely(!context))
+		return 0;
+
+	ax = kmalloc(sizeof(*ax), GFP_ATOMIC);
+	if (!ax)
+		return -ENOMEM;
+
+	if (u_notification != NULL) {
+		if (copy_from_user(&ax->notification, u_notification, sizeof(ax->notification)))
+			return -EFAULT;
+	} else
+		memset(&ax->notification, 0, sizeof(ax->notification));
+
+	ax->mqdes = mqdes;
+
+	ax->d.type = AUDIT_MQ_NOTIFY;
+	ax->d.next = context->aux;
+	context->aux = (void *)ax;
+	return 0;
+}
+
+/**
+ * audit_mq_getsetattr - record audit data for a POSIX MQ get/set attribute
+ * @mqdes: MQ descriptor
+ * @mqstat: MQ flags
+ *
+ * Returns 0 for success or NULL context or < 0 on error.
+ */
+int audit_mq_getsetattr(mqd_t mqdes, struct mq_attr *mqstat)
+{
+	struct audit_aux_data_mq_getsetattr *ax;
+	struct audit_context *context = current->audit_context;
+
+	if (!audit_enabled)
+		return 0;
+
+	if (likely(!context))
+		return 0;
+
+	ax = kmalloc(sizeof(*ax), GFP_ATOMIC);
+	if (!ax)
+		return -ENOMEM;
+
+	ax->mqdes = mqdes;
+	ax->mqstat = *mqstat;
+
+	ax->d.type = AUDIT_MQ_GETSETATTR;
+	ax->d.next = context->aux;
+	context->aux = (void *)ax;
+	return 0;
+}
+
+/**
  * audit_ipc_obj - record audit data for ipc object
  * @ipcp: ipc permissions
  *
-- 
George Wilson <ltcgcw@us.ibm.com>
IBM Linux Technology Center

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH] Audit of POSIX Message Queue Syscalls v.2
  2006-05-24 21:09 ` [PATCH] Audit of POSIX Message Queue Syscalls v.2 George C. Wilson
@ 2006-05-24 21:23   ` Linda Knippers
  2006-05-24 21:32   ` Amy Griffis
  2006-05-24 21:53   ` Steve Grubb
  2 siblings, 0 replies; 12+ messages in thread
From: Linda Knippers @ 2006-05-24 21:23 UTC (permalink / raw)
  To: George C. Wilson; +Cc: linux-audit

Hi George,

> 	> memory leak from above allocation.
> 	These do not appear to be leaks.  They always get freed in
> 	do_syscall_trace_leave(), both when the syscalls return -EFAULT and
> 	when audit is disabled.  I verified this with printk's.  With the
> 	check for audit enabled, they no longer get allocated needlessly.
> 	Unless a syscall can bypass do_syscall_trace_leave(), these look
> 	like they don't leak.

I think you do have some memory leaks.  For example:

> +int audit_mq_open(int oflag, mode_t mode, struct mq_attr __user *u_attr)
> +{
> +	struct audit_aux_data_mq_open *ax;
> +	struct audit_context *context = current->audit_context;
> +
> +	if (!audit_enabled)
> +		return 0;
> +
> +	if (likely(!context))
> +		return 0;
> +
> +	ax = kmalloc(sizeof(*ax), GFP_ATOMIC);
> +	if (!ax)
> +		return -ENOMEM;
> +
> +	if (u_attr != NULL) {
> +		if (copy_from_user(&ax->attr, u_attr, sizeof(ax->attr)))
> +			return -EFAULT;

If this return is taken, the memory allocated above will not be freed
at syscall exit time because the assignment of context->aux was not
made.  ax needs to be freed before returning from the error paths.

> +	} else
> +		memset(&ax->attr, 0, sizeof(ax->attr));
> +
> +	ax->oflag = oflag;
> +	ax->mode = mode;
> +
> +	ax->d.type = AUDIT_MQ_OPEN;
> +	ax->d.next = context->aux;
> +	context->aux = (void *)ax;
> +	return 0;
> +}

There are similar cases in other functions.

-- ljk

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] Audit of POSIX Message Queue Syscalls v.2
  2006-05-24 21:09 ` [PATCH] Audit of POSIX Message Queue Syscalls v.2 George C. Wilson
  2006-05-24 21:23   ` Linda Knippers
@ 2006-05-24 21:32   ` Amy Griffis
  2006-05-24 21:53   ` Steve Grubb
  2 siblings, 0 replies; 12+ messages in thread
From: Amy Griffis @ 2006-05-24 21:32 UTC (permalink / raw)
  To: linux-audit

On Wed, May 24, 2006 at 04:09:55PM -0500, George C. Wilson wrote:
> @@ -1230,6 +1298,200 @@ uid_t audit_get_loginuid(struct audit_co
>  }
>  
>  /**
> + * audit_mq_open - record audit data for a POSIX MQ open
> + * @oflag: open flag
> + * @mode: mode bits
> + * @u_attr: queue attributes
> + *
> + * Returns 0 for success or NULL context or < 0 on error.
> + */
> +int audit_mq_open(int oflag, mode_t mode, struct mq_attr __user *u_attr)
> +{
> +	struct audit_aux_data_mq_open *ax;
> +	struct audit_context *context = current->audit_context;
> +
> +	if (!audit_enabled)
> +		return 0;

Should be checking !context->in_syscall instead of !audit_enabled,
please see
https://www.redhat.com/archives/linux-audit/2006-May/msg00083.html

Same applies to all the new audit_mq_* routines.

> +
> +	if (likely(!context))
> +		return 0;
> +
> +	ax = kmalloc(sizeof(*ax), GFP_ATOMIC);
> +	if (!ax)
> +		return -ENOMEM;
> +
> +	if (u_attr != NULL) {
> +		if (copy_from_user(&ax->attr, u_attr, sizeof(ax->attr)))
> +			return -EFAULT;
> +	} else
> +		memset(&ax->attr, 0, sizeof(ax->attr));
> +
> +	ax->oflag = oflag;
> +	ax->mode = mode;
> +
> +	ax->d.type = AUDIT_MQ_OPEN;
> +	ax->d.next = context->aux;
> +	context->aux = (void *)ax;
> +	return 0;
> +}
> +
> +/**
> + * audit_mq_timedsend - record audit data for a POSIX MQ timed send
> + * @mqdes: MQ descriptor
> + * @msg_len: Message length
> + * @msg_prio: Message priority
> + * @abs_timeout: Message timeout in absolute time
> + *
> + * Returns 0 for success or NULL context or < 0 on error.
> + */
> +int audit_mq_timedsend(mqd_t mqdes, size_t msg_len, unsigned int msg_prio,
> +			const struct timespec __user *u_abs_timeout)
> +{
> +	struct audit_aux_data_mq_sendrecv *ax;
> +	struct audit_context *context = current->audit_context;
> +
> +	if (!audit_enabled)
> +		return 0;
> +
> +	if (likely(!context))
> +		return 0;
> +
> +	ax = kmalloc(sizeof(*ax), GFP_ATOMIC);
> +	if (!ax)
> +		return -ENOMEM;
> +
> +	if (u_abs_timeout != NULL) {
> +		if (copy_from_user(&ax->abs_timeout, u_abs_timeout, sizeof(ax->abs_timeout)))
> +			return -EFAULT;
> +	} else
> +		memset(&ax->abs_timeout, 0, sizeof(ax->abs_timeout));
> +
> +	ax->mqdes = mqdes;
> +	ax->msg_len = msg_len;
> +	ax->msg_prio = msg_prio;
> +
> +	ax->d.type = AUDIT_MQ_SENDRECV;
> +	ax->d.next = context->aux;
> +	context->aux = (void *)ax;
> +	return 0;
> +}
> +
> +/**
> + * audit_mq_timedreceive - record audit data for a POSIX MQ timed receive
> + * @mqdes: MQ descriptor
> + * @msg_len: Message length
> + * @msg_prio: Message priority
> + * @abs_timeout: Message timeout in absolute time
> + *
> + * Returns 0 for success or NULL context or < 0 on error.
> + */
> +int audit_mq_timedreceive(mqd_t mqdes, size_t msg_len,
> +				unsigned int __user *u_msg_prio,
> +				const struct timespec __user *u_abs_timeout)
> +{
> +	struct audit_aux_data_mq_sendrecv *ax;
> +	struct audit_context *context = current->audit_context;
> +
> +	if (!audit_enabled)
> +		return 0;
> +
> +	if (likely(!context))
> +		return 0;
> +
> +	ax = kmalloc(sizeof(*ax), GFP_ATOMIC);
> +	if (!ax)
> +		return -ENOMEM;
> +
> +	if (u_msg_prio != NULL) {
> +		if (get_user(ax->msg_prio, u_msg_prio))
> +			return -EFAULT;
> +	} else
> +		ax->msg_prio = 0;
> +
> +	if (u_abs_timeout != NULL) {
> +		if (copy_from_user(&ax->abs_timeout, u_abs_timeout, sizeof(ax->abs_timeout)))
> +			return -EFAULT;
> +	} else
> +		memset(&ax->abs_timeout, 0, sizeof(ax->abs_timeout));
> +
> +	ax->mqdes = mqdes;
> +	ax->msg_len = msg_len;
> +
> +	ax->d.type = AUDIT_MQ_SENDRECV;
> +	ax->d.next = context->aux;
> +	context->aux = (void *)ax;
> +	return 0;
> +}
> +
> +/**
> + * audit_mq_notify - record audit data for a POSIX MQ notify
> + * @mqdes: MQ descriptor
> + * @u_notification: Notification event
> + *
> + * Returns 0 for success or NULL context or < 0 on error.
> + */
> +
> +int audit_mq_notify(mqd_t mqdes, const struct sigevent __user *u_notification)
> +{
> +	struct audit_aux_data_mq_notify *ax;
> +	struct audit_context *context = current->audit_context;
> +
> +	if (!audit_enabled)
> +		return 0;
> +
> +	if (likely(!context))
> +		return 0;
> +
> +	ax = kmalloc(sizeof(*ax), GFP_ATOMIC);
> +	if (!ax)
> +		return -ENOMEM;
> +
> +	if (u_notification != NULL) {
> +		if (copy_from_user(&ax->notification, u_notification, sizeof(ax->notification)))
> +			return -EFAULT;
> +	} else
> +		memset(&ax->notification, 0, sizeof(ax->notification));
> +
> +	ax->mqdes = mqdes;
> +
> +	ax->d.type = AUDIT_MQ_NOTIFY;
> +	ax->d.next = context->aux;
> +	context->aux = (void *)ax;
> +	return 0;
> +}
> +
> +/**
> + * audit_mq_getsetattr - record audit data for a POSIX MQ get/set attribute
> + * @mqdes: MQ descriptor
> + * @mqstat: MQ flags
> + *
> + * Returns 0 for success or NULL context or < 0 on error.
> + */
> +int audit_mq_getsetattr(mqd_t mqdes, struct mq_attr *mqstat)
> +{
> +	struct audit_aux_data_mq_getsetattr *ax;
> +	struct audit_context *context = current->audit_context;
> +
> +	if (!audit_enabled)
> +		return 0;
> +
> +	if (likely(!context))
> +		return 0;
> +
> +	ax = kmalloc(sizeof(*ax), GFP_ATOMIC);
> +	if (!ax)
> +		return -ENOMEM;
> +
> +	ax->mqdes = mqdes;
> +	ax->mqstat = *mqstat;
> +
> +	ax->d.type = AUDIT_MQ_GETSETATTR;
> +	ax->d.next = context->aux;
> +	context->aux = (void *)ax;
> +	return 0;
> +}
> +
> +/**
>   * audit_ipc_obj - record audit data for ipc object
>   * @ipcp: ipc permissions
>   *
> -- 
> George Wilson <ltcgcw@us.ibm.com>
> IBM Linux Technology Center
> 
> --
> Linux-audit mailing list
> Linux-audit@redhat.com
> https://www.redhat.com/mailman/listinfo/linux-audit
> 

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] Audit of POSIX Message Queue Syscalls v.2
  2006-05-24 21:09 ` [PATCH] Audit of POSIX Message Queue Syscalls v.2 George C. Wilson
  2006-05-24 21:23   ` Linda Knippers
  2006-05-24 21:32   ` Amy Griffis
@ 2006-05-24 21:53   ` Steve Grubb
  2006-05-25  1:33     ` George C. Wilson
  2 siblings, 1 reply; 12+ messages in thread
From: Steve Grubb @ 2006-05-24 21:53 UTC (permalink / raw)
  To: linux-audit

On Wednesday 24 May 2006 17:09, George C. Wilson wrote:
> +extern int audit_mq_open(int oflag, mode_t mode, struct mq_attr __user *u_attr);
> +extern int audit_mq_timedsend(mqd_t mqdes, size_t msg_len, unsigned int msg_prio, const struct timespec __user *u_abs_timeout);
> +extern int audit_mq_timedreceive(mqd_t mqdes, size_t msg_len, unsigned int __user *u_msg_prio, const struct timespec __user *u_abs_timeout);
> +extern int audit_mq_notify(mqd_t mqdes, const struct sigevent __user *u_notification);
> +extern int audit_mq_getsetattr(mqd_t mqdes, struct mq_attr *mqstat);

We also recently updated all the audit hook functions to be inline functions that 
check audit_enable and call the real function if true.

-Steve

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] Audit of POSIX Message Queue Syscalls v.2
  2006-05-24 21:53   ` Steve Grubb
@ 2006-05-25  1:33     ` George C. Wilson
  0 siblings, 0 replies; 12+ messages in thread
From: George C. Wilson @ 2006-05-25  1:33 UTC (permalink / raw)
  To: Steve Grubb; +Cc: linux-audit

On Wed, May 24, 2006 at 05:53:15PM -0400, Steve Grubb wrote:
> On Wednesday 24 May 2006 17:09, George C. Wilson wrote:
> > +extern int audit_mq_open(int oflag, mode_t mode, struct mq_attr __user *u_attr);
> > +extern int audit_mq_timedsend(mqd_t mqdes, size_t msg_len, unsigned int msg_prio, const struct timespec __user *u_abs_timeout);
> > +extern int audit_mq_timedreceive(mqd_t mqdes, size_t msg_len, unsigned int __user *u_msg_prio, const struct timespec __user *u_abs_timeout);
> > +extern int audit_mq_notify(mqd_t mqdes, const struct sigevent __user *u_notification);
> > +extern int audit_mq_getsetattr(mqd_t mqdes, struct mq_attr *mqstat);
> 
> We also recently updated all the audit hook functions to be inline functions that 
> check audit_enable and call the real function if true.
> 
> -Steve

Well, thought I was ready to post the delta.  Inlining was one of the changes
Jose mentioned last go round.  I'll make this mod, too.  No post tonight,
though.

-- 
George Wilson <ltcgcw@us.ibm.com>
IBM Linux Technology Center

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2006-05-25  1:33 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-05-17  1:40 [PATCH] Audit of POSIX Message Queue Syscalls George C. Wilson
2006-05-17 13:34 ` Steve Grubb
2006-05-17 16:39   ` Amy Griffis
2006-05-17 18:11     ` Steve Grubb
2006-05-17 22:38   ` George C. Wilson
2006-05-17 14:34 ` Timothy R. Chavez
2006-05-17 18:27   ` Steve Grubb
2006-05-24 21:09 ` [PATCH] Audit of POSIX Message Queue Syscalls v.2 George C. Wilson
2006-05-24 21:23   ` Linda Knippers
2006-05-24 21:32   ` Amy Griffis
2006-05-24 21:53   ` Steve Grubb
2006-05-25  1:33     ` George C. Wilson

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox