OSDN Git Service

audit: Embed key into chunk
authorJan Kara <jack@suse.cz>
Mon, 12 Nov 2018 14:54:48 +0000 (09:54 -0500)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 13 Dec 2019 07:51:11 +0000 (08:51 +0100)
commit6ce317fdc212aa0cae3c0b375d6273161caad2e5
treeb7466074f6f0028ff16bc41bdfe5901777150a2d
parentb8252ec6ddd1067e6fce5abc84f7f15f5830b619
audit: Embed key into chunk

[ Upstream commit 8d20d6e9301d7b3777d66d47dd5b89acd645cd39 ]

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>
Signed-off-by: Sasha Levin <sashal@kernel.org>
kernel/audit_tree.c