All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] audit: audit on the future execution of a binary.
@ 2012-08-23 19:24 Peter Moody
  2012-09-06 21:34 ` Peter Moody
                   ` (2 more replies)
  0 siblings, 3 replies; 11+ messages in thread
From: Peter Moody @ 2012-08-23 19:24 UTC (permalink / raw)
  To: linux-audit

This adds the ability audit the actions of a not-yet-running process,
as well as the children of a not-yet-running process.

Signed-off-by: Peter Moody <pmoody@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

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PATCH] audit: audit on the future execution of a binary.
  2012-08-23 19:24 [PATCH] audit: audit on the future execution of a binary Peter Moody
@ 2012-09-06 21:34 ` Peter Moody
  2013-04-11 18:08 ` Eric Paris
  2013-07-04  2:48 ` Richard Guy Briggs
  2 siblings, 0 replies; 11+ messages in thread
From: Peter Moody @ 2012-09-06 21:34 UTC (permalink / raw)
  To: linux-audit

Hey Eric,

did you have any comments on this? Is there a better way to do this?

Cheers,
peter

On Thu, Aug 23, 2012 at 12:24 PM, Peter Moody <pmoody@google.com> 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.
>
> Signed-off-by: Peter Moody <pmoody@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
>



-- 
Peter Moody      Google    1.650.253.7306
Security Engineer  pgp:0xC3410038

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] audit: audit on the future execution of a binary.
  2012-08-23 19:24 [PATCH] audit: audit on the future execution of a binary Peter Moody
  2012-09-06 21:34 ` Peter Moody
@ 2013-04-11 18:08 ` Eric Paris
  2013-04-11 18:13   ` Peter Moody
  2013-07-04  2:48 ` Richard Guy Briggs
  2 siblings, 1 reply; 11+ messages in thread
From: Eric Paris @ 2013-04-11 18:08 UTC (permalink / raw)
  To: Peter Moody; +Cc: linux-audit

Is this late enough?  I suck a LOT as a maintainer.  Anyway, I'm not in love.

inode numbers are not unique across the system.  If you had 2 binaries, completely unrelated, that just happened to have the same i_ino, we'd have false positives.  I'm not, off the top of my head, thinking of a good way to fix it.  But it does seem to me like maybe it could be something like audit watches where we give the path to the kernel and do some marking on the inode in question inside the kernel.

Possibly such that we even remark it if another binary is dropped on top of the present binary?  I'll think on it for a bit...

----- Original Message -----
> This adds the ability audit the actions of a not-yet-running process,
> as well as the children of a not-yet-running process.
> 
> Signed-off-by: Peter Moody <pmoody@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
> 
> 

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] audit: audit on the future execution of a binary.
  2013-04-11 18:08 ` Eric Paris
@ 2013-04-11 18:13   ` Peter Moody
  0 siblings, 0 replies; 11+ messages in thread
From: Peter Moody @ 2013-04-11 18:13 UTC (permalink / raw)
  To: Eric Paris; +Cc: linux-audit

On Thu, Apr 11, 2013 at 11:08 AM, Eric Paris <eparis@redhat.com> wrote:
> Is this late enough?  I suck a LOT as a maintainer.  Anyway, I'm not in love.

Hah. I actually figured that you hated it, so 'not in love' is a step
up from what I was expecting.

> inode numbers are not unique across the system.  If you had 2 binaries, completely unrelated, that just happened to have the same i_ino, we'd have false positives.  I'm not, off the top of my head, thinking of a good way to fix it.  But it does seem to me like maybe it could be something like audit watches where we give the path to the kernel and do some marking on the inode in question inside the kernel.

I'd been meaning to get back to this, figuring that there were some
fundamental issues with the inode approach but I had a bunch of stuff
creep onto my plate in the intervening months and this wasn't a
must-have feature anyway.

If you do think of a better way to attack this, I'd be interested to
hear it. The watch sounds promising.

> Possibly such that we even remark it if another binary is dropped on top of the present binary?  I'll think on it for a bit...

Cheers,
peter

> ----- Original Message -----
>> This adds the ability audit the actions of a not-yet-running process,
>> as well as the children of a not-yet-running process.
>>
>> Signed-off-by: Peter Moody <pmoody@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
>>
>>



-- 
[ Peter Moody | Security Engineer | Google ]

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] audit: audit on the future execution of a binary.
  2012-08-23 19:24 [PATCH] audit: audit on the future execution of a binary Peter Moody
  2012-09-06 21:34 ` Peter Moody
  2013-04-11 18:08 ` Eric Paris
@ 2013-07-04  2:48 ` Richard Guy Briggs
  2013-07-07 22:41   ` Peter Moody
  2013-07-08 19:57   ` Steve Grubb
  2 siblings, 2 replies; 11+ messages in thread
