audit 2.3.4 released
by Steve Grubb
Hi,
I've just released a new version of the audit daemon. It can be downloaded
from http://people.redhat.com/sgrubb/audit. It will also be in rawhide
soon. The ChangeLog is:
- Parse path in CONFIG_CHANGE events
- In audisp-remote, fix retry logic for temporary network failures
- In auparse, add get_type_name function
- Add --no-config command option to aureport
- Fix interpretting MCS seliunx contexts in ausearch (#970675)
- In auparse, classify selinux contexts as MAC_LABEL field type
- In ausearch/report parse vm-ctx and img-ctx as selinux labels
- Update translation tables for the 3.14 kernel
Please let me know if you run across any problems with this release.
-Steve
10 years, 10 months
Audit Architecture doc
by Ashok Kumar J
Hi i need the Audit Architecture document. please send some good documents.
--
with regards
Ashok Kumar J
10 years, 10 months
Re: [PATCH] lib/vsprintf: add %pT format specifier
by Tetsuo Handa
Tetsuo Handa wrote:
> Geert Uytterhoeven wrote:
> > On Sat, Jan 11, 2014 at 12:59 AM, Andrew Morton
> > <akpm(a)linux-foundation.org> wrote:
> > >> +char *comm_name(char *buf, char *end, struct task_struct *tsk,
> > >> + struct printf_spec spec, const char *fmt)
> > >> +{
> > >> + char name[TASK_COMM_LEN];
> > >> +
> > >> + /* Caller can pass NULL instead of current. */
> > >> + if (!tsk)
> > >> + tsk = current;
> > >> + /* Not using get_task_comm() in case I'm in IRQ context. */
> > >> + memcpy(name, tsk->comm, TASK_COMM_LEN);
> >
> > So this may copy more bytes than the actual string length of tsk->comm.
> > As this is a temporary buffer, that just wastes cycles.
>
> For example, strncpy() in arch/x86/lib/string_32.c is
>
> char *strncpy(char *dest, const char *src, size_t count)
> {
> int d0, d1, d2, d3;
> asm volatile("1:\tdecl %2\n\t"
> "js 2f\n\t"
> "lodsb\n\t"
> "stosb\n\t"
> "testb %%al,%%al\n\t"
> "jne 1b\n\t"
> "rep\n\t"
> "stosb\n"
> "2:"
> : "=&S" (d0), "=&D" (d1), "=&c" (d2), "=&a" (d3)
> : "" (src), "1" (dest), "2" (count) : "memory");
> return dest;
> }
>
> and strncpy() in lib/string.c is
>
> char *strncpy(char *dest, const char *src, size_t count)
> {
> char *tmp = dest;
>
> while (count) {
> if ((*tmp = *src) != 0)
> src++;
> tmp++;
> count--;
> }
> return dest;
> }
>
> while memcpy(name, tsk->comm, TASK_COMM_LEN) is
>
> u64 *dest = (u64 *) name;
> u64 *src = (u64 *) tsk->comm;
> *dest++ = *src++;
> *dest = *src;
>
> if sizeof(long) == 64. I can't understand why unconditionally copying 8 bytes *
> 2 consumes more cycles than conditionally copying up to 16 bytes...
>
> Also, strncpy() in lib/string.c is not safe for copying task_struct->comm, for
> task_struct->comm can change at any moment.
>
> Initial state:
>
> p->comm contains "secret_commname\0"
>
> A reader calls strncpy(buf, p->comm, 16)
> In strncpy() does
>
> char *dest = buf
> char *src = tsk->comm
> char *tmp = dest
> while (16)
> if ((buf[0] = 's') != 0)
> src++
> tmp++;
> 15
> while (15)
> if ((buf[1] = 'e') != 0)
> src++
> tmp++
> 14
>
> At this moment preemption happens, and a writer jumps in.
> The writer calls set_task_comm(p, "x").
> Now p->comm contains "x\0cret_commname\0".
> The preemption ends and the reader continues the loop.
> Now *src == '\0' but continues copying.
>
> while (14)
> if ((buf[2] = 'c') != 0)
> src++
> tmp++
> 13
> (...snipped...)
> while (1)
> if ((buf[15] = '\0') != 0)
> tmp++
> 0
> return dest
>
> and gets "xecret_commname\0" in the buf.
Oops, my example was bad, though the conclusion does not changte.
Start with "Here We Go\0\0\0\0\0\0", and a preempted writer changes it to
"Let's Go\0\0\0\0\0\0\0\0" when a reader has copied 'H' 'e' 'r' 'e'. Then,
the reader gets "Heres Go\0\0\0\0\0\0\0\0" in the buf.
What I wanted to say is: Do not use strncpy() or strlcpy() for copying
task_struct->comm to temporary buffer, for it can be changed while reading it.
Hello, audit subsystem users.
Below are patches for avoiding racing in audit logs.
----------------------------------------
>From de04a5b08b611293b05b4b4fcc82dc1cd1b89ac3 Mon Sep 17 00:00:00 2001
From: Tetsuo Handa <penguin-kernel(a)I-love.SAKURA.ne.jp>
Date: Sun, 12 Jan 2014 16:28:12 +0900
Subject: [PATCH 1/4] exec: Add wrapper function for reading task_struct->comm.
Since task_struct->comm can be modified by other threads while the current
thread is reading it, it is recommended to use get_task_comm() for reading it.
However, since get_task_comm() holds task_struct->alloc_lock spinlock,
some users cannot use get_task_comm(). Also, a lot of users are directly
reading from task_struct->comm even if they can use get_task_comm().
Such users might obtain inconsistent result.
This patch introduces a wrapper function for reading task_struct->comm .
Currently this function does not provide consistency. I'm planning to change to
use RCU in the future. By using RCU, the comm name read from task_struct->comm
will be guaranteed to be consistent. But before modifying set_task_comm() to
use RCU, we need to kill direct ->comm users who do not use get_task_comm().
Users directly reading from task_struct->comm for printing purpose can use
%pT format specifier rather than this wrapper function.
Signed-off-by: Tetsuo Handa <penguin-kernel(a)I-love.SAKURA.ne.jp>
---
include/linux/sched.h | 18 ++++++++++++++++++
1 files changed, 18 insertions(+), 0 deletions(-)
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 53f97eb..a31e148 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -1665,6 +1665,24 @@ static inline cputime_t task_gtime(struct task_struct *t)
extern void task_cputime_adjusted(struct task_struct *p, cputime_t *ut, cputime_t *st);
extern void thread_group_cputime_adjusted(struct task_struct *p, cputime_t *ut, cputime_t *st);
+/**
+ * commcpy - Copy task_struct->comm to buffer.
+ *
+ * @buf: Buffer to copy @tsk->comm which must be at least TASK_COMM_LEN bytes.
+ * @tsk: Pointer to "struct task_struct".
+ *
+ * Returns @buf .
+ *
+ * Please use this wrapper function which will be updated in the future to read
+ * @tsk->comm in a consistent way using RCU.
+ */
+static inline char *commcpy(char *buf, const struct task_struct *tsk)
+{
+ memcpy(buf, tsk->comm, TASK_COMM_LEN);
+ buf[TASK_COMM_LEN - 1] = '\0';
+ return buf;
+}
+
/*
* Per process flags
*/
--
1.7.1
----------------------------------------
>From a09631ee2536d581b3c713690cf134cc84c8cce9 Mon Sep 17 00:00:00 2001
From: Tetsuo Handa <penguin-kernel(a)I-love.SAKURA.ne.jp>
Date: Sun, 12 Jan 2014 16:36:21 +0900
Subject: [PATCH 2/4] LSM: Pass comm name via commcpy()
When we pass task->comm to audit_log_untrustedstring(), we need to pass a
snapshot of it using commcpy() because task->comm can be changed from
"HelloLinuxWorld\0" (a string where
audit_string_contains_control("HelloLinuxWorld\0", 15) would return 0) to
"Good Morning\0\0\0\0" (a string where
audit_string_contains_control("Good Morning\0\0\0\0", 15) would return 1)
during a call to audit_log_untrustedstring(ab, task->comm). As a result,
the audit log will contain unexpected bytes (e.g. '"' and '\0') and might
confuse users who expect that the audit log does not contain such bytes.
Signed-off-by: Tetsuo Handa <penguin-kernel(a)I-love.SAKURA.ne.jp>
---
security/lsm_audit.c | 5 +++--
1 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/security/lsm_audit.c b/security/lsm_audit.c
index 9a62045..a6c9152 100644
--- a/security/lsm_audit.c
+++ b/security/lsm_audit.c
@@ -212,6 +212,7 @@ static void dump_common_audit_data(struct audit_buffer *ab,
struct common_audit_data *a)
{
struct task_struct *tsk = current;
+ char name[TASK_COMM_LEN];
/*
* To keep stack sizes in check force programers to notice if they
@@ -221,7 +222,7 @@ static void dump_common_audit_data(struct audit_buffer *ab,
BUILD_BUG_ON(sizeof(a->u) > sizeof(void *)*2);
audit_log_format(ab, " pid=%d comm=", tsk->pid);
- audit_log_untrustedstring(ab, tsk->comm);
+ audit_log_untrustedstring(ab, commcpy(name, tsk));
switch (a->type) {
case LSM_AUDIT_DATA_NONE:
@@ -280,7 +281,7 @@ static void dump_common_audit_data(struct audit_buffer *ab,
tsk = a->u.tsk;
if (tsk && tsk->pid) {
audit_log_format(ab, " pid=%d comm=", tsk->pid);
- audit_log_untrustedstring(ab, tsk->comm);
+ audit_log_untrustedstring(ab, commcpy(name, tsk));
}
break;
case LSM_AUDIT_DATA_NET:
--
1.7.1
----------------------------------------
>From a3679132e7c22e6c74e5cfc36237656e5b252c52 Mon Sep 17 00:00:00 2001
From: Tetsuo Handa <penguin-kernel(a)I-love.SAKURA.ne.jp>
Date: Sun, 12 Jan 2014 16:38:32 +0900
Subject: [PATCH 3/4] Integrity: Pass comm name via commcpy()
When we pass task->comm to audit_log_untrustedstring(), we need to pass a
snapshot of it using commcpy() because task->comm can be changed from
"HelloLinuxWorld\0" (a string where
audit_string_contains_control("HelloLinuxWorld\0", 15) would return 0) to
"Good Morning\0\0\0\0" (a string where
audit_string_contains_control("Good Morning\0\0\0\0", 15) would return 1)
during a call to audit_log_untrustedstring(ab, task->comm). As a result,
the audit log will contain unexpected bytes (e.g. '"' and '\0') and might
confuse users who expect that the audit log does not contain such bytes.
Signed-off-by: Tetsuo Handa <penguin-kernel(a)I-love.SAKURA.ne.jp>
---
security/integrity/integrity_audit.c | 3 ++-
1 files changed, 2 insertions(+), 1 deletions(-)
diff --git a/security/integrity/integrity_audit.c b/security/integrity/integrity_audit.c
index d7efb30..eb853d9 100644
--- a/security/integrity/integrity_audit.c
+++ b/security/integrity/integrity_audit.c
@@ -33,6 +33,7 @@ void integrity_audit_msg(int audit_msgno, struct inode *inode,
const char *cause, int result, int audit_info)
{
struct audit_buffer *ab;
+ char name[TASK_COMM_LEN];
if (!integrity_audit_info && audit_info == 1) /* Skip info messages */
return;
@@ -49,7 +50,7 @@ void integrity_audit_msg(int audit_msgno, struct inode *inode,
audit_log_format(ab, " cause=");
audit_log_string(ab, cause);
audit_log_format(ab, " comm=");
- audit_log_untrustedstring(ab, current->comm);
+ audit_log_untrustedstring(ab, commcpy(name, current));
if (fname) {
audit_log_format(ab, " name=");
audit_log_untrustedstring(ab, fname);
--
1.7.1
----------------------------------------
>From 8ac36b53256b1495ee3c12f3b52deabdd3e67d72 Mon Sep 17 00:00:00 2001
From: Tetsuo Handa <penguin-kernel(a)I-love.SAKURA.ne.jp>
Date: Sun, 12 Jan 2014 16:42:50 +0900
Subject: [PATCH 4/4] Audit: Pass comm name via commcpy()
When we pass task->comm to audit_log_untrustedstring(), we need to pass a
snapshot of it using commcpy() because task->comm can be changed from
"HelloLinuxWorld\0" (a string where
audit_string_contains_control("HelloLinuxWorld\0", 15) would return 0) to
"Good Morning\0\0\0\0" (a string where
audit_string_contains_control("Good Morning\0\0\0\0", 15) would return 1)
during a call to audit_log_untrustedstring(ab, task->comm). As a result,
the audit log will contain unexpected bytes (e.g. '"' and '\0') and might
confuse users who expect that the audit log does not contain such bytes.
Signed-off-by: Tetsuo Handa <penguin-kernel(a)I-love.SAKURA.ne.jp>
---
kernel/auditsc.c | 3 ++-
1 files changed, 2 insertions(+), 1 deletions(-)
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 90594c9..3b1bf3c 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -2352,6 +2352,7 @@ static void audit_log_task(struct audit_buffer *ab)
kuid_t auid, uid;
kgid_t gid;
unsigned int sessionid;
+ char name[TASK_COMM_LEN];
auid = audit_get_loginuid(current);
sessionid = audit_get_sessionid(current);
@@ -2364,7 +2365,7 @@ static void audit_log_task(struct audit_buffer *ab)
sessionid);
audit_log_task_context(ab);
audit_log_format(ab, " pid=%d comm=", current->pid);
- audit_log_untrustedstring(ab, current->comm);
+ audit_log_untrustedstring(ab, commcpy(name, current));
}
static void audit_log_abend(struct audit_buffer *ab, char *reason, long signr)
--
1.7.1
----------------------------------------
10 years, 10 months
[PATCH] audit: add arch field to seccomp event log
by Richard Guy Briggs
The AUDIT_SECCOMP record looks something like this:
type=SECCOMP msg=audit(1373478171.953:32775): auid=4325 uid=4325 gid=4325 ses=1 subj=unconfined_u:unconfined_r:unconfined_t:s0 pid=12381 comm="test" sig=31 syscall=231 compat=0 ip=0x39ea8bca89 code=0x0
In order to determine what syscall 231 maps to, we need to have the arch= field right before it.
To see the event, compile this test.c program:
=====
int main(void)
{
return seccomp_load(seccomp_init(SCMP_ACT_KILL));
}
=====
gcc -g test.c -o test -lseccomp
After running the program, find the record by: ausearch --start recent -m SECCOMP -i
---
kernel/auditsc.c | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 6874c1f..c464d44 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -2412,6 +2412,7 @@ void __audit_seccomp(unsigned long syscall, long signr, int code)
return;
audit_log_task(ab);
audit_log_format(ab, " sig=%ld", signr);
+ audit_log_format(ab, " arch=%x", current->audit_context->arch);
audit_log_format(ab, " syscall=%ld", syscall);
audit_log_format(ab, " compat=%d", is_compat_task());
audit_log_format(ab, " ip=0x%lx", KSTK_EIP(current));
--
1.7.1
10 years, 10 months
[ARCH question] Do syscall_get_nr and syscall_get_arguments always work?
by Andy Lutomirski
On Tue, Feb 4, 2014 at 11:32 AM, Andy Lutomirski <luto(a)amacapital.net> wrote:
> Now we get rid of __audit_syscall_entry. (This speeds up even the
> auditing-is-on case.) Instead we have __audit_start_record, which
> does more or less the same thing, except that (a) it doesn't BUG if
> in_syscall and (b) it *sets* TIF_SYSCALL_AUDIT. This relies on the
> fact that syscall_get_nr and syscall_get_arguments are reliable on
> x86_64. I suspect that they're reliable everywhere else, too. The
> idea is that there's nothing wrong with calling __audit_start_record
> more than once. (Maybe it should be called
> __audit_record_this_syscall.)
I'd like to make a change that can result in syscall_get_nr and
syscall_get_arguments being called (on current and
task_pt_regs(current)) from any system call (as opposed to being
called only from the audit/trace slowpaths). Is this safe?
Here's my somewhat clueless analysis:
On x86_64, I've tested it, and it works. The entry code saves all of
the argument registers, even in the fast path.
i386 and ia32_compat look okay, too.
If "stmia sp, {r0 - r12} @ Calling r0 - r12" does what I
think it does, then arm should be okay.
I'm totally guessing here, but e10_sync on aarch64 seems to save
enough registers. I admit to being a little bit surprised, though --
aarch64 is new, and if I were designing an ABI, I specify that
syscalls *don't* save registers.
ia64 has a comment in ivt.S that streamlined syscalls save nr in r15.
The rest come from unwind info (!). I assume this has something to do
with the magic ia64 register rotation thing. I have no idea what
happens if there's a NaT in an argument register.
I can't even find the system call entry point on mips.
Is there a semi-official answer here?
--Andy
10 years, 10 months
[PATCH v3] audit: Turn off TIF_SYSCALL_AUDIT when there are no rules
by Andy Lutomirski
This toggles TIF_SYSCALL_AUDIT as needed when rules change instead
of leaving it set whenever rules might be set in the future. This
reduces syscall latency from >60ns to closer to 40ns on my laptop.
This code is a little bit tricky. It's not safe to turn
TIF_SYSCALL_AUDIT off during a syscall that is being audited. So,
with this change, the only thing that ever turns TIF_SYSCALL_AUDIT
off after a process has been created is __audit_syscall_exit.
This has the somewhat odd side-effect that, unless there's a
'task,never' rule, every task's first syscall will use the slow
path. This should be more or less unnoticable (what's another
20-40ns at task creation time between friends?).
There is a user-visible effect of this change: if there are no audit
rules, then events like AVC denials will not result in a syscall
audit record being written. I'm happy to accept this minor loss in
debuggability in exchange for a massive speedup of all system calls
on default distribution configurations.
A better solution would be to ditch the syscall entry hook entirely
and use the syscall_get_xyz calls as needed to fill in the context.
This could be done on top of this patch, but it would be more code.
Cc: Oleg Nesterov <oleg(a)redhat.com>
Cc: Steve Grubb <sgrubb(a)redhat.com>
Cc: Eric Paris <eparis(a)redhat.com>
Signed-off-by: Andy Lutomirski <luto(a)amacapital.net>
---
Changes from v2 (actually v2.1):
- Use for_each_process_thread instead of do_each_thread :)
- Turn off TIF_SYSCALL_AUDIT lazily, thus hopefully avoiding all of
the nasty cases that Oleg noticed.
Changes from v1:
- For new tasks, set flags in a new audit_sync_flags callback instead of
in audit_alloc (thanks, Oleg).
- Rework locking.
- Use irqsave/irqrestore to avoid having to think about who else might have
taken spinlocks.
include/linux/audit.h | 8 ++++++--
kernel/auditfilter.c | 4 ++--
kernel/auditsc.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++++--
3 files changed, 63 insertions(+), 6 deletions(-)
diff --git a/include/linux/audit.h b/include/linux/audit.h
index aa865a9..ab00ffb 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -298,7 +298,8 @@ static inline void audit_mmap_fd(int fd, int flags)
__audit_mmap_fd(fd, flags);
}
-extern int audit_n_rules;
+extern void audit_inc_n_rules(void);
+extern void audit_dec_n_rules(void);
extern int audit_signals;
#else /* CONFIG_AUDITSYSCALL */
static inline int audit_alloc(struct task_struct *task)
@@ -404,7 +405,10 @@ static inline void audit_mmap_fd(int fd, int flags)
{ }
static inline void audit_ptrace(struct task_struct *t)
{ }
-#define audit_n_rules 0
+static inline void audit_inc_n_rules(void)
+{ }
+static inline void audit_dec_n_rules(void)
+{ }
#define audit_signals 0
#endif /* CONFIG_AUDITSYSCALL */
diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
index 14a78cc..4c7054b 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -903,7 +903,7 @@ static inline int audit_add_rule(struct audit_entry *entry)
}
#ifdef CONFIG_AUDITSYSCALL
if (!dont_count)
- audit_n_rules++;
+ audit_inc_n_rules();
if (!audit_match_signal(entry))
audit_signals++;
@@ -955,7 +955,7 @@ static inline int audit_del_rule(struct audit_entry *entry)
#ifdef CONFIG_AUDITSYSCALL
if (!dont_count)
- audit_n_rules--;
+ audit_dec_n_rules();
if (!audit_match_signal(entry))
audit_signals--;
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index 7aef2f4..d76947c 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -80,7 +80,7 @@
#define MAX_EXECVE_AUDIT_LEN 7500
/* number of audit rules */
-int audit_n_rules;
+static int audit_n_rules;
/* determines whether we collect data for signals sent */
int audit_signals;
@@ -911,6 +911,39 @@ static inline struct audit_context *audit_alloc_context(enum audit_state state)
return context;
}
+void audit_inc_n_rules()
+{
+ struct task_struct *p, *t;
+
+ read_lock(&tasklist_lock);
+ audit_n_rules++;
+ smp_wmb();
+ if (audit_n_rules == 1) {
+ /*
+ * We now have a rule; we need to hook syscall entry.
+ */
+ for_each_process_thread(p, t) {
+ if (t->audit_context)
+ set_tsk_thread_flag(t, TIF_SYSCALL_AUDIT);
+ }
+ }
+ read_unlock(&tasklist_lock);
+}
+
+void audit_dec_n_rules()
+{
+ read_lock(&tasklist_lock);
+ --audit_n_rules;
+ BUG_ON(audit_n_rules < 0);
+
+ /*
+ * If audit_n_rules == 0, then __audit_syscall_exit will clear
+ * TIF_SYSCALL_AUDIT.
+ */
+
+ read_unlock(&tasklist_lock);
+}
+
/**
* audit_alloc - allocate an audit context block for a task
* @tsk: task
@@ -938,11 +971,12 @@ int audit_alloc(struct task_struct *tsk)
if (!(context = audit_alloc_context(state))) {
kfree(key);
audit_log_lost("out of memory in audit_alloc");
+ clear_tsk_thread_flag(tsk, TIF_SYSCALL_AUDIT);
return -ENOMEM;
}
context->filterkey = key;
- tsk->audit_context = context;
+ tsk->audit_context = context;
set_tsk_thread_flag(tsk, TIF_SYSCALL_AUDIT);
return 0;
}
@@ -1528,6 +1562,25 @@ void __audit_syscall_exit(int success, long return_code)
context->filterkey = NULL;
}
tsk->audit_context = context;
+
+ if (ACCESS_ONCE(audit_n_rules) == 0) {
+ /*
+ * Either this is the very first syscall by this process or
+ * audit_dec_n_rules recently set audit_n_rules to zero.
+ */
+ smp_rmb();
+
+ /* audit_inc_n_rules could increment audit_n_rules here... */
+
+ clear_tsk_thread_flag(tsk, TIF_SYSCALL_AUDIT);
+
+ smp_rmb();
+
+ if (ACCESS_ONCE(audit_n_rules) != 0) {
+ /* ... if so, set TIF_SYSCALL_AUDIT again. */
+ set_tsk_thread_flag(tsk, TIF_SYSCALL_AUDIT);
+ }
+ }
}
static inline void handle_one(const struct inode *inode)
--
1.8.5.3
10 years, 10 months
[Bisected] CONFIG_AUDIT in linux-3.14-rc1+ breaking Linux Containers?
by Adam Richter
Hi.
If I take an Ubuntu 13.10-amd64 system and install an Ubuntu 13.04-i386 Linux Container, it works fine with kernel.org kernel releases through Linux-3.13, but, for Linux-13.14-rc1 and beyond, I cannot login with "lxc-console". In that case, if I try to log in as "ubuntu" with the correct password, it quickly tell me the login was incorrect, and prompts me with a new "login:" prompt, but without the delay that occurs if I type in the wrong password. I haven't bothered breaking into the "linux container", but, looking at its log files from the outside as it runs, I see some PAM errors about "operation not permitted."
I have reproduced this problem with the following container configurations, all on an
Ubuntu 13.10-amd64 hosts ("amd64" is Ubuntu's terminology, not my jibing Intel):
Ubuntu 13.04-i386
Ubuntu 13.10-i386
Ubuntu 13.10-amd64
I have also reproduced this with a kernel built from git://git.infradead.org/users/eparis/audit.git yesterday (Ubuntu 13.10-amd64 hosting an Ubuntu
13.04-i386 container).
I have also tried disabling CONFIG_AUDIT{SYSCALL,_WATCH,_TREE} and CONFIG_KVM_MMU_AUDIT from linux-3.14-rc2-x86_64 and still observed the same problem.
Doing a "git bisect" on Linus's public tree brought me to the following change (Ubuntu 13.10-x86_64 hosting an Ubuntu 13.04-i386
container):
33faba7fa7f2288d2f8aaea95958b2c97bf9ebfb is the first bad commit
commit 33faba7fa7f2288d2f8aaea95958b2c97bf9ebfb
Author: Richard Guy Briggs <rgb(a)redhat.com>
Date: Tue Jul 16 13:18:45 2013 -0400
audit: listen in all network namespaces
Convert audit from only
listening in init_net to use register_pernet_subsys()
to dynamically manage the netlink socket list.
Signed-off-by: Richard Guy Briggs <rgb(a)redhat.com>
Signed-off-by: Eric Paris <eparis(a)redhat.com>
:040000 040000 3c5f63118d5fe9b5a4f0a6dd828249979a10ffa0 c8feaa4fd9bc260cde3bb703ff20ae6938fabe6a M kernel
For those of you who are not used to using Linux Containers, here are some commands that should reproduce the bug, although I am going from memory rather than copying from my command history.
% sudo lxc-create -t ubuntu -n myubuntu13.04 -- --release raring --arch i386
# ^^ This takes a while. It installs a Linux distribution in a directory.
% sudo lxc-start -n myubuntu13.04 -d
% sudo lxc-console
-n myubuntu13.04
...Try to log in as "ubuntu" with password "ubuntu". When you'd done, do <ctrl-A>q to disconnect the session.
% sudo lxc-stop -n myubuntu13.04
# This next command basically does "rm -rf" on the container's directory tree.
% sudo lxc-destroy -n myubuntu13.04
In the above example, change "raring" to "saucy" if you want Ubuntu 13.10. You can change i386 to amd64 to try 64-bit. "myubuntu13.04" is just a name, which you can change to whatever you want. The Fedora container template shipped with Ubuntu 13.10 does not install for me, otherwise I would have tested that too.
I am not yet sure if this is really a kernel bug or if this is a case of a valid change in Linux kernel behavior exposing a bug elsewhere (for example, Ubuntu's PAM configuration). I am not a Linux Audit developer. I am hoping that, if this is a Linux Audit bug, you folks will be able to take it from here, but I'm happy to try to help as best I
can.
Thanks in advance for any help with this.
Adam
10 years, 10 months
[PATCH v7 1/3] mm: Create utility function for accessing a tasks commandline value
by William Roberts
introduce get_cmdline() for retreiving the value of a processes
proc/self/cmdline value.
Acked-by: David Rientjes <rientjes(a)google.com>
Acked-by: Stephen Smalley <sds(a)tycho.nsa.gov>
Acked-by: Richard Guy Briggs <rgb(a)redhat.com>
Signed-off-by: William Roberts <wroberts(a)tresys.com>
---
include/linux/mm.h | 1 +
mm/util.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 49 insertions(+)
diff --git a/include/linux/mm.h b/include/linux/mm.h
index f28f46e..db89a94 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -1175,6 +1175,7 @@ void account_page_writeback(struct page *page);
int set_page_dirty(struct page *page);
int set_page_dirty_lock(struct page *page);
int clear_page_dirty_for_io(struct page *page);
+int get_cmdline(struct task_struct *task, char *buffer, int buflen);
/* Is the vma a continuation of the stack vma above it? */
static inline int vma_growsdown(struct vm_area_struct *vma, unsigned long addr)
diff --git a/mm/util.c b/mm/util.c
index a24aa22..8122710 100644
--- a/mm/util.c
+++ b/mm/util.c
@@ -445,6 +445,54 @@ unsigned long vm_commit_limit(void)
return allowed;
}
+/**
+ * get_cmdline() - copy the cmdline value to a buffer.
+ * @task: the task whose cmdline value to copy.
+ * @buffer: the buffer to copy to.
+ * @buflen: the length of the buffer. Larger cmdline values are truncated
+ * to this length.
+ * Returns the size of the cmdline field copied. Note that the copy does
+ * not guarantee an ending NULL byte.
+ */
+int get_cmdline(struct task_struct *task, char *buffer, int buflen)
+{
+ int res = 0;
+ unsigned int len;
+ struct mm_struct *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 > buflen)
+ len = buflen;
+
+ res = access_process_vm(task, mm->arg_start, buffer, len, 0);
+
+ /*
+ * 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 < buflen) {
+ len = strnlen(buffer, res);
+ if (len < res) {
+ res = len;
+ } else {
+ len = mm->env_end - mm->env_start;
+ if (len > buflen - res)
+ len = buflen - res;
+ res += access_process_vm(task, mm->env_start,
+ buffer+res, len, 0);
+ res = strnlen(buffer, res);
+ }
+ }
+out_mm:
+ mmput(mm);
+out:
+ return res;
+}
/* Tracepoints definitions. */
EXPORT_TRACEPOINT_SYMBOL(kmalloc);
--
1.7.9.5
10 years, 10 months
[PATCH v5 1/3] mm: Create utility function for accessing a tasks commandline value
by William Roberts
introduce get_cmdline() for retreiving the value of a processes
proc/self/cmdline value.
Acked-by: David Rientjes <rientjes(a)google.com>
Acked-by: Stephen Smalley <sds(a)tycho.nsa.gov>
Signed-off-by: William Roberts <wroberts(a)tresys.com>
---
include/linux/mm.h | 1 +
mm/util.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 49 insertions(+)
diff --git a/include/linux/mm.h b/include/linux/mm.h
index f28f46e..db89a94 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -1175,6 +1175,7 @@ void account_page_writeback(struct page *page);
int set_page_dirty(struct page *page);
int set_page_dirty_lock(struct page *page);
int clear_page_dirty_for_io(struct page *page);
+int get_cmdline(struct task_struct *task, char *buffer, int buflen);
/* Is the vma a continuation of the stack vma above it? */
static inline int vma_growsdown(struct vm_area_struct *vma, unsigned long addr)
diff --git a/mm/util.c b/mm/util.c
index a24aa22..8122710 100644
--- a/mm/util.c
+++ b/mm/util.c
@@ -445,6 +445,54 @@ unsigned long vm_commit_limit(void)
return allowed;
}
+/**
+ * get_cmdline() - copy the cmdline value to a buffer.
+ * @task: the task whose cmdline value to copy.
+ * @buffer: the buffer to copy to.
+ * @buflen: the length of the buffer. Larger cmdline values are truncated
+ * to this length.
+ * Returns the size of the cmdline field copied. Note that the copy does
+ * not guarantee an ending NULL byte.
+ */
+int get_cmdline(struct task_struct *task, char *buffer, int buflen)
+{
+ int res = 0;
+ unsigned int len;
+ struct mm_struct *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 > buflen)
+ len = buflen;
+
+ res = access_process_vm(task, mm->arg_start, buffer, len, 0);
+
+ /*
+ * 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 < buflen) {
+ len = strnlen(buffer, res);
+ if (len < res) {
+ res = len;
+ } else {
+ len = mm->env_end - mm->env_start;
+ if (len > buflen - res)
+ len = buflen - res;
+ res += access_process_vm(task, mm->env_start,
+ buffer+res, len, 0);
+ res = strnlen(buffer, res);
+ }
+ }
+out_mm:
+ mmput(mm);
+out:
+ return res;
+}
/* Tracepoints definitions. */
EXPORT_TRACEPOINT_SYMBOL(kmalloc);
--
1.7.9.5
10 years, 10 months
VERY basic question
by Margaret M Sanders
Hi all. I 've been lurking around, listening for things I can use...but I'm not where you guys are at in terms of auditing. I still have a requirement, however.
So, help me to understand a very basic functioning of Linux (I imagine its basic).
In a standalone system:
How in the world do I capture, create and save human readable reports and then clear audit logs.
Which BASIC /var/log should every accidental sysad (like myself) be capturing?
I know where to put the audit rules, but at this point, I'm just sort of following instructions for that without any real sense of understanding. The farthest I've gotten is -w means watch.
If you guys would take a moment to ask such a rudimentary question, I might be able to move past go.
Thank you for your time.
Margaret M. Sanders
SwRI ISSO/ATA
10 years, 10 months