Hi Darrel,
On Wed, Mar 08, 2006 at 12:46:51PM -0600, Darrel Goeddel wrote:
>It seems like it would be cleaner to group the memory allocations
for
>the rule entry and the fields into a single function, as any audit
>rule must always have both. This would allow you to retain the
>assumption of the existence of fields in audit_free_rule.
I originally went with that approach, but later decided to break it
out to make a generic copy function (which I scrapped in favor of
the specialized helper because I didn't know anything about the
watches...). I'm assuming that this whole thing will need
modification based on your continued fs auditing work. I'll keep
this in mind for the next version.
Since the audit watches don't exist as of current git, you don't have
to worry too much about them. I'll add the necessary code to handle
them in the policy update path as part of the patch that introduces
them.
My only real question is whether it is appropriate to re-initialize
the opaque selinux fields on events other than policy update, or if
there should be a copy routine as well. You seemed to indicate that
re-initializing was the right thing in all cases. I'm just wanting to
confirm that.
If so, here are a couple of routines that I believe would suffice for
copying audit rules with selinux portions as a result of either policy
reload or filesystem events. What do you think?
static inline struct audit_entry *audit_init_entry(u32 field_count,
gfp_t gfp_mask)
{
struct audit_entry *entry;
struct audit_field *fields;
entry = kzalloc(sizeof(*entry), gfp_mask);
if (unlikely(!entry))
return NULL;
fields = kzalloc(sizeof(*fields) * field_count, gfp_mask);
if (unlikely(!fields)) {
kfree(entry);
return NULL;
}
entry->rule.fields = fields;
return entry;
}
static inline int audit_dupe_selinux_field(struct audit_field *df,
struct audit_field *sf)
{
int ret = 0;
char *se_str;
/* our own copy of se_str */
se_str = kstrdup(sf->se_str, GFP_ATOMIC);
if (unlikely(IS_ERR(se_str)))
return -ENOMEM;
df->se_str = se_str;
/* our own (refreshed) copy of se_rule */
ret = selinux_audit_rule_init(df->type, df->op, df->se_str,
&df->se_rule);
/* Keep currently invalid fields around in case they
* become valid after a policy reload. */
if (ret == -EINVAL) {
printk(KERN_WARNING "audit rule for selinux \'%s\' is invalid\n",
df->se_str);
ret = 0;
}
return ret;
}
static struct audit_entry *audit_dupe_rule(struct audit_krule *old)
{
u32 fcount = old->field_count;
struct audit_entry *entry;
struct audit_krule *new;
int i, err = 0;
entry = audit_init_entry(fcount, GFP_ATOMIC);
if (unlikely(!entry))
return ERR_PTR(-ENOMEM);
new = &entry->rule;
new->vers_ops = old->vers_ops;
new->flags = old->flags;
new->listnr = old->listnr;
new->action = old->action;
for (i = 0; i < AUDIT_BITMASK_SIZE; i++)
new->mask[i] = old->mask[i];
new->buflen = old->buflen;
new->field_count = old->field_count;
memcpy(new->fields, old->fields, sizeof(struct audit_field) * fcount);
for (i = 0; i < fcount; i++) {
switch (new->fields[i].type) {
case AUDIT_SE_USER:
case AUDIT_SE_ROLE:
case AUDIT_SE_TYPE:
case AUDIT_SE_SEN:
case AUDIT_SE_CLR:
err = audit_dupe_selinux_field(&new->fields[i],
&old->fields[i]);
}
if (err) {
audit_free_rule(entry);
return ERR_PTR(err);
}
}
return entry;
}