eb50e3a
From 43761473c254b45883a64441dd0bc85a42f3645c Mon Sep 17 00:00:00 2001
eb50e3a
From: Paul Moore <paul@paul-moore.com>
eb50e3a
Date: Tue, 19 Jul 2016 17:42:57 -0400
eb50e3a
Subject: [PATCH] audit: fix a double fetch in audit_log_single_execve_arg()
eb50e3a
eb50e3a
There is a double fetch problem in audit_log_single_execve_arg()
eb50e3a
where we first check the execve(2) argumnets for any "bad" characters
eb50e3a
which would require hex encoding and then re-fetch the arguments for
eb50e3a
logging in the audit record[1].  Of course this leaves a window of
eb50e3a
opportunity for an unsavory application to munge with the data.
eb50e3a
eb50e3a
This patch reworks things by only fetching the argument data once[2]
eb50e3a
into a buffer where it is scanned and logged into the audit
eb50e3a
records(s).  In addition to fixing the double fetch, this patch
eb50e3a
improves on the original code in a few other ways: better handling
eb50e3a
of large arguments which require encoding, stricter record length
eb50e3a
checking, and some performance improvements (completely unverified,
eb50e3a
but we got rid of some strlen() calls, that's got to be a good
eb50e3a
thing).
eb50e3a
eb50e3a
As part of the development of this patch, I've also created a basic
eb50e3a
regression test for the audit-testsuite, the test can be tracked on
eb50e3a
GitHub at the following link:
eb50e3a
eb50e3a
 * https://github.com/linux-audit/audit-testsuite/issues/25
eb50e3a
eb50e3a
[1] If you pay careful attention, there is actually a triple fetch
eb50e3a
problem due to a strnlen_user() call at the top of the function.
eb50e3a
eb50e3a
[2] This is a tiny white lie, we do make a call to strnlen_user()
eb50e3a
prior to fetching the argument data.  I don't like it, but due to the
eb50e3a
way the audit record is structured we really have no choice unless we
eb50e3a
copy the entire argument at once (which would require a rather
eb50e3a
wasteful allocation).  The good news is that with this patch the
eb50e3a
kernel no longer relies on this strnlen_user() value for anything
eb50e3a
beyond recording it in the log, we also update it with a trustworthy
eb50e3a
value whenever possible.
eb50e3a
eb50e3a
Reported-by: Pengfei Wang <wpengfeinudt@gmail.com>
eb50e3a
Cc: <stable@vger.kernel.org>
eb50e3a
Signed-off-by: Paul Moore <paul@paul-moore.com>
eb50e3a
---
eb50e3a
 kernel/auditsc.c | 332 +++++++++++++++++++++++++++----------------------------
eb50e3a
 1 file changed, 164 insertions(+), 168 deletions(-)
eb50e3a
eb50e3a
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
eb50e3a
index aa3feec..c65af21 100644
eb50e3a
--- a/kernel/auditsc.c
eb50e3a
+++ b/kernel/auditsc.c
eb50e3a
@@ -73,6 +73,7 @@
eb50e3a
 #include <linux/compat.h>
eb50e3a
 #include <linux/ctype.h>
eb50e3a
 #include <linux/string.h>
eb50e3a
+#include <linux/uaccess.h>
eb50e3a
 #include <uapi/linux/limits.h>
eb50e3a
 
eb50e3a
 #include "audit.h"
eb50e3a
@@ -82,7 +83,8 @@
eb50e3a
 #define AUDITSC_SUCCESS 1
eb50e3a
 #define AUDITSC_FAILURE 2
eb50e3a
 
eb50e3a
-/* no execve audit message should be longer than this (userspace limits) */
eb50e3a
+/* no execve audit message should be longer than this (userspace limits),
eb50e3a
+ * see the note near the top of audit_log_execve_info() about this value */
eb50e3a
 #define MAX_EXECVE_AUDIT_LEN 7500
eb50e3a
 
eb50e3a
 /* max length to print of cmdline/proctitle value during audit */
eb50e3a
@@ -992,184 +994,178 @@ static int audit_log_pid_context(struct audit_context *context, pid_t pid,
eb50e3a
 	return rc;
eb50e3a
 }
eb50e3a
 
