[PATCH] per arch syscall info

Chris Wright chrisw at osdl.org
Tue Mar 22 18:07:58 UTC 2005


* David Woodhouse (dwmw2 at 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)




More information about the Linux-audit mailing list