diff options
Diffstat (limited to 'kernel/auditsc.c')
| -rw-r--r-- | kernel/auditsc.c | 1585 | 
1 files changed, 773 insertions, 812 deletions
diff --git a/kernel/auditsc.c b/kernel/auditsc.c index f49a0318c2e..21eae3c05ec 100644 --- a/kernel/auditsc.c +++ b/kernel/auditsc.c @@ -42,13 +42,15 @@   * and <dustin.kirkland@us.ibm.com> for LSPP certification compliance.   */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +  #include <linux/init.h>  #include <asm/types.h> -#include <asm/atomic.h> +#include <linux/atomic.h>  #include <linux/fs.h>  #include <linux/namei.h>  #include <linux/mm.h> -#include <linux/module.h> +#include <linux/export.h>  #include <linux/slab.h>  #include <linux/mount.h>  #include <linux/socket.h> @@ -67,54 +69,28 @@  #include <linux/syscalls.h>  #include <linux/capability.h>  #include <linux/fs_struct.h> +#include <linux/compat.h> +#include <linux/ctype.h>  #include "audit.h" -/* AUDIT_NAMES is the number of slots we reserve in the audit_context - * for saving names from getname(). */ -#define AUDIT_NAMES    20 - -/* Indicates that audit should log the full pathname. */ -#define AUDIT_NAME_FULL -1 +/* flags stating the success for a syscall */ +#define AUDITSC_INVALID 0 +#define AUDITSC_SUCCESS 1 +#define AUDITSC_FAILURE 2  /* no execve audit message should be longer than this (userspace limits) */  #define MAX_EXECVE_AUDIT_LEN 7500 +/* max length to print of cmdline/proctitle value during audit */ +#define MAX_PROCTITLE_AUDIT_LEN 128 +  /* number of audit rules */  int audit_n_rules;  /* determines whether we collect data for signals sent */  int audit_signals; -struct audit_cap_data { -	kernel_cap_t		permitted; -	kernel_cap_t		inheritable; -	union { -		unsigned int	fE;		/* effective bit of a file capability */ -		kernel_cap_t	effective;	/* effective set of a process */ -	}; -}; - -/* When fs/namei.c:getname() is called, we store the pointer in name and - * we don't let putname() free it (instead we free all of the saved - * pointers at syscall exit time). - * - * Further, in fs/namei.c:path_lookup() we store the inode and device. */ -struct audit_names { -	const char	*name; -	int		name_len;	/* number of name's characters to log */ -	unsigned	name_put;	/* call __putname() for this name */ -	unsigned long	ino; -	dev_t		dev; -	umode_t		mode; -	uid_t		uid; -	gid_t		gid; -	dev_t		rdev; -	u32		osid; -	struct audit_cap_data fcap; -	unsigned int	fcap_ver; -}; -  struct audit_aux_data {  	struct audit_aux_data	*next;  	int			type; @@ -125,18 +101,11 @@ struct audit_aux_data {  /* Number of target pids per aux struct. */  #define AUDIT_AUX_PIDS	16 -struct audit_aux_data_execve { -	struct audit_aux_data	d; -	int argc; -	int envc; -	struct mm_struct *mm; -}; -  struct audit_aux_data_pids {  	struct audit_aux_data	d;  	pid_t			target_pid[AUDIT_AUX_PIDS]; -	uid_t			target_auid[AUDIT_AUX_PIDS]; -	uid_t			target_uid[AUDIT_AUX_PIDS]; +	kuid_t			target_auid[AUDIT_AUX_PIDS]; +	kuid_t			target_uid[AUDIT_AUX_PIDS];  	unsigned int		target_sessionid[AUDIT_AUX_PIDS];  	u32			target_sid[AUDIT_AUX_PIDS];  	char 			target_comm[AUDIT_AUX_PIDS][TASK_COMM_LEN]; @@ -151,109 +120,11 @@ struct audit_aux_data_bprm_fcaps {  	struct audit_cap_data	new_pcap;  }; -struct audit_aux_data_capset { -	struct audit_aux_data	d; -	pid_t			pid; -	struct audit_cap_data	cap; -}; -  struct audit_tree_refs {  	struct audit_tree_refs *next;  	struct audit_chunk *c[31];  }; -/* The per-task audit context. */ -struct audit_context { -	int		    dummy;	/* must be the first element */ -	int		    in_syscall;	/* 1 if task is in a syscall */ -	enum audit_state    state, current_state; -	unsigned int	    serial;     /* serial number for record */ -	int		    major;      /* syscall number */ -	struct timespec	    ctime;      /* time of syscall entry */ -	unsigned long	    argv[4];    /* syscall arguments */ -	long		    return_code;/* syscall return code */ -	u64		    prio; -	int		    return_valid; /* return code is valid */ -	int		    name_count; -	struct audit_names  names[AUDIT_NAMES]; -	char *		    filterkey;	/* key for rule that triggered record */ -	struct path	    pwd; -	struct audit_context *previous; /* For nested syscalls */ -	struct audit_aux_data *aux; -	struct audit_aux_data *aux_pids; -	struct sockaddr_storage *sockaddr; -	size_t sockaddr_len; -				/* Save things to print about task_struct */ -	pid_t		    pid, ppid; -	uid_t		    uid, euid, suid, fsuid; -	gid_t		    gid, egid, sgid, fsgid; -	unsigned long	    personality; -	int		    arch; - -	pid_t		    target_pid; -	uid_t		    target_auid; -	uid_t		    target_uid; -	unsigned int	    target_sessionid; -	u32		    target_sid; -	char		    target_comm[TASK_COMM_LEN]; - -	struct audit_tree_refs *trees, *first_trees; -	struct list_head killed_trees; -	int tree_count; - -	int type; -	union { -		struct { -			int nargs; -			long args[6]; -		} socketcall; -		struct { -			uid_t			uid; -			gid_t			gid; -			mode_t			mode; -			u32			osid; -			int			has_perm; -			uid_t			perm_uid; -			gid_t			perm_gid; -			mode_t			perm_mode; -			unsigned long		qbytes; -		} ipc; -		struct { -			mqd_t			mqdes; -			struct mq_attr 		mqstat; -		} mq_getsetattr; -		struct { -			mqd_t			mqdes; -			int			sigev_signo; -		} mq_notify; -		struct { -			mqd_t			mqdes; -			size_t			msg_len; -			unsigned int		msg_prio; -			struct timespec		abs_timeout; -		} mq_sendrecv; -		struct { -			int			oflag; -			mode_t			mode; -			struct mq_attr		attr; -		} mq_open; -		struct { -			pid_t			pid; -			struct audit_cap_data	cap; -		} capset; -		struct { -			int			fd; -			int			flags; -		} mmap; -	}; -	int fds[2]; - -#if AUDIT_DEBUG -	int		    put_count; -	int		    ino_count; -#endif -}; -  static inline int open_arg(int flags, int mask)  {  	int n = ACC_MODE(flags); @@ -305,21 +176,21 @@ static int audit_match_perm(struct audit_context *ctx, int mask)  	}  } -static int audit_match_filetype(struct audit_context *ctx, int which) +static int audit_match_filetype(struct audit_context *ctx, int val)  { -	unsigned index = which & ~S_IFMT; -	mode_t mode = which & S_IFMT; +	struct audit_names *n; +	umode_t mode = (umode_t)val;  	if (unlikely(!ctx))  		return 0; -	if (index >= ctx->name_count) -		return 0; -	if (ctx->names[index].ino == -1) -		return 0; -	if ((ctx->names[index].mode ^ mode) & S_IFMT) -		return 0; -	return 1; +	list_for_each_entry(n, &ctx->names_list, list) { +		if ((n->ino != -1) && +		    ((n->mode & S_IFMT) == mode)) +			return 1; +	} + +	return 0;  }  /* @@ -441,57 +312,202 @@ static int match_tree_refs(struct audit_context *ctx, struct audit_tree *tree)  	return 0;  } +static int audit_compare_uid(kuid_t uid, +			     struct audit_names *name, +			     struct audit_field *f, +			     struct audit_context *ctx) +{ +	struct audit_names *n; +	int rc; +  +	if (name) { +		rc = audit_uid_comparator(uid, f->op, name->uid); +		if (rc) +			return rc; +	} +  +	if (ctx) { +		list_for_each_entry(n, &ctx->names_list, list) { +			rc = audit_uid_comparator(uid, f->op, n->uid); +			if (rc) +				return rc; +		} +	} +	return 0; +} + +static int audit_compare_gid(kgid_t gid, +			     struct audit_names *name, +			     struct audit_field *f, +			     struct audit_context *ctx) +{ +	struct audit_names *n; +	int rc; +  +	if (name) { +		rc = audit_gid_comparator(gid, f->op, name->gid); +		if (rc) +			return rc; +	} +  +	if (ctx) { +		list_for_each_entry(n, &ctx->names_list, list) { +			rc = audit_gid_comparator(gid, f->op, n->gid); +			if (rc) +				return rc; +		} +	} +	return 0; +} + +static int audit_field_compare(struct task_struct *tsk, +			       const struct cred *cred, +			       struct audit_field *f, +			       struct audit_context *ctx, +			       struct audit_names *name) +{ +	switch (f->val) { +	/* process to file object comparisons */ +	case AUDIT_COMPARE_UID_TO_OBJ_UID: +		return audit_compare_uid(cred->uid, name, f, ctx); +	case AUDIT_COMPARE_GID_TO_OBJ_GID: +		return audit_compare_gid(cred->gid, name, f, ctx); +	case AUDIT_COMPARE_EUID_TO_OBJ_UID: +		return audit_compare_uid(cred->euid, name, f, ctx); +	case AUDIT_COMPARE_EGID_TO_OBJ_GID: +		return audit_compare_gid(cred->egid, name, f, ctx); +	case AUDIT_COMPARE_AUID_TO_OBJ_UID: +		return audit_compare_uid(tsk->loginuid, name, f, ctx); +	case AUDIT_COMPARE_SUID_TO_OBJ_UID: +		return audit_compare_uid(cred->suid, name, f, ctx); +	case AUDIT_COMPARE_SGID_TO_OBJ_GID: +		return audit_compare_gid(cred->sgid, name, f, ctx); +	case AUDIT_COMPARE_FSUID_TO_OBJ_UID: +		return audit_compare_uid(cred->fsuid, name, f, ctx); +	case AUDIT_COMPARE_FSGID_TO_OBJ_GID: +		return audit_compare_gid(cred->fsgid, name, f, ctx); +	/* uid comparisons */ +	case AUDIT_COMPARE_UID_TO_AUID: +		return audit_uid_comparator(cred->uid, f->op, tsk->loginuid); +	case AUDIT_COMPARE_UID_TO_EUID: +		return audit_uid_comparator(cred->uid, f->op, cred->euid); +	case AUDIT_COMPARE_UID_TO_SUID: +		return audit_uid_comparator(cred->uid, f->op, cred->suid); +	case AUDIT_COMPARE_UID_TO_FSUID: +		return audit_uid_comparator(cred->uid, f->op, cred->fsuid); +	/* auid comparisons */ +	case AUDIT_COMPARE_AUID_TO_EUID: +		return audit_uid_comparator(tsk->loginuid, f->op, cred->euid); +	case AUDIT_COMPARE_AUID_TO_SUID: +		return audit_uid_comparator(tsk->loginuid, f->op, cred->suid); +	case AUDIT_COMPARE_AUID_TO_FSUID: +		return audit_uid_comparator(tsk->loginuid, f->op, cred->fsuid); +	/* euid comparisons */ +	case AUDIT_COMPARE_EUID_TO_SUID: +		return audit_uid_comparator(cred->euid, f->op, cred->suid); +	case AUDIT_COMPARE_EUID_TO_FSUID: +		return audit_uid_comparator(cred->euid, f->op, cred->fsuid); +	/* suid comparisons */ +	case AUDIT_COMPARE_SUID_TO_FSUID: +		return audit_uid_comparator(cred->suid, f->op, cred->fsuid); +	/* gid comparisons */ +	case AUDIT_COMPARE_GID_TO_EGID: +		return audit_gid_comparator(cred->gid, f->op, cred->egid); +	case AUDIT_COMPARE_GID_TO_SGID: +		return audit_gid_comparator(cred->gid, f->op, cred->sgid); +	case AUDIT_COMPARE_GID_TO_FSGID: +		return audit_gid_comparator(cred->gid, f->op, cred->fsgid); +	/* egid comparisons */ +	case AUDIT_COMPARE_EGID_TO_SGID: +		return audit_gid_comparator(cred->egid, f->op, cred->sgid); +	case AUDIT_COMPARE_EGID_TO_FSGID: +		return audit_gid_comparator(cred->egid, f->op, cred->fsgid); +	/* sgid comparison */ +	case AUDIT_COMPARE_SGID_TO_FSGID: +		return audit_gid_comparator(cred->sgid, f->op, cred->fsgid); +	default: +		WARN(1, "Missing AUDIT_COMPARE define.  Report as a bug\n"); +		return 0; +	} +	return 0; +} +  /* Determine if any context name data matches a rule's watch data */  /* Compare a task_struct with an audit_rule.  Return 1 on match, 0 - * otherwise. */ + * otherwise. + * + * If task_creation is true, this is an explicit indication that we are + * filtering a task rule at task creation time.  This and tsk == current are + * the only situations where tsk->cred may be accessed without an rcu read lock. + */  static int audit_filter_rules(struct task_struct *tsk,  			      struct audit_krule *rule,  			      struct audit_context *ctx,  			      struct audit_names *name, -			      enum audit_state *state) +			      enum audit_state *state, +			      bool task_creation)  { -	const struct cred *cred = get_task_cred(tsk); -	int i, j, need_sid = 1; +	const struct cred *cred; +	int i, need_sid = 1;  	u32 sid; +	cred = rcu_dereference_check(tsk->cred, tsk == current || task_creation); +  	for (i = 0; i < rule->field_count; i++) {  		struct audit_field *f = &rule->fields[i]; +		struct audit_names *n;  		int result = 0; +		pid_t pid;  		switch (f->type) {  		case AUDIT_PID: -			result = audit_comparator(tsk->pid, f->op, f->val); +			pid = task_pid_nr(tsk); +			result = audit_comparator(pid, f->op, f->val);  			break;  		case AUDIT_PPID:  			if (ctx) {  				if (!ctx->ppid) -					ctx->ppid = sys_getppid(); +					ctx->ppid = task_ppid_nr(tsk);  				result = audit_comparator(ctx->ppid, f->op, f->val);  			}  			break;  		case AUDIT_UID: -			result = audit_comparator(cred->uid, f->op, f->val); +			result = audit_uid_comparator(cred->uid, f->op, f->uid);  			break;  		case AUDIT_EUID: -			result = audit_comparator(cred->euid, f->op, f->val); +			result = audit_uid_comparator(cred->euid, f->op, f->uid);  			break;  		case AUDIT_SUID: -			result = audit_comparator(cred->suid, f->op, f->val); +			result = audit_uid_comparator(cred->suid, f->op, f->uid);  			break;  		case AUDIT_FSUID: -			result = audit_comparator(cred->fsuid, f->op, f->val); +			result = audit_uid_comparator(cred->fsuid, f->op, f->uid);  			break;  		case AUDIT_GID: -			result = audit_comparator(cred->gid, f->op, f->val); +			result = audit_gid_comparator(cred->gid, f->op, f->gid); +			if (f->op == Audit_equal) { +				if (!result) +					result = in_group_p(f->gid); +			} else if (f->op == Audit_not_equal) { +				if (result) +					result = !in_group_p(f->gid); +			}  			break;  		case AUDIT_EGID: -			result = audit_comparator(cred->egid, f->op, f->val); +			result = audit_gid_comparator(cred->egid, f->op, f->gid); +			if (f->op == Audit_equal) { +				if (!result) +					result = in_egroup_p(f->gid); +			} else if (f->op == Audit_not_equal) { +				if (result) +					result = !in_egroup_p(f->gid); +			}  			break;  		case AUDIT_SGID: -			result = audit_comparator(cred->sgid, f->op, f->val); +			result = audit_gid_comparator(cred->sgid, f->op, f->gid);  			break;  		case AUDIT_FSGID: -			result = audit_comparator(cred->fsgid, f->op, f->val); +			result = audit_gid_comparator(cred->fsgid, f->op, f->gid);  			break;  		case AUDIT_PERS:  			result = audit_comparator(tsk->personality, f->op, f->val); @@ -514,12 +530,14 @@ static int audit_filter_rules(struct task_struct *tsk,  			}  			break;  		case AUDIT_DEVMAJOR: -			if (name) -				result = audit_comparator(MAJOR(name->dev), -							  f->op, f->val); -			else if (ctx) { -				for (j = 0; j < ctx->name_count; j++) { -					if (audit_comparator(MAJOR(ctx->names[j].dev),	f->op, f->val)) { +			if (name) { +				if (audit_comparator(MAJOR(name->dev), f->op, f->val) || +				    audit_comparator(MAJOR(name->rdev), f->op, f->val)) +					++result; +			} else if (ctx) { +				list_for_each_entry(n, &ctx->names_list, list) { +					if (audit_comparator(MAJOR(n->dev), f->op, f->val) || +					    audit_comparator(MAJOR(n->rdev), f->op, f->val)) {  						++result;  						break;  					} @@ -527,12 +545,14 @@ static int audit_filter_rules(struct task_struct *tsk,  			}  			break;  		case AUDIT_DEVMINOR: -			if (name) -				result = audit_comparator(MINOR(name->dev), -							  f->op, f->val); -			else if (ctx) { -				for (j = 0; j < ctx->name_count; j++) { -					if (audit_comparator(MINOR(ctx->names[j].dev), f->op, f->val)) { +			if (name) { +				if (audit_comparator(MINOR(name->dev), f->op, f->val) || +				    audit_comparator(MINOR(name->rdev), f->op, f->val)) +					++result; +			} else if (ctx) { +				list_for_each_entry(n, &ctx->names_list, list) { +					if (audit_comparator(MINOR(n->dev), f->op, f->val) || +					    audit_comparator(MINOR(n->rdev), f->op, f->val)) {  						++result;  						break;  					} @@ -541,10 +561,34 @@ static int audit_filter_rules(struct task_struct *tsk,  			break;  		case AUDIT_INODE:  			if (name) -				result = (name->ino == f->val); +				result = audit_comparator(name->ino, f->op, f->val);  			else if (ctx) { -				for (j = 0; j < ctx->name_count; j++) { -					if (audit_comparator(ctx->names[j].ino, f->op, f->val)) { +				list_for_each_entry(n, &ctx->names_list, list) { +					if (audit_comparator(n->ino, f->op, f->val)) { +						++result; +						break; +					} +				} +			} +			break; +		case AUDIT_OBJ_UID: +			if (name) { +				result = audit_uid_comparator(name->uid, f->op, f->uid); +			} else if (ctx) { +				list_for_each_entry(n, &ctx->names_list, list) { +					if (audit_uid_comparator(n->uid, f->op, f->uid)) { +						++result; +						break; +					} +				} +			} +			break; +		case AUDIT_OBJ_GID: +			if (name) { +				result = audit_gid_comparator(name->gid, f->op, f->gid); +			} else if (ctx) { +				list_for_each_entry(n, &ctx->names_list, list) { +					if (audit_gid_comparator(n->gid, f->op, f->gid)) {  						++result;  						break;  					} @@ -562,7 +606,10 @@ static int audit_filter_rules(struct task_struct *tsk,  		case AUDIT_LOGINUID:  			result = 0;  			if (ctx) -				result = audit_comparator(tsk->loginuid, f->op, f->val); +				result = audit_uid_comparator(tsk->loginuid, f->op, f->uid); +			break; +		case AUDIT_LOGINUID_SET: +			result = audit_comparator(audit_loginuid_set(tsk), f->op, f->val);  			break;  		case AUDIT_SUBJ_USER:  		case AUDIT_SUBJ_ROLE: @@ -599,11 +646,10 @@ static int audit_filter_rules(struct task_struct *tsk,  					           name->osid, f->type, f->op,  					           f->lsm_rule, ctx);  				} else if (ctx) { -					for (j = 0; j < ctx->name_count; j++) { -						if (security_audit_rule_match( -						      ctx->names[j].osid, -						      f->type, f->op, -						      f->lsm_rule, ctx)) { +					list_for_each_entry(n, &ctx->names_list, list) { +						if (security_audit_rule_match(n->osid, f->type, +									      f->op, f->lsm_rule, +									      ctx)) {  							++result;  							break;  						} @@ -635,12 +681,12 @@ static int audit_filter_rules(struct task_struct *tsk,  		case AUDIT_FILETYPE:  			result = audit_match_filetype(ctx, f->val);  			break; +		case AUDIT_FIELD_COMPARE: +			result = audit_field_compare(tsk, cred, f, ctx, name); +			break;  		} - -		if (!result) { -			put_cred(cred); +		if (!result)  			return 0; -		}  	}  	if (ctx) { @@ -656,7 +702,6 @@ static int audit_filter_rules(struct task_struct *tsk,  	case AUDIT_NEVER:    *state = AUDIT_DISABLED;	    break;  	case AUDIT_ALWAYS:   *state = AUDIT_RECORD_CONTEXT; break;  	} -	put_cred(cred);  	return 1;  } @@ -671,7 +716,8 @@ static enum audit_state audit_filter_task(struct task_struct *tsk, char **key)  	rcu_read_lock();  	list_for_each_entry_rcu(e, &audit_filter_list[AUDIT_FILTER_TASK], list) { -		if (audit_filter_rules(tsk, &e->rule, NULL, NULL, &state)) { +		if (audit_filter_rules(tsk, &e->rule, NULL, NULL, +				       &state, true)) {  			if (state == AUDIT_RECORD_CONTEXT)  				*key = kstrdup(e->rule.filterkey, GFP_ATOMIC);  			rcu_read_unlock(); @@ -682,6 +728,22 @@ static enum audit_state audit_filter_task(struct task_struct *tsk, char **key)  	return AUDIT_BUILD_CONTEXT;  } +static int audit_in_mask(const struct audit_krule *rule, unsigned long val) +{ +	int word, bit; + +	if (val > 0xffffffff) +		return false; + +	word = AUDIT_WORD(val); +	if (word >= AUDIT_BITMASK_SIZE) +		return false; + +	bit = AUDIT_BIT(val); + +	return rule->mask[word] & bit; +} +  /* At syscall entry and exit time, this filter is called if the   * audit_state is not low enough that auditing cannot take place, but is   * also not high enough that we already know we have to write an audit @@ -699,13 +761,10 @@ static enum audit_state audit_filter_syscall(struct task_struct *tsk,  	rcu_read_lock();  	if (!list_empty(list)) { -		int word = AUDIT_WORD(ctx->major); -		int bit  = AUDIT_BIT(ctx->major); -  		list_for_each_entry_rcu(e, list, list) { -			if ((e->rule.mask[word] & bit) == bit && +			if (audit_in_mask(&e->rule, ctx->major) &&  			    audit_filter_rules(tsk, &e->rule, ctx, NULL, -					       &state)) { +					       &state, false)) {  				rcu_read_unlock();  				ctx->current_state = state;  				return state; @@ -716,50 +775,61 @@ static enum audit_state audit_filter_syscall(struct task_struct *tsk,  	return AUDIT_BUILD_CONTEXT;  } -/* At syscall exit time, this filter is called if any audit_names[] have been +/* + * Given an audit_name check the inode hash table to see if they match. + * Called holding the rcu read lock to protect the use of audit_inode_hash + */ +static int audit_filter_inode_name(struct task_struct *tsk, +				   struct audit_names *n, +				   struct audit_context *ctx) { +	int h = audit_hash_ino((u32)n->ino); +	struct list_head *list = &audit_inode_hash[h]; +	struct audit_entry *e; +	enum audit_state state; + +	if (list_empty(list)) +		return 0; + +	list_for_each_entry_rcu(e, list, list) { +		if (audit_in_mask(&e->rule, ctx->major) && +		    audit_filter_rules(tsk, &e->rule, ctx, n, &state, false)) { +			ctx->current_state = state; +			return 1; +		} +	} + +	return 0; +} + +/* At syscall exit time, this filter is called if any audit_names have been   * collected during syscall processing.  We only check rules in sublists at hash - * buckets applicable to the inode numbers in audit_names[]. + * buckets applicable to the inode numbers in audit_names.   * Regarding audit_state, same rules apply as for audit_filter_syscall().   */  void audit_filter_inodes(struct task_struct *tsk, struct audit_context *ctx)  { -	int i; -	struct audit_entry *e; -	enum audit_state state; +	struct audit_names *n;  	if (audit_pid && tsk->tgid == audit_pid)  		return;  	rcu_read_lock(); -	for (i = 0; i < ctx->name_count; i++) { -		int word = AUDIT_WORD(ctx->major); -		int bit  = AUDIT_BIT(ctx->major); -		struct audit_names *n = &ctx->names[i]; -		int h = audit_hash_ino((u32)n->ino); -		struct list_head *list = &audit_inode_hash[h]; - -		if (list_empty(list)) -			continue; -		list_for_each_entry_rcu(e, list, list) { -			if ((e->rule.mask[word] & bit) == bit && -			    audit_filter_rules(tsk, &e->rule, ctx, n, &state)) { -				rcu_read_unlock(); -				ctx->current_state = state; -				return; -			} -		} +	list_for_each_entry(n, &ctx->names_list, list) { +		if (audit_filter_inode_name(tsk, n, ctx)) +			break;  	}  	rcu_read_unlock();  } -static inline struct audit_context *audit_get_context(struct task_struct *tsk, +/* Transfer the audit context pointer to the caller, clearing it in the tsk's struct */ +static inline struct audit_context *audit_take_context(struct task_struct *tsk,  						      int return_valid,  						      long return_code)  {  	struct audit_context *context = tsk->audit_context; -	if (likely(!context)) +	if (!context)  		return NULL;  	context->return_valid = return_valid; @@ -790,23 +860,30 @@ static inline struct audit_context *audit_get_context(struct task_struct *tsk,  	return context;  } +static inline void audit_proctitle_free(struct audit_context *context) +{ +	kfree(context->proctitle.value); +	context->proctitle.value = NULL; +	context->proctitle.len = 0; +} +  static inline void audit_free_names(struct audit_context *context)  { -	int i; +	struct audit_names *n, *next;  #if AUDIT_DEBUG == 2  	if (context->put_count + context->ino_count != context->name_count) { -		printk(KERN_ERR "%s:%d(:%d): major=%d in_syscall=%d" -		       " name_count=%d put_count=%d" -		       " ino_count=%d [NOT freeing]\n", -		       __FILE__, __LINE__, +		int i = 0; + +		pr_err("%s:%d(:%d): major=%d in_syscall=%d" +		       " name_count=%d put_count=%d ino_count=%d" +		       " [NOT freeing]\n", __FILE__, __LINE__,  		       context->serial, context->major, context->in_syscall,  		       context->name_count, context->put_count,  		       context->ino_count); -		for (i = 0; i < context->name_count; i++) { -			printk(KERN_ERR "names[%d] = %p = %s\n", i, -			       context->names[i].name, -			       context->names[i].name ?: "(null)"); +		list_for_each_entry(n, &context->names_list, list) { +			pr_err("names[%d] = %p = %s\n", i++, n->name, +			       n->name->name ?: "(null)");  		}  		dump_stack();  		return; @@ -817,9 +894,12 @@ static inline void audit_free_names(struct audit_context *context)  	context->ino_count  = 0;  #endif -	for (i = 0; i < context->name_count; i++) { -		if (context->names[i].name && context->names[i].name_put) -			__putname(context->names[i].name); +	list_for_each_entry_safe(n, next, &context->names_list, list) { +		list_del(&n->list); +		if (n->name && n->name_put) +			final_putname(n->name); +		if (n->should_free) +			kfree(n);  	}  	context->name_count = 0;  	path_put(&context->pwd); @@ -841,22 +921,17 @@ static inline void audit_free_aux(struct audit_context *context)  	}  } -static inline void audit_zero_context(struct audit_context *context, -				      enum audit_state state) -{ -	memset(context, 0, sizeof(*context)); -	context->state      = state; -	context->prio = state == AUDIT_RECORD_CONTEXT ? ~0ULL : 0; -} -  static inline struct audit_context *audit_alloc_context(enum audit_state state)  {  	struct audit_context *context; -	if (!(context = kmalloc(sizeof(*context), GFP_KERNEL))) +	context = kzalloc(sizeof(*context), GFP_KERNEL); +	if (!context)  		return NULL; -	audit_zero_context(context, state); +	context->state = state; +	context->prio = state == AUDIT_RECORD_CONTEXT ? ~0ULL : 0;  	INIT_LIST_HEAD(&context->killed_trees); +	INIT_LIST_HEAD(&context->names_list);  	return context;  } @@ -879,8 +954,10 @@ int audit_alloc(struct task_struct *tsk)  		return 0; /* Return if not auditing. */  	state = audit_filter_task(tsk, &key); -	if (likely(state == AUDIT_DISABLED)) +	if (state == AUDIT_DISABLED) { +		clear_tsk_thread_flag(tsk, TIF_SYSCALL_AUDIT);  		return 0; +	}  	if (!(context = audit_alloc_context(state))) {  		kfree(key); @@ -896,91 +973,18 @@ int audit_alloc(struct task_struct *tsk)  static inline void audit_free_context(struct audit_context *context)  { -	struct audit_context *previous; -	int		     count = 0; - -	do { -		previous = context->previous; -		if (previous || (count &&  count < 10)) { -			++count; -			printk(KERN_ERR "audit(:%d): major=%d name_count=%d:" -			       " freeing multiple contexts (%d)\n", -			       context->serial, context->major, -			       context->name_count, count); -		} -		audit_free_names(context); -		unroll_tree_refs(context, NULL, 0); -		free_tree_refs(context); -		audit_free_aux(context); -		kfree(context->filterkey); -		kfree(context->sockaddr); -		kfree(context); -		context  = previous; -	} while (context); -	if (count >= 10) -		printk(KERN_ERR "audit: freed %d contexts\n", count); -} - -void audit_log_task_context(struct audit_buffer *ab) -{ -	char *ctx = NULL; -	unsigned len; -	int error; -	u32 sid; - -	security_task_getsecid(current, &sid); -	if (!sid) -		return; - -	error = security_secid_to_secctx(sid, &ctx, &len); -	if (error) { -		if (error != -EINVAL) -			goto error_path; -		return; -	} - -	audit_log_format(ab, " subj=%s", ctx); -	security_release_secctx(ctx, len); -	return; - -error_path: -	audit_panic("error in audit_log_task_context"); -	return; -} - -EXPORT_SYMBOL(audit_log_task_context); - -static void audit_log_task_info(struct audit_buffer *ab, struct task_struct *tsk) -{ -	char name[sizeof(tsk->comm)]; -	struct mm_struct *mm = tsk->mm; -	struct vm_area_struct *vma; - -	/* tsk == current */ - -	get_task_comm(name, tsk); -	audit_log_format(ab, " comm="); -	audit_log_untrustedstring(ab, name); - -	if (mm) { -		down_read(&mm->mmap_sem); -		vma = mm->mmap; -		while (vma) { -			if ((vma->vm_flags & VM_EXECUTABLE) && -			    vma->vm_file) { -				audit_log_d_path(ab, "exe=", -						 &vma->vm_file->f_path); -				break; -			} -			vma = vma->vm_next; -		} -		up_read(&mm->mmap_sem); -	} -	audit_log_task_context(ab); +	audit_free_names(context); +	unroll_tree_refs(context, NULL, 0); +	free_tree_refs(context); +	audit_free_aux(context); +	kfree(context->filterkey); +	kfree(context->sockaddr); +	audit_proctitle_free(context); +	kfree(context);  }  static int audit_log_pid_context(struct audit_context *context, pid_t pid, -				 uid_t auid, uid_t uid, unsigned int sessionid, +				 kuid_t auid, kuid_t uid, unsigned int sessionid,  				 u32 sid, char *comm)  {  	struct audit_buffer *ab; @@ -992,14 +996,17 @@ static int audit_log_pid_context(struct audit_context *context, pid_t pid,  	if (!ab)  		return rc; -	audit_log_format(ab, "opid=%d oauid=%d ouid=%d oses=%d", pid, auid, -			 uid, sessionid); -	if (security_secid_to_secctx(sid, &ctx, &len)) { -		audit_log_format(ab, " obj=(none)"); -		rc = 1; -	} else { -		audit_log_format(ab, " obj=%s", ctx); -		security_release_secctx(ctx, len); +	audit_log_format(ab, "opid=%d oauid=%d ouid=%d oses=%d", pid, +			 from_kuid(&init_user_ns, auid), +			 from_kuid(&init_user_ns, uid), sessionid); +	if (sid) { +		if (security_secid_to_secctx(sid, &ctx, &len)) { +			audit_log_format(ab, " obj=(none)"); +			rc = 1; +		} else { +			audit_log_format(ab, " obj=%s", ctx); +			security_release_secctx(ctx, len); +		}  	}  	audit_log_format(ab, " ocomm=");  	audit_log_untrustedstring(ab, comm); @@ -1011,7 +1018,7 @@ static int audit_log_pid_context(struct audit_context *context, pid_t pid,  /*   * to_send and len_sent accounting are very loose estimates.  We aren't   * really worried about a hard cap to MAX_EXECVE_AUDIT_LEN so much as being - * within about 500 bytes (next page boundry) + * within about 500 bytes (next page boundary)   *   * why snprintf?  an int is up to 12 digits long.  if we just assumed when   * logging that a[%d]= was going to be 16 characters long we would be wasting @@ -1156,20 +1163,16 @@ static int audit_log_single_execve_arg(struct audit_context *context,  }  static void audit_log_execve_info(struct audit_context *context, -				  struct audit_buffer **ab, -				  struct audit_aux_data_execve *axi) +				  struct audit_buffer **ab)  { -	int i; -	size_t len, len_sent = 0; +	int i, len; +	size_t len_sent = 0;  	const char __user *p;  	char *buf; -	if (axi->mm != current->mm) -		return; /* execve failed, no additional info */ +	p = (const char __user *)current->mm->arg_start; -	p = (const char __user *)axi->mm->arg_start; - -	audit_log_format(*ab, "argc=%d", axi->argc); +	audit_log_format(*ab, "argc=%d", context->execve.argc);  	/*  	 * we need some kernel buffer to hold the userspace args.  Just @@ -1179,11 +1182,11 @@ static void audit_log_execve_info(struct audit_context *context,  	 */  	buf = kmalloc(MAX_EXECVE_AUDIT_LEN + 1, GFP_KERNEL);  	if (!buf) { -		audit_panic("out of memory for argv string\n"); +		audit_panic("out of memory for argv string");  		return;  	} -	for (i = 0; i < axi->argc; i++) { +	for (i = 0; i < context->execve.argc; i++) {  		len = audit_log_single_execve_arg(context, ab, i,  						  &len_sent, p, buf);  		if (len <= 0) @@ -1193,35 +1196,6 @@ static void audit_log_execve_info(struct audit_context *context,  	kfree(buf);  } -static void audit_log_cap(struct audit_buffer *ab, char *prefix, kernel_cap_t *cap) -{ -	int i; - -	audit_log_format(ab, " %s=", prefix); -	CAP_FOR_EACH_U32(i) { -		audit_log_format(ab, "%08x", cap->cap[(_KERNEL_CAPABILITY_U32S-1) - i]); -	} -} - -static void audit_log_fcaps(struct audit_buffer *ab, struct audit_names *name) -{ -	kernel_cap_t *perm = &name->fcap.permitted; -	kernel_cap_t *inh = &name->fcap.inheritable; -	int log = 0; - -	if (!cap_isclear(*perm)) { -		audit_log_cap(ab, "cap_fp", perm); -		log = 1; -	} -	if (!cap_isclear(*inh)) { -		audit_log_cap(ab, "cap_fi", inh); -		log = 1; -	} - -	if (log) -		audit_log_format(ab, " cap_fe=%d cap_fver=%x", name->fcap.fE, name->fcap_ver); -} -  static void show_special(struct audit_context *context, int *call_panic)  {  	struct audit_buffer *ab; @@ -1242,8 +1216,10 @@ static void show_special(struct audit_context *context, int *call_panic)  	case AUDIT_IPC: {  		u32 osid = context->ipc.osid; -		audit_log_format(ab, "ouid=%u ogid=%u mode=%#o", -			 context->ipc.uid, context->ipc.gid, context->ipc.mode); +		audit_log_format(ab, "ouid=%u ogid=%u mode=%#ho", +				 from_kuid(&init_user_ns, context->ipc.uid), +				 from_kgid(&init_user_ns, context->ipc.gid), +				 context->ipc.mode);  		if (osid) {  			char *ctx = NULL;  			u32 len; @@ -1259,19 +1235,19 @@ static void show_special(struct audit_context *context, int *call_panic)  			audit_log_end(ab);  			ab = audit_log_start(context, GFP_KERNEL,  					     AUDIT_IPC_SET_PERM); +			if (unlikely(!ab)) +				return;  			audit_log_format(ab, -				"qbytes=%lx ouid=%u ogid=%u mode=%#o", +				"qbytes=%lx ouid=%u ogid=%u mode=%#ho",  				context->ipc.qbytes,  				context->ipc.perm_uid,  				context->ipc.perm_gid,  				context->ipc.perm_mode); -			if (!ab) -				return;  		}  		break; }  	case AUDIT_MQ_OPEN: {  		audit_log_format(ab, -			"oflag=0x%x mode=%#o mq_flags=0x%lx mq_maxmsg=%ld " +			"oflag=0x%x mode=%#ho mq_flags=0x%lx mq_maxmsg=%ld "  			"mq_msgsize=%ld mq_curmsgs=%ld",  			context->mq_open.oflag, context->mq_open.mode,  			context->mq_open.attr.mq_flags, @@ -1313,31 +1289,74 @@ static void show_special(struct audit_context *context, int *call_panic)  		audit_log_format(ab, "fd=%d flags=0x%x", context->mmap.fd,  				 context->mmap.flags);  		break; } +	case AUDIT_EXECVE: { +		audit_log_execve_info(context, &ab); +		break; }  	}  	audit_log_end(ab);  } +static inline int audit_proctitle_rtrim(char *proctitle, int len) +{ +	char *end = proctitle + len - 1; +	while (end > proctitle && !isprint(*end)) +		end--; + +	/* catch the case where proctitle is only 1 non-print character */ +	len = end - proctitle + 1; +	len -= isprint(proctitle[len-1]) == 0; +	return len; +} + +static void audit_log_proctitle(struct task_struct *tsk, +			 struct audit_context *context) +{ +	int res; +	char *buf; +	char *msg = "(null)"; +	int len = strlen(msg); +	struct audit_buffer *ab; + +	ab = audit_log_start(context, GFP_KERNEL, AUDIT_PROCTITLE); +	if (!ab) +		return;	/* audit_panic or being filtered */ + +	audit_log_format(ab, "proctitle="); + +	/* Not  cached */ +	if (!context->proctitle.value) { +		buf = kmalloc(MAX_PROCTITLE_AUDIT_LEN, GFP_KERNEL); +		if (!buf) +			goto out; +		/* Historically called this from procfs naming */ +		res = get_cmdline(tsk, buf, MAX_PROCTITLE_AUDIT_LEN); +		if (res == 0) { +			kfree(buf); +			goto out; +		} +		res = audit_proctitle_rtrim(buf, res); +		if (res == 0) { +			kfree(buf); +			goto out; +		} +		context->proctitle.value = buf; +		context->proctitle.len = res; +	} +	msg = context->proctitle.value; +	len = context->proctitle.len; +out: +	audit_log_n_untrustedstring(ab, msg, len); +	audit_log_end(ab); +} +  static void audit_log_exit(struct audit_context *context, struct task_struct *tsk)  { -	const struct cred *cred;  	int i, call_panic = 0;  	struct audit_buffer *ab;  	struct audit_aux_data *aux; -	const char *tty; +	struct audit_names *n;  	/* tsk == current */ -	context->pid = tsk->pid; -	if (!context->ppid) -		context->ppid = sys_getppid(); -	cred = current_cred(); -	context->uid   = cred->uid; -	context->gid   = cred->gid; -	context->euid  = cred->euid; -	context->suid  = cred->suid; -	context->fsuid = cred->fsuid; -	context->egid  = cred->egid; -	context->sgid  = cred->sgid; -	context->fsgid = cred->fsgid;  	context->personality = tsk->personality;  	ab = audit_log_start(context, GFP_KERNEL, AUDIT_SYSCALL); @@ -1352,32 +1371,13 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts  				 (context->return_valid==AUDITSC_SUCCESS)?"yes":"no",  				 context->return_code); -	spin_lock_irq(&tsk->sighand->siglock); -	if (tsk->signal && tsk->signal->tty && tsk->signal->tty->name) -		tty = tsk->signal->tty->name; -	else -		tty = "(none)"; -	spin_unlock_irq(&tsk->sighand->siglock); -  	audit_log_format(ab, -		  " a0=%lx a1=%lx a2=%lx a3=%lx items=%d" -		  " ppid=%d pid=%d auid=%u uid=%u gid=%u" -		  " euid=%u suid=%u fsuid=%u" -		  " egid=%u sgid=%u fsgid=%u tty=%s ses=%u", -		  context->argv[0], -		  context->argv[1], -		  context->argv[2], -		  context->argv[3], -		  context->name_count, -		  context->ppid, -		  context->pid, -		  tsk->loginuid, -		  context->uid, -		  context->gid, -		  context->euid, context->suid, context->fsuid, -		  context->egid, context->sgid, context->fsgid, tty, -		  tsk->sessionid); - +			 " a0=%lx a1=%lx a2=%lx a3=%lx items=%d", +			 context->argv[0], +			 context->argv[1], +			 context->argv[2], +			 context->argv[3], +			 context->name_count);  	audit_log_task_info(ab, tsk);  	audit_log_key(ab, context->filterkey); @@ -1391,11 +1391,6 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts  		switch (aux->type) { -		case AUDIT_EXECVE: { -			struct audit_aux_data_execve *axi = (void *)aux; -			audit_log_execve_info(context, &ab, axi); -			break; } -  		case AUDIT_BPRM_FCAPS: {  			struct audit_aux_data_bprm_fcaps *axs = (void *)aux;  			audit_log_format(ab, "fver=%x", axs->fcap_ver); @@ -1459,71 +1454,20 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts  	if (context->pwd.dentry && context->pwd.mnt) {  		ab = audit_log_start(context, GFP_KERNEL, AUDIT_CWD);  		if (ab) { -			audit_log_d_path(ab, "cwd=", &context->pwd); +			audit_log_d_path(ab, " cwd=", &context->pwd);  			audit_log_end(ab);  		}  	} -	for (i = 0; i < context->name_count; i++) { -		struct audit_names *n = &context->names[i]; - -		ab = audit_log_start(context, GFP_KERNEL, AUDIT_PATH); -		if (!ab) -			continue; /* audit_panic has been called */ - -		audit_log_format(ab, "item=%d", i); - -		if (n->name) { -			switch(n->name_len) { -			case AUDIT_NAME_FULL: -				/* log the full path */ -				audit_log_format(ab, " name="); -				audit_log_untrustedstring(ab, n->name); -				break; -			case 0: -				/* name was specified as a relative path and the -				 * directory component is the cwd */ -				audit_log_d_path(ab, "name=", &context->pwd); -				break; -			default: -				/* log the name's directory component */ -				audit_log_format(ab, " name="); -				audit_log_n_untrustedstring(ab, n->name, -							    n->name_len); -			} -		} else -			audit_log_format(ab, " name=(null)"); - -		if (n->ino != (unsigned long)-1) { -			audit_log_format(ab, " inode=%lu" -					 " dev=%02x:%02x mode=%#o" -					 " ouid=%u ogid=%u rdev=%02x:%02x", -					 n->ino, -					 MAJOR(n->dev), -					 MINOR(n->dev), -					 n->mode, -					 n->uid, -					 n->gid, -					 MAJOR(n->rdev), -					 MINOR(n->rdev)); -		} -		if (n->osid != 0) { -			char *ctx = NULL; -			u32 len; -			if (security_secid_to_secctx( -				n->osid, &ctx, &len)) { -				audit_log_format(ab, " osid=%u", n->osid); -				call_panic = 2; -			} else { -				audit_log_format(ab, " obj=%s", ctx); -				security_release_secctx(ctx, len); -			} -		} - -		audit_log_fcaps(ab, n); -		audit_log_end(ab); +	i = 0; +	list_for_each_entry(n, &context->names_list, list) { +		if (n->hidden) +			continue; +		audit_log_name(context, n, NULL, i++, &call_panic);  	} +	audit_log_proctitle(tsk, context); +  	/* Send end of event record to help user space know we are finished */  	ab = audit_log_start(context, GFP_KERNEL, AUDIT_EOE);  	if (ab) @@ -1538,12 +1482,12 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts   *   * Called from copy_process and do_exit   */ -void audit_free(struct task_struct *tsk) +void __audit_free(struct task_struct *tsk)  {  	struct audit_context *context; -	context = audit_get_context(tsk, 0, 0); -	if (likely(!context)) +	context = audit_take_context(tsk, 0, 0); +	if (!context)  		return;  	/* Check for system calls that do not go through the exit @@ -1576,7 +1520,7 @@ void audit_free(struct task_struct *tsk)   * will only be written if another part of the kernel requests that it   * be written).   */ -void audit_syscall_entry(int arch, int major, +void __audit_syscall_entry(int arch, int major,  			 unsigned long a1, unsigned long a2,  			 unsigned long a3, unsigned long a4)  { @@ -1584,45 +1528,9 @@ void audit_syscall_entry(int arch, int major,  	struct audit_context *context = tsk->audit_context;  	enum audit_state     state; -	if (unlikely(!context)) +	if (!context)  		return; -	/* -	 * This happens only on certain architectures that make system -	 * calls in kernel_thread via the entry.S interface, instead of -	 * with direct calls.  (If you are porting to a new -	 * architecture, hitting this condition can indicate that you -	 * got the _exit/_leave calls backward in entry.S.) -	 * -	 * i386     no -	 * x86_64   no -	 * ppc64    yes (see arch/powerpc/platforms/iseries/misc.S) -	 * -	 * This also happens with vm86 emulation in a non-nested manner -	 * (entries without exits), so this case must be caught. -	 */ -	if (context->in_syscall) { -		struct audit_context *newctx; - -#if AUDIT_DEBUG -		printk(KERN_ERR -		       "audit(:%d) pid=%d in syscall=%d;" -		       " entering syscall=%d\n", -		       context->serial, tsk->pid, context->major, major); -#endif -		newctx = audit_alloc_context(context->state); -		if (newctx) { -			newctx->previous   = context; -			context		   = newctx; -			tsk->audit_context = newctx; -		} else	{ -			/* If we can't alloc a new context, the best we -			 * can do is to leak memory (any pending putname -			 * will be lost).  The only other alternative is -			 * to abandon auditing. */ -			audit_zero_context(context, context->state); -		} -	}  	BUG_ON(context->in_syscall || context->name_count);  	if (!audit_enabled) @@ -1641,7 +1549,7 @@ void audit_syscall_entry(int arch, int major,  		context->prio = 0;  		state = audit_filter_syscall(tsk, context, &audit_filter_list[AUDIT_FILTER_ENTRY]);  	} -	if (likely(state == AUDIT_DISABLED)) +	if (state == AUDIT_DISABLED)  		return;  	context->serial     = 0; @@ -1651,45 +1559,29 @@ void audit_syscall_entry(int arch, int major,  	context->ppid       = 0;  } -void audit_finish_fork(struct task_struct *child) -{ -	struct audit_context *ctx = current->audit_context; -	struct audit_context *p = child->audit_context; -	if (!p || !ctx) -		return; -	if (!ctx->in_syscall || ctx->current_state != AUDIT_RECORD_CONTEXT) -		return; -	p->arch = ctx->arch; -	p->major = ctx->major; -	memcpy(p->argv, ctx->argv, sizeof(ctx->argv)); -	p->ctime = ctx->ctime; -	p->dummy = ctx->dummy; -	p->in_syscall = ctx->in_syscall; -	p->filterkey = kstrdup(ctx->filterkey, GFP_KERNEL); -	p->ppid = current->pid; -	p->prio = ctx->prio; -	p->current_state = ctx->current_state; -} -  /**   * audit_syscall_exit - deallocate audit context after a system call - * @valid: success/failure flag - * @return_code: syscall return value + * @success: success value of the syscall + * @return_code: return value of the syscall   *   * Tear down after system call.  If the audit context has been marked as   * auditable (either because of the AUDIT_RECORD_CONTEXT state from - * filtering, or because some other part of the kernel write an audit + * filtering, or because some other part of the kernel wrote an audit   * message), then write out the syscall information.  In call cases,   * free the names stored from getname().   */ -void audit_syscall_exit(int valid, long return_code) +void __audit_syscall_exit(int success, long return_code)  {  	struct task_struct *tsk = current;  	struct audit_context *context; -	context = audit_get_context(tsk, valid, return_code); +	if (success) +		success = AUDITSC_SUCCESS; +	else +		success = AUDITSC_FAILURE; -	if (likely(!context)) +	context = audit_take_context(tsk, success, return_code); +	if (!context)  		return;  	if (context->in_syscall && context->current_state == AUDIT_RECORD_CONTEXT) @@ -1701,28 +1593,21 @@ void audit_syscall_exit(int valid, long return_code)  	if (!list_empty(&context->killed_trees))  		audit_kill_trees(&context->killed_trees); -	if (context->previous) { -		struct audit_context *new_context = context->previous; -		context->previous  = NULL; -		audit_free_context(context); -		tsk->audit_context = new_context; -	} else { -		audit_free_names(context); -		unroll_tree_refs(context, NULL, 0); -		audit_free_aux(context); -		context->aux = NULL; -		context->aux_pids = NULL; -		context->target_pid = 0; -		context->target_sid = 0; -		context->sockaddr_len = 0; -		context->type = 0; -		context->fds[0] = -1; -		if (context->state != AUDIT_RECORD_CONTEXT) { -			kfree(context->filterkey); -			context->filterkey = NULL; -		} -		tsk->audit_context = context; +	audit_free_names(context); +	unroll_tree_refs(context, NULL, 0); +	audit_free_aux(context); +	context->aux = NULL; +	context->aux_pids = NULL; +	context->target_pid = 0; +	context->target_sid = 0; +	context->sockaddr_len = 0; +	context->type = 0; +	context->fds[0] = -1; +	if (context->state != AUDIT_RECORD_CONTEXT) { +		kfree(context->filterkey); +		context->filterkey = NULL;  	} +	tsk->audit_context = context;  }  static inline void handle_one(const struct inode *inode) @@ -1745,7 +1630,7 @@ static inline void handle_one(const struct inode *inode)  	if (likely(put_tree_ref(context, chunk)))  		return;  	if (unlikely(!grow_tree_refs(context))) { -		printk(KERN_WARNING "out of memory, audit has lost a tree reference\n"); +		pr_warn("out of memory, audit has lost a tree reference\n");  		audit_set_auditable(context);  		audit_put_chunk(chunk);  		unroll_tree_refs(context, p, count); @@ -1804,8 +1689,7 @@ retry:  			goto retry;  		}  		/* too bad */ -		printk(KERN_WARNING -			"out of memory, audit has lost a tree reference\n"); +		pr_warn("out of memory, audit has lost a tree reference\n");  		unroll_tree_refs(context, p, count);  		audit_set_auditable(context);  		return; @@ -1814,6 +1698,55 @@ retry:  #endif  } +static struct audit_names *audit_alloc_name(struct audit_context *context, +						unsigned char type) +{ +	struct audit_names *aname; + +	if (context->name_count < AUDIT_NAMES) { +		aname = &context->preallocated_names[context->name_count]; +		memset(aname, 0, sizeof(*aname)); +	} else { +		aname = kzalloc(sizeof(*aname), GFP_NOFS); +		if (!aname) +			return NULL; +		aname->should_free = true; +	} + +	aname->ino = (unsigned long)-1; +	aname->type = type; +	list_add_tail(&aname->list, &context->names_list); + +	context->name_count++; +#if AUDIT_DEBUG +	context->ino_count++; +#endif +	return aname; +} + +/** + * audit_reusename - fill out filename with info from existing entry + * @uptr: userland ptr to pathname + * + * Search the audit_names list for the current audit context. If there is an + * existing entry with a matching "uptr" then return the filename + * associated with that audit_name. If not, return NULL. + */ +struct filename * +__audit_reusename(const __user char *uptr) +{ +	struct audit_context *context = current->audit_context; +	struct audit_names *n; + +	list_for_each_entry(n, &context->names_list, list) { +		if (!n->name) +			continue; +		if (n->name->uptr == uptr) +			return n->name; +	} +	return NULL; +} +  /**   * audit_getname - add a name to the list   * @name: name to add @@ -1821,28 +1754,34 @@ retry:   * Add a name to the list of audit names for this context.   * Called from fs/namei.c:getname().   */ -void __audit_getname(const char *name) +void __audit_getname(struct filename *name)  {  	struct audit_context *context = current->audit_context; - -	if (IS_ERR(name) || !name) -		return; +	struct audit_names *n;  	if (!context->in_syscall) {  #if AUDIT_DEBUG == 2 -		printk(KERN_ERR "%s:%d(:%d): ignoring getname(%p)\n", +		pr_err("%s:%d(:%d): ignoring getname(%p)\n",  		       __FILE__, __LINE__, context->serial, name);  		dump_stack();  #endif  		return;  	} -	BUG_ON(context->name_count >= AUDIT_NAMES); -	context->names[context->name_count].name = name; -	context->names[context->name_count].name_len = AUDIT_NAME_FULL; -	context->names[context->name_count].name_put = 1; -	context->names[context->name_count].ino  = (unsigned long)-1; -	context->names[context->name_count].osid = 0; -	++context->name_count; + +#if AUDIT_DEBUG +	/* The filename _must_ have a populated ->name */ +	BUG_ON(!name->name); +#endif + +	n = audit_alloc_name(context, AUDIT_TYPE_UNKNOWN); +	if (!n) +		return; + +	n->name = name; +	n->name_len = AUDIT_NAME_FULL; +	n->name_put = true; +	name->aname = n; +  	if (!context->pwd.dentry)  		get_fs_pwd(current->fs, &context->pwd);  } @@ -1854,144 +1793,124 @@ void __audit_getname(const char *name)   * then we delay the putname until syscall exit.   * Called from include/linux/fs.h:putname().   */ -void audit_putname(const char *name) +void audit_putname(struct filename *name)  {  	struct audit_context *context = current->audit_context;  	BUG_ON(!context); -	if (!context->in_syscall) { +	if (!name->aname || !context->in_syscall) {  #if AUDIT_DEBUG == 2 -		printk(KERN_ERR "%s:%d(:%d): __putname(%p)\n", +		pr_err("%s:%d(:%d): final_putname(%p)\n",  		       __FILE__, __LINE__, context->serial, name);  		if (context->name_count) { -			int i; -			for (i = 0; i < context->name_count; i++) -				printk(KERN_ERR "name[%d] = %p = %s\n", i, -				       context->names[i].name, -				       context->names[i].name ?: "(null)"); -		} +			struct audit_names *n; +			int i = 0; + +			list_for_each_entry(n, &context->names_list, list) +				pr_err("name[%d] = %p = %s\n", i++, n->name, +				       n->name->name ?: "(null)"); +			}  #endif -		__putname(name); +		final_putname(name);  	}  #if AUDIT_DEBUG  	else {  		++context->put_count;  		if (context->put_count > context->name_count) { -			printk(KERN_ERR "%s:%d(:%d): major=%d" -			       " in_syscall=%d putname(%p) name_count=%d" -			       " put_count=%d\n", +			pr_err("%s:%d(:%d): major=%d in_syscall=%d putname(%p)" +			       " name_count=%d put_count=%d\n",  			       __FILE__, __LINE__,  			       context->serial, context->major, -			       context->in_syscall, name, context->name_count, -			       context->put_count); +			       context->in_syscall, name->name, +			       context->name_count, context->put_count);  			dump_stack();  		}  	}  #endif  } -static int audit_inc_name_count(struct audit_context *context, -				const struct inode *inode) -{ -	if (context->name_count >= AUDIT_NAMES) { -		if (inode) -			printk(KERN_DEBUG "audit: name_count maxed, losing inode data: " -			       "dev=%02x:%02x, inode=%lu\n", -			       MAJOR(inode->i_sb->s_dev), -			       MINOR(inode->i_sb->s_dev), -			       inode->i_ino); - -		else -			printk(KERN_DEBUG "name_count maxed, losing inode data\n"); -		return 1; -	} -	context->name_count++; -#if AUDIT_DEBUG -	context->ino_count++; -#endif -	return 0; -} - - -static inline int audit_copy_fcaps(struct audit_names *name, const struct dentry *dentry) -{ -	struct cpu_vfs_cap_data caps; -	int rc; - -	memset(&name->fcap.permitted, 0, sizeof(kernel_cap_t)); -	memset(&name->fcap.inheritable, 0, sizeof(kernel_cap_t)); -	name->fcap.fE = 0; -	name->fcap_ver = 0; - -	if (!dentry) -		return 0; - -	rc = get_vfs_caps_from_disk(dentry, &caps); -	if (rc) -		return rc; - -	name->fcap.permitted = caps.permitted; -	name->fcap.inheritable = caps.inheritable; -	name->fcap.fE = !!(caps.magic_etc & VFS_CAP_FLAGS_EFFECTIVE); -	name->fcap_ver = (caps.magic_etc & VFS_CAP_REVISION_MASK) >> VFS_CAP_REVISION_SHIFT; - -	return 0; -} - - -/* Copy inode data into an audit_names. */ -static void audit_copy_inode(struct audit_names *name, const struct dentry *dentry, -			     const struct inode *inode) -{ -	name->ino   = inode->i_ino; -	name->dev   = inode->i_sb->s_dev; -	name->mode  = inode->i_mode; -	name->uid   = inode->i_uid; -	name->gid   = inode->i_gid; -	name->rdev  = inode->i_rdev; -	security_inode_getsecid(inode, &name->osid); -	audit_copy_fcaps(name, dentry); -} -  /** - * audit_inode - store the inode and device from a lookup + * __audit_inode - store the inode and device from a lookup   * @name: name being audited   * @dentry: dentry being audited - * - * Called from fs/namei.c:path_lookup(). + * @flags: attributes for this particular entry   */ -void __audit_inode(const char *name, const struct dentry *dentry) +void __audit_inode(struct filename *name, const struct dentry *dentry, +		   unsigned int flags)  { -	int idx;  	struct audit_context *context = current->audit_context;  	const struct inode *inode = dentry->d_inode; +	struct audit_names *n; +	bool parent = flags & AUDIT_INODE_PARENT;  	if (!context->in_syscall)  		return; -	if (context->name_count -	    && context->names[context->name_count-1].name -	    && context->names[context->name_count-1].name == name) -		idx = context->name_count - 1; -	else if (context->name_count > 1 -		 && context->names[context->name_count-2].name -		 && context->names[context->name_count-2].name == name) -		idx = context->name_count - 2; -	else { -		/* FIXME: how much do we care about inodes that have no -		 * associated name? */ -		if (audit_inc_name_count(context, inode)) -			return; -		idx = context->name_count - 1; -		context->names[idx].name = NULL; + +	if (!name) +		goto out_alloc; + +#if AUDIT_DEBUG +	/* The struct filename _must_ have a populated ->name */ +	BUG_ON(!name->name); +#endif +	/* +	 * If we have a pointer to an audit_names entry already, then we can +	 * just use it directly if the type is correct. +	 */ +	n = name->aname; +	if (n) { +		if (parent) { +			if (n->type == AUDIT_TYPE_PARENT || +			    n->type == AUDIT_TYPE_UNKNOWN) +				goto out; +		} else { +			if (n->type != AUDIT_TYPE_PARENT) +				goto out; +		} +	} + +	list_for_each_entry_reverse(n, &context->names_list, list) { +		/* does the name pointer match? */ +		if (!n->name || n->name->name != name->name) +			continue; + +		/* match the correct record type */ +		if (parent) { +			if (n->type == AUDIT_TYPE_PARENT || +			    n->type == AUDIT_TYPE_UNKNOWN) +				goto out; +		} else { +			if (n->type != AUDIT_TYPE_PARENT) +				goto out; +		} +	} + +out_alloc: +	/* unable to find the name from a previous getname(). Allocate a new +	 * anonymous entry. +	 */ +	n = audit_alloc_name(context, AUDIT_TYPE_NORMAL); +	if (!n) +		return; +out: +	if (parent) { +		n->name_len = n->name ? parent_len(n->name->name) : AUDIT_NAME_FULL; +		n->type = AUDIT_TYPE_PARENT; +		if (flags & AUDIT_INODE_HIDDEN) +			n->hidden = true; +	} else { +		n->name_len = AUDIT_NAME_FULL; +		n->type = AUDIT_TYPE_NORMAL;  	}  	handle_path(dentry); -	audit_copy_inode(&context->names[idx], dentry, inode); +	audit_copy_inode(n, dentry, inode);  }  /** - * audit_inode_child - collect inode info for created/removed objects - * @dentry: dentry being audited + * __audit_inode_child - collect inode info for created/removed objects   * @parent: inode of dentry parent + * @dentry: dentry being audited + * @type:   AUDIT_TYPE_* value that we're looking for   *   * For syscalls that create or remove filesystem objects, audit_inode   * can only collect information for the filesystem object's parent. @@ -2001,15 +1920,14 @@ void __audit_inode(const char *name, const struct dentry *dentry)   * must be hooked prior, in order to capture the target inode during   * unsuccessful attempts.   */ -void __audit_inode_child(const struct dentry *dentry, -			 const struct inode *parent) +void __audit_inode_child(const struct inode *parent, +			 const struct dentry *dentry, +			 const unsigned char type)  { -	int idx;  	struct audit_context *context = current->audit_context; -	const char *found_parent = NULL, *found_child = NULL;  	const struct inode *inode = dentry->d_inode;  	const char *dname = dentry->d_name.name; -	int dirlen = 0; +	struct audit_names *n, *found_parent = NULL, *found_child = NULL;  	if (!context->in_syscall)  		return; @@ -2017,71 +1935,65 @@ void __audit_inode_child(const struct dentry *dentry,  	if (inode)  		handle_one(inode); -	/* parent is more likely, look for it first */ -	for (idx = 0; idx < context->name_count; idx++) { -		struct audit_names *n = &context->names[idx]; - -		if (!n->name) +	/* look for a parent entry first */ +	list_for_each_entry(n, &context->names_list, list) { +		if (!n->name || n->type != AUDIT_TYPE_PARENT)  			continue;  		if (n->ino == parent->i_ino && -		    !audit_compare_dname_path(dname, n->name, &dirlen)) { -			n->name_len = dirlen; /* update parent data in place */ -			found_parent = n->name; -			goto add_names; +		    !audit_compare_dname_path(dname, n->name->name, n->name_len)) { +			found_parent = n; +			break;  		}  	} -	/* no matching parent, look for matching child */ -	for (idx = 0; idx < context->name_count; idx++) { -		struct audit_names *n = &context->names[idx]; +	/* is there a matching child entry? */ +	list_for_each_entry(n, &context->names_list, list) { +		/* can only match entries that have a name */ +		if (!n->name || n->type != type) +			continue; -		if (!n->name) +		/* if we found a parent, make sure this one is a child of it */ +		if (found_parent && (n->name != found_parent->name))  			continue; -		/* strcmp() is the more likely scenario */ -		if (!strcmp(dname, n->name) || -		     !audit_compare_dname_path(dname, n->name, &dirlen)) { -			if (inode) -				audit_copy_inode(n, NULL, inode); -			else -				n->ino = (unsigned long)-1; -			found_child = n->name; -			goto add_names; +		if (!strcmp(dname, n->name->name) || +		    !audit_compare_dname_path(dname, n->name->name, +						found_parent ? +						found_parent->name_len : +						AUDIT_NAME_FULL)) { +			found_child = n; +			break;  		}  	} -add_names:  	if (!found_parent) { -		if (audit_inc_name_count(context, parent)) +		/* create a new, "anonymous" parent record */ +		n = audit_alloc_name(context, AUDIT_TYPE_PARENT); +		if (!n)  			return; -		idx = context->name_count - 1; -		context->names[idx].name = NULL; -		audit_copy_inode(&context->names[idx], NULL, parent); +		audit_copy_inode(n, NULL, parent);  	}  	if (!found_child) { -		if (audit_inc_name_count(context, inode)) +		found_child = audit_alloc_name(context, type); +		if (!found_child)  			return; -		idx = context->name_count - 1;  		/* Re-use the name belonging to the slot for a matching parent  		 * directory. All names for this context are relinquished in  		 * audit_free_names() */  		if (found_parent) { -			context->names[idx].name = found_parent; -			context->names[idx].name_len = AUDIT_NAME_FULL; +			found_child->name = found_parent->name; +			found_child->name_len = AUDIT_NAME_FULL;  			/* don't call __putname() */ -			context->names[idx].name_put = 0; -		} else { -			context->names[idx].name = NULL; +			found_child->name_put = false;  		} - -		if (inode) -			audit_copy_inode(&context->names[idx], NULL, inode); -		else -			context->names[idx].ino = (unsigned long)-1;  	} +	if (inode) +		audit_copy_inode(found_child, dentry, inode); +	else +		found_child->ino = (unsigned long)-1;  }  EXPORT_SYMBOL_GPL(__audit_inode_child); @@ -2113,37 +2025,78 @@ int auditsc_get_stamp(struct audit_context *ctx,  /* global counter which is incremented every time something logs in */  static atomic_t session_id = ATOMIC_INIT(0); +static int audit_set_loginuid_perm(kuid_t loginuid) +{ +	/* if we are unset, we don't need privs */ +	if (!audit_loginuid_set(current)) +		return 0; +	/* if AUDIT_FEATURE_LOGINUID_IMMUTABLE means never ever allow a change*/ +	if (is_audit_feature_set(AUDIT_FEATURE_LOGINUID_IMMUTABLE)) +		return -EPERM; +	/* it is set, you need permission */ +	if (!capable(CAP_AUDIT_CONTROL)) +		return -EPERM; +	/* reject if this is not an unset and we don't allow that */ +	if (is_audit_feature_set(AUDIT_FEATURE_ONLY_UNSET_LOGINUID) && uid_valid(loginuid)) +		return -EPERM; +	return 0; +} + +static void audit_log_set_loginuid(kuid_t koldloginuid, kuid_t kloginuid, +				   unsigned int oldsessionid, unsigned int sessionid, +				   int rc) +{ +	struct audit_buffer *ab; +	uid_t uid, oldloginuid, loginuid; + +	if (!audit_enabled) +		return; + +	uid = from_kuid(&init_user_ns, task_uid(current)); +	oldloginuid = from_kuid(&init_user_ns, koldloginuid); +	loginuid = from_kuid(&init_user_ns, kloginuid), + +	ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_LOGIN); +	if (!ab) +		return; +	audit_log_format(ab, "pid=%d uid=%u", task_pid_nr(current), uid); +	audit_log_task_context(ab); +	audit_log_format(ab, " old-auid=%u auid=%u old-ses=%u ses=%u res=%d", +			 oldloginuid, loginuid, oldsessionid, sessionid, !rc); +	audit_log_end(ab); +} +  /** - * audit_set_loginuid - set a task's audit_context loginuid - * @task: task whose audit context is being modified + * audit_set_loginuid - set current task's audit_context loginuid   * @loginuid: loginuid value   *   * Returns 0.   *   * Called (set) from fs/proc/base.c::proc_loginuid_write().   */ -int audit_set_loginuid(struct task_struct *task, uid_t loginuid) +int audit_set_loginuid(kuid_t loginuid)  { -	unsigned int sessionid = atomic_inc_return(&session_id); -	struct audit_context *context = task->audit_context; +	struct task_struct *task = current; +	unsigned int oldsessionid, sessionid = (unsigned int)-1; +	kuid_t oldloginuid; +	int rc; -	if (context && context->in_syscall) { -		struct audit_buffer *ab; +	oldloginuid = audit_get_loginuid(current); +	oldsessionid = audit_get_sessionid(current); + +	rc = audit_set_loginuid_perm(loginuid); +	if (rc) +		goto out; + +	/* are we setting or clearing? */ +	if (uid_valid(loginuid)) +		sessionid = (unsigned int)atomic_inc_return(&session_id); -		ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_LOGIN); -		if (ab) { -			audit_log_format(ab, "login pid=%d uid=%u " -				"old auid=%u new auid=%u" -				" old ses=%u new ses=%u", -				task->pid, task_uid(task), -				task->loginuid, loginuid, -				task->sessionid, sessionid); -			audit_log_end(ab); -		} -	}  	task->sessionid = sessionid;  	task->loginuid = loginuid; -	return 0; +out: +	audit_log_set_loginuid(oldloginuid, loginuid, oldsessionid, sessionid, rc); +	return rc;  }  /** @@ -2153,7 +2106,7 @@ int audit_set_loginuid(struct task_struct *task, uid_t loginuid)   * @attr: queue attributes   *   */ -void __audit_mq_open(int oflag, mode_t mode, struct mq_attr *attr) +void __audit_mq_open(int oflag, umode_t mode, struct mq_attr *attr)  {  	struct audit_context *context = current->audit_context; @@ -2253,7 +2206,7 @@ void __audit_ipc_obj(struct kern_ipc_perm *ipcp)   *   * Called only after audit_ipc_obj().   */ -void __audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode) +void __audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid, umode_t mode)  {  	struct audit_context *context = current->audit_context; @@ -2264,44 +2217,31 @@ void __audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mod  	context->ipc.has_perm = 1;  } -int audit_bprm(struct linux_binprm *bprm) +void __audit_bprm(struct linux_binprm *bprm)  { -	struct audit_aux_data_execve *ax;  	struct audit_context *context = current->audit_context; -	if (likely(!audit_enabled || !context || context->dummy)) -		return 0; - -	ax = kmalloc(sizeof(*ax), GFP_KERNEL); -	if (!ax) -		return -ENOMEM; - -	ax->argc = bprm->argc; -	ax->envc = bprm->envc; -	ax->mm = bprm->mm; -	ax->d.type = AUDIT_EXECVE; -	ax->d.next = context->aux; -	context->aux = (void *)ax; -	return 0; +	context->type = AUDIT_EXECVE; +	context->execve.argc = bprm->argc;  }  /**   * audit_socketcall - record audit data for sys_socketcall - * @nargs: number of args + * @nargs: number of args, which should not be more than AUDITSC_ARGS.   * @args: args array   *   */ -void audit_socketcall(int nargs, unsigned long *args) +int __audit_socketcall(int nargs, unsigned long *args)  {  	struct audit_context *context = current->audit_context; -	if (likely(!context || context->dummy)) -		return; - +	if (nargs <= 0 || nargs > AUDITSC_ARGS || !args) +		return -EINVAL;  	context->type = AUDIT_SOCKETCALL;  	context->socketcall.nargs = nargs;  	memcpy(context->socketcall.args, args, nargs * sizeof(unsigned long)); +	return 0;  }  /** @@ -2324,13 +2264,10 @@ void __audit_fd_pair(int fd1, int fd2)   *   * Returns 0 for success or NULL context or < 0 on error.   */ -int audit_sockaddr(int len, void *a) +int __audit_sockaddr(int len, void *a)  {  	struct audit_context *context = current->audit_context; -	if (likely(!context || context->dummy)) -		return 0; -  	if (!context->sockaddr) {  		void *p = kmalloc(sizeof(struct sockaddr_storage), GFP_KERNEL);  		if (!p) @@ -2347,7 +2284,7 @@ void __audit_ptrace(struct task_struct *t)  {  	struct audit_context *context = current->audit_context; -	context->target_pid = t->pid; +	context->target_pid = task_pid_nr(t);  	context->target_auid = audit_get_loginuid(t);  	context->target_uid = task_uid(t);  	context->target_sessionid = audit_get_sessionid(t); @@ -2368,12 +2305,12 @@ int __audit_signal_info(int sig, struct task_struct *t)  	struct audit_aux_data_pids *axp;  	struct task_struct *tsk = current;  	struct audit_context *ctx = tsk->audit_context; -	uid_t uid = current_uid(), t_uid = task_uid(t); +	kuid_t uid = current_uid(), t_uid = task_uid(t);  	if (audit_pid && t->tgid == audit_pid) {  		if (sig == SIGTERM || sig == SIGHUP || sig == SIGUSR1 || sig == SIGUSR2) { -			audit_sig_pid = tsk->pid; -			if (tsk->loginuid != -1) +			audit_sig_pid = task_pid_nr(tsk); +			if (uid_valid(tsk->loginuid))  				audit_sig_uid = tsk->loginuid;  			else  				audit_sig_uid = uid; @@ -2386,7 +2323,7 @@ int __audit_signal_info(int sig, struct task_struct *t)  	/* optimize the common case by putting first signal recipient directly  	 * in audit_context */  	if (!ctx->target_pid) { -		ctx->target_pid = t->tgid; +		ctx->target_pid = task_tgid_nr(t);  		ctx->target_auid = audit_get_loginuid(t);  		ctx->target_uid = t_uid;  		ctx->target_sessionid = audit_get_sessionid(t); @@ -2407,7 +2344,7 @@ int __audit_signal_info(int sig, struct task_struct *t)  	}  	BUG_ON(axp->pid_count >= AUDIT_AUX_PIDS); -	axp->target_pid[axp->pid_count] = t->tgid; +	axp->target_pid[axp->pid_count] = task_tgid_nr(t);  	axp->target_auid[axp->pid_count] = audit_get_loginuid(t);  	axp->target_uid[axp->pid_count] = t_uid;  	axp->target_sessionid[axp->pid_count] = audit_get_sessionid(t); @@ -2466,18 +2403,16 @@ int __audit_log_bprm_fcaps(struct linux_binprm *bprm,  /**   * __audit_log_capset - store information about the arguments to the capset syscall - * @pid: target pid of the capset call   * @new: the new credentials   * @old: the old (current) credentials   *   * Record the aguments userspace sent to sys_capset for later printing by the   * audit system if applicable   */ -void __audit_log_capset(pid_t pid, -		       const struct cred *new, const struct cred *old) +void __audit_log_capset(const struct cred *new, const struct cred *old)  {  	struct audit_context *context = current->audit_context; -	context->capset.pid = pid; +	context->capset.pid = task_pid_nr(current);  	context->capset.cap.effective   = new->cap_effective;  	context->capset.cap.inheritable = new->cap_effective;  	context->capset.cap.permitted   = new->cap_permitted; @@ -2492,6 +2427,34 @@ void __audit_mmap_fd(int fd, int flags)  	context->type = AUDIT_MMAP;  } +static void audit_log_task(struct audit_buffer *ab) +{ +	kuid_t auid, uid; +	kgid_t gid; +	unsigned int sessionid; +	struct mm_struct *mm = current->mm; + +	auid = audit_get_loginuid(current); +	sessionid = audit_get_sessionid(current); +	current_uid_gid(&uid, &gid); + +	audit_log_format(ab, "auid=%u uid=%u gid=%u ses=%u", +			 from_kuid(&init_user_ns, auid), +			 from_kuid(&init_user_ns, uid), +			 from_kgid(&init_user_ns, gid), +			 sessionid); +	audit_log_task_context(ab); +	audit_log_format(ab, " pid=%d comm=", task_pid_nr(current)); +	audit_log_untrustedstring(ab, current->comm); +	if (mm) { +		down_read(&mm->mmap_sem); +		if (mm->exe_file) +			audit_log_d_path(ab, " exe=", &mm->exe_file->f_path); +		up_read(&mm->mmap_sem); +	} else +		audit_log_format(ab, " exe=(null)"); +} +  /**   * audit_core_dumps - record information about processes that end abnormally   * @signr: signal value @@ -2502,10 +2465,6 @@ void __audit_mmap_fd(int fd, int flags)  void audit_core_dumps(long signr)  {  	struct audit_buffer *ab; -	u32 sid; -	uid_t auid = audit_get_loginuid(current), uid; -	gid_t gid; -	unsigned int sessionid = audit_get_sessionid(current);  	if (!audit_enabled)  		return; @@ -2514,24 +2473,26 @@ void audit_core_dumps(long signr)  		return;  	ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_ANOM_ABEND); -	current_uid_gid(&uid, &gid); -	audit_log_format(ab, "auid=%u uid=%u gid=%u ses=%u", -			 auid, uid, gid, sessionid); -	security_task_getsecid(current, &sid); -	if (sid) { -		char *ctx = NULL; -		u32 len; +	if (unlikely(!ab)) +		return; +	audit_log_task(ab); +	audit_log_format(ab, " sig=%ld", signr); +	audit_log_end(ab); +} -		if (security_secid_to_secctx(sid, &ctx, &len)) -			audit_log_format(ab, " ssid=%u", sid); -		else { -			audit_log_format(ab, " subj=%s", ctx); -			security_release_secctx(ctx, len); -		} -	} -	audit_log_format(ab, " pid=%d comm=", current->pid); -	audit_log_untrustedstring(ab, current->comm); +void __audit_seccomp(unsigned long syscall, long signr, int code) +{ +	struct audit_buffer *ab; + +	ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_SECCOMP); +	if (unlikely(!ab)) +		return; +	audit_log_task(ab);  	audit_log_format(ab, " sig=%ld", signr); +	audit_log_format(ab, " syscall=%ld", syscall); +	audit_log_format(ab, " compat=%d", is_compat_task()); +	audit_log_format(ab, " ip=0x%lx", KSTK_EIP(current)); +	audit_log_format(ab, " code=0x%x", code);  	audit_log_end(ab);  }  | 