eb50e3a
-/*
eb50e3a
- * to_send and len_sent accounting are very loose estimates.  We aren't
eb50e3a
- * really worried about a hard cap to MAX_EXECVE_AUDIT_LEN so much as being
eb50e3a
- * within about 500 bytes (next page boundary)
eb50e3a
- *
eb50e3a
- * why snprintf?  an int is up to 12 digits long.  if we just assumed when
eb50e3a
- * logging that a[%d]= was going to be 16 characters long we would be wasting
eb50e3a
- * space in every audit message.  In one 7500 byte message we can log up to
eb50e3a
- * about 1000 min size arguments.  That comes down to about 50% waste of space
eb50e3a
- * if we didn't do the snprintf to find out how long arg_num_len was.
eb50e3a
- */
eb50e3a
-static int audit_log_single_execve_arg(struct audit_context *context,
eb50e3a
-					struct audit_buffer **ab,
eb50e3a
-					int arg_num,
eb50e3a
-					size_t *len_sent,
eb50e3a
-					const char __user *p,
eb50e3a
-					char *buf)
eb50e3a
+static void audit_log_execve_info(struct audit_context *context,
eb50e3a
+				  struct audit_buffer **ab)
eb50e3a
 {
eb50e3a
-	char arg_num_len_buf[12];
eb50e3a
-	const char __user *tmp_p = p;
eb50e3a
-	/* how many digits are in arg_num? 5 is the length of ' a=""' */
eb50e3a
-	size_t arg_num_len = snprintf(arg_num_len_buf, 12, "%d", arg_num) + 5;
eb50e3a
-	size_t len, len_left, to_send;
eb50e3a
-	size_t max_execve_audit_len = MAX_EXECVE_AUDIT_LEN;
eb50e3a
-	unsigned int i, has_cntl = 0, too_long = 0;
eb50e3a
-	int ret;
eb50e3a
-
eb50e3a
-	/* strnlen_user includes the null we don't want to send */
eb50e3a
-	len_left = len = strnlen_user(p, MAX_ARG_STRLEN) - 1;
eb50e3a
-
eb50e3a
-	/*
eb50e3a
-	 * We just created this mm, if we can't find the strings
eb50e3a
-	 * we just copied into it something is _very_ wrong. Similar
eb50e3a
-	 * for strings that are too long, we should not have created
eb50e3a
-	 * any.
eb50e3a
-	 */
eb50e3a
-	if (WARN_ON_ONCE(len < 0 || len > MAX_ARG_STRLEN - 1)) {
eb50e3a
-		send_sig(SIGKILL, current, 0);
eb50e3a
-		return -1;
eb50e3a
+	long len_max;
eb50e3a
+	long len_rem;
eb50e3a
+	long len_full;
eb50e3a
+	long len_buf;
eb50e3a
+	long len_abuf;
eb50e3a
+	long len_tmp;
eb50e3a
+	bool require_data;
eb50e3a
+	bool encode;
eb50e3a
+	unsigned int iter;
eb50e3a
+	unsigned int arg;
eb50e3a
+	char *buf_head;
eb50e3a
+	char *buf;
eb50e3a
+	const char __user *p = (const char __user *)current->mm->arg_start;
eb50e3a
+
eb50e3a
+	/* NOTE: this buffer needs to be large enough to hold all the non-arg
eb50e3a
+	 *       data we put in the audit record for this argument (see the
eb50e3a
+	 *       code below) ... at this point in time 96 is plenty */
eb50e3a
+	char abuf[96];
eb50e3a
+
eb50e3a
+	/* NOTE: we set MAX_EXECVE_AUDIT_LEN to a rather arbitrary limit, the
eb50e3a
+	 *       current value of 7500 is not as important as the fact that it
eb50e3a
+	 *       is less than 8k, a setting of 7500 gives us plenty of wiggle
eb50e3a
+	 *       room if we go over a little bit in the logging below */
eb50e3a
+	WARN_ON_ONCE(MAX_EXECVE_AUDIT_LEN > 7500);
eb50e3a
+	len_max = MAX_EXECVE_AUDIT_LEN;
eb50e3a
+
eb50e3a
+	/* scratch buffer to hold the userspace args */
eb50e3a
+	buf_head = kmalloc(MAX_EXECVE_AUDIT_LEN + 1, GFP_KERNEL);
eb50e3a
+	if (!buf_head) {
eb50e3a
+		audit_panic("out of memory for argv string");
eb50e3a
+		return;
eb50e3a
 	}
eb50e3a
+	buf = buf_head;
eb50e3a
 
eb50e3a
-	/* walk the whole argument looking for non-ascii chars */
eb50e3a
+	audit_log_format(*ab, "argc=%d", context->execve.argc);
eb50e3a
+
eb50e3a
+	len_rem = len_max;
eb50e3a
+	len_buf = 0;
eb50e3a
+	len_full = 0;
eb50e3a
+	require_data = true;
eb50e3a
+	encode = false;
eb50e3a
+	iter = 0;
eb50e3a
+	arg = 0;
eb50e3a
 	do {
eb50e3a
-		if (len_left > MAX_EXECVE_AUDIT_LEN)
eb50e3a
-			to_send = MAX_EXECVE_AUDIT_LEN;
eb50e3a
-		else
eb50e3a
-			to_send = len_left;
eb50e3a
-		ret = copy_from_user(buf, tmp_p, to_send);
eb50e3a
-		/*
eb50e3a
-		 * There is no reason for this copy to be short. We just
eb50e3a
-		 * copied them here, and the mm hasn't been exposed to user-
eb50e3a
-		 * space yet.
eb50e3a
-		 */
eb50e3a
-		if (ret) {
eb50e3a
-			WARN_ON(1);
eb50e3a
-			send_sig(SIGKILL, current, 0);
eb50e3a
-			return -1;
eb50e3a
-		}
eb50e3a
-		buf[to_send] = '\0';
eb50e3a
-		has_cntl = audit_string_contains_control(buf, to_send);
eb50e3a
-		if (has_cntl) {
eb50e3a
-			/*
eb50e3a
-			 * hex messages get logged as 2 bytes, so we can only
eb50e3a
-			 * send half as much in each message
eb50e3a
-			 */
eb50e3a
-			max_execve_audit_len = MAX_EXECVE_AUDIT_LEN / 2;
eb50e3a
-			break;
eb50e3a
-		}
eb50e3a
-		len_left -= to_send;
eb50e3a
-		tmp_p += to_send;
eb50e3a
-	} while (len_left > 0);
eb50e3a
-
eb50e3a
-	len_left = len;
eb50e3a
-
eb50e3a
-	if (len > max_execve_audit_len)
eb50e3a
-		too_long = 1;
eb50e3a
-
eb50e3a
-	/* rewalk the argument actually logging the message */
eb50e3a
-	for (i = 0; len_left > 0; i++) {
eb50e3a
-		int room_left;
eb50e3a
-
eb50e3a
-		if (len_left > max_execve_audit_len)
eb50e3a
-			to_send = max_execve_audit_len;
eb50e3a
-		else
eb50e3a
-			to_send = len_left;
eb50e3a
-
eb50e3a
-		/* do we have space left to send this argument in this ab? */
eb50e3a
-		room_left = MAX_EXECVE_AUDIT_LEN - arg_num_len - *len_sent;
eb50e3a
-		if (has_cntl)
eb50e3a
-			room_left -= (to_send * 2);
eb50e3a
-		else
eb50e3a
-			room_left -= to_send;
eb50e3a
-		if (room_left < 0) {
eb50e3a
-			*len_sent = 0;
eb50e3a
-			audit_log_end(*ab);
eb50e3a
-			*ab = audit_log_start(context, GFP_KERNEL, AUDIT_EXECVE);
eb50e3a
-			if (!*ab)
eb50e3a
-				return 0;
eb50e3a
-		}
eb50e3a
+		/* NOTE: we don't ever want to trust this value for anything
eb50e3a
+		 *       serious, but the audit record format insists we
eb50e3a
+		 *       provide an argument length for really long arguments,
eb50e3a
+		 *       e.g. > MAX_EXECVE_AUDIT_LEN, so we have no choice but
eb50e3a
+		 *       to use strncpy_from_user() to obtain this value for
eb50e3a
+		 *       recording in the log, although we don't use it
eb50e3a
+		 *       anywhere here to avoid a double-fetch problem */
eb50e3a
+		if (len_full == 0)
eb50e3a
+			len_full = strnlen_user(p, MAX_ARG_STRLEN) - 1;
eb50e3a
+
eb50e3a
+		/* read more data from userspace */
eb50e3a
+		if (require_data) {
eb50e3a
+			/* can we make more room in the buffer? */
eb50e3a
+			if (buf != buf_head) {
eb50e3a
+				memmove(buf_head, buf, len_buf);
eb50e3a
+				buf = buf_head;
eb50e3a
+			}
eb50e3a
+
eb50e3a
+			/* fetch as much as we can of the argument */
eb50e3a
+			len_tmp = strncpy_from_user(&buf_head[len_buf], p,
eb50e3a
+						    len_max - len_buf);
eb50e3a
+			if (len_tmp == -EFAULT) {
eb50e3a
+				/* unable to copy from userspace */
eb50e3a
+				send_sig(SIGKILL, current, 0);
eb50e3a
+				goto out;
eb50e3a
+			} else if (len_tmp == (len_max - len_buf)) {
eb50e3a
+				/* buffer is not large enough */
eb50e3a
+				require_data = true;
eb50e3a
+				/* NOTE: if we are going to span multiple
eb50e3a
+				 *       buffers force the encoding so we stand
eb50e3a
+				 *       a chance at a sane len_full value and
eb50e3a
+				 *       consistent record encoding */
eb50e3a
+				encode = true;
eb50e3a
+				len_full = len_full * 2;
eb50e3a
+				p += len_tmp;
eb50e3a
+			} else {
eb50e3a
+				require_data = false;
eb50e3a
+				if (!encode)
eb50e3a
+					encode = audit_string_contains_control(
eb50e3a
+								buf, len_tmp);
eb50e3a
+				/* try to use a trusted value for len_full */
eb50e3a
+				if (len_full < len_max)
eb50e3a
+					len_full = (encode ?
eb50e3a
+						    len_tmp * 2 : len_tmp);
eb50e3a
+				p += len_tmp + 1;
eb50e3a
+			}
eb50e3a
+			len_buf += len_tmp;
eb50e3a
+			buf_head[len_buf] = '\0';
eb50e3a
 
eb50e3a
-		/*
eb50e3a
-		 * first record needs to say how long the original string was
eb50e3a
-		 * so we can be sure nothing was lost.
eb50e3a
-		 */
eb50e3a
-		if ((i == 0) && (too_long))
eb50e3a
-			audit_log_format(*ab, " a%d_len=%zu", arg_num,
eb50e3a
-					 has_cntl ? 2*len : len);
eb50e3a
-
eb50e3a
-		/*
eb50e3a
-		 * normally arguments are small enough to fit and we already
eb50e3a
-		 * filled buf above when we checked for control characters
eb50e3a
-		 * so don't bother with another copy_from_user
eb50e3a
-		 */
eb50e3a
-		if (len >= max_execve_audit_len)
eb50e3a
-			ret = copy_from_user(buf, p, to_send);
eb50e3a
-		else
eb50e3a
-			ret = 0;
eb50e3a
-		if (ret) {
eb50e3a
-			WARN_ON(1);
eb50e3a
-			send_sig(SIGKILL, current, 0);
eb50e3a
-			return -1;
eb50e3a
+			/* length of the buffer in the audit record? */
eb50e3a
+			len_abuf = (encode ? len_buf * 2 : len_buf + 2);
eb50e3a
 		}
eb50e3a
-		buf[to_send] = '\0';
eb50e3a
-
eb50e3a
-		/* actually log it */
eb50e3a
-		audit_log_format(*ab, " a%d", arg_num);
eb50e3a
-		if (too_long)
eb50e3a
-			audit_log_format(*ab, "[%d]", i);
eb50e3a
-		audit_log_format(*ab, "=");
eb50e3a
-		if (has_cntl)
eb50e3a
-			audit_log_n_hex(*ab, buf, to_send);
eb50e3a
-		else
eb50e3a
-			audit_log_string(*ab, buf);
eb50e3a
-
eb50e3a
-		p += to_send;
eb50e3a
-		len_left -= to_send;
eb50e3a
-		*len_sent += arg_num_len;
eb50e3a
-		if (has_cntl)
eb50e3a
-			*len_sent += to_send * 2;
eb50e3a
-		else
eb50e3a
-			*len_sent += to_send;
eb50e3a
-	}
eb50e3a
-	/* include the null we didn't log */
eb50e3a
-	return len + 1;
eb50e3a
-}
eb50e3a
 
eb50e3a
-static void audit_log_execve_info(struct audit_context *context,
eb50e3a
-				  struct audit_buffer **ab)
eb50e3a
-{
eb50e3a
-	int i, len;
eb50e3a
-	size_t len_sent = 0;
eb50e3a
-	const char __user *p;
eb50e3a
-	char *buf;
eb50e3a
+		/* write as much as we can to the audit log */
eb50e3a
+		if (len_buf > 0) {
eb50e3a
+			/* NOTE: some magic numbers here - basically if we
eb50e3a
+			 *       can't fit a reasonable amount of data into the
eb50e3a
+			 *       existing audit buffer, flush it and start with
eb50e3a
+			 *       a new buffer */
eb50e3a
+			if ((sizeof(abuf) + 8) > len_rem) {
eb50e3a
+				len_rem = len_max;
eb50e3a
+				audit_log_end(*ab);
eb50e3a
+				*ab = audit_log_start(context,
eb50e3a
+						      GFP_KERNEL, AUDIT_EXECVE);
eb50e3a
+				if (!*ab)
eb50e3a
+					goto out;
eb50e3a
+			}
eb50e3a
 
eb50e3a
-	p = (const char __user *)current->mm->arg_start;
eb50e3a
+			/* create the non-arg portion of the arg record */
eb50e3a
+			len_tmp = 0;
eb50e3a
+			if (require_data || (iter > 0) ||
eb50e3a
+			    ((len_abuf + sizeof(abuf)) > len_rem)) {
eb50e3a
+				if (iter == 0) {
eb50e3a
+					len_tmp += snprintf(&abuf[len_tmp],
eb50e3a
+							sizeof(abuf) - len_tmp,
eb50e3a
+							" a%d_len=%lu",
eb50e3a
+							arg, len_full);
eb50e3a
+				}
eb50e3a
+				len_tmp += snprintf(&abuf[len_tmp],
eb50e3a
+						    sizeof(abuf) - len_tmp,
eb50e3a
+						    " a%d[%d]=", arg, iter++);
eb50e3a
+			} else
eb50e3a
+				len_tmp += snprintf(&abuf[len_tmp],
eb50e3a
+						    sizeof(abuf) - len_tmp,
eb50e3a
+						    " a%d=", arg);
eb50e3a
+			WARN_ON(len_tmp >= sizeof(abuf));
eb50e3a
+			abuf[sizeof(abuf) - 1] = '\0';
eb50e3a
+
eb50e3a
+			/* log the arg in the audit record */
eb50e3a
+			audit_log_format(*ab, "%s", abuf);
eb50e3a
+			len_rem -= len_tmp;
eb50e3a
+			len_tmp = len_buf;
eb50e3a
+			if (encode) {
eb50e3a
+				if (len_abuf > len_rem)
eb50e3a
+					len_tmp = len_rem / 2; /* encoding */
eb50e3a
+				audit_log_n_hex(*ab, buf, len_tmp);
eb50e3a
+				len_rem -= len_tmp * 2;
eb50e3a
+				len_abuf -= len_tmp * 2;
eb50e3a
+			} else {
eb50e3a
+				if (len_abuf > len_rem)
eb50e3a
+					len_tmp = len_rem - 2; /* quotes */
eb50e3a
+				audit_log_n_string(*ab, buf, len_tmp);
eb50e3a
+				len_rem -= len_tmp + 2;
eb50e3a
+				/* don't subtract the "2" because we still need
eb50e3a
+				 * to add quotes to the remaining string */
eb50e3a
+				len_abuf -= len_tmp;
eb50e3a
+			}
eb50e3a
+			len_buf -= len_tmp;
eb50e3a
+			buf += len_tmp;
eb50e3a
+		}
eb50e3a
 
eb50e3a
-	audit_log_format(*ab, "argc=%d", context->execve.argc);
eb50e3a
+		/* ready to move to the next argument? */
eb50e3a
+		if ((len_buf == 0) && !require_data) {
eb50e3a
+			arg++;
eb50e3a
+			iter = 0;
eb50e3a
+			len_full = 0;
eb50e3a
+			require_data = true;
eb50e3a
+			encode = false;
eb50e3a
+		}
eb50e3a
+	} while (arg < context->execve.argc);
eb50e3a
 
eb50e3a
-	/*
eb50e3a
-	 * we need some kernel buffer to hold the userspace args.  Just
eb50e3a
-	 * allocate one big one rather than allocating one of the right size
eb50e3a
-	 * for every single argument inside audit_log_single_execve_arg()
eb50e3a
-	 * should be <8k allocation so should be pretty safe.
eb50e3a
-	 */
eb50e3a
-	buf = kmalloc(MAX_EXECVE_AUDIT_LEN + 1, GFP_KERNEL);
eb50e3a
-	if (!buf) {
eb50e3a
-		audit_panic("out of memory for argv string");
eb50e3a
-		return;
eb50e3a
-	}
eb50e3a
+	/* NOTE: the caller handles the final audit_log_end() call */
eb50e3a
 
eb50e3a
-	for (i = 0; i < context->execve.argc; i++) {
eb50e3a
-		len = audit_log_single_execve_arg(context, ab, i,
eb50e3a
-						  &len_sent, p, buf);
eb50e3a
-		if (len <= 0)
eb50e3a
-			break;
eb50e3a
-		p += len;
eb50e3a
-	}
eb50e3a
-	kfree(buf);
eb50e3a
+out:
eb50e3a
+	kfree(buf_head);
eb50e3a
 }
eb50e3a
 
eb50e3a
 static void show_special(struct audit_context *context, int *call_panic)