[PATCH] audit: audit on the future execution of a binary.

Richard Guy Briggs rgb at redhat.com
Thu Jul 4 02:48:56 UTC 2013


On Thu, Aug 23, 2012 at 12:24:00PM -0700, Peter Moody wrote:
> This adds the ability audit the actions of a not-yet-running process,
> as well as the children of a not-yet-running process.

Hi Peter,

I've gone back over the discussion of this feature and some of the
background in the past couple of years on this list...

We've got a kernel deadline coming up in the next month if we want to
get something included in RHEL7 if you have the interest and time to
evolve this patch (the userspace patch can follow...).

As has been discussed, passing in an inode reference is incomplete,
since it would need to be qualified by a device reference at minimum.
And even then, it isn't atomic and could change by the time the kernel
even sees this rule request.

So, the next step is to convert the path to a device/inode in the kernel.  If
this is done at the time of registering the filter rule, if/when the
rule is invalidated then the rule would be dropped, logged.  It also
means that anything else also hardlinked to it would be acted upon.

Going one step further, if instead we can arrange an fsnotify() hook on
rule registration, we could act on that path when it is executed,
renamed, unlinked (and destroyed if the refcount goes to zero), etc.

So, it should be passed as a path, logging the rule addition with path
only at first.  When the rule is triggered then log the requested path,
effective path, device/inode along with the user context.

The user, carefully crafting other rules can give other information.

A watch on the containing directory (/usr/bin) could help in case that
executable pathname disappears and re-appears since the containing
directory is less likely to go away, but it will be noisy.

Does all this make sense?

Let's deal later with namespaces, containers, mounts, chroots, bind
mounts, etc...


> Signed-off-by: Peter Moody <pmoody at google.com>
> ---
>  include/linux/audit.h |    2 ++
>  kernel/auditfilter.c  |    6 ++++++
>  kernel/auditsc.c      |   47 +++++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 55 insertions(+), 0 deletions(-)
> 
> diff --git a/include/linux/audit.h b/include/linux/audit.h
> index 22f292a..5506cb1 100644
> --- a/include/linux/audit.h
> +++ b/include/linux/audit.h
> @@ -260,6 +260,8 @@
>  #define AUDIT_OBJ_UID	109
>  #define AUDIT_OBJ_GID	110
>  #define AUDIT_FIELD_COMPARE	111
> +#define AUDIT_EXE	112
> +#define AUDIT_EXE_CHILDREN	113
>  
>  #define AUDIT_ARG0      200
>  #define AUDIT_ARG1      (AUDIT_ARG0+1)
> diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
> index a6c3f1a..1e6c571 100644
> --- a/kernel/auditfilter.c
> +++ b/kernel/auditfilter.c
> @@ -546,6 +546,12 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,
>  			if (f->val > AUDIT_MAX_FIELD_COMPARE)
>  				goto exit_free;
>  			break;
> +		case AUDIT_EXE:
> +		case AUDIT_EXE_CHILDREN:
> +			if (f->op != Audit_equal) {
> +				goto exit_free;
> +			}
> +			break;
>  		default:
>  			goto exit_free;
>  		}
> diff --git a/kernel/auditsc.c b/kernel/auditsc.c
> index 4b96415..9cebe95 100644
> --- a/kernel/auditsc.c
> +++ b/kernel/auditsc.c
> @@ -46,6 +46,7 @@
>  #include <asm/types.h>
>  #include <linux/atomic.h>
>  #include <linux/fs.h>
> +#include <linux/dcache.h>
>  #include <linux/namei.h>
>  #include <linux/mm.h>
>  #include <linux/export.h>
> @@ -68,6 +69,7 @@
>  #include <linux/capability.h>
>  #include <linux/fs_struct.h>
>  #include <linux/compat.h>
> +#include <linux/sched.h>
>  
>  #include "audit.h"
>  
> @@ -592,6 +594,35 @@ static int audit_field_compare(struct task_struct *tsk,
>  	return 0;
>  }
>  
> +int audit_match_exe(struct task_struct *tsk, struct audit_field *f)
> +{
> +	int result = 0;
> +	struct mm_struct *mm;
> +	struct vm_area_struct *vma;
> +
> +	if (!tsk)
> +		goto out;
> +
> +	mm = tsk->mm;
> +	if (!mm)
> +		goto out;
> +
> +	down_read(&mm->mmap_sem);
> +	vma = mm->mmap;
> +	while (vma) {
> +		if ((vma->vm_flags & VM_EXECUTABLE) &&
> +		    vma->vm_file) {
> +			struct inode *ino = vma->vm_file->f_path.dentry->d_inode;
> +			result = audit_comparator(ino->i_ino, f->op, f->val);
> +			break;
> +		}
> +		vma = vma->vm_next;
> +	}
> +	up_read(&mm->mmap_sem);
> +out:
> +	return result;
> +}
> +
>  /* Determine if any context name data matches a rule's watch data */
>  /* Compare a task_struct with an audit_rule.  Return 1 on match, 0
>   * otherwise.
> @@ -629,6 +660,22 @@ static int audit_filter_rules(struct task_struct *tsk,
>  				result = audit_comparator(ctx->ppid, f->op, f->val);
>  			}
>  			break;
> +		case AUDIT_EXE:
> +			result = audit_match_exe(tsk, f);
> +			break;
> +		case AUDIT_EXE_CHILDREN:
> +		{
> +			struct task_struct *ptsk;
> +			for (ptsk = tsk;
> +			     ptsk->parent->pid > 0;
> +			     ptsk = find_task_by_vpid(ptsk->parent->pid)) {
> +				if (audit_match_exe(ptsk, f)) {
> +					++result;
> +					break;
> +				}
> +			}
> +		}
> +			break;
>  		case AUDIT_UID:
>  			result = audit_comparator(cred->uid, f->op, f->val);
>  			break;
> -- 
> 1.7.7.3

- RGB

--
Richard Guy Briggs <rbriggs at redhat.com>
Senior Software Engineer
Kernel Security
AMER ENG Base Operating Systems
Remote, Ottawa, Canada
Voice: +1.647.777.2635
Internal: (81) 32635
Alt: +1.613.693.0684x3545




More information about the Linux-audit mailing list