bk://linux-audit.bkbits.net/audit-2.6-mm
chrisw@osdl.org|ChangeSet|20050303195709|62478 chrisw

# This is a BitKeeper generated diff -Nru style patch.
#
# ChangeSet
#   2005/03/03 21:49:19-08:00 akpm@bix.(none) 
#   Merge bk://linux-audit.bkbits.net/audit-2.6-mm
#   into bix.(none):/usr/src/bk-audit
# 
# kernel/auditsc.c
#   2005/03/03 21:49:13-08:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2005/03/03 11:57:09-08:00 chrisw@osdl.org 
#   Inode audit records are currently showing only name, inode, and dev.
#   The device is calculated incorrectly, and similarly dev based filtering
#   is broken.  Fix device node problems and add some more useful data to
#   inode audit record -- mode, uid, gid of inode.
#   
#   Signed-off-by: Chris Wright <chrisw@osdl.org>
# 
# kernel/auditsc.c
#   2005/03/03 11:55:34-08:00 chrisw@osdl.org +21 -12
#   fix audit_inode and dev filtering
# 
# include/linux/audit.h
#   2005/03/03 11:55:24-08:00 chrisw@osdl.org +5 -2
#   audit_inode now takes inode object
# 
# fs/namei.c
#   2005/03/03 11:53:57-08:00 chrisw@osdl.org +1 -3
#   audit_inode now takes inode object
# 
# ChangeSet
#   2005/03/03 11:21:52-08:00 jdike@addtoit.com 
#   
#   For UML, this is fine as far as it goes, but you're adding register references
#   to arch-independent code, so this is needed as well:
#   
#   Signed-off-by: Jeff Dike <jdike@addtoit.com>
#   Signed-off-by: Chris Wright <chrisw@osdl.org>
# 
# arch/um/kernel/ptrace.c
#   2005/03/03 08:42:41-08:00 jdike@addtoit.com +8 -4
#   Re: 2.6.11-rc5-mm1
# 
# ChangeSet
#   2005/03/01 22:07:42-08:00 akpm@bix.(none) 
#   Merge bk://linux-audit.bkbits.net/audit-2.6-mm
#   into bix.(none):/usr/src/bk-audit
# 
# kernel/auditsc.c
#   2005/03/01 22:07:38-08:00 akpm@bix.(none) +0 -0
#   Auto merged
# 
# ChangeSet
#   2005/03/01 14:34:18-08:00 chrisw@osdl.org 
#   A closer sweep of configurable audit symbols shows the following need
#   audit.h included when audit.h is detangled from fs.h.
#   
#           arch/um/kernel/ptrace.c    for audit_syscall_entry/exit
#           arch/s390/kernel/ptrace.c  for audit_syscall_entry/exit
#           arch/mips/kernel/ptrace.c  for audit_syscall_entry/exit
#   
#   Signed-off-by: Chris Wright <chrisw@osdl.org>
# 
# arch/um/kernel/ptrace.c
#   2005/03/01 14:34:12-08:00 chrisw@osdl.org +1 -0
#   include audit.h for audit_syscall_entry/exit
# 
# arch/s390/kernel/ptrace.c
#   2005/03/01 14:34:12-08:00 chrisw@osdl.org +1 -0
#   include audit.h for audit_syscall_entry/exit
# 
# arch/mips/kernel/ptrace.c
#   2005/03/01 14:34:12-08:00 chrisw@osdl.org +1 -0
#   include audit.h for audit_syscall_entry/exit
# 
# ChangeSet
#   2005/03/01 14:30:53-08:00 chrisw@osdl.org 
#   Currently touching audit.h triggers a large rebuild because it's sucked
#   in via fs.h.  It's there because of the getname()/putname() requirements
#   that come with CONFIG_AUDITSYSCALL.  Remove header dependency by pushing
#   relevant putname() implementation into fs/namei.c.  It adds function
#   call overhead for putname() callers when CONFIG_AUDITSYSCALL is set,
#   quite minor cost for detangled source.
#   
#   Signed-off-by: Chris Wright <chrisw@osdl.org>
# 
# kernel/auditsc.c
#   2005/03/01 14:30:46-08:00 chrisw@osdl.org +3 -2
#   audit_getname call is completely selfcontained now, and audit_putname
#   no longer needs to be exported since it's not inlined in fs.h.
# 
# include/linux/fs.h
#   2005/03/01 14:30:46-08:00 chrisw@osdl.org +1 -8
#   Move putname implementation to fs/namei.c when CONFIG_AUDITSYSCALL
#   is set.  Remove audit.h include to detangle from fs.h.
# 
# fs/proc/base.c
#   2005/03/01 14:30:46-08:00 chrisw@osdl.org +1 -0
#   add audit.h include for audit_get/set_loginuid
# 
# fs/namei.c
#   2005/03/01 14:30:46-08:00 chrisw@osdl.org +13 -2
#   Move putname implementation to fs/namei.c when CONFIG_AUDITSYSCALL
#   is set.
# 
# ChangeSet
#   2005/03/01 09:15:37+00:00 dwmw2@shinybook.infradead.org 
#   Audit IPC object owner/permission changes.
#   
#   Add linked list of auxiliary data to audit_context
#   Add callbacks in IPC_SET functions to record requested changes.
#   
#   Signed-off-by: David Woodhouse <dwmw2@infradead.org>
# 
# kernel/auditsc.c
#   2005/03/01 09:15:21+00:00 dwmw2@shinybook.infradead.org +76 -0
#   Implement linked list for auxiliary data, use it for audit_ipc_perms()
# 
# ipc/shm.c
#   2005/03/01 09:15:21+00:00 dwmw2@shinybook.infradead.org +3 -0
#   Call audit_ipc_perms() for IPC_SET
# 
# ipc/sem.c
#   2005/03/01 09:15:21+00:00 dwmw2@shinybook.infradead.org +3 -0
#   Call audit_ipc_perms() for IPC_SET
# 
# ipc/msg.c
#   2005/03/01 09:15:21+00:00 dwmw2@shinybook.infradead.org +3 -0
#   Call audit_ipc_perms() for IPC_SET
# 
# include/linux/audit.h
#   2005/03/01 09:15:21+00:00 dwmw2@shinybook.infradead.org +2 -0
#   Add audit_ipc_perms() definition.
# 
diff -Nru a/arch/mips/kernel/ptrace.c b/arch/mips/kernel/ptrace.c
--- a/arch/mips/kernel/ptrace.c	2005-03-03 21:50:39 -08:00
+++ b/arch/mips/kernel/ptrace.c	2005-03-03 21:50:39 -08:00
@@ -25,6 +25,7 @@
 #include <linux/smp_lock.h>
 #include <linux/user.h>
 #include <linux/security.h>
