* David Woodhouse (dwmw2(a)infradead.org) wrote:
On Wed, 2005-03-16 at 18:13 -0800, Chris Wright wrote:
> +/* distinguish syscall tables */
> +#define AUDIT_ARCH_IA32 0
> +#define AUDIT_ARCH_X86_64 1
> +#define AUDIT_ARCH_IA64 2
> +#define AUDIT_ARCH_PPC 3
> +#define AUDIT_ARCH_PPC64 4
> +#define AUDIT_ARCH_MIPS 5
I really don't like making up a new centralised number space for these.
So much so that I almost suggested using strings. I don't like the cost
of filtering on those though. Let's compromise and use existing numbers,
like the ELF machine types.
Ah yes, much better plan.
This is the patch from my audit.15 kernel which should be turning up
shortly. We finish the arch identifiers, fix the ptrace/audit ordering
problem, fix the return code of syscalls to be 'long', and use an
explicit success/failure flag on architectures where that's conveyed
separately from the return code.
Nice cleanup.
I also stopped logging the arch for a second time in syscall exit.
Agreed, I see no reason to keep it (was never triggered in a meaningful
way in my limited testing). BTW, what about arch/um?
--- linux-2.6.9/kernel/auditsc.c.auditarch 2005-03-18
14:13:01.000000000 +0000
+++ linux-2.6.9/kernel/auditsc.c 2005-03-22 14:28:14.095999744 +0000
@@ -124,7 +124,7 @@ struct audit_context {
int major; /* syscall number */
unsigned long argv[4]; /* syscall arguments */
int return_valid; /* return code is valid */
- int return_code;/* syscall return code */
+ long return_code;/* syscall return code */
int auditable; /* 1 if record should be written */
int name_count;
struct audit_names names[AUDIT_NAMES];
@@ -136,6 +136,7 @@ struct audit_context {
uid_t uid, euid, suid, fsuid;
gid_t gid, egid, sgid, fsgid;
unsigned long personality;
+ int arch;
struct list_head wtrail; /* The list of watched files/dirs that were
* accessed and determined to be valid and
* unfiltered in this audit_context
@@ -372,6 +373,10 @@ static int audit_filter_rules(struct tas
case AUDIT_PERS:
result = (tsk->personality == value);
break;
+ case AUDIT_ARCH:
+ if (ctx)
+ result = (ctx->arch == value);
+ break;
case AUDIT_EXIT:
if (ctx && ctx->return_valid)
@@ -379,7 +384,7 @@ static int audit_filter_rules(struct tas
break;
case AUDIT_SUCCESS:
if (ctx && ctx->return_valid)
- result = (ctx->return_code >= 0);
+ result = (ctx->return_valid == AUDITSC_SUCCESS);
break;
case AUDIT_DEVMAJOR:
if (ctx) {
@@ -679,8 +684,11 @@ static void audit_log_exit(struct audit_
audit_log_format(ab, "syscall=%d", context->major);
if (context->personality != PER_LINUX)
audit_log_format(ab, " per=%lx", context->personality);
+ audit_log_format(ab, " arch=%d", context->arch);
if (context->return_valid)
- audit_log_format(ab, " exit=%d", context->return_code);
+ audit_log_format(ab, " success=%s exit=%ld",
+ (context->return_valid==AUDITSC_SUCCESS)?"yes":"no",
Kinda surprised to see a string as opposed to decimal value, but
it also doesn't really matter ;-)
+ context->return_code);
audit_log_format(ab,
" a0=%lx a1=%lx a2=%lx a3=%lx items=%d"
" pid=%d loginuid=%d uid=%d gid=%d"
@@ -821,7 +829,7 @@ static inline unsigned int audit_serial(
* then the record will be written at syscall exit time (otherwise, it
* will only be written if another part of the kernel requests that it
* be written). */
-void audit_syscall_entry(struct task_struct *tsk, int major,
+void audit_syscall_entry(struct task_struct *tsk, int arch, int major,
unsigned long a1, unsigned long a2,
unsigned long a3, unsigned long a4)
{
@@ -875,6 +883,7 @@ void audit_syscall_entry(struct task_str
if (!audit_enabled)
return;
+ context->arch = arch;
context->major = major;
context->argv[0] = a1;
context->argv[1] = a2;
@@ -898,13 +907,13 @@ void audit_syscall_entry(struct task_str
* filtering, or because some other part of the kernel write an audit
* message), then write out the syscall information. In call cases,
* free the names stored from getname(). */
-void audit_syscall_exit(struct task_struct *tsk, int return_code)
+void audit_syscall_exit(struct task_struct *tsk, int valid, long return_code)
{
struct audit_context *context;
get_task_struct(tsk);
task_lock(tsk);
- context = audit_get_context(tsk, 1, return_code);
+ context = audit_get_context(tsk, valid, return_code);
task_unlock(tsk);
/* Not having a context here is ok, since the parent may have
@@ -917,6 +926,7 @@ void audit_syscall_exit(struct task_stru
context->in_syscall = 0;
context->auditable = 0;
+
if (context->previous) {
struct audit_context *new_context = context->previous;
context->previous = NULL;
--- linux-2.6.9/arch/s390/kernel/ptrace.c.auditarch 2004-10-18 22:55:07.000000000 +0100
+++ linux-2.6.9/arch/s390/kernel/ptrace.c 2005-03-22 14:25:23.251013360 +0000
@@ -707,18 +707,13 @@ out:
asmlinkage void
syscall_trace(struct pt_regs *regs, int entryexit)
{
- if (unlikely(current->audit_context)) {
- if (!entryexit)
- audit_syscall_entry(current, regs->gprs[2],
- regs->orig_gpr2, regs->gprs[3],
- regs->gprs[4], regs->gprs[5]);
- else
- audit_syscall_exit(current, regs->gprs[2]);
- }
+ if (unlikely(current->audit_context) && entryexit)
+ audit_syscall_exit(current, AUDITSC_RESULT(regs->gprs[2]), regs->gprs[2]);
+
if (!test_thread_flag(TIF_SYSCALL_TRACE))
- return;
+ goto out;
if (!(current->ptrace & PT_PTRACED))
- return;
+ goto out;
ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
? 0x80 : 0));
@@ -731,4 +726,10 @@ syscall_trace(struct pt_regs *regs, int
send_sig(current->exit_code, current, 1);
current->exit_code = 0;
}
+ out:
+ if (unlikely(current->audit_context) && !entryexit)
+ audit_syscall_entry(current,
+ test_thread_flag(TIF_31BIT)?AUDIT_ARCH_S390:AUDIT_ARCH_S390X,
+ regs->gprs[2], regs->orig_gpr2, regs->gprs[3],
+ regs->gprs[4], regs->gprs[5]);
}
--- linux-2.6.9/arch/ppc64/kernel/ptrace.c.auditarch 2005-03-18 14:13:01.000000000 +0000
+++ linux-2.6.9/arch/ppc64/kernel/ptrace.c 2005-03-22 14:25:23.215018832 +0000
@@ -303,20 +303,24 @@ static void do_syscall_trace(void)
void do_syscall_trace_enter(struct pt_regs *regs)
{
+ if (test_thread_flag(TIF_SYSCALL_TRACE)
+ && (current->ptrace & PT_PTRACED))
+ do_syscall_trace();
+
if (unlikely(current->audit_context))
- audit_syscall_entry(current, regs->gpr[0],
+ audit_syscall_entry(current,
+ test_thread_flag(TIF_32BIT)?AUDIT_ARCH_PPC:AUDIT_ARCH_PPC64,
+ regs->gpr[0],
regs->gpr[3], regs->gpr[4],
regs->gpr[5], regs->gpr[6]);
-
- if (test_thread_flag(TIF_SYSCALL_TRACE)
- && (current->ptrace & PT_PTRACED))
- do_syscall_trace();
}
void do_syscall_trace_leave(struct pt_regs *regs)
{
if (unlikely(current->audit_context))
- audit_syscall_exit(current, regs->result);
+ audit_syscall_exit(current,
+ (regs->ccr&0x1000)?AUDITSC_FAILURE:AUDITSC_SUCCESS,
+ regs->result);
if ((test_thread_flag(TIF_SYSCALL_TRACE)
|| test_thread_flag(TIF_SINGLESTEP))
--- linux-2.6.9/arch/x86_64/kernel/ptrace.c.auditarch 2004-10-18 22:53:46.000000000
+0100
+++ linux-2.6.9/arch/x86_64/kernel/ptrace.c 2005-03-22 14:34:51.447034792 +0000
@@ -517,22 +517,27 @@ static void syscall_trace(struct pt_regs
}
}
+#define audit_arch() \
+ (test_thread_flag(TIF_IA32) ? AUDIT_ARCH_I386 : AUDIT_ARCH_X86_64)
+
asmlinkage void syscall_trace_enter(struct pt_regs *regs)
{
+ if (test_thread_flag(TIF_SYSCALL_TRACE)
+ && (current->ptrace & PT_PTRACED))
+ syscall_trace(regs);
+
if (unlikely(current->audit_context))
- audit_syscall_entry(current, regs->orig_rax,
+ audit_syscall_entry(current, audit_arch(), regs->orig_rax,
regs->rdi, regs->rsi,
regs->rdx, regs->r10);
- if (test_thread_flag(TIF_SYSCALL_TRACE)
- && (current->ptrace & PT_PTRACED))
- syscall_trace(regs);
}
asmlinkage void syscall_trace_leave(struct pt_regs *regs)
{
if (unlikely(current->audit_context))
- audit_syscall_exit(current, regs->rax);
+ audit_syscall_exit(current, AUDITSC_RESULT(regs->rax),
+ regs->rax);
if ((test_thread_flag(TIF_SYSCALL_TRACE)
|| test_thread_flag(TIF_SINGLESTEP))
--- linux-2.6.9/arch/mips/kernel/ptrace.c.auditarch 2004-10-18 22:55:36.000000000 +0100
+++ linux-2.6.9/arch/mips/kernel/ptrace.c 2005-03-22 14:39:32.757005608 +0000
@@ -305,19 +305,13 @@ out:
*/
asmlinkage void do_syscall_trace(struct pt_regs *regs, int entryexit)
{
- if (unlikely(current->audit_context)) {
- if (!entryexit)
- audit_syscall_entry(current, regs->orig_eax,
- regs->regs[4], regs->regs[5],
- regs->regs[6], regs->regs[7]);
- else
- audit_syscall_exit(current, regs->regs[2]);
- }
+ if (unlikely(current->audit_context) && entryexit)
+ audit_syscall_exit(current, AUDITSC_RESULT(regs->regs[2]), regs->regs[2]);
if (!test_thread_flag(TIF_SYSCALL_TRACE))
- return;
+ goto out;
if (!(current->ptrace & PT_PTRACED))
- return;
+ goto out;
/* The 0x80 provides a way for the tracing parent to distinguish
between a syscall stop and SIGTRAP delivery */
@@ -333,4 +327,9 @@ asmlinkage void do_syscall_trace(struct
send_sig(current->exit_code, current, 1);
current->exit_code = 0;
}
+ out:
+ if (unlikely(current->audit_context) && )
Woops, lost !entryexit
+ audit_syscall_entry(current, audit_arch(), regs->orig_eax,
+ regs->regs[4], regs->regs[5],
+ regs->regs[6], regs->regs[7]);
}
--- linux-2.6.9/arch/i386/kernel/ptrace.c.auditarch 2004-10-18 22:53:45.000000000 +0100
+++ linux-2.6.9/arch/i386/kernel/ptrace.c 2005-03-22 14:30:39.853075920 +0000
@@ -530,20 +530,14 @@ out:
__attribute__((regparm(3)))
void do_syscall_trace(struct pt_regs *regs, int entryexit)
{
- if (unlikely(current->audit_context)) {
- if (!entryexit)
- audit_syscall_entry(current, regs->orig_eax,
- regs->ebx, regs->ecx,
- regs->edx, regs->esi);
- else
- audit_syscall_exit(current, regs->eax);
- }
+ if (unlikely(current->audit_context) && entryexit)
+ audit_syscall_exit(current, AUDITSC_RESULT(regs->eax), regs->eax);
if (!test_thread_flag(TIF_SYSCALL_TRACE) &&
!test_thread_flag(TIF_SINGLESTEP))
- return;
+ goto out;
if (!(current->ptrace & PT_PTRACED))
- return;
+ goto out;
/* the 0x80 provides a way for the tracing parent to distinguish
between a syscall stop and SIGTRAP delivery */
ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD) &&
@@ -558,4 +552,9 @@ void do_syscall_trace(struct pt_regs *re
send_sig(current->exit_code, current, 1);
current->exit_code = 0;
}
+ out:
+ if (unlikely(current->audit_context) && !entryexit)
+ audit_syscall_entry(current, AUDIT_ARCH_I386, regs->orig_eax,
+ regs->ebx, regs->ecx, regs->edx, regs->esi);
+
}
--- linux-2.6.9/arch/ia64/kernel/ptrace.c.auditarch 2004-10-18 22:55:29.000000000 +0100
+++ linux-2.6.9/arch/ia64/kernel/ptrace.c 2005-03-22 14:38:02.299044824 +0000
@@ -17,6 +17,7 @@
#include <linux/smp_lock.h>
#include <linux/user.h>
#include <linux/security.h>
+#include <linux/audit.h>
#include <asm/pgtable.h>
#include <asm/processor.h>
@@ -1511,17 +1511,22 @@ syscall_trace_enter (long arg0, long arg
struct pt_regs *regs = (struct pt_regs *) &stack;
long syscall;
+ if (test_thread_flag(TIF_SYSCALL_TRACE) && (current->ptrace &
PT_PTRACED))
+ syscall_trace();
+
if (unlikely(current->audit_context)) {
- if (IS_IA32_PROCESS(regs))
+ int arch;
+
+ if (IS_IA32_PROCESS(regs)) {
syscall = regs->r1;
- else
+ arch = AUDIT_ARCH_I386;
+ } else {
syscall = regs->r15;
-
- audit_syscall_entry(current, syscall, arg0, arg1, arg2, arg3);
+ arch = AUDIT_ARCH_IA64;
+ }
+ audit_syscall_entry(current, arch, syscall, arg0, arg1, arg2, arg3);
}
- if (test_thread_flag(TIF_SYSCALL_TRACE) && (current->ptrace &
PT_PTRACED))
- syscall_trace();
}
/* "asmlinkage" so the input arguments are preserved... */
@@ -1530,7 +1535,9 @@ syscall_trace_leave (long arg0, long arg
long arg4, long arg5, long arg6, long arg7, long stack)
{
if (unlikely(current->audit_context))
- audit_syscall_exit(current, ((struct pt_regs *) &stack)->r8);
+ audit_syscall_exit(current,
+ AUDITSC_RESULT(((struct pt_regs *) &stack)->r8),
+ ((struct pt_regs *) &stack)->r8);
if (test_thread_flag(TIF_SYSCALL_TRACE) && (current->ptrace &
PT_PTRACED))
syscall_trace();
--- linux-2.6.9/include/linux/audit.h.auditarch 2005-03-18 14:13:01.000000000 +0000
+++ linux-2.6.9/include/linux/audit.h 2005-03-22 14:46:49.005983264 +0000
@@ -28,6 +28,8 @@
#include <linux/list.h>
#include <linux/spinlock.h>
#include <asm/atomic.h>
+#include <linux/sched.h>
+#include <linux/elf.h>
#endif
/* Request and reply types */
@@ -75,6 +77,7 @@
#define AUDIT_FSGID 8
#define AUDIT_LOGINUID 9
#define AUDIT_PERS 10
+#define AUDIT_ARCH 11
/* These are ONLY useful when checking
* at syscall exit time (AUDIT_AT_EXIT). */
@@ -108,6 +111,38 @@
/* 32 byte max key size */
#define AUDIT_FILTERKEY_MAX 32
+/* distinguish syscall tables */
+#define __AUDIT_ARCH_64BIT 0x80000000
+#define __AUDIT_ARCH_LE 0x40000000
+#define AUDIT_ARCH_ALPHA (EM_ALPHA|__AUDIT_ARCH_64BIT|__AUDIT_ARCH_LE)
+#define AUDIT_ARCH_ARM (EM_ARM|__AUDIT_ARCH_LE)
+#define AUDIT_ARCH_ARMEB (EM_ARM)
+#define AUDIT_ARCH_CRIS (EM_CRIS|__AUDIT_ARCH_LE)
+#define AUDIT_ARCH_FRV (EM_FRV)
+#define AUDIT_ARCH_H8300 (EM_H8_300)
+#define AUDIT_ARCH_I386 (EM_386|__AUDIT_ARCH_LE)
+#define AUDIT_ARCH_IA64 (EM_IA_64|__AUDIT_ARCH_64BIT|__AUDIT_ARCH_LE)
+#define AUDIT_ARCH_M32R (EM_M32R)
+#define AUDIT_ARCH_M68K (EM_68K)
+#define AUDIT_ARCH_MIPS (EM_MIPS)
+#define AUDIT_ARCH_MIPSEL (EM_MIPS|__AUDIT_ARCH_LE)
+#define AUDIT_ARCH_MIPS64 (EM_MIPS|__AUDIT_ARCH_64BIT)
+#define AUDIT_ARCH_MIPSEL64 (EM_MIPS|__AUDIT_ARCH_64BIT|__AUDIT_ARCH_LE)
+#define AUDIT_ARCH_PARISC (EM_PARISC)
+#define AUDIT_ARCH_PARISC64 (EM_PARISC|__AUDIT_ARCH_64BIT)
+#define AUDIT_ARCH_PPC (EM_PPC)
+#define AUDIT_ARCH_PPC64 (EM_PPC64|__AUDIT_ARCH_64BIT)
+#define AUDIT_ARCH_S390 (EM_S390)
+#define AUDIT_ARCH_S390X (EM_S390|__AUDIT_ARCH_64BIT)
+#define AUDIT_ARCH_SH (EM_SH)
+#define AUDIT_ARCH_SHEL (EM_SH|__AUDIT_ARCH_LE)
+#define AUDIT_ARCH_SH64 (EM_SH|__AUDIT_ARCH_64BIT)
+#define AUDIT_ARCH_SHEL64 (EM_SH|__AUDIT_ARCH_64BIT|__AUDIT_ARCH_LE)
+#define AUDIT_ARCH_SPARC (EM_SPARC)
+#define AUDIT_ARCH_SPARC64 (EM_SPARC64|__AUDIT_ARCH_64BIT)
+#define AUDIT_ARCH_V850 (EM_V850|__AUDIT_ARCH_LE)
+#define AUDIT_ARCH_X86_64 (EM_X86_64|__AUDIT_ARCH_64BIT|__AUDIT_ARCH_LE)
Heh, now we have to get audit support in all those extra arches ;-)
+
#ifndef __KERNEL__
struct audit_message {
struct nlmsghdr nlh;
@@ -164,15 +199,19 @@ struct audit_buffer;
struct audit_context;
struct inode;
+#define AUDITSC_INVALID 0
+#define AUDITSC_SUCCESS 1
+#define AUDITSC_FAILURE 2
+#define AUDITSC_RESULT(x) ( ((long)(x))<0?AUDITSC_FAILURE:AUDITSC_SUCCESS )
#ifdef CONFIG_AUDITSYSCALL
/* These are defined in auditsc.c */
/* Public API */
extern int audit_alloc(struct task_struct *task);
extern void audit_free(struct task_struct *task);
-extern void audit_syscall_entry(struct task_struct *task,
+extern void audit_syscall_entry(struct task_struct *task, int table,
int major, unsigned long a0, unsigned long a1,
unsigned long a2, unsigned long a3);
-extern void audit_syscall_exit(struct task_struct *task, int return_code);
+extern void audit_syscall_exit(struct task_struct *task, int failed, long return_code);
extern void audit_getname(const char *name);
extern void audit_putname(const char *name);
extern void audit_inode(const char *name, const struct inode *inode);
@@ -188,8 +227,8 @@ extern int audit_ipc_perms(unsigned long
#else
#define audit_alloc(t) ({ 0; })
#define audit_free(t) do { ; } while (0)
-#define audit_syscall_entry(t,a,b,c,d,e) do { ; } while (0)
-#define audit_syscall_exit(t,r) do { ; } while (0)
+#define audit_syscall_entry(t,ta,a,b,c,d,e) do { ; } while (0)
+#define audit_syscall_exit(t,ta,r) do { ; } while (0)
Insignificant nits for audit_syscall_exit() ...s/ta/f/ And, might as
well use 'arch' across the board for audit_syscall_entry().
#define audit_getname(n) do { ; } while (0)
#define audit_putname(n) do { ; } while (0)
#define audit_inode(n,i) do { ; } while (0)