On Tuesday 03 January 2006 18:05, Amy Griffis wrote:
These message types use struct audit_rule, which doesn't support
an
additional buffer.
Ah, Ok.
> > ????????????????????????return -EINVAL;
> > ????????????????/* fallthrough */
> > ????????case AUDIT_LIST:
> > ????????????????err = audit_receive_filter(nlh->nlmsg_type,
> > NETLINK_CB(skb).pid, -??????????????????????????????????????? ? uid,
> > seq, data, loginuid); +??????????????????????????????????????? ? uid,
> > seq, data, nlmsg_len(nlh), +??????????????????????????????????????? ?
> > loginuid); +???????????????break;
> > +???????case AUDIT_ADD_RULE:
> > +???????case AUDIT_DEL_RULE:
> > +???????????????if (nlmsg_len(nlh) < sizeof(struct audit_rule_xprt))
>
> Same.
The netlink packet length is passed along through
audit_receive_filter() to audit_xprt_to_entry(), where it can be
referenced while processing the buffer.
In the last incarnation of file system audit code, we tried hard to validate
the length before ever allocating any kernel memory of any kind. I was trying
to trace through to see where the length is really checked to ensure the
payload is legit.
> > +???????char *str;
> > +
> > +???????if (!*bufp || (len > *remaining))
> > +???????????????return ERR_PTR(-EINVAL);
>
> len should always be <= PATH_MAX*2. That must be checked for as well or
> there could be wrapping.
I'm confused about the significance of the value PATH_MAX*2 and how
that relates here. Could you clarify?
In order to make sure people aren't playing games by abusing the audit system,
I was thinking that you could do a check that the length isn't too big also.
If you have a u32 for len, and someone passes -1, then you have a large
positive number. To detect these problems, you have to check for a legal
upper bounds. In this case, the longest string should be PATH_MAX. I guess
the "*2" only applies to actual audit records rather than the file path for
rules.
> > +/* Common user-space to kernel rule translation. */
> > +static struct audit_entry *audit_to_entry_common(struct audit_rule
> > *rule) +{
> > +???????unsigned listnr;
> > +???????struct audit_entry *entry;
> > +???????int i, err;
> > +
> > +???????if (rule->field_count < 0 || rule->field_count >
> > AUDIT_MAX_FIELDS) +???????????????goto exit_err;
>
> field_count is u32 & cannot be less than 0. It should be checked to make
> sure its not 0, though.
I thought it was okay to specify a rule with no fields, i.e.
auditctl -a entry,always -S swapon
OK...right. So the < 0 part can be deleted.
> > -/* Check to see if two rules are identical. ?It is called
from
> > - * audit_add_rule during AUDIT_ADD and
> > - * audit_del_rule during AUDIT_DEL. */
> > -static int audit_compare_rule(struct audit_rule *a, struct audit_rule
> > *b) +/* Translate struct audit_rule_xprt to kernel's rule
> > respresentation. */ +static struct audit_entry
> > *audit_xprt_to_entry(struct audit_rule_xprt *xprt,
> > +??????????????????????????????????????? ? ? ? int dlen) ?{
> > +???????int err = 0;
> > +???????struct audit_entry *entry;
> > +???????void *bufp;
> > +???????/* int remaining = dlen - sizeof(struct audit_rule_xprt); */
> > ????????int i;
> > ?
> > -???????if (a->flags != b->flags)
> > -???????????????return 1;
> > +???????entry = audit_to_entry_common((struct audit_rule *)xprt);
> > +???????if (IS_ERR(entry))
> > +???????????????goto exit_nofree;
> > +
> > +???????bufp = xprt->buf;
>
> What uses bufp?
Nothing right now, but it should be used by a consumer adding code to
the switch statement.
OK, I thought the patch was complete. Nevermind.
> > +/* Pack a filter field's string representation into data block. */
> > +static inline int audit_pack_string(void **bufp, char *str)
>
> What calls this?
This should be called by a consumer from the switch in
audit_krule_to_xprt().
I really need to see the consumer to finish evaluating the use of the
interface. I just want to make sure there's no vulnerabilities that will give
hackers a chance.
-Steve