[PATCH 3/3] audit: dont allocate whole pages

William Roberts bill.c.roberts at gmail.com
Tue Nov 19 19:41:04 UTC 2013


Rather then cacheing whole pages, use kmalloc to potentially
cache a smaller size.

Change-Id: I9fb749dc2bdac506d1bc6f2259fbbdeeec87b298
Signed-off-by: William Roberts <wroberts at tresys.com>
---
 fs/proc/base.c          |   87 ++++++++++++++++++++++++++++++++++++++---------
 include/linux/proc_fs.h |    4 ++-
 kernel/auditsc.c        |   43 +++++++++++++++--------
 3 files changed, 102 insertions(+), 32 deletions(-)

diff --git a/fs/proc/base.c b/fs/proc/base.c
index 25b73d3..a44135f 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -209,35 +209,70 @@ struct mm_struct *mm_for_maps(struct task_struct *task)
 	return mm_access(task, PTRACE_MODE_READ);
 }
 
-int proc_pid_cmdline(struct task_struct *task, char *buffer)
+/* Returns the length of the VM area containing the tasks cmdline info 0 indicates success */
+int proc_pid_cmdline_length(struct task_struct *task, unsigned int *len)
+{
+	int res = -1;
+	struct mm_struct *mm;
+
+	if (!task || !len)
+		return 0;
+
+	mm = get_task_mm(task);
+	if (!mm)
+		goto out;
+	if (!mm->arg_end)
+		goto out_mm;	/* Shh! No looking before we're done */
+
+	*len = mm->arg_end - mm->arg_start;
+	res = 0;
+out_mm:
+	mmput(mm);
+out:
+	return res;
+}
+
+/* Copy's the tasks cmdline data into buf, truncating at buflen */
+int proc_pid_copy_cmdline_to_buf(struct task_struct *task, char *buf, unsigned int buflen)
 {
 	int res = 0;
 	unsigned int len;
-	struct mm_struct *mm = get_task_mm(task);
+	struct mm_struct *mm;
+
+	if (!buflen || !buf)
+		return 0;
+
+	mm = get_task_mm(task);
 	if (!mm)
 		goto out;
 	if (!mm->arg_end)
 		goto out_mm;	/* Shh! No looking before we're done */
 
- 	len = mm->arg_end - mm->arg_start;
- 
-	if (len > PAGE_SIZE)
-		len = PAGE_SIZE;
- 
-	res = access_process_vm(task, mm->arg_start, buffer, len, 0);
+	res = access_process_vm(task, mm->arg_start, buf, buflen, 0);
+	if (res <= 0)
+		goto out_mm;
+
+	/* Truncate to res if buflen is longer */
+	if (res > buflen)
+		res = buflen;
 
-	// If the nul at the end of args has been overwritten, then
-	// assume application is using setproctitle(3).
-	if (res > 0 && buffer[res-1] != '\0' && len < PAGE_SIZE) {
-		len = strnlen(buffer, res);
+	/*
+	 * If the nul at the end of args has been overwritten, then
+	 * assume application is using setproctitle(3).
+	 */
+	if (buf[res-1] != '\0') {
+		/* Nul between start and end of vm space? If so truncate size down */
+		len = strnlen(buf, res);
 		if (len < res) {
 		    res = len;
 		} else {
+			/* No nul, truncate to buflen if too big to fit */
 			len = mm->env_end - mm->env_start;
-			if (len > PAGE_SIZE - res)
-				len = PAGE_SIZE - res;
-			res += access_process_vm(task, mm->env_start, buffer+res, len, 0);
-			res = strnlen(buffer, res);
+			if (len > buflen - res)
+				len = buflen - res;
+			/* Copy in any remaining data */
+			res += access_process_vm(task, mm->env_start, buf+res, len, 0);
+			res = strnlen(buf, res);
 		}
 	}
 out_mm:
@@ -246,6 +281,26 @@ out:
 	return res;
 }
 
+static int proc_pid_cmdline(struct task_struct *task, char *buffer)
+{
+	unsigned int len;
+	int res = proc_pid_cmdline_length(task, &len);
+	if (res)
+		return 0;
+
+	/* The caller of this allocates a page */
+	if (len > PAGE_SIZE)
+		len = PAGE_SIZE;
+
+	res = proc_pid_copy_cmdline_to_buf(task, buffer, len);
+	/*
+	 * Ensure NULL terminated! Application could
+	 * could be using setproctitle(3).
+	 */
+	buffer[res-1] = '\0';
+	return res;
+}
+
 static int proc_pid_auxv(struct task_struct *task, char *buffer)
 {
 	struct mm_struct *mm = mm_for_maps(task);
diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h
index d85ac14..045dfa5 100644
--- a/include/linux/proc_fs.h
+++ b/include/linux/proc_fs.h
@@ -118,7 +118,9 @@ struct pid_namespace;
 
 extern int pid_ns_prepare_proc(struct pid_namespace *ns);
 extern void pid_ns_release_proc(struct pid_namespace *ns);
-extern int proc_pid_cmdline(struct task_struct *task, char *buffer);
+
+extern int proc_pid_cmdline_length(struct task_struct *task, unsigned int *len);
+extern int proc_pid_copy_cmdline_to_buf(struct task_struct *task, char *buf, unsigned int buflen);
 
 /*
  * proc_tty.c
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index db64b66..34a6c1d 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -1049,7 +1049,7 @@ static inline void audit_cmdline_free(struct audit_context *ctx)
 {
 	if (!ctx->cmdline)
 		return;
-	free_page((unsigned long)ctx->cmdline);
+	kfree(ctx->cmdline);
 	ctx->cmdline = NULL;
 }
 
@@ -1164,30 +1164,43 @@ error_path:
 
 EXPORT_SYMBOL(audit_log_task_context);
 
-static char *audit_cmdline_get_page(struct audit_buffer *ab,
+static char *audit_cmdline_get(struct audit_buffer *ab,
 				  struct task_struct *tsk)
 {
 	int len;
-	unsigned long page;
+	int res;
+	char *buf;
 
-	/* Get the process cmdline */
-	page = __get_free_page(GFP_TEMPORARY);
-	if (!page) {
+	res = proc_pid_cmdline_length(tsk, &len);
+	if (res != 0 || len == 0)
 		return NULL;
-	}
-	len = proc_pid_cmdline(tsk, (char *)page);
-	if (len <= 0) {
-		free_page(page);
+
+	if (len > PATH_MAX)
+		len = PATH_MAX;
+
+	buf = kmalloc(len, GFP_KERNEL);
+	if (!buf)
+		return NULL;
+
+	res = proc_pid_copy_cmdline_to_buf(tsk, buf, len);
+	if (res <= 0) {
+		kfree(buf);
 		return NULL;
 	}
+
+	/*
+	 * res is guarenteed not to be longer than
+	 * the buf as it was truncated to len
+	 * in proc_pid_copy_cmdline_to_buf()
+	 */
+	len = res;
+
 	/*
 	 * Ensure NULL terminated! Application could
 	 * could be using setproctitle(3).
 	 */
-	((char *)page)[len-1] = '\0';
-
-	/* XXX: Re-alloc to something smaller then a page here? */
-	return ((char *)page);
+	buf[len-1] = '\0';
+	return buf;
 }
 
 static void audit_log_cmdline(struct audit_buffer *ab, struct task_struct *tsk,
@@ -1203,7 +1216,7 @@ static void audit_log_cmdline(struct audit_buffer *ab, struct task_struct *tsk,
 		goto out;
 	}
 	/* Not cached yet */
-	context->cmdline = audit_cmdline_get_page(ab, tsk);
+	context->cmdline = audit_cmdline_get(ab, tsk);
 	if (!context->cmdline)
 		goto out;
 	msg = context->cmdline;
-- 
1.7.9.5




More information about the Linux-audit mailing list