+#include <linux/audit.h>
 
 #include <asm/cpu.h>
 #include <asm/fpu.h>
diff -Nru a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c
--- a/arch/s390/kernel/ptrace.c	2005-03-03 21:50:39 -08:00
+++ b/arch/s390/kernel/ptrace.c	2005-03-03 21:50:39 -08:00
@@ -31,6 +31,7 @@
 #include <linux/ptrace.h>
 #include <linux/user.h>
 #include <linux/security.h>
+#include <linux/audit.h>
 
 #include <asm/segment.h>
 #include <asm/page.h>
diff -Nru a/arch/um/kernel/ptrace.c b/arch/um/kernel/ptrace.c
--- a/arch/um/kernel/ptrace.c	2005-03-03 21:50:39 -08:00
+++ b/arch/um/kernel/ptrace.c	2005-03-03 21:50:39 -08:00
@@ -9,6 +9,7 @@
 #include "linux/smp_lock.h"
 #include "linux/security.h"
 #include "linux/ptrace.h"
+#include "linux/audit.h"
 #ifdef CONFIG_PROC_MM
 #include "linux/proc_mm.h"
 #endif
@@ -336,11 +337,15 @@
 
 	if (unlikely(current->audit_context)) {
 		if (!entryexit)
-			audit_syscall_entry(current, regs->orig_eax,
-					    regs->ebx, regs->ecx,
-					    regs->edx, regs->esi);
+			audit_syscall_entry(current, 
+					    UPT_SYSCALL_NR(&regs->regs),
+					    UPT_SYSCALL_ARG1(&regs->regs),
+					    UPT_SYSCALL_ARG2(&regs->regs),
+					    UPT_SYSCALL_ARG3(&regs->regs),
+					    UPT_SYSCALL_ARG4(&regs->regs));
 		else
-			audit_syscall_exit(current, regs->eax);
+			audit_syscall_exit(current, 
+					   UPT_SYSCALL_RET(&regs->regs));
 	}
 
 	/* Fake a debug trap */
