[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[PATCH 1/3] Audit: break up execve argument lists into multiple records



    Break the auditing of a list of execve arguments into smaller records if there
    are a too many.  The limit is currently around 7.5k of arguments as userspace
    has an 8k buffer limit and will drop messages which are longer.
    
    Signed-off-by: Eric Paris <eparis redhat com>
---
Basically the same patch as last time, used a #define, cleaned up a
memory leak on a malloc failure code path.  Other than that it's the
same.

7500 also is a good size because it means we never need more than a 2 page allocation.
I'd say this is a good thing as even if we used a full netlink message of 32k its just
making it harder on the kernel to have the memory it needs.  I think userspace will want
to get fixed eventually to handle a full 32k just in case, but keeping the kernel under
8k when we know we can seems like a good idea.

 kernel/auditsc.c |   39 +++++++++++++++++++++++++++++++++------
 1 files changed, 33 insertions(+), 6 deletions(-)

diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 04f3ffb..4176db6 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -78,6 +78,9 @@ extern struct list_head audit_filter_list[];
 /* Indicates that audit should log the full pathname. */
 #define AUDIT_NAME_FULL -1
 
+/* no execve audit message should be longer than this (userspace limits) */
+#define MAX_EXECVE_AUDIT_LEN 7500
+
 /* number of audit rules */
 int audit_n_rules;
 
@@ -819,11 +822,12 @@ static int audit_log_pid_context(struct audit_context *context, pid_t pid,
 	return rc;
 }
 
-static void audit_log_execve_info(struct audit_buffer *ab,
+static void audit_log_execve_info(struct audit_context *context,
+		struct audit_buffer **ab,
 		struct audit_aux_data_execve *axi)
 {
 	int i;
-	long len, ret;
+	long len, ret, len_sent = 0;
 	const char __user *p;
 	char *buf;
 
@@ -833,7 +837,11 @@ static void audit_log_execve_info(struct audit_buffer *ab,
 	p = (const char __user *)axi->mm->arg_start;
 
 	for (i = 0; i < axi->argc; i++, p += len) {
+		char tmp_buf[12];
+		/* how many digits are in i? */
+		int i_len = snprintf(tmp_buf, 12, "%d", i);
 		len = strnlen_user(p, MAX_ARG_STRLEN);
+
 		/*
 		 * We just created this mm, if we can't find the strings
 		 * we just copied into it something is _very_ wrong. Similar
@@ -862,9 +870,28 @@ static void audit_log_execve_info(struct audit_buffer *ab,
 			send_sig(SIGKILL, current, 0);
 		}
 
-		audit_log_format(ab, "a%d=", i);
-		audit_log_untrustedstring(ab, buf);
-		audit_log_format(ab, "\n");
+		/*
+		 * If there are a lot of args just break them into multiple
+		 * messages.  the last ab started will get closed by the
+		 * caller.
+		 *
+		 * + 3 + i_len because we know at least a = and \n will be sent
+		 * as well as the number of digits in i (i_len).
+		 */
+		len_sent += (len + 3 + i_len);
+		if (len_sent > MAX_EXECVE_AUDIT_LEN) {
+			len_sent = len + 3 + i_len;
+			audit_log_end(*ab);
+			*ab = audit_log_start(context, GFP_KERNEL, AUDIT_EXECVE);
+			if (!*ab) {
+				kfree(buf);
+				return;
+			}
+		}
+
+		audit_log_format(*ab, "a%d=", i);
+		audit_log_untrustedstring(*ab, buf);
+		audit_log_format(*ab, "\n");
 
 		kfree(buf);
 	}
@@ -1010,7 +1037,7 @@ static void audit_log_exit(struct audit_context *context, struct task_struct *ts
 
 		case AUDIT_EXECVE: {
 			struct audit_aux_data_execve *axi = (void *)aux;
-			audit_log_execve_info(ab, axi);
+			audit_log_execve_info(context, &ab, axi);
 			break; }
 
 		case AUDIT_SOCKETCALL: {



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]