diff options
Diffstat (limited to 'kernel/audit.c')
| -rw-r--r-- | kernel/audit.c | 516 | 
1 files changed, 350 insertions, 166 deletions
diff --git a/kernel/audit.c b/kernel/audit.c index 0b084fa44b1..21c7fa615bd 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -49,6 +49,8 @@  #include <linux/slab.h>  #include <linux/err.h>  #include <linux/kthread.h> +#include <linux/kernel.h> +#include <linux/syscalls.h>  #include <linux/audit.h> @@ -265,7 +267,6 @@ void audit_log_lost(const char *message)  }  static int audit_log_config_change(char *function_name, int new, int old, -				   kuid_t loginuid, u32 sessionid, u32 sid,  				   int allow_changes)  {  	struct audit_buffer *ab; @@ -274,29 +275,17 @@ static int audit_log_config_change(char *function_name, int new, int old,  	ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_CONFIG_CHANGE);  	if (unlikely(!ab))  		return rc; -	audit_log_format(ab, "%s=%d old=%d auid=%u ses=%u", function_name, new, -			 old, from_kuid(&init_user_ns, loginuid), sessionid); -	if (sid) { -		char *ctx = NULL; -		u32 len; - -		rc = security_secid_to_secctx(sid, &ctx, &len); -		if (rc) { -			audit_log_format(ab, " sid=%u", sid); -			allow_changes = 0; /* Something weird, deny request */ -		} else { -			audit_log_format(ab, " subj=%s", ctx); -			security_release_secctx(ctx, len); -		} -	} +	audit_log_format(ab, "%s=%d old=%d", function_name, new, old); +	audit_log_session_info(ab); +	rc = audit_log_task_context(ab); +	if (rc) +		allow_changes = 0; /* Something weird, deny request */  	audit_log_format(ab, " res=%d", allow_changes);  	audit_log_end(ab);  	return rc;  } -static int audit_do_config_change(char *function_name, int *to_change, -				  int new, kuid_t loginuid, u32 sessionid, -				  u32 sid) +static int audit_do_config_change(char *function_name, int *to_change, int new)  {  	int allow_changes, rc = 0, old = *to_change; @@ -307,8 +296,7 @@ static int audit_do_config_change(char *function_name, int *to_change,  		allow_changes = 1;  	if (audit_enabled != AUDIT_OFF) { -		rc = audit_log_config_change(function_name, new, old, loginuid, -					     sessionid, sid, allow_changes); +		rc = audit_log_config_change(function_name, new, old, allow_changes);  		if (rc)  			allow_changes = 0;  	} @@ -322,44 +310,37 @@ static int audit_do_config_change(char *function_name, int *to_change,  	return rc;  } -static int audit_set_rate_limit(int limit, kuid_t loginuid, u32 sessionid, -				u32 sid) +static int audit_set_rate_limit(int limit)  { -	return audit_do_config_change("audit_rate_limit", &audit_rate_limit, -				      limit, loginuid, sessionid, sid); +	return audit_do_config_change("audit_rate_limit", &audit_rate_limit, limit);  } -static int audit_set_backlog_limit(int limit, kuid_t loginuid, u32 sessionid, -				   u32 sid) +static int audit_set_backlog_limit(int limit)  { -	return audit_do_config_change("audit_backlog_limit", &audit_backlog_limit, -				      limit, loginuid, sessionid, sid); +	return audit_do_config_change("audit_backlog_limit", &audit_backlog_limit, limit);  } -static int audit_set_enabled(int state, kuid_t loginuid, u32 sessionid, u32 sid) +static int audit_set_enabled(int state)  {  	int rc;  	if (state < AUDIT_OFF || state > AUDIT_LOCKED)  		return -EINVAL; -	rc =  audit_do_config_change("audit_enabled", &audit_enabled, state, -				     loginuid, sessionid, sid); - +	rc =  audit_do_config_change("audit_enabled", &audit_enabled, state);  	if (!rc)  		audit_ever_enabled |= !!state;  	return rc;  } -static int audit_set_failure(int state, kuid_t loginuid, u32 sessionid, u32 sid) +static int audit_set_failure(int state)  {  	if (state != AUDIT_FAIL_SILENT  	    && state != AUDIT_FAIL_PRINTK  	    && state != AUDIT_FAIL_PANIC)  		return -EINVAL; -	return audit_do_config_change("audit_failure", &audit_failure, state, -				      loginuid, sessionid, sid); +	return audit_do_config_change("audit_failure", &audit_failure, state);  }  /* @@ -417,34 +398,53 @@ static void kauditd_send_skb(struct sk_buff *skb)  		consume_skb(skb);  } -static int kauditd_thread(void *dummy) +/* + * flush_hold_queue - empty the hold queue if auditd appears + * + * If auditd just started, drain the queue of messages already + * sent to syslog/printk.  Remember loss here is ok.  We already + * called audit_log_lost() if it didn't go out normally.  so the + * race between the skb_dequeue and the next check for audit_pid + * doesn't matter. + * + * If you ever find kauditd to be too slow we can get a perf win + * by doing our own locking and keeping better track if there + * are messages in this queue.  I don't see the need now, but + * in 5 years when I want to play with this again I'll see this + * note and still have no friggin idea what i'm thinking today. + */ +static void flush_hold_queue(void)  {  	struct sk_buff *skb; +	if (!audit_default || !audit_pid) +		return; + +	skb = skb_dequeue(&audit_skb_hold_queue); +	if (likely(!skb)) +		return; + +	while (skb && audit_pid) { +		kauditd_send_skb(skb); +		skb = skb_dequeue(&audit_skb_hold_queue); +	} + +	/* +	 * if auditd just disappeared but we +	 * dequeued an skb we need to drop ref +	 */ +	if (skb) +		consume_skb(skb); +} + +static int kauditd_thread(void *dummy) +{  	set_freezable();  	while (!kthread_should_stop()) { -		/* -		 * if auditd just started drain the queue of messages already -		 * sent to syslog/printk.  remember loss here is ok.  we already -		 * called audit_log_lost() if it didn't go out normally.  so the -		 * race between the skb_dequeue and the next check for audit_pid -		 * doesn't matter. -		 * -		 * if you ever find kauditd to be too slow we can get a perf win -		 * by doing our own locking and keeping better track if there -		 * are messages in this queue.  I don't see the need now, but -		 * in 5 years when I want to play with this again I'll see this -		 * note and still have no friggin idea what i'm thinking today. -		 */ -		if (audit_default && audit_pid) { -			skb = skb_dequeue(&audit_skb_hold_queue); -			if (unlikely(skb)) { -				while (skb && audit_pid) { -					kauditd_send_skb(skb); -					skb = skb_dequeue(&audit_skb_hold_queue); -				} -			} -		} +		struct sk_buff *skb; +		DECLARE_WAITQUEUE(wait, current); + +		flush_hold_queue();  		skb = skb_dequeue(&audit_skb_queue);  		wake_up(&audit_backlog_wait); @@ -453,19 +453,18 @@ static int kauditd_thread(void *dummy)  				kauditd_send_skb(skb);  			else  				audit_printk_skb(skb); -		} else { -			DECLARE_WAITQUEUE(wait, current); -			set_current_state(TASK_INTERRUPTIBLE); -			add_wait_queue(&kauditd_wait, &wait); - -			if (!skb_queue_len(&audit_skb_queue)) { -				try_to_freeze(); -				schedule(); -			} +			continue; +		} +		set_current_state(TASK_INTERRUPTIBLE); +		add_wait_queue(&kauditd_wait, &wait); -			__set_current_state(TASK_RUNNING); -			remove_wait_queue(&kauditd_wait, &wait); +		if (!skb_queue_len(&audit_skb_queue)) { +			try_to_freeze(); +			schedule();  		} + +		__set_current_state(TASK_RUNNING); +		remove_wait_queue(&kauditd_wait, &wait);  	}  	return 0;  } @@ -579,13 +578,14 @@ static int audit_netlink_ok(struct sk_buff *skb, u16 msg_type)  		return -EPERM;  	switch (msg_type) { -	case AUDIT_GET:  	case AUDIT_LIST: -	case AUDIT_LIST_RULES: -	case AUDIT_SET:  	case AUDIT_ADD: -	case AUDIT_ADD_RULE:  	case AUDIT_DEL: +		return -EOPNOTSUPP; +	case AUDIT_GET: +	case AUDIT_SET: +	case AUDIT_LIST_RULES: +	case AUDIT_ADD_RULE:  	case AUDIT_DEL_RULE:  	case AUDIT_SIGNAL_INFO:  	case AUDIT_TTY_GET: @@ -608,12 +608,10 @@ static int audit_netlink_ok(struct sk_buff *skb, u16 msg_type)  	return err;  } -static int audit_log_common_recv_msg(struct audit_buffer **ab, u16 msg_type, -				     kuid_t auid, u32 ses, u32 sid) +static int audit_log_common_recv_msg(struct audit_buffer **ab, u16 msg_type)  {  	int rc = 0; -	char *ctx = NULL; -	u32 len; +	uid_t uid = from_kuid(&init_user_ns, current_uid());  	if (!audit_enabled) {  		*ab = NULL; @@ -623,33 +621,21 @@ static int audit_log_common_recv_msg(struct audit_buffer **ab, u16 msg_type,  	*ab = audit_log_start(NULL, GFP_KERNEL, msg_type);  	if (unlikely(!*ab))  		return rc; -	audit_log_format(*ab, "pid=%d uid=%u auid=%u ses=%u", -			 task_tgid_vnr(current), -			 from_kuid(&init_user_ns, current_uid()), -			 from_kuid(&init_user_ns, auid), ses); -	if (sid) { -		rc = security_secid_to_secctx(sid, &ctx, &len); -		if (rc) -			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 uid=%u", task_tgid_vnr(current), uid); +	audit_log_session_info(*ab); +	audit_log_task_context(*ab);  	return rc;  }  static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)  { -	u32			seq, sid; +	u32			seq;  	void			*data;  	struct audit_status	*status_get, status_set;  	int			err;  	struct audit_buffer	*ab;  	u16			msg_type = nlh->nlmsg_type; -	kuid_t			loginuid; /* loginuid of sender */ -	u32			sessionid;  	struct audit_sig_info   *sig_data;  	char			*ctx = NULL;  	u32			len; @@ -668,9 +654,6 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)  			return err;  		}  	} -	loginuid = audit_get_loginuid(current); -	sessionid = audit_get_sessionid(current); -	security_task_getsecid(current, &sid);  	seq  = nlh->nlmsg_seq;  	data = nlmsg_data(nlh); @@ -691,14 +674,12 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)  			return -EINVAL;  		status_get   = (struct audit_status *)data;  		if (status_get->mask & AUDIT_STATUS_ENABLED) { -			err = audit_set_enabled(status_get->enabled, -						loginuid, sessionid, sid); +			err = audit_set_enabled(status_get->enabled);  			if (err < 0)  				return err;  		}  		if (status_get->mask & AUDIT_STATUS_FAILURE) { -			err = audit_set_failure(status_get->failure, -						loginuid, sessionid, sid); +			err = audit_set_failure(status_get->failure);  			if (err < 0)  				return err;  		} @@ -706,22 +687,17 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)  			int new_pid = status_get->pid;  			if (audit_enabled != AUDIT_OFF) -				audit_log_config_change("audit_pid", new_pid, -							audit_pid, loginuid, -							sessionid, sid, 1); - +				audit_log_config_change("audit_pid", new_pid, audit_pid, 1);  			audit_pid = new_pid;  			audit_nlk_portid = NETLINK_CB(skb).portid;  		}  		if (status_get->mask & AUDIT_STATUS_RATE_LIMIT) { -			err = audit_set_rate_limit(status_get->rate_limit, -						   loginuid, sessionid, sid); +			err = audit_set_rate_limit(status_get->rate_limit);  			if (err < 0)  				return err;  		}  		if (status_get->mask & AUDIT_STATUS_BACKLOG_LIMIT) -			err = audit_set_backlog_limit(status_get->backlog_limit, -						      loginuid, sessionid, sid); +			err = audit_set_backlog_limit(status_get->backlog_limit);  		break;  	case AUDIT_USER:  	case AUDIT_FIRST_USER_MSG ... AUDIT_LAST_USER_MSG: @@ -729,25 +705,22 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)  		if (!audit_enabled && msg_type != AUDIT_USER_AVC)  			return 0; -		err = audit_filter_user(); +		err = audit_filter_user(msg_type);  		if (err == 1) {  			err = 0;  			if (msg_type == AUDIT_USER_TTY) { -				err = tty_audit_push_task(current, loginuid, -							     sessionid); +				err = tty_audit_push_current();  				if (err)  					break;  			} -			audit_log_common_recv_msg(&ab, msg_type, -						  loginuid, sessionid, sid); - +			audit_log_common_recv_msg(&ab, msg_type);  			if (msg_type != AUDIT_USER_TTY)  				audit_log_format(ab, " msg='%.1024s'",  						 (char *)data);  			else {  				int size; -				audit_log_format(ab, " msg="); +				audit_log_format(ab, " data=");  				size = nlmsg_len(nlh);  				if (size > 0 &&  				    ((unsigned char *)data)[size - 1] == '\0') @@ -758,50 +731,24 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)  			audit_log_end(ab);  		}  		break; -	case AUDIT_ADD: -	case AUDIT_DEL: -		if (nlmsg_len(nlh) < sizeof(struct audit_rule)) -			return -EINVAL; -		if (audit_enabled == AUDIT_LOCKED) { -			audit_log_common_recv_msg(&ab, AUDIT_CONFIG_CHANGE, -						  loginuid, sessionid, sid); - -			audit_log_format(ab, " audit_enabled=%d res=0", -					 audit_enabled); -			audit_log_end(ab); -			return -EPERM; -		} -		/* fallthrough */ -	case AUDIT_LIST: -		err = audit_receive_filter(msg_type, NETLINK_CB(skb).portid, -					   seq, data, nlmsg_len(nlh), -					   loginuid, sessionid, sid); -		break;  	case AUDIT_ADD_RULE:  	case AUDIT_DEL_RULE:  		if (nlmsg_len(nlh) < sizeof(struct audit_rule_data))  			return -EINVAL;  		if (audit_enabled == AUDIT_LOCKED) { -			audit_log_common_recv_msg(&ab, AUDIT_CONFIG_CHANGE, -						  loginuid, sessionid, sid); - -			audit_log_format(ab, " audit_enabled=%d res=0", -					 audit_enabled); +			audit_log_common_recv_msg(&ab, AUDIT_CONFIG_CHANGE); +			audit_log_format(ab, " audit_enabled=%d res=0", audit_enabled);  			audit_log_end(ab);  			return -EPERM;  		}  		/* fallthrough */  	case AUDIT_LIST_RULES:  		err = audit_receive_filter(msg_type, NETLINK_CB(skb).portid, -					   seq, data, nlmsg_len(nlh), -					   loginuid, sessionid, sid); +					   seq, data, nlmsg_len(nlh));  		break;  	case AUDIT_TRIM:  		audit_trim_trees(); - -		audit_log_common_recv_msg(&ab, AUDIT_CONFIG_CHANGE, -					  loginuid, sessionid, sid); - +		audit_log_common_recv_msg(&ab, AUDIT_CONFIG_CHANGE);  		audit_log_format(ab, " op=trim res=1");  		audit_log_end(ab);  		break; @@ -831,8 +778,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)  		/* OK, here comes... */  		err = audit_tag_tree(old, new); -		audit_log_common_recv_msg(&ab, AUDIT_CONFIG_CHANGE, -					  loginuid, sessionid, sid); +		audit_log_common_recv_msg(&ab, AUDIT_CONFIG_CHANGE);  		audit_log_format(ab, " op=make_equiv old=");  		audit_log_untrustedstring(ab, old); @@ -871,27 +817,30 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)  		struct audit_tty_status s;  		struct task_struct *tsk = current; -		spin_lock_irq(&tsk->sighand->siglock); +		spin_lock(&tsk->sighand->siglock);  		s.enabled = tsk->signal->audit_tty != 0; -		spin_unlock_irq(&tsk->sighand->siglock); +		s.log_passwd = tsk->signal->audit_tty_log_passwd; +		spin_unlock(&tsk->sighand->siglock);  		audit_send_reply(NETLINK_CB(skb).portid, seq,  				 AUDIT_TTY_GET, 0, 0, &s, sizeof(s));  		break;  	}  	case AUDIT_TTY_SET: { -		struct audit_tty_status *s; +		struct audit_tty_status s;  		struct task_struct *tsk = current; -		if (nlh->nlmsg_len < sizeof(struct audit_tty_status)) -			return -EINVAL; -		s = data; -		if (s->enabled != 0 && s->enabled != 1) +		memset(&s, 0, sizeof(s)); +		/* guard against past and future API changes */ +		memcpy(&s, data, min(sizeof(s), (size_t)nlh->nlmsg_len)); +		if ((s.enabled != 0 && s.enabled != 1) || +		    (s.log_passwd != 0 && s.log_passwd != 1))  			return -EINVAL; -		spin_lock_irq(&tsk->sighand->siglock); -		tsk->signal->audit_tty = s->enabled != 0; -		spin_unlock_irq(&tsk->sighand->siglock); +		spin_lock(&tsk->sighand->siglock); +		tsk->signal->audit_tty = s.enabled; +		tsk->signal->audit_tty_log_passwd = s.log_passwd; +		spin_unlock(&tsk->sighand->siglock);  		break;  	}  	default: @@ -1434,6 +1383,14 @@ void audit_log_d_path(struct audit_buffer *ab, const char *prefix,  	kfree(pathname);  } +void audit_log_session_info(struct audit_buffer *ab) +{ +	u32 sessionid = audit_get_sessionid(current); +	uid_t auid = from_kuid(&init_user_ns, audit_get_loginuid(current)); + +	audit_log_format(ab, " auid=%u ses=%u\n", auid, sessionid); +} +  void audit_log_key(struct audit_buffer *ab, char *key)  {  	audit_log_format(ab, " key="); @@ -1443,6 +1400,224 @@ void audit_log_key(struct audit_buffer *ab, char *key)  		audit_log_format(ab, "(null)");  } +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]); +	} +} + +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 inline int audit_copy_fcaps(struct audit_names *name, +				   const struct dentry *dentry) +{ +	struct cpu_vfs_cap_data caps; +	int rc; + +	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. */ +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_log_name - produce AUDIT_PATH record from struct audit_names + * @context: audit_context for the task + * @n: audit_names structure with reportable details + * @path: optional path to report instead of audit_names->name + * @record_num: record number to report when handling a list of names + * @call_panic: optional pointer to int that will be updated if secid fails + */ +void audit_log_name(struct audit_context *context, struct audit_names *n, +		    struct path *path, int record_num, int *call_panic) +{ +	struct audit_buffer *ab; +	ab = audit_log_start(context, GFP_KERNEL, AUDIT_PATH); +	if (!ab) +		return; + +	audit_log_format(ab, "item=%d", record_num); + +	if (path) +		audit_log_d_path(ab, " name=", path); +	else 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->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->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=%#ho" +				 " ouid=%u ogid=%u rdev=%02x:%02x", +				 n->ino, +				 MAJOR(n->dev), +				 MINOR(n->dev), +				 n->mode, +				 from_kuid(&init_user_ns, n->uid), +				 from_kgid(&init_user_ns, 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); +			if (call_panic) +				*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); +} + +int 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 0; + +	error = security_secid_to_secctx(sid, &ctx, &len); +	if (error) { +		if (error != -EINVAL) +			goto error_path; +		return 0; +	} + +	audit_log_format(ab, " subj=%s", ctx); +	security_release_secctx(ctx, len); +	return 0; + +error_path: +	audit_panic("error in audit_log_task_context"); +	return error; +} +EXPORT_SYMBOL(audit_log_task_context); + +void audit_log_task_info(struct audit_buffer *ab, struct task_struct *tsk) +{ +	const struct cred *cred; +	char name[sizeof(tsk->comm)]; +	struct mm_struct *mm = tsk->mm; +	char *tty; + +	if (!ab) +		return; + +	/* tsk == current */ +	cred = current_cred(); + +	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, +			 " ppid=%ld pid=%d auid=%u uid=%u gid=%u" +			 " euid=%u suid=%u fsuid=%u" +			 " egid=%u sgid=%u fsgid=%u ses=%u tty=%s", +			 sys_getppid(), +			 tsk->pid, +			 from_kuid(&init_user_ns, audit_get_loginuid(tsk)), +			 from_kuid(&init_user_ns, cred->uid), +			 from_kgid(&init_user_ns, cred->gid), +			 from_kuid(&init_user_ns, cred->euid), +			 from_kuid(&init_user_ns, cred->suid), +			 from_kuid(&init_user_ns, cred->fsuid), +			 from_kgid(&init_user_ns, cred->egid), +			 from_kgid(&init_user_ns, cred->sgid), +			 from_kgid(&init_user_ns, cred->fsgid), +			 audit_get_sessionid(tsk), tty); + +	get_task_comm(name, tsk); +	audit_log_format(ab, " comm="); +	audit_log_untrustedstring(ab, name); + +	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); +	} +	audit_log_task_context(ab); +} +EXPORT_SYMBOL(audit_log_task_info); +  /**   * audit_log_link_denied - report a link restriction denial   * @operation: specific link opreation @@ -1451,19 +1626,28 @@ void audit_log_key(struct audit_buffer *ab, char *key)  void audit_log_link_denied(const char *operation, struct path *link)  {  	struct audit_buffer *ab; +	struct audit_names *name; + +	name = kzalloc(sizeof(*name), GFP_NOFS); +	if (!name) +		return; +	/* Generate AUDIT_ANOM_LINK with subject, operation, outcome. */  	ab = audit_log_start(current->audit_context, GFP_KERNEL,  			     AUDIT_ANOM_LINK);  	if (!ab) -		return; -	audit_log_format(ab, "op=%s action=denied", operation); -	audit_log_format(ab, " pid=%d comm=", current->pid); -	audit_log_untrustedstring(ab, current->comm); -	audit_log_d_path(ab, " path=", link); -	audit_log_format(ab, " dev="); -	audit_log_untrustedstring(ab, link->dentry->d_inode->i_sb->s_id); -	audit_log_format(ab, " ino=%lu", link->dentry->d_inode->i_ino); +		goto out; +	audit_log_format(ab, "op=%s", operation); +	audit_log_task_info(ab, current); +	audit_log_format(ab, " res=0");  	audit_log_end(ab); + +	/* Generate AUDIT_PATH record with object. */ +	name->type = AUDIT_TYPE_NORMAL; +	audit_copy_inode(name, link->dentry, link->dentry->d_inode); +	audit_log_name(current->audit_context, name, link, 0, NULL); +out: +	kfree(name);  }  /**  |