On 15/08/06, Paul Moore wrote:
> On Wednesday, August 05, 2015 04:29:37 PM Richard Guy Briggs wrote:
> > This adds the ability audit the actions of a not-yet-running process.
> > 
> > This patch implements the ability to filter on the executable path.  Instead
> > of just hard coding the ino and dev of the executable we care about at the
> > moment the rule is inserted into the kernel, use the new audit_fsnotify
> > infrastructure to manage this dynamically.  This means that if the filename
> > does not yet exist but the containing directory does, or if the inode in
> > question is unlinked and creat'd (aka updated) the rule will just continue
> > to work.  If the containing directory is moved or deleted or the filesystem
> > is unmounted, the rule is deleted automatically.  A future enhancement
> > would be to have the rule survive across directory disruptions.
> > 
> > This is a heavily modified version of a patch originally submitted by Eric
> > Paris with some ideas from Peter Moody.
> > 
> > Cc: Peter Moody <pe...@hda3.com>
> > Cc: Eric Paris <epa...@redhat.com>
> > Signed-off-by: Richard Guy Briggs <r...@redhat.com>
> > ---
> >  include/linux/audit.h      |    1 +
> >  include/uapi/linux/audit.h |    5 +++-
> >  kernel/audit.h             |    4 +++
> >  kernel/audit_tree.c        |    2 +
> >  kernel/audit_watch.c       |   31 +++++++++++++++++++++++++
> >  kernel/auditfilter.c       |   53 ++++++++++++++++++++++++++++++++++++++++-
> >  kernel/auditsc.c           |    3 ++
> >  7 files changed, 97 insertions(+), 2 deletions(-)
> 
> Merged, although some more minor whitespace tweaks were necessary for 
> checkpatch.  On a related note, if you're not running ./scripts/checlpatch.pl 
> on your patches before sending them out, I would recommend it.  It isn't 
> perfect, but it can catch some silly things that we all do from time to time.

No excuses...  I have been running it pretty regularly and got lazy and
distracted with patch revisions.  I can't say I agree with the no space
before closing round parenthesis due to legibility, but will comply.

> Also, one last thing.  It is pretty late in the -rcX cycle to merge these two 
> patches, but considering that we've been talking about these for a while, I'm 
> reasonably okay merging them.  In the future, if it isn't in audit#next by 
> the 
> time -rc5 is released, it isn't going to make the merge window.

I've been quite aware of that looming merge window...  This feature has
been iterating for a while, so there are no big surprises.  I was aiming
for earlier.  :)