diff -Nru a/fs/namei.c b/fs/namei.c
--- a/fs/namei.c	2005-03-03 21:50:39 -08:00
+++ b/fs/namei.c	2005-03-03 21:50:39 -08:00
@@ -148,11 +148,22 @@
 			result = ERR_PTR(retval);
 		}
 	}
-	if (unlikely(current->audit_context) && !IS_ERR(result) && result)
-		audit_getname(result);
+	audit_getname(result);
 	return result;
 }
 
+#ifdef CONFIG_AUDITSYSCALL
+void putname(const char *name)
+{
+	if (unlikely(current->audit_context))
+		audit_putname(name);
+	else
+		__putname(name);
+}
+EXPORT_SYMBOL(putname);
+#endif
+
+
 /**
  * generic_permission  -  check for access rights on a Posix-like filesystem
  * @inode:	inode to check access rights for
@@ -981,9 +992,7 @@
 	retval = link_path_walk(name, nd);
 	if (unlikely(current->audit_context
 		     && nd && nd->dentry && nd->dentry->d_inode))
-		audit_inode(name,
-			    nd->dentry->d_inode->i_ino,
-			    nd->dentry->d_inode->i_rdev);
+		audit_inode(name, nd->dentry->d_inode);
 	return retval;
 }
 
diff -Nru a/fs/proc/base.c b/fs/proc/base.c
--- a/fs/proc/base.c	2005-03-03 21:50:39 -08:00
+++ b/fs/proc/base.c	2005-03-03 21:50:39 -08:00
@@ -32,6 +32,7 @@
 #include <linux/mount.h>
 #include <linux/security.h>
 #include <linux/ptrace.h>
+#include <linux/audit.h>
 #include "internal.h"
 
 /*
diff -Nru a/include/linux/audit.h b/include/linux/audit.h
--- a/include/linux/audit.h	2005-03-03 21:50:39 -08:00
+++ b/include/linux/audit.h	2005-03-03 21:50:39 -08:00
@@ -131,6 +131,9 @@
 #endif
 
 #ifdef CONFIG_AUDITSYSCALL
+/* forward decl for audit_inode */
+struct inode;
+
 /* These are defined in auditsc.c */
 				/* Public API */
 extern int  audit_alloc(struct task_struct *task);
@@ -141,7 +144,7 @@
 extern void audit_syscall_exit(struct task_struct *task, int return_code);
 extern void audit_getname(const char *name);
 extern void audit_putname(const char *name);
-extern void audit_inode(const char *name, unsigned long ino, dev_t rdev);
+extern void audit_inode(const char *name, const struct inode *inode);
 
 				/* Private API (for audit.c only) */
 extern int  audit_receive_filter(int type, int pid, int uid, int seq,
@@ -150,6 +153,7 @@
 			    struct timespec *t, int *serial);
 extern int  audit_set_loginuid(struct audit_context *ctx, 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);
 #else
 #define audit_alloc(t) ({ 0; })
 #define audit_free(t) do { ; } while (0)
@@ -157,8 +161,9 @@
 #define audit_syscall_exit(t,r) do { ; } while (0)
 #define audit_getname(n) do { ; } while (0)
 #define audit_putname(n) do { ; } while (0)
-#define audit_inode(n,i,d) do { ; } while (0)
+#define audit_inode(n,i) do { ; } while (0)
 #define audit_get_loginuid(c) ({ -1; })
+#define audit_ipc_perms(q,u,g,m) ({ 0; })
 #endif
 
 #ifdef CONFIG_AUDIT
diff -Nru a/include/linux/fs.h b/include/linux/fs.h
--- a/include/linux/fs.h	2005-03-03 21:50:38 -08:00
+++ b/include/linux/fs.h	2005-03-03 21:50:39 -08:00
@@ -210,7 +210,6 @@
 #include <linux/list.h>
 #include <linux/radix-tree.h>
 #include <linux/prio_tree.h>
-#include <linux/audit.h>
 #include <linux/init.h>
 
 #include <asm/atomic.h>
@@ -1268,13 +1267,7 @@
 #ifndef CONFIG_AUDITSYSCALL
 #define putname(name)   __putname(name)
 #else
-#define putname(name)							\
-	do {								\
-		if (unlikely(current->audit_context))			\
-			audit_putname(name);				\
-		else							\
-			__putname(name);				\
-	} while (0)
+extern void putname(const char *name);
 #endif
 
 extern int register_blkdev(unsigned int, const char *);