From: Richard Guy Briggs @ 2013-07-04  2:48 UTC (permalink / raw)
  To: Peter Moody; +Cc: linux-audit

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@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@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

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] audit: audit on the future execution of a binary.
  2013-07-04  2:48 ` Richard Guy Briggs
@ 2013-07-07 22:41   ` Peter Moody
  2013-07-08 19:35     ` Richard Guy Briggs
  2013-07-08 19:57   ` Steve Grubb
  1 sibling, 1 reply; 11+ messages in thread
From: Peter Moody @ 2013-07-07 22:41 UTC (permalink / raw)
  To: Richard Guy Briggs; +Cc: linux-audit


On Wed, Jul 03 2013 at 19:48, Richard Guy Briggs wrote:
> 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?

Hey Richard,

Sorry for the late reply, we had a short week last week.

This makes a lot of sense, yes. Unfortunately I think it's unlikely that
I'll have a chance to work on this in time for your freeze b/c my wife
is due on Friday and as much as I'd like to thin that I'll be able to
get some free time during paternity leave to do some kernel hacking,
everyone tells me I'm crazy to think that.

I *think* I'm the only one who's been asking for this feature, so
hopefully my not getting to it won't be putting anyone out.

Cheers,
peter

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

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] audit: audit on the future execution of a binary.
  2013-07-07 22:41   ` Peter Moody
@ 2013-07-08 19:35     ` Richard Guy Briggs
  0 siblings, 0 replies; 11+ messages in thread
From: Richard Guy Briggs @ 2013-07-08 19:35 UTC (permalink / raw)
  To: Peter Moody; +Cc: linux-audit

On Sun, Jul 07, 2013 at 03:41:41PM -0700, Peter Moody wrote:
> 
> On Wed, Jul 03 2013 at 19:48, Richard Guy Briggs wrote:
> > 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?
> 
> Hey Richard,
> 
> Sorry for the late reply, we had a short week last week.

No worries.

> This makes a lot of sense, yes. Unfortunately I think it's unlikely that
> I'll have a chance to work on this in time for your freeze b/c my wife
> is due on Friday and as much as I'd like to thin that I'll be able to
> get some free time during paternity leave to do some kernel hacking,
> everyone tells me I'm crazy to think that.

A bit delusional, yes.  First child, I gather.  Welcome to parenting.
It is quite a ride.  It can be a lot of fun.  :)

> I *think* I'm the only one who's been asking for this feature, so
> hopefully my not getting to it won't be putting anyone out.

What's your timeline and availability?

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

- RGB

--
Richard Guy Briggs <rbriggs@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

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] audit: audit on the future execution of a binary.
  2013-07-04  2:48 ` Richard Guy Briggs
  2013-07-07 22:41   ` Peter Moody
@ 2013-07-08 19:57   ` Steve Grubb
  2013-07-09 19:03     ` Steve Grubb
  1 sibling, 1 reply; 11+ messages in thread
From: Steve Grubb @ 2013-07-08 19:57 UTC (permalink / raw)
  To: linux-audit; +Cc: Richard Guy Briggs

On Wednesday, July 03, 2013 10:48:56 PM Richard Guy Briggs wrote:
> 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.

This sounds like how I would expect it to be. You pass a path and the kernel 
converts is very much like filesystem watches to device/inode. But the next 
step is when the execve syscall matches with the path, then the rule is 
further converted to have the pid instead of the inode/device. This is 
basically following the established pattern we already have for watching files.

 
> 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.

Not sure this is necessary. If this is done for file system watches, then its 
an established pattern and we should continue to follow it.

