All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Paul E. McKenney" <paulmck@us.ibm.com>
To: Rik Faith <faith@redhat.com>
Cc: Andrew Morton <akpm@osdl.org>, linux-kernel@vger.kernel.org
Subject: Re: [PATCH] Light-weight Auditing Framework
Date: Wed, 24 Mar 2004 19:01:08 -0800	[thread overview]
Message-ID: <20040325030108.GI1301@us.ibm.com> (raw)
In-Reply-To: <16480.42052.58724.753984@neuro.alephnull.com>

Looks good to me from an RCU viewpoint!

						Thanx, Paul

On Tue, Mar 23, 2004 at 03:55:32PM -0500, Rik Faith wrote:
> On Wed 17 Mar 2004 16:45:02 -0800,
>    Paul E. McKenney <paulmck@us.ibm.com> wrote:
> > On Wed, Mar 17, 2004 at 04:14:04AM -0500, Rik Faith wrote:
> > > On Fri 12 Mar 2004 10:50:33 -0800,
> > >    Paul E. McKenney <paulmck@us.ibm.com> wrote:
> > > > o	I don't see any rcu_read_lock() or rcu_read_unlock() calls.
> > > 
> > > Fixed.
> > 
> > Much improved!
> > 
> > Since audit_receive_filter() is only called with audit_netlink_sem
> > held, it cannot race with either audit_del_rule() or audit_add_rule(),
> > so the list_for_each_entry_rcu()s may be replaced by
> > list_for_each_entry()s, and the rcu_read_{un,}lock()s removed.
> > 
> > Not a fatal problem, just a bit of unnecessary overhead.
> 
> A fix for this is part of the attached patch.
> 
> Other features of the attached patch are:
>     1) generalized the ability to test for inequality
>     2) added syscall exit status reporting and testing
>     3) added ability to report and test first 4 syscall arguments
>        (this adds a large amount of flexibility for little cost;
>        not implemented or tested on ppc64)
>     4) added ability to report and test personality
> 
> User-space demo program enhanced for new fields and inequality testing:
> http://people.redhat.com/faith/audit/auditd-0.5.tar.gz
> 
> 
> This patch is against 2.6.5-rc2, but also applies against 2.6.5-rc2-mm1.
> 
>  arch/i386/kernel/ptrace.c   |    5 -
>  arch/ppc64/kernel/ptrace.c  |    6 +
>  arch/x86_64/kernel/ptrace.c |   11 +-
>  include/linux/audit.h       |   19 +++-
>  kernel/auditsc.c            |  170 ++++++++++++++++++++++++++------------------
>  5 files changed, 126 insertions(+), 85 deletions(-)
> 
> 
> diff -rupP --exclude-from=ignore linux-2.6.4-pristine/arch/i386/kernel/ptrace.c linux-2.6.4/arch/i386/kernel/ptrace.c
> --- linux-2.6.4-pristine/arch/i386/kernel/ptrace.c	2004-03-23 15:08:10.000000000 -0500
> +++ linux-2.6.4/arch/i386/kernel/ptrace.c	2004-03-23 15:37:41.000000000 -0500
> @@ -528,9 +528,10 @@ void do_syscall_trace(struct pt_regs *re
>  	if (unlikely(current->audit_context)) {
>  		if (!entryexit)
>  			audit_syscall_entry(current, regs->orig_eax,
> -					    regs->ebx);
> +					    regs->ebx, regs->ecx,
> +					    regs->edx, regs->esi);
>  		else
> -			audit_syscall_exit(current);
> +			audit_syscall_exit(current, regs->eax);
>  	}
>  
>  	if (!test_thread_flag(TIF_SYSCALL_TRACE))
> diff -rupP --exclude-from=ignore linux-2.6.4-pristine/arch/ppc64/kernel/ptrace.c linux-2.6.4/arch/ppc64/kernel/ptrace.c
> --- linux-2.6.4-pristine/arch/ppc64/kernel/ptrace.c	2004-03-23 15:08:10.000000000 -0500
> +++ linux-2.6.4/arch/ppc64/kernel/ptrace.c	2004-03-23 15:37:38.000000000 -0500
> @@ -308,7 +308,9 @@ static void do_syscall_trace(void)
>  void do_syscall_trace_enter(struct pt_regs *regs)
>  {
>  	if (unlikely(current->audit_context))
> -		audit_syscall_entry(current, regs->gpr[0], regs->gpr[3]);
> +		audit_syscall_entry(current, 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))
> @@ -318,7 +320,7 @@ void do_syscall_trace_enter(struct pt_re
>  void do_syscall_trace_leave(void)
>  {
>  	if (unlikely(current->audit_context))
> -		audit_syscall_exit(current);
> +		audit_syscall_exit(current, 0);	/* FIXME: pass pt_regs */
>  
>  	if (test_thread_flag(TIF_SYSCALL_TRACE)
>  	    && (current->ptrace & PT_PTRACED))
> diff -rupP --exclude-from=ignore linux-2.6.4-pristine/arch/x86_64/kernel/ptrace.c linux-2.6.4/arch/x86_64/kernel/ptrace.c
> --- linux-2.6.4-pristine/arch/x86_64/kernel/ptrace.c	2004-03-23 15:08:10.000000000 -0500
> +++ linux-2.6.4/arch/x86_64/kernel/ptrace.c	2004-03-23 15:37:42.000000000 -0500
> @@ -497,11 +497,6 @@ static void syscall_trace(struct pt_regs
>  	       current_thread_info()->flags, current->ptrace); 
>  #endif
>  
> -	if (!test_thread_flag(TIF_SYSCALL_TRACE))
> -		return; 
> -	if (!(current->ptrace & PT_PTRACED))
> -		return;
> -	
>  	ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
>  				? 0x80 : 0));
>  	/*
> @@ -518,7 +513,9 @@ static void syscall_trace(struct pt_regs
>  asmlinkage void syscall_trace_enter(struct pt_regs *regs)
>  {
>  	if (unlikely(current->audit_context))
> -		audit_syscall_entry(current, regs->orig_rax, regs->rdi);
> +		audit_syscall_entry(current, regs->orig_rax,
> +				    regs->rdi, regs->rsi,
> +				    regs->rdx, regs->r10);
>  
>  	if (test_thread_flag(TIF_SYSCALL_TRACE)
>  	    && (current->ptrace & PT_PTRACED))
> @@ -528,7 +525,7 @@ asmlinkage void syscall_trace_enter(stru
>  asmlinkage void syscall_trace_leave(struct pt_regs *regs)
>  {
>  	if (unlikely(current->audit_context))
> -		audit_syscall_exit(current);
> +		audit_syscall_exit(current, regs->rax);
>  
>  	if (test_thread_flag(TIF_SYSCALL_TRACE)
>  	    && (current->ptrace & PT_PTRACED))
> diff -rupP --exclude-from=ignore linux-2.6.4-pristine/include/linux/audit.h linux-2.6.4/include/linux/audit.h
> --- linux-2.6.4-pristine/include/linux/audit.h	2004-03-23 15:08:10.000000000 -0500
> +++ linux-2.6.4/include/linux/audit.h	2004-03-23 15:09:58.000000000 -0500
> @@ -66,6 +66,7 @@
>  #define AUDIT_SGID	7
>  #define AUDIT_FSGID	8
>  #define AUDIT_LOGINUID	9
> +#define AUDIT_PERS	10
>  
>  				/* These are ONLY useful when checking
>  				 * at syscall exit time (AUDIT_AT_EXIT). */
> @@ -73,7 +74,14 @@
>  #define AUDIT_DEVMINOR	101
>  #define AUDIT_INODE	102
>  #define AUDIT_EXIT	103
> -#define AUDIT_NOTEXIT	104
> +#define AUDIT_SUCCESS   104	/* exit >= 0; value ignored */
> +
> +#define AUDIT_ARG0      200
> +#define AUDIT_ARG1      (AUDIT_ARG0+1)
> +#define AUDIT_ARG2      (AUDIT_ARG0+2)
> +#define AUDIT_ARG3      (AUDIT_ARG0+3)
> +
> +#define AUDIT_NEGATE    0x80000000
>  
>  
>  /* Status symbols */
> @@ -134,8 +142,9 @@ struct audit_context;
>  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,
> -				int major, int minor);
> -extern void audit_syscall_exit(struct task_struct *task);
> +				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_getname(const char *name);
>  extern void audit_putname(const char *name);
>  extern void audit_inode(const char *name, unsigned long ino, dev_t rdev);
> @@ -149,8 +158,8 @@ extern int  audit_set_loginuid(struct au
>  #else
>  #define audit_alloc(t) ({ 0; })
>  #define audit_free(t) do { ; } while (0)
> -#define audit_syscall_entry(t,a,b) do { ; } while (0)
> -#define audit_syscall_exit(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_getname(n) do { ; } while (0)
>  #define audit_putname(n) do { ; } while (0)
>  #define audit_inode(n,i,d) do { ; } while (0)
> diff -rupP --exclude-from=ignore linux-2.6.4-pristine/kernel/auditsc.c linux-2.6.4/kernel/auditsc.c
> --- linux-2.6.4-pristine/kernel/auditsc.c	2004-03-23 15:08:10.000000000 -0500
> +++ linux-2.6.4/kernel/auditsc.c	2004-03-23 15:38:48.000000000 -0500
> @@ -99,7 +99,9 @@ struct audit_context {
>  	struct timespec	    ctime;      /* time of syscall entry */
>  	uid_t		    loginuid;   /* login uid (identity) */
>  	int		    major;      /* syscall number */
> -	int		    minor;      /* function for multiplex syscalls */
> +	unsigned long	    argv[4];    /* syscall arguments */
> +	int		    return_valid; /* return code is valid */
> +	int		    return_code;/* syscall return code */
>  	int		    auditable;  /* 1 if record should be written */
>  	int		    name_count;
>  	struct audit_names  names[AUDIT_NAMES];
> @@ -109,6 +111,7 @@ struct audit_context {
>  	pid_t		    pid;
>  	uid_t		    uid, euid, suid, fsuid;
>  	gid_t		    gid, egid, sgid, fsgid;
> +	unsigned long	    personality;
>  
>  #if AUDIT_DEBUG
>  	int		    put_count;
> @@ -231,17 +234,17 @@ int audit_receive_filter(int type, int p
>  
>  	switch (type) {
>  	case AUDIT_LIST:
> -		rcu_read_lock();
> -		list_for_each_entry_rcu(entry, &audit_tsklist, list)
> +		/* The *_rcu iterators not needed here because we are
> +		   always called with audit_netlink_sem held. */ 
> +		list_for_each_entry(entry, &audit_tsklist, list)
>  			audit_send_reply(pid, seq, AUDIT_LIST, 0, 1,
>  					 &entry->rule, sizeof(entry->rule));
> -		list_for_each_entry_rcu(entry, &audit_entlist, list)
> +		list_for_each_entry(entry, &audit_entlist, list)
>  			audit_send_reply(pid, seq, AUDIT_LIST, 0, 1,
>  					 &entry->rule, sizeof(entry->rule));
> -		list_for_each_entry_rcu(entry, &audit_extlist, list)
> +		list_for_each_entry(entry, &audit_extlist, list)
>  			audit_send_reply(pid, seq, AUDIT_LIST, 0, 1,
>  					 &entry->rule, sizeof(entry->rule));
> -		rcu_read_unlock();
>  		audit_send_reply(pid, seq, AUDIT_LIST, 1, 1, NULL, 0);
>  		break;
>  	case AUDIT_ADD:
> @@ -286,94 +289,100 @@ static int audit_filter_rules(struct tas
>  			      enum audit_state *state)
>  {
>  	int i, j;
> -	int found;
>  
>  	for (i = 0; i < rule->field_count; i++) {
> -		u32 value = rule->values[i];
> +		u32 field  = rule->fields[i] & ~AUDIT_NEGATE;
> +		u32 value  = rule->values[i];
> +		int result = 0;
>  
> -		switch (rule->fields[i]) {
> +		switch (field) {
>  		case AUDIT_PID:
> -			if (tsk->pid   != value)
> -				return 0;
> +			result = (tsk->pid == value);
>  			break;
>  		case AUDIT_UID:
> -			if (tsk->uid   != value)
> -				return 0;
> +			result = (tsk->uid == value);
>  			break;
>  		case AUDIT_EUID:
> -			if (tsk->euid  != value)
> -				return 0;
> +			result = (tsk->euid == value);
>  			break;
>  		case AUDIT_SUID:
> -			if (tsk->suid  != value)
> -				return 0;
> +			result = (tsk->suid == value);
>  			break;
>  		case AUDIT_FSUID:
> -			if (tsk->fsuid != value)
> -				return 0;
> +			result = (tsk->fsuid == value);
>  			break;
>  		case AUDIT_GID:
> -			if (tsk->gid   != value)
> -				return 0;
> +			result = (tsk->gid == value);
>  			break;
>  		case AUDIT_EGID:
> -			if (tsk->egid  != value)
> -				return 0;
> +			result = (tsk->egid == value);
>  			break;
>  		case AUDIT_SGID:
> -			if (tsk->sgid  != value)
> -				return 0;
> +			result = (tsk->sgid == value);
>  			break;
>  		case AUDIT_FSGID:
> -			if (tsk->fsgid != value)
> -				return 0;
> +			result = (tsk->fsgid == value);
>  			break;
> +		case AUDIT_PERS:
> +			result = (tsk->personality == value);
> +			break;
> +
>  		case AUDIT_EXIT:
> -			if (tsk->exit_code!=value)
> -				return 0;
> +			if (ctx && ctx->return_valid)
> +				result = (ctx->return_code == value);
>  			break;
> -		case AUDIT_NOTEXIT:
> -			if (tsk->exit_code==value)
> -				return 0;
> +		case AUDIT_SUCCESS:
> +			if (ctx && ctx->return_valid)
> +				result = (ctx->return_code >= 0);
>  			break;
>  		case AUDIT_DEVMAJOR:
> -			if (!ctx)
> -				return 0;
> -			found = 0;
> -			for (j = 0; !found && j < ctx->name_count; j++) {
> -				if (MAJOR(ctx->names[j].rdev) == value)
> -					++found;
> +			if (ctx) {
> +				for (j = 0; j < ctx->name_count; j++) {
> +					if (MAJOR(ctx->names[j].rdev)==value) {
> +						++result;
> +						break;
> +					}
> +				}
>  			}
> -			if (!found)
> -				return 0;
>  			break;
>  		case AUDIT_DEVMINOR:
> -			if (!ctx)
> -				return 0;
> -			found = 0;
> -			for (j = 0; !found && j < ctx->name_count; j++) {
> -				if (MINOR(ctx->names[j].rdev) == value)
> -					++found;
> +			if (ctx) {
> +				for (j = 0; j < ctx->name_count; j++) {
> +					if (MINOR(ctx->names[j].rdev)==value) {
> +						++result;
> +						break;
> +					}
> +				}
>  			}
> -			if (!found)
> -				return 0;
>  			break;
>  		case AUDIT_INODE:
> -			if (!ctx)
> -				return 0;
> -			found = 0;
> -			for (j = 0; !found && j < ctx->name_count; j++) {
> -				if (ctx->names[j].ino == value)
> -					++found;
> +			if (ctx) {
> +				for (j = 0; j < ctx->name_count; j++) {
> +					if (MINOR(ctx->names[j].ino)==value) {
> +						++result;
> +						break;
> +					}
> +				}
>  			}
> -			if (!found)
> -				return 0;
>  			break;
>  		case AUDIT_LOGINUID:
> -			if (!ctx || ctx->loginuid != value)
> -				return 0;
> +			result = 0;
> +			if (ctx)
> +				result = (ctx->loginuid == value);
> +			break;
> +		case AUDIT_ARG0:
> +		case AUDIT_ARG1:
> +		case AUDIT_ARG2:
> +		case AUDIT_ARG3:
> +			if (ctx)
> +				result = (ctx->argv[field-AUDIT_ARG0]==value);
>  			break;
>  		}
> +
> +		if (rule->fields[i] & AUDIT_NEGATE)
> +			result = !result;
> +		if (!result)
> +			return 0;
>  	}
>  	switch (rule->action) {
>  	case AUDIT_NEVER:    *state = AUDIT_DISABLED;	    break;
> @@ -430,12 +439,17 @@ static enum audit_state audit_filter_sys
>  }
>  
>  /* This should be called with task_lock() held. */
> -static inline struct audit_context *audit_get_context(struct task_struct *tsk)
> +static inline struct audit_context *audit_get_context(struct task_struct *tsk,
> +						      int return_valid,
> +						      int return_code)
>  {
>  	struct audit_context *context = tsk->audit_context;
>  
>  	if (likely(!context))
>  		return NULL;
> +	context->return_valid = return_valid;
> +	context->return_code  = return_code;
> +
>  	if (context->in_syscall && !context->auditable) {
>  		enum audit_state state;
>  		state = audit_filter_syscall(tsk, context, &audit_extlist);
> @@ -452,6 +466,7 @@ static inline struct audit_context *audi
>  	context->egid = tsk->egid;
>  	context->sgid = tsk->sgid;
>  	context->fsgid = tsk->fsgid;
> +	context->personality = tsk->personality;
>  	tsk->audit_context = NULL;
>  	return context;
>  }
> @@ -565,14 +580,25 @@ static inline void audit_free_context(st
>  static void audit_log_exit(struct audit_context *context)
>  {
>  	int i;
> +	struct audit_buffer *ab;
>  
> -	audit_log(context,
> -		  "syscall=%d,0x%x items=%d"
> +	ab = audit_log_start(context);
> +	if (!ab)
> +		return;		/* audit_panic has been called */
> +	audit_log_format(ab, "syscall=%d", context->major);
> +	if (context->personality != PER_LINUX)
> +		audit_log_format(ab, " per=%lx", context->personality);
> +	if (context->return_valid)
> +		audit_log_format(ab, " exit=%u", 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"
>  		  " euid=%d suid=%d fsuid=%d"
>  		  " egid=%d sgid=%d fsgid=%d",
> -		  context->major,
> -		  context->minor,
> +		  context->argv[0],
> +		  context->argv[1],
> +		  context->argv[2],
> +		  context->argv[3],
>  		  context->name_count,
>  		  context->pid,
>  		  context->loginuid,
> @@ -580,8 +606,9 @@ static void audit_log_exit(struct audit_
>  		  context->gid,
>  		  context->euid, context->suid, context->fsuid,
>  		  context->egid, context->sgid, context->fsgid);
> +	audit_log_end(ab);
>  	for (i = 0; i < context->name_count; i++) {
> -		struct audit_buffer  *ab = audit_log_start(context);
> +		ab = audit_log_start(context);
>  		if (!ab)
>  			continue; /* audit_panic has been called */
>  		audit_log_format(ab, "item=%d", i);
> @@ -608,7 +635,7 @@ void audit_free(struct task_struct *tsk)
>  	struct audit_context *context;
>  
>  	task_lock(tsk);
> -	context = audit_get_context(tsk);
> +	context = audit_get_context(tsk, 0, 0);
>  	task_unlock(tsk);
>  
>  	if (likely(!context))
> @@ -659,7 +686,9 @@ 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, int minor)
> +void audit_syscall_entry(struct task_struct *tsk, int major,
> +			 unsigned long a1, unsigned long a2,
> +			 unsigned long a3, unsigned long a4)
>  {
>  	struct audit_context *context = tsk->audit_context;
>  	enum audit_state     state;
> @@ -712,7 +741,10 @@ void audit_syscall_entry(struct task_str
>  		return;
>  
>  	context->major      = major;
> -	context->minor      = minor; /* Only valid for some calls */
> +	context->argv[0]    = a1;
> +	context->argv[1]    = a2;
> +	context->argv[2]    = a3;
> +	context->argv[3]    = a4;
>  
>  	state = context->state;
>  	if (state == AUDIT_SETUP_CONTEXT || state == AUDIT_BUILD_CONTEXT)
> @@ -731,13 +763,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)
> +void audit_syscall_exit(struct task_struct *tsk, int return_code)
>  {
>  	struct audit_context *context;
>  
>  	get_task_struct(tsk);
>  	task_lock(tsk);
> -	context = audit_get_context(tsk);
> +	context = audit_get_context(tsk, 1, return_code);
>  	task_unlock(tsk);
>  
>  	/* Not having a context here is ok, since the parent may have
> 
> 
> 

      parent reply	other threads:[~2004-03-25  3:01 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2004-03-11 14:25 [PATCH] Light-weight Auditing Framework Rik Faith
2004-03-11 14:49 ` Stephen Smalley
2004-03-11 19:21 ` Andrew Morton
2004-03-12  5:21   ` Rik Faith
2004-03-12 15:18     ` Rik Faith
2004-03-12  6:02   ` James Morris
2004-03-12 18:50 ` Paul E. McKenney
2004-03-17  9:14   ` Rik Faith
2004-03-18  0:45     ` Paul E. McKenney
2004-03-23 20:55       ` Rik Faith
2004-03-24 13:44         ` Rik Faith
2004-03-25  3:01         ` Paul E. McKenney [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20040325030108.GI1301@us.ibm.com \
    --to=paulmck@us.ibm.com \
    --cc=akpm@osdl.org \
    --cc=faith@redhat.com \
    --cc=linux-kernel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.