diff -Nru a/ipc/msg.c b/ipc/msg.c
--- a/ipc/msg.c	2005-03-03 21:50:38 -08:00
+++ b/ipc/msg.c	2005-03-03 21:50:38 -08:00
@@ -25,6 +25,7 @@
 #include <linux/security.h>
 #include <linux/sched.h>
 #include <linux/syscalls.h>
+#include <linux/audit.h>
 #include <asm/current.h>
 #include <asm/uaccess.h>
 #include "util.h"
@@ -425,6 +426,8 @@
 			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;
diff -Nru a/ipc/sem.c b/ipc/sem.c
--- a/ipc/sem.c	2005-03-03 21:50:39 -08:00
+++ b/ipc/sem.c	2005-03-03 21:50:39 -08:00
@@ -72,6 +72,7 @@
 #include <linux/smp_lock.h>
 #include <linux/security.h>
 #include <linux/syscalls.h>
+#include <linux/audit.h>
 #include <asm/uaccess.h>
 #include "util.h"
 
@@ -803,6 +804,8 @@
 	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)
diff -Nru a/ipc/shm.c b/ipc/shm.c
--- a/ipc/shm.c	2005-03-03 21:50:39 -08:00
+++ b/ipc/shm.c	2005-03-03 21:50:39 -08:00
@@ -27,6 +27,7 @@
 #include <linux/shmem_fs.h>
 #include <linux/security.h>
 #include <linux/syscalls.h>
+#include <linux/audit.h>
 #include <asm/uaccess.h>
 
 #include "util.h"
@@ -600,6 +601,8 @@
 			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;
diff -Nru a/kernel/auditsc.c b/kernel/auditsc.c
--- a/kernel/auditsc.c	2005-03-03 21:50:39 -08:00
+++ b/kernel/auditsc.c	2005-03-03 21:50:39 -08:00
@@ -89,9 +89,30 @@
 struct audit_names {
 	const char	*name;
 	unsigned long	ino;
+	dev_t		dev;
+	umode_t		mode;
+	uid_t		uid;
+	gid_t		gid;
 	dev_t		rdev;
 };
 
