Skip to contentSkip to conversation

Reporting file descriptors and exec args

PATCH In review John D. Ramsdell 3 participants 4 messages Sep 12, 2006 – Sep 14, 2006

Subsystems (5)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 Reporting file descriptors and exec args

Here is a version of the previous patch that was produced using the correct options to diff. This patch is by Jeremy Latt. In addition to adding reports of the file descriptors created by the pipe and socketpair system calls, it also adds reports of the string arguments to the system calls open and execve. Knowing the name of the file opened or exec'ed is also crucial to the analysis performed by Polgen.

John

fs/exec.c +3 -0
diff -uprN -X 2.6.16/Documentation/dontdiff 2.6.16/fs/exec.c linux-2.6.16-jlatt/fs/exec.c
@@ -49,6 +49,7 @@
 #include <linux/rmap.h>
 #include <linux/acct.h>
 #include <linux/cn_proc.h>
+#include <linux/audit.h>
 
 #include <asm/uaccess.h>
 #include <asm/mmu_context.h>
@@ -1173,6 +1174,8 @@ int do_execve(char * filename,
 	if ((retval = bprm->argc) < 0)
 		goto out_mm;
 
+	audit_execve(bprm->argc, argv);
+
 	bprm->envc = count(envp, bprm->p / sizeof(void *));
 	if ((retval = bprm->envc) < 0)
 		goto out_mm;
fs/pipe.c +2 -0
diff -uprN -X 2.6.16/Documentation/dontdiff 2.6.16/fs/pipe.c linux-2.6.16-jlatt/fs/pipe.c
@@ -15,6 +15,7 @@
 #include <linux/pipe_fs_i.h>
 #include <linux/uio.h>
 #include <linux/highmem.h>
+#include <linux/audit.h>
 
 #include <asm/uaccess.h>
 #include <asm/ioctls.h>
@@ -781,6 +782,7 @@ int do_pipe(int *fd)
 	fd_install(j, f2);
 	fd[0] = i;
 	fd[1] = j;
+	audit_fd_pair(i, j);
 	return 0;
 
 close_f12_inode_i_j:
include/linux/audit.h +6 -0
diff -uprN -X 2.6.16/Documentation/dontdiff 2.6.16/include/linux/audit.h linux-2.6.16-jlatt/include/linux/audit.h
@@ -68,6 +68,8 @@
 #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_EXECVE    1309 /* exec arguments */
+#define AUDIT_FD_PAIR   1312 /* audit record for pipe/socketpair */
 
 #define AUDIT_AVC		1400	/* SE Linux avc denial or grant */
 #define AUDIT_SELINUX_ERR	1401	/* Internal SE Linux Errors */
@@ -238,6 +240,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_execve(int argc, char __user *__user *argv);
+extern int audit_fd_pair(int fd1, int fd2);
 #else
 #define audit_alloc(t) ({ 0; })
 #define audit_free(t) do { ; } while (0)
@@ -255,6 +259,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_execve(a, b) ({ 0; })
+#define audit_fd_pair(a, b) ({ 0; })
 #endif
 
 #ifdef CONFIG_AUDIT
kernel/auditsc.c +148 -2

192 lines not on this page · raw message

net/socket.c +3 -1
diff -uprN -X 2.6.16/Documentation/dontdiff 2.6.16/net/socket.c linux-2.6.16-jlatt/net/socket.c
@@ -1256,8 +1256,10 @@ asmlinkage long sys_socketpair(int famil
 	err = put_user(fd1, &usockvec[0]); 
 	if (!err)
 		err = put_user(fd2, &usockvec[1]);
-	if (!err)
+	if (!err) {
+		audit_fd_pair(fd1, fd2);
 		return 0;
+	}
 
 	sys_close(fd2);
 	sys_close(fd1);
#1 lore raw
Quoted 5 lines · John D. Ramsdell
kernel/auditsc.c +5 -0
+static const char *elide(const char *str) 
+{
+	static char buf[1025];
+
+	if (strnlen(str, 1025) >= 1025) {

kernel/auditsc.c static void audit_log_task_info(struct a · line 835

Quoted 10 lines
kernel/auditsc.c +10 -0
+		memcpy(buf, str, 1021);
+		buf[1021] = '.';
+		buf[1022] = '.';
+		buf[1023] = '.';
+		buf[1024] = '\0';
+		return buf;
+	}
+	
+	return str;
+}

... serialized by...?

kernel/auditsc.c static void audit_log_exit(struct audit_ · line 859

Quoted 13 lines

static void audit_log_exit(struct audit_context *context, gfp_t gfp_mask) {

kernel/auditsc.c +6 -0
 	int i;
@@ -820,6 +851,16 @@ static void audit_log_exit(struct audit_
 		audit_log_format(ab, " success=%s exit=%ld", 
 				 (context->return_valid==AUDITSC_SUCCESS)?"yes":"no",
 				 context->return_code);
+
+	switch (context->major) {
+        case __NR_open:
+			audit_log_format(ab, " filename=");
+			audit_log_untrustedstring(ab, 
+					elide((const char *)context->argv[0]));

Oh, lovely. So let me see if I've got it right - now anybody can trigger reading from any location in kernel memory. Including iomem. Or not mapped address range - less interesting (oops instead of mangling hardware), but easier to guess.

BTW, you still have problem with __NR_open on biarch targets...

#2 lore raw
In reply to John D. Ramsdell

Do we really want to start adding information to the audit records that isn't security relevant? There are alot of system calls that return data through pointer arguments. Would we stop with just these two?

For open and execve, does the PATH part of the audit record not give you what you need?

-- ljk

Quoted 301 lines · John D. Ramsdell

Here is a version of the previous patch that was produced using the correct options to diff. This patch is by Jeremy Latt. In addition to adding reports of the file descriptors created by the pipe and socketpair system calls, it also adds reports of the string arguments to the system calls open and execve. Knowing the name of the file opened or exec'ed is also crucial to the analysis performed by Polgen.

John

diff -uprN -X 2.6.16/Documentation/dontdiff 2.6.16/fs/exec.c linux-2.6.16-jlatt/fs/exec.c

fs/exec.c +3 -0
@@ -49,6 +49,7 @@
 #include <linux/rmap.h>
 #include <linux/acct.h>
 #include <linux/cn_proc.h>
+#include <linux/audit.h>
 
 #include <asm/uaccess.h>
 #include <asm/mmu_context.h>
@@ -1173,6 +1174,8 @@ int do_execve(char * filename,
 	if ((retval = bprm->argc) < 0)
 		goto out_mm;
 
+	audit_execve(bprm->argc, argv);
+
 	bprm->envc = count(envp, bprm->p / sizeof(void *));
 	if ((retval = bprm->envc) < 0)
 		goto out_mm;

diff -uprN -X 2.6.16/Documentation/dontdiff 2.6.16/fs/pipe.c linux-2.6.16-jlatt/fs/pipe.c

fs/pipe.c +2 -0
@@ -15,6 +15,7 @@
 #include <linux/pipe_fs_i.h>
 #include <linux/uio.h>
 #include <linux/highmem.h>
+#include <linux/audit.h>
 
 #include <asm/uaccess.h>
 #include <asm/ioctls.h>
@@ -781,6 +782,7 @@ int do_pipe(int *fd)
 	fd_install(j, f2);
 	fd[0] = i;
 	fd[1] = j;
+	audit_fd_pair(i, j);
 	return 0;
 
 close_f12_inode_i_j:

diff -uprN -X 2.6.16/Documentation/dontdiff 2.6.16/include/linux/audit.h linux-2.6.16-jlatt/include/linux/audit.h

include/linux/audit.h +6 -0
@@ -68,6 +68,8 @@
 #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_EXECVE    1309 /* exec arguments */
+#define AUDIT_FD_PAIR   1312 /* audit record for pipe/socketpair */
 
 #define AUDIT_AVC		1400	/* SE Linux avc denial or grant */
 #define AUDIT_SELINUX_ERR	1401	/* Internal SE Linux Errors */
@@ -238,6 +240,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_execve(int argc, char __user *__user *argv);
+extern int audit_fd_pair(int fd1, int fd2);
 #else
 #define audit_alloc(t) ({ 0; })
 #define audit_free(t) do { ; } while (0)
@@ -255,6 +259,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_execve(a, b) ({ 0; })
+#define audit_fd_pair(a, b) ({ 0; })
 #endif
 
 #ifdef CONFIG_AUDIT

diff -uprN -X 2.6.16/Documentation/dontdiff 2.6.16/kernel/auditsc.c linux-2.6.16-jlatt/kernel/auditsc.c

kernel/auditsc.c +148 -2
@@ -44,6 +44,10 @@
 #include <linux/compiler.h>
 #include <asm/unistd.h>
 
+#include <linux/in.h>
+#include <linux/socket.h>
+#include <linux/binfmts.h>
+
 /* 0 = no checking
    1 = put_count checking
    2 = verbose put_count checking
@@ -129,6 +133,17 @@ struct audit_aux_data_sockaddr {
 	char			a[0];
 };
 
+struct audit_aux_data_fd_pair {
+	struct audit_aux_data d;
+	int fd[2];
+};
+
+struct audit_aux_data_execve {
+    struct audit_aux_data d;
+    int argc;
+    char args[0];
+};
+
 struct audit_aux_data_path {
 	struct audit_aux_data	d;
 	struct dentry		*dentry;
@@ -598,7 +613,7 @@ static int audit_filter_user_rules(struc
 int audit_filter_user(struct netlink_skb_parms *cb, int type)
 {
 	struct audit_entry *e;
-	enum audit_state   state;
+	enum audit_state state = AUDIT_DISABLED;
 	int ret = 1;
 
 	rcu_read_lock();
@@ -803,6 +818,22 @@ static void audit_log_task_info(struct a
 	up_read(&mm->mmap_sem);
 }
 
+static const char *elide(const char *str) 
+{
+	static char buf[1025];
+
+	if (strnlen(str, 1025) >= 1025) {
+		memcpy(buf, str, 1021);
+		buf[1021] = '.';
+		buf[1022] = '.';
+		buf[1023] = '.';
+		buf[1024] = '\0';
+		return buf;
+	}
+	
+	return str;
+}
+
 static void audit_log_exit(struct audit_context *context, gfp_t gfp_mask)
 {
 	int i;
@@ -820,6 +851,16 @@ static void audit_log_exit(struct audit_
 		audit_log_format(ab, " success=%s exit=%ld", 
 				 (context->return_valid==AUDITSC_SUCCESS)?"yes":"no",
 				 context->return_code);
+
+	switch (context->major) {
+        case __NR_open:
+			audit_log_format(ab, " filename=");
+			audit_log_untrustedstring(ab, 
+					elide((const char *)context->argv[0]));
+            break;
+	}
+
+
 	audit_log_format(ab,
 		  " a0=%lx a1=%lx a2=%lx a3=%lx items=%d"
 		  " pid=%d auid=%u uid=%u gid=%u"
@@ -872,7 +913,21 @@ 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_EXECVE: {
+			int i, pos;
+			struct audit_aux_data_execve *axs = (void *)aux;
+            audit_log_format(ab, "argc=%d", axs->argc);
+			pos = 0;
+			for(i=0; i < axs->argc; i++) {
+				audit_log_format(ab, " arg%d=", i);
+				audit_log_untrustedstring(ab, elide(axs->args+pos));
+				pos += strlen(axs->args+pos)+1;
+			}
+			break; }
+		case AUDIT_FD_PAIR: {
+			struct audit_aux_data_fd_pair *axs = (void *)aux;
+			audit_log_format(ab, "fd0=%d fd1=%d", axs->fd[0], axs->fd[1]);
+			break; }
 		}
 		audit_log_end(ab);
 	}
@@ -1237,6 +1292,97 @@ int audit_socketcall(int nargs, unsigned
 	return 0;
 }
 
+int audit_fd_pair(int fd1, int fd2)
+{
+	struct audit_context *context; 
+	struct audit_aux_data_fd_pair *ax;
+
+	context = current->audit_context;
+	if (likely(!context)) {
+		return 0;
+	}
+
+	ax = kmalloc(sizeof(*ax), GFP_KERNEL);
+	if (!ax) {
+		return -ENOMEM;
+	}
+
+	ax->fd[0] = fd1;
+	ax->fd[1] = fd2;
+
+	ax->d.type = AUDIT_FD_PAIR;
+	ax->d.next = context->aux;
+	context->aux = (void *)ax;
+	return 0;
+}
+
+/* includes \0 at end, and just long enough to trigger elipsis */
+#define MAX_ARG_LENGTH 1026
+
+int audit_execve(int argc, char __user *__user *argv) 
+{
+	struct audit_aux_data_execve *ax;
+	int i;
+	int off;
+	int bytes_to_malloc;
+	struct audit_context *context; 
+
+	context = current->audit_context;
+	if (likely(!context)) {
+		return 0;
+	}
+
+	bytes_to_malloc = sizeof(*ax);
+
+	for (i = 0; i < argc; i++) {
+		int len;
+
+		len = strnlen_user(argv[i], MAX_ARG_LENGTH);
+		if (!len) {
+			return -EFAULT;
+		} else if (len > MAX_ARG_LENGTH) {
+			len = MAX_ARG_LENGTH;
+		}
+		bytes_to_malloc += len;
+	}
+
+	ax = kmalloc(bytes_to_malloc, GFP_KERNEL);
+	if (!ax) {
+		return -ENOMEM;
+	} 
+
+	off = 0;
+	for (i=0; i<argc; i++) {
+		int len;
+		char __user *arg;
+
+		if (get_user(arg, argv+i)) {
+			goto err_out;
+		}
+
+		len = strnlen_user(arg, MAX_ARG_LENGTH);
+		if (!len) {
+			goto err_out;
+		} else if (len > MAX_ARG_LENGTH) {
+			len = MAX_ARG_LENGTH;
+		}
+		if (copy_from_user(ax->args+off, arg, len-1)) {
+			goto err_out;
+		}
+		off += len;
+		ax->args[off-1] = '\0';
+	}
+
+	ax->d.type = AUDIT_EXECVE;
+	ax->d.next = context->aux;
+	ax->argc = argc;
+	context->aux = (void *)ax;
+	return 0;
+err_out:
+	kfree(ax);
+	return -EFAULT;
+}
+
 int audit_sockaddr(int len, void *a)
 {
 	struct audit_aux_data_sockaddr *ax;

diff -uprN -X 2.6.16/Documentation/dontdiff 2.6.16/net/socket.c linux-2.6.16-jlatt/net/socket.c

net/socket.c +3 -2
@@ -1256,8 +1256,10 @@ asmlinkage long sys_socketpair(int famil
 	err = put_user(fd1, &usockvec[0]); 
 	if (!err)
 		err = put_user(fd2, &usockvec[1]);
-	if (!err)
+	if (!err) {
+		audit_fd_pair(fd1, fd2);
 		return 0;
+	}
 
 	sys_close(fd2);
 	sys_close(fd1);
 
--

Linux-audit mailing list
[email protected]
https://www.redhat.com/mailman/listinfo/linux-audit

#3 lore raw

I withdraw the previously submitted kernel patch. In addition to the errors already pointed out on this list, the patch was produced several months ago, and the kernel has changed since then. In addition, the audit records for execve and open in the latest kernel already includes the information of interest. From the perspective of polgen, all that is currently missing is the file descriptors created by the pipe and socketpair system calls, and we'll be back with just that patch once it's properly prepared.

I have been relying on others to create kernel patches, and neglected to familiarize myself with the accepted practice for submitting patches. I will ensure that future patches follow the rules.

John