diff options
Diffstat (limited to 'kernel/audit.c')
| -rw-r--r-- | kernel/audit.c | 47 | 
1 files changed, 31 insertions, 16 deletions
| diff --git a/kernel/audit.c b/kernel/audit.c index 121d37e700a6..e4bbe2c70c26 100644 --- a/kernel/audit.c +++ b/kernel/audit.c @@ -718,7 +718,7 @@ static int kauditd_send_queue(struct sock *sk, u32 portid,  {  	int rc = 0;  	struct sk_buff *skb; -	static unsigned int failed = 0; +	unsigned int failed = 0;  	/* NOTE: kauditd_thread takes care of all our locking, we just use  	 *       the netlink info passed to us (e.g. sk and portid) */ @@ -735,32 +735,30 @@ static int kauditd_send_queue(struct sock *sk, u32 portid,  			continue;  		} +retry:  		/* grab an extra skb reference in case of error */  		skb_get(skb);  		rc = netlink_unicast(sk, skb, portid, 0);  		if (rc < 0) { -			/* fatal failure for our queue flush attempt? */ +			/* send failed - try a few times unless fatal error */  			if (++failed >= retry_limit ||  			    rc == -ECONNREFUSED || rc == -EPERM) { -				/* yes - error processing for the queue */  				sk = NULL;  				if (err_hook)  					(*err_hook)(skb); -				if (!skb_hook) -					goto out; -				/* keep processing with the skb_hook */ +				if (rc == -EAGAIN) +					rc = 0; +				/* continue to drain the queue */  				continue;  			} else -				/* no - requeue to preserve ordering */ -				skb_queue_head(queue, skb); +				goto retry;  		} else { -			/* it worked - drop the extra reference and continue */ +			/* skb sent - drop the extra reference and continue */  			consume_skb(skb);  			failed = 0;  		}  	} -out:  	return (rc >= 0 ? 0 : rc);  } @@ -1446,7 +1444,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)  			if (err)  				return err;  		} -		sig_data = kmalloc(sizeof(*sig_data) + len, GFP_KERNEL); +		sig_data = kmalloc(struct_size(sig_data, ctx, len), GFP_KERNEL);  		if (!sig_data) {  			if (audit_sig_sid)  				security_release_secctx(ctx, len); @@ -1459,7 +1457,7 @@ static int audit_receive_msg(struct sk_buff *skb, struct nlmsghdr *nlh)  			security_release_secctx(ctx, len);  		}  		audit_send_reply(skb, seq, AUDIT_SIGNAL_INFO, 0, 0, -				 sig_data, sizeof(*sig_data) + len); +				 sig_data, struct_size(sig_data, ctx, len));  		kfree(sig_data);  		break;  	case AUDIT_TTY_GET: { @@ -1542,6 +1540,20 @@ static void audit_receive(struct sk_buff  *skb)  		nlh = nlmsg_next(nlh, &len);  	}  	audit_ctl_unlock(); + +	/* can't block with the ctrl lock, so penalize the sender now */ +	if (audit_backlog_limit && +	    (skb_queue_len(&audit_queue) > audit_backlog_limit)) { +		DECLARE_WAITQUEUE(wait, current); + +		/* wake kauditd to try and flush the queue */ +		wake_up_interruptible(&kauditd_wait); + +		add_wait_queue_exclusive(&audit_backlog_wait, &wait); +		set_current_state(TASK_UNINTERRUPTIBLE); +		schedule_timeout(audit_backlog_wait_time); +		remove_wait_queue(&audit_backlog_wait, &wait); +	}  }  /* Log information about who is connecting to the audit multicast socket */ @@ -1609,7 +1621,8 @@ static int __net_init audit_net_init(struct net *net)  		audit_panic("cannot initialize netlink socket in namespace");  		return -ENOMEM;  	} -	aunet->sk->sk_sndtimeo = MAX_SCHEDULE_TIMEOUT; +	/* limit the timeout in case auditd is blocked/stopped */ +	aunet->sk->sk_sndtimeo = HZ / 10;  	return 0;  } @@ -1825,7 +1838,9 @@ struct audit_buffer *audit_log_start(struct audit_context *ctx, gfp_t gfp_mask,  	 *    task_tgid_vnr() since auditd_pid is set in audit_receive_msg()  	 *    using a PID anchored in the caller's namespace  	 * 2. generator holding the audit_cmd_mutex - we don't want to block -	 *    while holding the mutex */ +	 *    while holding the mutex, although we do penalize the sender +	 *    later in audit_receive() when it is safe to block +	 */  	if (!(auditd_test_task(current) || audit_ctl_owner_current())) {  		long stime = audit_backlog_wait_time; @@ -2132,7 +2147,7 @@ int audit_log_task_context(struct audit_buffer *ab)  	int error;  	u32 sid; -	security_task_getsecid_subj(current, &sid); +	security_current_getsecid_subj(&sid);  	if (!sid)  		return 0; @@ -2353,7 +2368,7 @@ int audit_signal_info(int sig, struct task_struct *t)  			audit_sig_uid = auid;  		else  			audit_sig_uid = uid; -		security_task_getsecid_subj(current, &audit_sig_sid); +		security_current_getsecid_subj(&audit_sig_sid);  	}  	return audit_signal_info_syscall(t); |