/* * Reference counting: * * audit_parent: lifetime is from audit_init_parent() to receipt of an FS_IGNORED * event. Each audit_watch holds a reference to its associated parent. * * audit_watch: if added to lists, lifetime is from audit_init_watch() to * audit_remove_watch(). Additionally, an audit_watch may exist * temporarily to assist in searching existing filter data. Each * audit_krule holds a reference to its associated watch.
*/
staticvoid audit_get_parent(struct audit_parent *parent)
{ if (likely(parent))
fsnotify_get_mark(&parent->mark);
}
staticvoid audit_put_parent(struct audit_parent *parent)
{ if (likely(parent))
fsnotify_put_mark(&parent->mark);
}
/* * Find and return the audit_parent on the given inode. If found a reference * is taken on this parent.
*/ staticinlinestruct audit_parent *audit_find_parent(struct inode *inode)
{ struct audit_parent *parent = NULL; struct fsnotify_mark *entry;
watch = audit_init_watch(path); if (IS_ERR(watch)) return PTR_ERR(watch);
krule->watch = watch;
return 0;
}
/* Duplicate the given audit watch. The new watch's rules list is initialized
* to an empty list and wlist is undefined. */ staticstruct audit_watch *audit_dupe_watch(struct audit_watch *old)
{ char *path; struct audit_watch *new;
path = kstrdup(old->path, GFP_KERNEL); if (unlikely(!path)) return ERR_PTR(-ENOMEM);
new = audit_init_watch(path); if (IS_ERR(new)) {
kfree(path); goto out;
}
if (!audit_enabled) return;
ab = audit_log_start(audit_context(), GFP_NOFS, AUDIT_CONFIG_CHANGE); if (!ab) return;
audit_log_session_info(ab);
audit_log_format(ab, "op=%s path=", op);
audit_log_untrustedstring(ab, w->path);
audit_log_key(ab, r->filterkey);
audit_log_format(ab, " list=%d res=1", r->listnr);
audit_log_end(ab);
}
/* Update inode info in audit rules based on filesystem event. */ staticvoid audit_update_watch(struct audit_parent *parent, conststruct qstr *dname, dev_t dev, unsignedlong ino, unsigned invalidating)
{ struct audit_watch *owatch, *nwatch, *nextw; struct audit_krule *r, *nextr; struct audit_entry *oentry, *nentry;
mutex_lock(&audit_filter_mutex); /* Run all of the watches on this parent looking for the one that
* matches the given dname */
list_for_each_entry_safe(owatch, nextw, &parent->watches, wlist) { if (audit_compare_dname_path(dname, owatch->path,
AUDIT_NAME_FULL)) continue;
/* If the update involves invalidating rules, do the inode-based
* filtering now, so we don't omit records. */ if (invalidating && !audit_dummy_context())
audit_filter_inodes(current, audit_context());
/* updating ino will likely change which audit_hash_list we
* are on so we need a new watch for the new list */
nwatch = audit_dupe_watch(owatch); if (IS_ERR(nwatch)) {
mutex_unlock(&audit_filter_mutex);
audit_panic("error updating watch, skipping"); return;
}
nwatch->dev = dev;
nwatch->ino = ino;
nentry = audit_dupe_rule(&oentry->rule); if (IS_ERR(nentry)) {
list_del(&oentry->rule.list);
audit_panic("error updating watch, removing");
} else { int h = audit_hash_ino((u32)ino);
/* * nentry->rule.watch == oentry->rule.watch so * we must drop that reference and set it to our * new watch.
*/
audit_put_watch(nentry->rule.watch);
audit_get_watch(nwatch);
nentry->rule.watch = nwatch;
list_add(&nentry->rule.rlist, &nwatch->rules);
list_add_rcu(&nentry->list, &audit_inode_hash[h]);
list_replace(&oentry->rule.list,
&nentry->rule.list);
} if (oentry->rule.exe)
audit_remove_mark(oentry->rule.exe);
call_rcu(&oentry->rcu, audit_free_rule_rcu);
}
audit_remove_watch(owatch); goto add_watch_to_parent; /* event applies to a single watch */
}
mutex_unlock(&audit_filter_mutex); return;
/* Associate the given rule with an existing parent.
* Caller must hold audit_filter_mutex. */ staticvoid audit_add_to_parent(struct audit_krule *krule, struct audit_parent *parent)
{ struct audit_watch *w, *watch = krule->watch; int watch_found = 0;
BUG_ON(!mutex_is_locked(&audit_filter_mutex));
list_for_each_entry(w, &parent->watches, wlist) { if (strcmp(watch->path, w->path)) continue;
watch_found = 1;
/* put krule's ref to temporary watch */
audit_put_watch(watch);
/* Find a matching watch entry, or add this one.
* Caller must hold audit_filter_mutex. */ int audit_add_watch(struct audit_krule *krule, struct list_head **list)
{ struct audit_watch *watch = krule->watch; struct audit_parent *parent; struct path parent_path; int h, ret = 0;
/* * When we will be calling audit_add_to_parent, krule->watch might have * been updated and watch might have been freed. * So we need to keep a reference of watch.
*/
audit_get_watch(watch);
mutex_unlock(&audit_filter_mutex);
/* Avoid calling path_lookup under audit_filter_mutex. */
ret = audit_get_nd(watch, &parent_path);
/* either find an old parent or attach a new one */
parent = audit_find_parent(d_backing_inode(parent_path.dentry)); if (!parent) {
parent = audit_init_parent(&parent_path); if (IS_ERR(parent)) {
ret = PTR_ERR(parent); goto error;
}
}
if (list_empty(&watch->rules)) { /* * audit_remove_watch() drops our reference to 'parent' which * can get freed. Grab our own reference to be safe.
*/
audit_get_parent(parent);
audit_remove_watch(watch); if (list_empty(&parent->watches))
fsnotify_destroy_mark(&parent->mark, audit_watch_group);
audit_put_parent(parent);
}
}
/* Update watch data in audit rules based on fsnotify events. */ staticint audit_watch_handle_event(struct fsnotify_mark *inode_mark, u32 mask, struct inode *inode, struct inode *dir, conststruct qstr *dname, u32 cookie)
{ struct audit_parent *parent;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.