[PATCH] Reporting file descriptors and exec args

Linda Knippers linda.knippers at hp.com
Tue Sep 12 22:10:53 UTC 2006


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

John D. Ramsdell wrote:
> 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
> 
> Signed-off-by: John D. Ramsdell <ramsdell at mitre.org>
> diff -uprN -X 2.6.16/Documentation/dontdiff 2.6.16/fs/exec.c linux-2.6.16-jlatt/fs/exec.c
> --- 2.6.16/fs/exec.c	2006-03-20 00:53:29.000000000 -0500
> +++ linux-2.6.16-jlatt/fs/exec.c	2006-09-12 16:08:05.000000000 -0400
> @@ -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
> --- 2.6.16/fs/pipe.c	2006-03-20 00:53:29.000000000 -0500
> +++ linux-2.6.16-jlatt/fs/pipe.c	2006-09-12 16:08:22.000000000 -0400
> @@ -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
> --- 2.6.16/include/linux/audit.h	2006-03-20 00:53:29.000000000 -0500
> +++ linux-2.6.16-jlatt/include/linux/audit.h	2006-09-12 16:07:13.000000000 -0400
> @@ -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
> --- 2.6.16/kernel/auditsc.c	2006-03-20 00:53:29.000000000 -0500
> +++ linux-2.6.16-jlatt/kernel/auditsc.c	2006-09-12 16:13:03.000000000 -0400
> @@ -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
> --- 2.6.16/net/socket.c	2006-03-20 00:53:29.000000000 -0500
> +++ linux-2.6.16-jlatt/net/socket.c	2006-09-12 16:05:49.000000000 -0400
> @@ -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
> Linux-audit at redhat.com
> https://www.redhat.com/mailman/listinfo/linux-audit




More information about the Linux-audit mailing list