> > diff --git a/include/linux/audit.h b/include/linux/audit.h
> > index c2e7e3a..aee456f 100644
> > --- a/include/linux/audit.h
> > +++ b/include/linux/audit.h
> > @@ -59,6 +59,7 @@ struct audit_krule {
> >     struct audit_field      *inode_f; /* quick access to an inode field */
> >     struct audit_watch      *watch; /* associated watch */
> >     struct audit_tree       *tree;  /* associated watched tree */
> > +   struct audit_fsnotify_mark      *exe;
> >     struct list_head        rlist;  /* entry in audit_{watch,tree}.rules 
> > list */
> >     struct list_head        list;   /* for AUDIT_LIST* purposes only */
> >     u64                     prio;
> > diff --git a/include/uapi/linux/audit.h b/include/uapi/linux/audit.h
> > index 971df22..e2ca600 100644
> > --- a/include/uapi/linux/audit.h
> > +++ b/include/uapi/linux/audit.h
> > @@ -266,6 +266,7 @@
> >  #define AUDIT_OBJ_UID      109
> >  #define AUDIT_OBJ_GID      110
> >  #define AUDIT_FIELD_COMPARE        111
> > +#define AUDIT_EXE  112
> > 
> >  #define AUDIT_ARG0      200
> >  #define AUDIT_ARG1      (AUDIT_ARG0+1)
> > @@ -324,8 +325,10 @@ enum {
> > 
> >  #define AUDIT_FEATURE_BITMAP_BACKLOG_LIMIT 0x00000001
> >  #define AUDIT_FEATURE_BITMAP_BACKLOG_WAIT_TIME     0x00000002
> > +#define AUDIT_FEATURE_BITMAP_EXECUTABLE_PATH       0x00000004
> >  #define AUDIT_FEATURE_BITMAP_ALL (AUDIT_FEATURE_BITMAP_BACKLOG_LIMIT | \
> > -                             AUDIT_FEATURE_BITMAP_BACKLOG_WAIT_TIME)
> > +                             AUDIT_FEATURE_BITMAP_BACKLOG_WAIT_TIME | \
> > +                             AUDIT_FEATURE_BITMAP_EXECUTABLE_PATH )
> > 
> >  /* deprecated: AUDIT_VERSION_* */
> >  #define AUDIT_VERSION_LATEST               AUDIT_FEATURE_BITMAP_ALL
> > diff --git a/kernel/audit.h b/kernel/audit.h
> > index 46d10dd..dadf86a 100644
> > --- a/kernel/audit.h
> > +++ b/kernel/audit.h
> > @@ -277,6 +277,8 @@ extern char *audit_mark_path(struct audit_fsnotify_mark
> > *mark); extern void audit_remove_mark(struct audit_fsnotify_mark
> > *audit_mark); extern void audit_remove_mark_rule(struct audit_krule
> > *krule);
> >  extern int audit_mark_compare(struct audit_fsnotify_mark *mark, unsigned
> > long ino, dev_t dev); +extern int audit_dupe_exe(struct audit_krule *new,
> > struct audit_krule *old); +extern int audit_exe_compare(struct task_struct
> > *tsk, struct audit_fsnotify_mark *mark);
> > 
> >  #else
> >  #define audit_put_watch(w) {}
> > @@ -292,6 +294,8 @@ extern int audit_mark_compare(struct audit_fsnotify_mark
> > *mark, unsigned long in #define audit_remove_mark(m)
> >  #define audit_remove_mark_rule(k)
> >  #define audit_mark_compare(m, i, d) 0
> > +#define audit_exe_compare(t, m) (-EINVAL)
> > +#define audit_dupe_exe(n, o) (-EINVAL)
> >  #endif /* CONFIG_AUDIT_WATCH */
> > 
> >  #ifdef CONFIG_AUDIT_TREE
> > diff --git a/kernel/audit_tree.c b/kernel/audit_tree.c
> > index b0f9877..94ecdab 100644
> > --- a/kernel/audit_tree.c
> > +++ b/kernel/audit_tree.c
> > @@ -479,6 +479,8 @@ static void kill_rules(struct audit_tree *tree)
> >             if (rule->tree) {
> >                     /* not a half-baked one */
> >                     audit_tree_log_remove_rule(rule);
> > +                   if (entry->rule.exe)
> > +                           audit_remove_mark(entry->rule.exe);
> >                     rule->tree = NULL;
> >                     list_del_rcu(&entry->list);
> >                     list_del(&entry->rule.list);
> > diff --git a/kernel/audit_watch.c b/kernel/audit_watch.c
> > index c668bfc..1255dbf 100644
> > --- a/kernel/audit_watch.c
> > +++ b/kernel/audit_watch.c
> > @@ -312,6 +312,8 @@ static void audit_update_watch(struct audit_parent
> > *parent, list_replace(&oentry->rule.list,
> >                                          &nentry->rule.list);
> >                     }
> > +                   if (oentry->rule.exe)
> > +                           audit_remove_mark(oentry->rule.exe);
> > 
> >                     audit_watch_log_rule_change(r, owatch, "updated_rules");
> > 
> > @@ -342,6 +344,8 @@ static void audit_remove_parent_watches(struct
> > audit_parent *parent) list_for_each_entry_safe(r, nextr, &w->rules, rlist)
> > {
> >                     e = container_of(r, struct audit_entry, rule);
> >                     audit_watch_log_rule_change(r, w, "remove_rule");
> > +                   if (e->rule.exe)
> > +                           audit_remove_mark(e->rule.exe);
> >                     list_del(&r->rlist);
> >                     list_del(&r->list);
> >                     list_del_rcu(&e->list);
> > @@ -514,3 +518,30 @@ static int __init audit_watch_init(void)
> >     return 0;
> >  }
> >  device_initcall(audit_watch_init);
> > +
> > +int audit_dupe_exe(struct audit_krule *new, struct audit_krule *old)
> > +{
> > +   struct audit_fsnotify_mark *audit_mark;
> > +   char *pathname;
> > +
> > +   pathname = kstrdup(audit_mark_path(old->exe), GFP_KERNEL);
> > +   if (!pathname)
> > +           return -ENOMEM;
> > +
> > +   audit_mark = audit_alloc_mark(new, pathname, strlen(pathname));
> > +   if (IS_ERR(audit_mark)) {
> > +           kfree(pathname);
> > +           return PTR_ERR(audit_mark);
> > +   }
> > +   new->exe = audit_mark;
> > +
> > +   return 0;
> > +}
> > +
> > +int audit_exe_compare(struct task_struct *tsk, struct audit_fsnotify_mark
> > *mark) +{
> > +   unsigned long ino = tsk->mm->exe_file->f_inode->i_ino;
> > +   dev_t dev = tsk->mm->exe_file->f_inode->i_sb->s_dev;
> > +
> > +   return audit_mark_compare(mark, ino, dev);
> > +}
> > diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
> > index 3d99196..c662638 100644
> > --- a/kernel/auditfilter.c
> > +++ b/kernel/auditfilter.c
> > @@ -405,6 +405,12 @@ 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:
> > +           if (f->op != Audit_equal)
> > +                   return -EINVAL;
> > +           if (entry->rule.listnr != AUDIT_FILTER_EXIT)
> > +                   return -EINVAL;
> > +           break;
> >     };
> >     return 0;
> >  }
> > @@ -419,6 +425,7 @@ static struct audit_entry *audit_data_to_entry(struct
> > audit_rule_data *data, size_t remain = datasz - sizeof(struct
> > audit_rule_data);
> >     int i;
> >     char *str;
> > +   struct audit_fsnotify_mark *audit_mark;
> > 
> >     entry = audit_to_entry_common(data);
> >     if (IS_ERR(entry))
> > @@ -539,6 +546,24 @@ 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:
> > +                   if (entry->rule.exe || f->val > PATH_MAX)
> > +                           goto exit_free;
> > +                   str = audit_unpack_string(&bufp, &remain, f->val);
> > +                   if (IS_ERR(str)) {
> > +                           err = PTR_ERR(str);
> > +                           goto exit_free;
> > +                   }
> > +                   entry->rule.buflen += f->val;
> > +
> > +                   audit_mark = audit_alloc_mark(&entry->rule, str, 
> > f->val);
> > +                   if (IS_ERR(audit_mark)) {
> > +                           kfree(str);
> > +                           err = PTR_ERR(audit_mark);
> > +                           goto exit_free;
> > +                   }
> > +                   entry->rule.exe = audit_mark;
> > +                   break;
> >             }
> >     }
> > 
> > @@ -551,6 +576,8 @@ exit_nofree:
> >  exit_free:
> >     if (entry->rule.tree)
> >             audit_put_tree(entry->rule.tree); /* that's the temporary one */
> > +   if (entry->rule.exe)
> > +           audit_remove_mark(entry->rule.exe); /* that's the template one 
> > */
> >     audit_free_rule(entry);
> >     return ERR_PTR(err);
> >  }
> > @@ -615,6 +642,10 @@ 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:
> > +                   data->buflen += data->values[i] =
> > +                           audit_pack_string(&bufp, 
> > audit_mark_path(krule->exe));
> > +                   break;
> >             case AUDIT_LOGINUID_SET:
> >                     if (krule->pflags & AUDIT_LOGINUID_LEGACY && !f->val) {
> >                             data->fields[i] = AUDIT_LOGINUID;
> > @@ -678,6 +709,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:
> > +                   /* both paths exist based on above type compare */
> > +                   if (strcmp(audit_mark_path(a->exe),
> > +                              audit_mark_path(b->exe)))
> > +                           return 1;
> > +                   break;
> >             case AUDIT_UID:
> >             case AUDIT_EUID:
> >             case AUDIT_SUID:
> > @@ -799,8 +836,14 @@ struct audit_entry *audit_dupe_rule(struct audit_krule
> > *old) err = -ENOMEM;
> >                     else
> >                             new->filterkey = fk;
> > +                   break;
> > +           case AUDIT_EXE:
> > +                   err = audit_dupe_exe(new, old);
> > +                   break;
> >             }
> >             if (err) {
> > +                   if (new->exe)
> > +                           audit_remove_mark(new->exe);
> >                     audit_free_rule(entry);
> >                     return ERR_PTR(err);
> >             }
> > @@ -963,6 +1006,9 @@ int audit_del_rule(struct audit_entry *entry)
> >     if (e->rule.tree)
> >             audit_remove_tree_rule(&e->rule);
> > 
> > +   if (e->rule.exe)
> > +           audit_remove_mark_rule(&e->rule);
> > +
> >  #ifdef CONFIG_AUDITSYSCALL
> >     if (!dont_count)
> >             audit_n_rules--;
> > @@ -1067,8 +1113,11 @@ int audit_rule_change(int type, __u32 portid, int
> > seq, void *data, WARN_ON(1);
> >     }
> > 
> > -   if (err || type == AUDIT_DEL_RULE)
> > +   if (err || type == AUDIT_DEL_RULE) {
> > +           if (entry->rule.exe)
> > +                   audit_remove_mark(entry->rule.exe);
> >             audit_free_rule(entry);
> > +   }
> > 
> >     return err;
> >  }
> > @@ -1360,6 +1409,8 @@ static int update_lsm_rule(struct audit_krule *r)
> >             return 0;
> > 
> >     nentry = audit_dupe_rule(r);
> > +   if (entry->rule.exe)
> > +           audit_remove_mark(entry->rule.exe);
> >     if (IS_ERR(nentry)) {
> >             /* save the first error encountered for the
> >              * return value */
> > diff --git a/kernel/auditsc.c b/kernel/auditsc.c
> > index 701ea5c..e9bac2b 100644
> > --- a/kernel/auditsc.c
> > +++ b/kernel/auditsc.c
> > @@ -466,6 +466,9 @@ static int audit_filter_rules(struct task_struct *tsk,
> >                             result = audit_comparator(ctx->ppid, f->op, 
> > f->val);
> >                     }
> >                     break;
> > +           case AUDIT_EXE:
> > +                   result = audit_exe_compare(tsk, rule->exe);
> > +                   break;
> >             case AUDIT_UID:
> >                     result = audit_uid_comparator(cred->uid, f->op, f->uid);
> >                     break;
> 
> -- 
> paul moore
> security @ redhat
> 

- RGB

--
Richard Guy Briggs <rbri...@redhat.com>
Senior Software Engineer, Kernel Security, AMER ENG Base Operating Systems, Red 
Hat
Remote, Ottawa, Canada
Voice: +1.647.777.2635, Internal: (81) 32635, Alt: +1.613.693.0684x3545
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to