On 2018-06-04 13:32, Ondrej Mosnacek wrote:
2018-06-01 22:05 GMT+02:00 Richard Guy Briggs
<rgb(a)redhat.com>:
> On 2018-06-01 10:12, Ondrej Mosnacek wrote:
>> 2018-05-31 22:52 GMT+02:00 Richard Guy Briggs <rgb(a)redhat.com>:
>> > On 2018-05-30 10:45, Ondrej Mosnacek wrote:
>> >> This patch allows the AUDIR_DIR field to be used also with the exclude
>> >> filter.
>> >>
>> >> Not-yet-signed-off-by: Ondrej Mosnacek <omosnace(a)redhat.com>
>> >> ---
>> >> kernel/audit.c | 5 +++--
>> >> kernel/audit.h | 32 +++++++++++++++++++++++++++++++-
>> >> kernel/audit_tree.c | 4 +++-
>> >> kernel/auditfilter.c | 6 +++++-
>> >> kernel/auditsc.c | 28 ----------------------------
>> >> 5 files changed, 42 insertions(+), 33 deletions(-)
>> >>
>> >> diff --git a/kernel/audit.c b/kernel/audit.c
>> >> index e7478cb58079..aac5b6ecc11d 100644
>> >> --- a/kernel/audit.c
>> >> +++ b/kernel/audit.c
>> >> @@ -1333,7 +1333,8 @@ static int audit_receive_msg(struct sk_buff *skb,
struct nlmsghdr *nlh)
>> >> if (!audit_enabled && msg_type !=
AUDIT_USER_AVC)
>> >> return 0;
>> >>
>> >> - err = audit_filter(msg_type, AUDIT_FILTER_USER);
>> >> + // FIXME: do we need to pass the context here?
>> >> + err = audit_filter(msg_type, AUDIT_FILTER_USER, NULL);
>> >> if (err == 1) { /* match or error */
>> >> err = 0;
>> >> if (msg_type == AUDIT_USER_TTY) {
>> >> @@ -1754,7 +1755,7 @@ struct audit_buffer *audit_log_start(struct
audit_context *ctx, gfp_t gfp_mask,
>> >> if (audit_initialized != AUDIT_INITIALIZED)
>> >> return NULL;
>> >>
>> >> - if (unlikely(!audit_filter(type, AUDIT_FILTER_TYPE)))
>> >> + if (unlikely(!audit_filter(type, AUDIT_FILTER_TYPE, ctx)))
>> >> return NULL;
>> >>
>> >> /* NOTE: don't ever fail/sleep on these two conditions:
>> >> diff --git a/kernel/audit.h b/kernel/audit.h
>> >> index 214e14948370..43cfeba25802 100644
>> >> --- a/kernel/audit.h
>> >> +++ b/kernel/audit.h
>> >> @@ -324,13 +324,43 @@ extern void audit_kill_trees(struct list_head
*list);
>> >> #define audit_kill_trees(list) BUG()
>> >> #endif
>> >>
>> >> +struct audit_tree_refs {
>> >> + struct audit_tree_refs *next;
>> >> + struct audit_chunk *c[31];
>> >> +};
>> >> +
>> >> +/* A utility function to match tree refs: */
>> >> +static inline int match_tree_refs(struct audit_context *ctx, struct
audit_tree *tree)
>> >> +{
>> >> +#ifdef CONFIG_AUDIT_TREE
>> >> + struct audit_tree_refs *p;
>> >> + int n;
>> >> + if (!tree)
>> >> + return 0;
>> >> + /* full ones */
>> >> + for (p = ctx->first_trees; p != ctx->trees; p = p->next)
{
>> >> + for (n = 0; n < 31; n++)
>> >> + if (audit_tree_match(p->c[n], tree))
>> >> + return 1;
>> >> + }
>> >> + /* partial */
>> >> + if (p) {
>> >> + for (n = ctx->tree_count; n < 31; n++)
>> >> + if (audit_tree_match(p->c[n], tree))
>> >> + return 1;
>> >> + }
>> >> +#endif
>> >> + return 0;
>> >> +}
>> >> +
>> >> extern char *audit_unpack_string(void **bufp, size_t *remain, size_t
len);
>> >>
>> >> extern pid_t audit_sig_pid;
>> >> extern kuid_t audit_sig_uid;
>> >> extern u32 audit_sig_sid;
>> >>
>> >> -extern int audit_filter(int msgtype, unsigned int listtype);
>> >> +extern int audit_filter(int msgtype, unsigned int listtype,
>> >> + struct audit_context *ctx);
>> >>
>> >> #ifdef CONFIG_AUDITSYSCALL
>> >> extern int audit_signal_info(int sig, struct task_struct *t);
>> >> diff --git a/kernel/audit_tree.c b/kernel/audit_tree.c
>> >> index 67e6956c0b61..d4d36389c3d7 100644
>> >> --- a/kernel/audit_tree.c
>> >> +++ b/kernel/audit_tree.c
>> >> @@ -675,9 +675,11 @@ void audit_trim_trees(void)
>> >>
>> >> int audit_make_tree(struct audit_krule *rule, char *pathname, u32 op)
>> >> {
>> >> + if (krule->listnr != AUDIT_FILTER_EXIT &&
>> >> + krule->listnr != AUDIT_FILTER_TYPE)
>> >> + return -EINVAL;
>> >>
>> >> if (pathname[0] != '/' ||
>> >> - rule->listnr != AUDIT_FILTER_EXIT ||
>> >> op != Audit_equal ||
>> >> rule->inode_f || rule->watch || rule->tree)
>> >> return -EINVAL;
>> >> diff --git a/kernel/auditfilter.c b/kernel/auditfilter.c
>> >> index 6db9847ca031..e1d70cb77ea3 100644
>> >> --- a/kernel/auditfilter.c
>> >> +++ b/kernel/auditfilter.c
>> >> @@ -1309,7 +1309,7 @@ int audit_compare_dname_path(const char *dname,
const char *path, int parentlen)
>> >> return strncmp(p, dname, dlen);
>> >> }
>> >>
>> >> -int audit_filter(int msgtype, unsigned int listtype)
>> >> +int audit_filter(int msgtype, unsigned int listtype, struct
audit_context *ctx)
>> >> {
>> >> struct audit_entry *e;
>> >> int ret = 1; /* Audit by default */
>> >> @@ -1363,6 +1363,10 @@ int audit_filter(int msgtype, unsigned int
listtype)
>> >> if (f->op == Audit_not_equal)
>> >> result = !result;
>> >> break;
>> >> + case AUDIT_DIR:
>> >> + if (ctx)
>> >> + result = match_tree_refs(ctx,
e->rule.tree);
>> >
>> > I don't see why you need to send a context to audit_filter, since the
>> > rest of the function assumes the current task you can just use
>> > audit_context() to hand to match_tree_refs(). You could even check that
>> > ctx isn't NULL in match_tree_refs() to hide that code from
>> > audit_filter().
>>
>> I wasn't sure if I could do that, since audit_filter didn't need the
>> context until now and it is called from two places:
>>
>> audit_log_start -- which accepts context as an argument (doesn't get
>> it from task, and it can be called with ctx == NULL).
>
> Alright, if current has no context, then match_tree_refs() could test
> for a NULL context and return since there are no trees to check. Having
> said that, there are cases where audit_log_start() is deliberately
> handed a NULL context which should be honoured. It appears we don't
> have a choice but to pass in the context.
OK, so I'll leave that part as it is.
>
>> audit_receive_msg -- this function doesn't work with context at all,
>> so I wasn't sure if audit_filter should consider it being NULL or if
>> it should get it from the current task. My hunch is the second option
>> is the right one, but the first one is safer (AUDIT_DIR will simply
>> never be checked here). I don't have such insight into the logic of
>> audit_context's lifetime, so I need someone to tell me what makes more
>> sense here.
>
> That is starting to work with context. The recent FEATURE_CHANGE patch
> to connect records of the same event uses current->audit_context (now
> audit_context()) from audit_log_feature_change() called from
> audit_set_feature() called from audit_receive_msg().
>
> There is also a work in progress to convert all the CONFIG_CHANGE
> records over. I'm just trying to track down all the instances.
OK, so does that mean that I should just pass audit_context() instead
of NULL in audit_receive_msg()?
Reluctantly, yes.
The part that calls audit_filter()
only deals with user messages
(AUDIT_USER/AUDIT_FIRST..LAST_USER_MESSAGE) -- does it make sense to
use the task's context in AUDIT_FILTER_USER (right now just with
AUDIT_DIR)? It already filters based on the task's credentials, so
perhaps it does, but I don't know...
I've got opinions both ways on USER messages. I don't see the
additional information value of linking USER messages to SYSCALL
records, but I do see the single event consolidation advantage.
>> >> + break;
>> >> default:
>> >> goto unlock_and_return;
>> >> }
>> >> diff --git a/kernel/auditsc.c b/kernel/auditsc.c
>> >> index ceb1c4596c51..0d00b9354886 100644
>> >> --- a/kernel/auditsc.c
>> >> +++ b/kernel/auditsc.c
>> >> @@ -125,11 +125,6 @@ struct audit_aux_data_bprm_fcaps {
>> >> struct audit_cap_data new_pcap;
>> >> };
>> >>
>> >> -struct audit_tree_refs {
>> >> - struct audit_tree_refs *next;
>> >> - struct audit_chunk *c[31];
>> >> -};
>> >> -
>> >> static int audit_match_perm(struct audit_context *ctx, int mask)
>> >> {
>> >> unsigned n;
>> >> @@ -286,29 +281,6 @@ static void free_tree_refs(struct audit_context
*ctx)
>> >> }
>> >> }
>> >>
>> >> -static int match_tree_refs(struct audit_context *ctx, struct
audit_tree *tree)
>> >> -{
>> >> -#ifdef CONFIG_AUDIT_TREE
>> >> - struct audit_tree_refs *p;
>> >> - int n;
>> >> - if (!tree)
>> >> - return 0;
>> >> - /* full ones */
>> >> - for (p = ctx->first_trees; p != ctx->trees; p = p->next)
{
>> >> - for (n = 0; n < 31; n++)
>> >> - if (audit_tree_match(p->c[n], tree))
>> >> - return 1;
>> >> - }
>> >> - /* partial */
>> >> - if (p) {
>> >> - for (n = ctx->tree_count; n < 31; n++)
>> >> - if (audit_tree_match(p->c[n], tree))
>> >> - return 1;
>> >> - }
>> >> -#endif
>> >> - return 0;
>> >> -}
>> >> -
>> >
>> > Why did you move match_tree_refs() out of auditsc.c?
>>
>> Because now it can be called from both 'audit_filter_rules()' (defined
>> in auditsc.c) and 'audit_filter()' (defined in auditfilter.c).
>
> So since kernel/audit.h is included in all kernel/audit*.c files, having
> the prototype in there from any kernel/audit*.c file should make the
> function available to all functions in kernel/audit*.c files.
You're right, I could have just added a declaration and export the
function from auditsc.c... I will need to add a fallback definition
for when CONFIG_AUDITSYSCALL is not enabled, but in that case tasks
never have audit_context set anyway, so it's fine. I will just export
the function in the next version.
>
>> I'm actually playing with the idea of unifying the filtering logic in
>> these two functions, where sharing this function wouldn't be
>> necessary. However, that is quite a big change (a lot of LOC being
>> moved around) so I'd prefer the simple & dirty approach now and keep
>> the cleanup for a later patch.
>
> Some of the filtering has already been refactored and merged. More
> wouldn't hurt.
>
>> Thanks for the comments!
>>
>> >> static int audit_compare_uid(kuid_t uid,
>> >> struct audit_names *name,
>> >> struct audit_field *f,
>> >> --
>> >> 2.17.0
>> >>
>> >
>> > - RGB
>> >
>> > --
>> > Richard Guy Briggs <rgb(a)redhat.com>
>> > Sr. S/W Engineer, Kernel Security, Base Operating Systems
>> > Remote, Ottawa, Red Hat Canada
>> > IRC: rgb, SunRaycer
>> > Voice: +1.647.777.2635, Internal: (81) 32635
>>
>> --
>> Ondrej Mosnacek <omosnace at redhat dot com>
>> Associate Software Engineer, Security Technologies
>> Red Hat, Inc.
>
> - RGB
>
> --
> Richard Guy Briggs <rgb(a)redhat.com>
> Sr. S/W Engineer, Kernel Security, Base Operating Systems
> Remote, Ottawa, Red Hat Canada
> IRC: rgb, SunRaycer
> Voice: +1.647.777.2635, Internal: (81) 32635
--
Ondrej Mosnacek <omosnace at redhat dot com>
Associate Software Engineer, Security Technologies
Red Hat, Inc.
- RGB
--
Richard Guy Briggs <rgb(a)redhat.com>
Sr. S/W Engineer, Kernel Security, Base Operating Systems
Remote, Ottawa, Red Hat Canada
IRC: rgb, SunRaycer
Voice: +1.647.777.2635, Internal: (81) 32635