+struct audit_aux_data {
+	struct audit_aux_data	*next;
+	int			type;
+};
+
+#define AUDIT_AUX_IPCPERM	0
+
+struct audit_aux_data_ipcctl {
+	struct audit_aux_data	d;
+	struct ipc_perm		p;
+	unsigned long		qbytes;
+	uid_t			uid;
+	gid_t			gid;
+	mode_t			mode;
+};
+
+
 /* The per-task audit context. */
 struct audit_context {
 	int		    in_syscall;	/* 1 if task is in a syscall */
@@ -107,6 +128,7 @@
 	int		    name_count;
 	struct audit_names  names[AUDIT_NAMES];
 	struct audit_context *previous; /* For nested syscalls */
+	struct audit_aux_data *aux;
 
 				/* Save things to print about task_struct */
 	pid_t		    pid;
@@ -338,7 +360,7 @@
 		case AUDIT_DEVMAJOR:
 			if (ctx) {
 				for (j = 0; j < ctx->name_count; j++) {
-					if (MAJOR(ctx->names[j].rdev)==value) {
+					if (MAJOR(ctx->names[j].dev)==value) {
 						++result;
 						break;
 					}
@@ -348,7 +370,7 @@
 		case AUDIT_DEVMINOR:
 			if (ctx) {
 				for (j = 0; j < ctx->name_count; j++) {
-					if (MINOR(ctx->names[j].rdev)==value) {
+					if (MINOR(ctx->names[j].dev)==value) {
 						++result;
 						break;
 					}
@@ -504,6 +526,16 @@
 	context->name_count = 0;
 }
 
+static inline void audit_free_aux(struct audit_context *context)
+{
+	struct audit_aux_data *aux;
+
+	while ((aux = context->aux)) {
+		context->aux = aux->next;
+		kfree(aux);
+	}
+}
+
 static inline void audit_zero_context(struct audit_context *context,
 				      enum audit_state state)
 {
@@ -570,6 +602,7 @@
 			       context->name_count, count);
 		}
 		audit_free_names(context);
+		audit_free_aux(context);
 		kfree(context);
 		context  = previous;
 	} while (context);
@@ -607,6 +640,29 @@
 		  context->euid, context->suid, context->fsuid,
 		  context->egid, context->sgid, context->fsgid);
 	audit_log_end(ab);
+	while (context->aux) {
+		struct audit_aux_data *aux;
+
+		ab = audit_log_start(context);
+		if (!ab)
+			continue; /* audit_panic has been called */
+
+		aux = context->aux;
+		context->aux = aux->next;
+
+		audit_log_format(ab, "auxitem=%d", aux->type);
+		switch (aux->type) {
+		case AUDIT_AUX_IPCPERM: {
+			struct audit_aux_data_ipcctl *axi = (void *)aux;
+			audit_log_format(ab, 
+					 " qbytes=%lx uid=%d gid=%d mode=%x",
+					 axi->qbytes, axi->uid, axi->gid, axi->mode);
+			}
+		}
+		audit_log_end(ab);
+		kfree(aux);
+	}
+
 	for (i = 0; i < context->name_count; i++) {
 		ab = audit_log_start(context);
 		if (!ab)
@@ -616,12 +672,14 @@
 			audit_log_format(ab, " name=%s",
 					 context->names[i].name);
 		if (context->names[i].ino != (unsigned long)-1)
-			audit_log_format(ab, " inode=%lu",
-					 context->names[i].ino);
-		/* FIXME: should use format_dev_t, but ab structure is
-		 * opaque. */
-		if (context->names[i].rdev != -1)
-			audit_log_format(ab, " dev=%02x:%02x",
+			audit_log_format(ab, " inode=%lu dev=%02x:%02x mode=%#o"
+					     " uid=%d gid=%d rdev=%02x:%02x",
+					 context->names[i].ino,
+					 MAJOR(context->names[i].dev),
+					 MINOR(context->names[i].dev),
+					 context->names[i].mode,
+					 context->names[i].uid,
+					 context->names[i].gid,
 					 MAJOR(context->names[i].rdev),
 					 MINOR(context->names[i].rdev));
 		audit_log_end(ab);
@@ -789,6 +847,7 @@
 		tsk->audit_context = new_context;
 	} else {
 		audit_free_names(context);
+		audit_free_aux(context);
 		audit_zero_context(context, context->state);
 		tsk->audit_context = context;
 	}
@@ -800,7 +859,9 @@
 {
 	struct audit_context *context = current->audit_context;
 
-	BUG_ON(!context);
+	if (!context || IS_ERR(name) || !name)
+		return;
+
 	if (!context->in_syscall) {
 #if AUDIT_DEBUG == 2
 		printk(KERN_ERR "%s:%d(:%d): ignoring getname(%p)\n",
@@ -812,7 +873,6 @@
 	BUG_ON(context->name_count >= AUDIT_NAMES);
 	context->names[context->name_count].name = name;
 	context->names[context->name_count].ino  = (unsigned long)-1;
-	context->names[context->name_count].rdev = -1;
 	++context->name_count;
 }
 
@@ -855,11 +915,10 @@
 	}
 #endif
 }
-EXPORT_SYMBOL(audit_putname);
 
 /* Store the inode and device from a lookup.  Called from
  * fs/namei.c:path_lookup(). */
-void audit_inode(const char *name, unsigned long ino, dev_t rdev)
+void audit_inode(const char *name, const struct inode *inode)
 {
 	int idx;
 	struct audit_context *context = current->audit_context;
@@ -885,8 +944,12 @@
 		++context->ino_count;
 #endif
 	}
-	context->names[idx].ino  = ino;
-	context->names[idx].rdev = rdev;
+	context->names[idx].ino  = inode->i_ino;
+	context->names[idx].dev	 = inode->i_sb->s_dev;
+	context->names[idx].mode = inode->i_mode;
+	context->names[idx].uid  = inode->i_uid;
+	context->names[idx].gid  = inode->i_gid;
+	context->names[idx].rdev = inode->i_rdev;
 }
 
 void audit_get_stamp(struct audit_context *ctx,
@@ -926,4 +989,27 @@
 uid_t audit_get_loginuid(struct audit_context *ctx)
 {
 	return ctx ? ctx->loginuid : -1;
+}
+
+int audit_ipc_perms(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode)
+{
+	struct audit_aux_data_ipcctl *ax;
+	struct audit_context *context = current->audit_context;
+
+	if (likely(!context))
+		return 0;
+
+	ax = kmalloc(sizeof(*ax), GFP_KERNEL);
+	if (!ax)
+		return -ENOMEM;
+
+	ax->qbytes = qbytes;
+	ax->uid = uid;
+	ax->gid = gid;
+	ax->mode = mode;
+
+	ax->d.type = AUDIT_AUX_IPCPERM;
+	ax->d.next = context->aux;
+	context->aux = (void *)ax;
+	return 0;
 }