-Steve

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] audit: audit on the future execution of a binary.
  2013-07-08 19:57   ` Steve Grubb
@ 2013-07-09 19:03     ` Steve Grubb
  2013-09-20 16:18       ` Steve Grubb
  0 siblings, 1 reply; 11+ messages in thread
From: Steve Grubb @ 2013-07-09 19:03 UTC (permalink / raw)
  To: linux-audit

On Sunday, July 07, 2013 15:41:41 Peter Moody wrote:
>I *think* I'm the only one who's been asking for this feature, so
>hopefully my not getting to it won't be putting anyone out.


The reason that this is needed is that what we have available for auditing 
strange problems that a particular program might have is the 
equivalent of audit by inode. You have to have the pid in order to write a 
rule. Another invocation and we need a new rule. This feature would allow you 
to do investigations like:

- give me all EPERM events generated by apache.
- give me all files opened by gnash
- give me all execve calls made by bind
- record any time sendmail fails to change uid
- exclude any opens with ENOENT by top secret processes  <- real important

-Steve

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] audit: audit on the future execution of a binary.
  2013-07-09 19:03     ` Steve Grubb
@ 2013-09-20 16:18       ` Steve Grubb
  0 siblings, 0 replies; 11+ messages in thread
From: Steve Grubb @ 2013-09-20 16:18 UTC (permalink / raw)
  To: linux-audit

On Tuesday, July 09, 2013 03:03:59 PM Steve Grubb wrote:
> On Sunday, July 07, 2013 15:41:41 Peter Moody wrote:
> >I *think* I'm the only one who's been asking for this feature, so
> >hopefully my not getting to it won't be putting anyone out.
> 
> The reason that this is needed is that what we have available for auditing
> strange problems that a particular program might have is the
> equivalent of audit by inode. You have to have the pid in order to write a
> rule. Another invocation and we need a new rule. This feature would allow
> you to do investigations like:
> 
> - give me all EPERM events generated by apache.
> - give me all files opened by gnash
> - give me all execve calls made by bind
> - record any time sendmail fails to change uid
> - exclude any opens with ENOENT by top secret processes  <- real important

Another use case someone asked for this week:

- Give me all files transferred by scp.


-Steve

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH] audit: audit on the future execution of a binary.
  2014-05-05 20:41 [PATCH] audit: log on the future execution of a path Richard Guy Briggs
@ 2014-05-05 20:41 ` Richard Guy Briggs
  0 siblings, 0 replies; 11+ messages in thread
From: Richard Guy Briggs @ 2014-05-05 20:41 UTC (permalink / raw)
  To: linux-audit; +Cc: Richard Guy Briggs

Enable creation of rules to monitor for the execution of a future path.

This adds the ability to audit the actions of a not-yet-running process,
possibly not-yet-existing path, as well as the children of a process/path.

A path is supplied and stored with the rule, which is subsequently compared
with the path stored by sys_execve() when called.

Based-on-code-by: Peter Moody <pmoody@google.com>
Signed-off-by: Richard Guy Briggs <rgb@redhat.com>
---
 include/linux/audit.h      |    1 +
 include/uapi/linux/audit.h |    2 ++
 kernel/auditfilter.c       |   35 +++++++++++++++++++++++++++++++++++
 kernel/auditsc.c           |   35 +++++++++++++++++++++++++++++++++++
 4 files changed, 73 insertions(+), 0 deletions(-)

diff --git a/include/linux/audit.h b/include/linux/audit.h
index 7c42075..293759e 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -62,6 +62,7 @@ struct audit_krule {
 	struct list_head	rlist;	/* entry in audit_{watch,tree}.rules list */
 	struct list_head	list;	/* for AUDIT_LIST* purposes only */
 	u64			prio;
+	char			*path; /* associated path */
 };
 
 struct audit_field {
diff --git a/include/uapi/linux/audit.h b/include/uapi/linux/audit.h
index 573dc36..f4a72b9 100644
--- a/include/uapi/linux/audit.h
+++ b/include/uapi/linux/audit.h
@@ -266,6 +266,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 6daea0a..3309943 100644
--- a/kernel/auditfilter.c
+++ b/kernel/auditfilter.c
@@ -87,6 +87,7 @@ static inline void audit_free_rule(struct audit_entry *e)
 		}
 	kfree(erule->fields);
 	kfree(erule->filterkey);
+	kfree(erule->path);
 	kfree(e);
 }
 
@@ -390,6 +391,11 @@ static int audit_field_valid(struct audit_entry *entry, struct audit_field *f)
 		if (f->val > AUDIT_MAX_FIELD_COMPARE)
 			return -EINVAL;
 		break;
+	case AUDIT_EXE:
+	case AUDIT_EXE_CHILDREN:
+		if (f->op != Audit_equal)
+			return -EINVAL;
+		break;
 	};
 	return 0;
 }
