• Eric Biggers's avatar
    blk-mq: release crypto keyslot before reporting I/O complete · 9cd1e566
    Eric Biggers authored
    Once all I/O using a blk_crypto_key has completed, filesystems can call
    blk_crypto_evict_key().  However, the block layer currently doesn't call
    blk_crypto_put_keyslot() until the request is being freed, which happens
    after upper layers have been told (via bio_endio()) the I/O has
    completed.  This causes a race condition where blk_crypto_evict_key()
    can see 'slot_refs != 0' without there being an actual bug.
    
    This makes __blk_crypto_evict_key() hit the
    'WARN_ON_ONCE(atomic_read(&slot->slot_refs) != 0)' and return without
    doing anything, eventually causing a use-after-free in
    blk_crypto_reprogram_all_keys().  (This is a very rare bug and has only
    been seen when per-file keys are being used with fscrypt.)
    
    There are two options to fix this: either release the keyslot before
    bio_endio() is called on the request's last bio, or make
    __blk_crypto_evict_key() ignore slot_refs.  Let's go with the first
    solution, since it preserves the ability to report bugs (via
    WARN_ON_ONCE) where a key is evicted while still in-use.
    
    Fixes: a892c8d5 ("block: Inline encryption support for blk-mq")
    Cc: stable@vger.kernel.org
    Reviewed-by: default avatarNathan Huckleberry <nhuck@google.com>
    Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
    Signed-off-by: default avatarEric Biggers <ebiggers@google.com>
    Link: https://lore.kernel.org/r/20230315183907.53675-2-ebiggers@kernel.orgSigned-off-by: default avatarJens Axboe <axboe@kernel.dk>
    9cd1e566
blk-merge.c 31.4 KB