[PATCH 3/3] Audit: remove the limit on execve arguments when audit is running
by Eric Paris
Remove the limitation on argv size. The audit system now logs arguments in
smaller chunks (currently about 8k due to userspace audit system buffer sizes)
so this is no longer a requirement.
Signed-off-by: Eric Paris <eparis(a)redhat.com>
Acked-by: Peter Zijlstra <a.p.zijlstra(a)chello.nl>
---
This patch hasn't changed since the last series, just reposted as 3/3 and rediffed.
kernel/auditsc.c | 10 ----------
kernel/sysctl.c | 11 -----------
2 files changed, 0 insertions(+), 21 deletions(-)
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index ffc8d4b..5d39727 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -1917,8 +1917,6 @@ int __audit_ipc_set_perm(unsigned long qbytes, uid_t uid, gid_t gid, mode_t mode
return 0;
}
-int audit_argv_kb = 32;
-
int audit_bprm(struct linux_binprm *bprm)
{
struct audit_aux_data_execve *ax;
@@ -1927,14 +1925,6 @@ int audit_bprm(struct linux_binprm *bprm)
if (likely(!audit_enabled || !context || context->dummy))
return 0;
- /*
- * Even though the stack code doesn't limit the arg+env size any more,
- * the audit code requires that _all_ arguments be logged in a single
- * netlink skb. Hence cap it :-(
- */
- if (bprm->argv_len > (audit_argv_kb << 10))
- return -E2BIG;
-
ax = kmalloc(sizeof(*ax), GFP_KERNEL);
if (!ax)
return -ENOMEM;
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 53a456e..88e5d06 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -77,7 +77,6 @@ extern int percpu_pagelist_fraction;
extern int compat_log;
extern int maps_protect;
extern int sysctl_stat_interval;
-extern int audit_argv_kb;
/* this is needed for the proc_dointvec_minmax for [fs_]overflow UID and GID */
static int maxolduid = 65535;
@@ -347,16 +346,6 @@ static ctl_table kern_table[] = {
.mode = 0644,
.proc_handler = &proc_dointvec,
},
-#ifdef CONFIG_AUDITSYSCALL
- {
- .ctl_name = CTL_UNNUMBERED,
- .procname = "audit_argv_kb",
- .data = &audit_argv_kb,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = &proc_dointvec,
- },
-#endif
{
.ctl_name = KERN_CORE_PATTERN,
.procname = "core_pattern",
17 years
[PATCH 2/3] Audit: break a large single execve argument into smaller records
by Eric Paris
support single arguments that are large, not just large lists of execve args.
This also means we never have to get a kernel buffer larger than
MAX_EXECVE_AUDIT_LEN no matter how large the argument is. Before this patch
we could need to allocate 32 consecutive pages to hold one argument which could
pretty easily oom.
a single argument larger than MAX_EXECVE_AUDIT_LEN is broken into multiple
records and have a format like a10[0] a10[1] a10[2] etc.
Signed-off-by: Eric Paris <eparis(a)redhat.com>
---
example audit log (about 50k long) for the whole patch series can be
found at http://people.redhat.com/~eparis/audit/audit.log the execve in
question was something like:
program_name [about 50 arguments] [one argument which is about 17k long] [about 1000 arguments]
kernel/auditsc.c | 42 +++++++++++++++++++++++++++++++++++++++++
1 files changed, 42 insertions(+), 0 deletions(-)
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 4176db6..ffc8d4b 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -853,6 +853,48 @@ static void audit_log_execve_info(struct audit_context *context,
send_sig(SIGKILL, current, 0);
}
+ if (unlikely(len > MAX_EXECVE_AUDIT_LEN)) {
+ /* deal with single arugments > MAX_EXECVE_AUDIT_LEN */
+ int j;
+ const long tmplen = sizeof(char) * MAX_EXECVE_AUDIT_LEN;
+
+ buf = kmalloc(tmplen + 1, GFP_KERNEL);
+ if (!buf) {
+ audit_panic("out of memory for argv string\n");
+ return;
+ }
+ buf[tmplen] = '\0';
+ for (j = 0; len > 0; j++) {
+ if (len > tmplen) {
+ ret = copy_from_user(buf, p, tmplen);
+ p += tmplen;
+ len -= tmplen;
+ } else {
+ ret = copy_from_user(buf, p, len);
+ /* p is at the next arg */
+ p += len;
+ /* 27 is the max length of a%d[%d] */
+ len_sent = len + 27;
+ len = 0;
+ }
+ if (ret) {
+ WARN_ON(1);
+ send_sig(SIGKILL, current, 0);
+ }
+ audit_log_end(*ab);
+ *ab = audit_log_start(context, GFP_KERNEL,
+ AUDIT_EXECVE);
+ if (!*ab) {
+ kfree(buf);
+ return;
+ }
+ audit_log_format(*ab, "a%d[%d]=", i, j);
+ audit_log_untrustedstring(*ab, buf);
+ audit_log_format(*ab, "\n");
+ }
+ continue;
+ }
+
buf = kmalloc(len, GFP_KERNEL);
if (!buf) {
audit_panic("out of memory for argv string\n");
17 years
[PATCH 1/3] Audit: break up execve argument lists into multiple records
by Eric Paris
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(a)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: {
17 years
[PATCH 1/2] Audit: break up execve arguments into multiple records
by Eric Paris
Break the auditing of execve arguments into smaller records if there are
a lot. Currently the limit is 32k if audit is on (intended to fit in a
single netlink message) but userspace actually has trouble a little over
8k. This patch takes long argument lists and just emits them in
sequential records. We log all of them and userspace is happy! It also
means we don't need as much kernel memory to hold the buffer while we
build that one huge record.
Signed-off-by: Eric Paris <eparis(a)redhat.com>
---
kernel/auditsc.c | 39 +++++++++++++++++++++++++++++++++------
1 files changed, 33 insertions(+), 6 deletions(-)
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 04f3ffb..f9f61db 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -819,11 +819,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 +834,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 +867,31 @@ 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.
+ *
+ * 7500 bytes just seemed like an arbitrily large enough
+ * number to minimize message and keep allocations in
+ * in audit_expand nice and small. (some audit userspace
+ * can't handle messages > ~8k)
+ *
+ * add +3 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 > 7500) {
+ len_sent = len + 3 + i_len;
+ audit_log_end(*ab);
+ *ab = audit_log_start(context, GFP_KERNEL, AUDIT_EXECVE);
+ if (!*ab)
+ 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: {
17 years, 1 month
[PATCH] Audit: close race between audit_syscall_exit and proc_loginuid_read
by Eric Paris
audit_syscall_exit() calls audit_get_context() which returns the
tsk->audit_context but then also sets tsk->audit_context=NULL. A few
lines later audit_syscall_exit sets the audit_context (either back to
audit_context or to a different context)
During this window when tsk->audit_context is NULL it is possible that
another process will try to read /proc/pid/loginuid and will get a -1.
There does not appear to be a good reason to set audit_context to null
in the get function so this patch merely leaves the audit_context alone
so there is no period of time in which audit_context is not pointing to
a valid context.
Signed-off-by: Eric Paris <eparis(a)redhat.com>
---
Easily tested, I opened 2 shells.
shell #1 I read /proc/shell2/loginuid in a very very tight loop.
shell #2 I ran a tight loop adding and removing audit rules
without the patch I often saw -1 as the loginuid but with the patch I
always got the correct behavior.
kernel/auditsc.c | 5 +++--
1 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 04f3ffb..62ace9b 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -598,7 +598,6 @@ static inline struct audit_context *audit_get_context(struct task_struct *tsk,
get_context:
- tsk->audit_context = NULL;
return context;
}
@@ -1135,6 +1134,8 @@ void audit_free(struct task_struct *tsk)
if (likely(!context))
return;
+ tsk->audit_context = NULL;
+
/* Check for system calls that do not go through the exit
* function (e.g., exit_group), then free context block.
* We use GFP_ATOMIC here because we might be doing this
@@ -1266,9 +1267,9 @@ void audit_syscall_exit(int valid, long return_code)
if (context->previous) {
struct audit_context *new_context = context->previous;
+ tsk->audit_context = new_context;
context->previous = NULL;
audit_free_context(context);
- tsk->audit_context = new_context;
} else {
audit_free_names(context);
audit_free_aux(context);
17 years, 1 month
Re: [PATCH 1/2] Audit: break up execve arguments into multiple records
by Steve Grubb
On Wednesday 03 October 2007 13:21:58 Eric Paris wrote:
> > Do you have an example of what the event would look like with this patch
> > applied?
>
> attached. That is 100k or so of execve args, wow!
Looks good, thanks. I just wanted to make sure everyone could see how this
would turn out.
-Steve
17 years, 1 month
OBJ_PID records
by Steve Grubb
Hi,
I was noticing that I'm seeing OBJ_PID records sometimes when there is
MAC_POLICY_LOAD event. I didn't think these two would go together. I'm seeing
this:
type=OBJ_PID msg=audit(09/18/2007 06:26:21.236:216) : opid=3211
obj=user_u:system_r:unconfined_t:s0
type=SYSCALL msg=audit(09/18/2007 06:26:21.236:216) : arch=x86_64
syscall=write success=yes exit=1592854 a0=4 a1=2aaaaaae2000 a2=184e16 a3=0
items=0 ppid=3333 pid=3334 auid=sgrubb uid=root gid=root euid=root suid=root
fsuid=root egid=root sgid=root fsgid=root tty=pts0 comm=load_policy
exe=/usr/sbin/load_policy subj=user_u:system_r:load_policy_t:s0 key=(null)
type=MAC_POLICY_LOAD msg=audit(09/18/2007 06:26:21.236:216) : policy loaded
auid=sgrubb
Shouldn't these only come out when kill (or its friends) is in effect? The
above syscall was a write. I don't think the current syscall is being taken
into account in audit_match_signal.
-Steve
17 years, 1 month
[ANNOUNCE] The Linux Test Project has been Released for SEPTEMBER 2007
by Subrata Modak
Dear All,
The Linux Test Project test suite has been released for the month of
SEPTEMBER 2007. The latest version of the test-suite contains 3000+
tests for the Linux OS and can be found at http://ltp.sourceforge.net/.
Latest happenings in LTP can also be found at:
http://ltp.sourceforge.net/wiki/,
http://ltp.sourceforge.net/wikiArchives.php, and,
IRC: irc.freenode.org #ltp.
Our web site also contains other information such as:
- A Linux test tools matrix
- Technical papers
- How To's on Linux testing
- Code coverage analysis tool.
Release Highlights:
* Enabling Kernel Version Comparisns for Lots of Testcase(s),
* Removal of Connectathon Testcases for want of GPLV2 license,
* Patching of NUMA Testcases for better Statistics Collection,
* Fixes for KDUMP scripts errors,
* Mandatory generation of failed testcases file,
* Fix of LTP output format as pointed out by Andrew Morton,
* Update of OPENHPI testsuite to 2.10.0,
Note(s) from the Maintainer:
LTP output will see new formats in the coming days. This will make
interpreting output more easily and conceptually. Hope that Real Time
Linux Testcases will see the light of the day by this month end.
We would encourage the community to post results to
ltp-results(a)lists.sf.net,
patches, new tests, bugs or comments/questions to ltp-list(a)lists.sf.net,
http://sourceforge.net/tracker/?func=add&group_id=3382&atid=103382
(for New Bug(s)),
http://sourceforge.net/tracker/?func=add&group_id=3382&atid=303382
(for New Patch(s)),
http://sourceforge.net/tracker/?func=add&group_id=3382&atid=353382
(for New Feature Request(s))
Please also see the ChangeLog Attached (SEPTEMBER 2007):
Happy testing,
Regards--
Subrata,
17 years, 1 month