@@ -539,6 +545,16 @@ static struct audit_entry *audit_data_to_entry(struct audit_rule_data *data,
 			entry->rule.buflen += f->val;
 			entry->rule.filterkey = str;
 			break;
+		case AUDIT_EXE:
+		case AUDIT_EXE_CHILDREN:
+			if (entry->rule.path || f->val > PATH_MAX)
+				goto exit_free;
+			str = audit_unpack_string(&bufp, &remain, f->val);
+			if (IS_ERR(str))
+				goto exit_free;
+			entry->rule.buflen += f->val;
+			entry->rule.path = str;
+			break;
 		}
 	}
 
@@ -617,6 +633,11 @@ static struct audit_rule_data *audit_krule_to_data(struct audit_krule *krule)
 			data->buflen += data->values[i] =
 				audit_pack_string(&bufp, krule->filterkey);
 			break;
+		case AUDIT_EXE:
+		case AUDIT_EXE_CHILDREN:
+			data->buflen += data->values[i] =
+				audit_pack_string(&bufp, krule->path);
+			break;
 		default:
 			data->values[i] = f->val;
 		}
@@ -672,6 +693,12 @@ static int audit_compare_rule(struct audit_krule *a, struct audit_krule *b)
 			if (strcmp(a->filterkey, b->filterkey))
 				return 1;
 			break;
+		case AUDIT_EXE:
+		case AUDIT_EXE_CHILDREN:
+			/* both paths exist based on above type compare */
+			if (strcmp(a->path, b->path))
+				return 1;
+			break;
 		case AUDIT_UID:
 		case AUDIT_EUID:
 		case AUDIT_SUID:
@@ -742,6 +769,7 @@ struct audit_entry *audit_dupe_rule(struct audit_krule *old)
 	struct audit_entry *entry;
 	struct audit_krule *new;
 	char *fk;
+	char *path;
 	int i, err = 0;
 
 	entry = audit_init_entry(fcount);
@@ -793,6 +821,13 @@ struct audit_entry *audit_dupe_rule(struct audit_krule *old)
 				err = -ENOMEM;
 			else
 				new->filterkey = fk;
+		case AUDIT_EXE:
+		case AUDIT_EXE_CHILDREN:
+			path = kstrdup(old->path, GFP_KERNEL);
+			if (unlikely(!path))
+				err = -ENOMEM;
+			else
+				new->path = path;
 		}
 		if (err) {
 			audit_free_rule(entry);
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index f251a5e..6c6963d 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -48,6 +48,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>
@@ -70,6 +71,7 @@
 #include <linux/capability.h>
 #include <linux/fs_struct.h>
 #include <linux/compat.h>
+#include <linux/sched.h>
 #include <linux/ctype.h>
 
 #include "audit.h"
@@ -432,6 +434,23 @@ static int audit_field_compare(struct task_struct *tsk,
 	return 0;
 }
 
+int audit_match_exe(struct task_struct *tsk, struct audit_context *ctx, struct audit_names *name, unsigned char *path)
+{
+	struct audit_names *n;
+
+	if ((!tsk || !tsk->audit_context) && !ctx && !name)
+		return 0;
+
+	if (name)
+		if (!strcmp(name->name->name, path))
+			return 1;
+		
+	list_for_each_entry(n, &(ctx ?: tsk->audit_context)->names_list, list)
+		if (n->name && !strcmp(n->name->name, path))
+			return 1;
+	return 0;
+}
+
 /* 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.
@@ -471,6 +490,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, ctx, name, rule->path);
+			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, ctx, name, rule->path)) {
+					++result;
+					break;
+				}
+			}
+		}
+			break;
 		case AUDIT_UID:
 			result = audit_uid_comparator(cred->uid, f->op, f->uid);
 			break;
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2014-05-05 20:41 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-08-23 19:24 [PATCH] audit: audit on the future execution of a binary Peter Moody
2012-09-06 21:34 ` Peter Moody
2013-04-11 18:08 ` Eric Paris
2013-04-11 18:13   ` Peter Moody
2013-07-04  2:48 ` Richard Guy Briggs
2013-07-07 22:41   ` Peter Moody
2013-07-08 19:35     ` Richard Guy Briggs
2013-07-08 19:57   ` Steve Grubb
2013-07-09 19:03     ` Steve Grubb
2013-09-20 16:18       ` Steve Grubb
2014-05-05 20:41 [PATCH] audit: log on the future execution of a path Richard Guy Briggs
2014-05-05 20:41 ` [PATCH] audit: audit on the future execution of a binary Richard Guy Briggs

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.