audit: Embed key into chunk
authorJan Kara <jack@suse.cz>
Mon, 12 Nov 2018 14:54:48 +0000 (09:54 -0500)
committerPaul Moore <paul@paul-moore.com>
Mon, 12 Nov 2018 14:54:48 +0000 (09:54 -0500)
commit8d20d6e9301d7b3777d66d47dd5b89acd645cd39
treea299211173a342d7239635d4c5ac199d234d06e5
parentb1e4603b92d8aef8776e5673dc13fedb68d32ea4
audit: Embed key into chunk

Currently chunk hash key (which is in fact pointer to the inode) is
derived as chunk->mark.conn->obj. It is tricky to make this dereference
reliable for hash table lookups only under RCU as mark can get detached
from the connector and connector gets freed independently of the
running lookup. Thus there is a possible use after free / NULL ptr
dereference issue:

CPU1 CPU2
untag_chunk()
  ...
audit_tree_lookup()
  list_for_each_entry_rcu(p, list, hash) {
  list_del_rcu(&chunk->hash);
  fsnotify_destroy_mark(entry);
  fsnotify_put_mark(entry)
    chunk_to_key(p)
      if (!chunk->mark.connector)
    ...
    hlist_del_init_rcu(&mark->obj_list);
    if (hlist_empty(&conn->list)) {
      inode = fsnotify_detach_connector_from_object(conn);
    mark->connector = NULL;
    ...
    frees connector from workqueue
      chunk->mark.connector->obj

This race is probably impossible to hit in practice as the race window
on CPU1 is very narrow and CPU2 has a lot of code to execute. Still it's
better to have this fixed. Since the inode the chunk is attached to is
constant during chunk's lifetime it is easy to cache the key in the
chunk itself and thus avoid these issues.

Reviewed-by: Richard Guy Briggs <rgb@redhat.com>
Signed-off-by: Jan Kara <jack@suse.cz>
Signed-off-by: Paul Moore <paul@paul-moore.com>
kernel/audit_tree.c