mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2025-01-09 15:29:16 +00:00
72a6e22c60
The fscache_cookie_lru_timer is initialized when the fscache module is inserted, but is not deleted when the fscache module is removed. If timer_reduce() is called before removing the fscache module, the fscache_cookie_lru_timer will be added to the timer list of the current cpu. Afterwards, a use-after-free will be triggered in the softIRQ after removing the fscache module, as follows: ================================================================== BUG: unable to handle page fault for address: fffffbfff803c9e9 PF: supervisor read access in kernel mode PF: error_code(0x0000) - not-present page PGD 21ffea067 P4D 21ffea067 PUD 21ffe6067 PMD 110a7c067 PTE 0 Oops: Oops: 0000 [#1] PREEMPT SMP KASAN PTI CPU: 1 UID: 0 PID: 0 Comm: swapper/1 Tainted: G W 6.11.0-rc3 #855 Tainted: [W]=WARN RIP: 0010:__run_timer_base.part.0+0x254/0x8a0 Call Trace: <IRQ> tmigr_handle_remote_up+0x627/0x810 __walk_groups.isra.0+0x47/0x140 tmigr_handle_remote+0x1fa/0x2f0 handle_softirqs+0x180/0x590 irq_exit_rcu+0x84/0xb0 sysvec_apic_timer_interrupt+0x6e/0x90 </IRQ> <TASK> asm_sysvec_apic_timer_interrupt+0x1a/0x20 RIP: 0010:default_idle+0xf/0x20 default_idle_call+0x38/0x60 do_idle+0x2b5/0x300 cpu_startup_entry+0x54/0x60 start_secondary+0x20d/0x280 common_startup_64+0x13e/0x148 </TASK> Modules linked in: [last unloaded: netfs] ================================================================== Therefore delete fscache_cookie_lru_timer when removing the fscahe module. Fixes: 12bb21a29c19 ("fscache: Implement cookie user counting and resource pinning") Cc: stable@kernel.org Signed-off-by: Baokun Li <libaokun1@huawei.com> Link: https://lore.kernel.org/r/20240826112056.2458299-1-libaokun@huaweicloud.com Acked-by: David Howells <dhowells@redhat.com> Signed-off-by: Christian Brauner <brauner@kernel.org>
110 lines
2.6 KiB
C
110 lines
2.6 KiB
C
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
/* General filesystem local caching manager
|
|
*
|
|
* Copyright (C) 2021 Red Hat, Inc. All Rights Reserved.
|
|
* Written by David Howells (dhowells@redhat.com)
|
|
*/
|
|
|
|
#define FSCACHE_DEBUG_LEVEL CACHE
|
|
#include <linux/module.h>
|
|
#include <linux/init.h>
|
|
#include "internal.h"
|
|
#define CREATE_TRACE_POINTS
|
|
#include <trace/events/fscache.h>
|
|
|
|
EXPORT_TRACEPOINT_SYMBOL(fscache_access_cache);
|
|
EXPORT_TRACEPOINT_SYMBOL(fscache_access_volume);
|
|
EXPORT_TRACEPOINT_SYMBOL(fscache_access);
|
|
|
|
struct workqueue_struct *fscache_wq;
|
|
EXPORT_SYMBOL(fscache_wq);
|
|
|
|
/*
|
|
* Mixing scores (in bits) for (7,20):
|
|
* Input delta: 1-bit 2-bit
|
|
* 1 round: 330.3 9201.6
|
|
* 2 rounds: 1246.4 25475.4
|
|
* 3 rounds: 1907.1 31295.1
|
|
* 4 rounds: 2042.3 31718.6
|
|
* Perfect: 2048 31744
|
|
* (32*64) (32*31/2 * 64)
|
|
*/
|
|
#define HASH_MIX(x, y, a) \
|
|
( x ^= (a), \
|
|
y ^= x, x = rol32(x, 7),\
|
|
x += y, y = rol32(y,20),\
|
|
y *= 9 )
|
|
|
|
static inline unsigned int fold_hash(unsigned long x, unsigned long y)
|
|
{
|
|
/* Use arch-optimized multiply if one exists */
|
|
return __hash_32(y ^ __hash_32(x));
|
|
}
|
|
|
|
/*
|
|
* Generate a hash. This is derived from full_name_hash(), but we want to be
|
|
* sure it is arch independent and that it doesn't change as bits of the
|
|
* computed hash value might appear on disk. The caller must guarantee that
|
|
* the source data is a multiple of four bytes in size.
|
|
*/
|
|
unsigned int fscache_hash(unsigned int salt, const void *data, size_t len)
|
|
{
|
|
const __le32 *p = data;
|
|
unsigned int a, x = 0, y = salt, n = len / sizeof(__le32);
|
|
|
|
for (; n; n--) {
|
|
a = le32_to_cpu(*p++);
|
|
HASH_MIX(x, y, a);
|
|
}
|
|
return fold_hash(x, y);
|
|
}
|
|
|
|
/*
|
|
* initialise the fs caching module
|
|
*/
|
|
int __init fscache_init(void)
|
|
{
|
|
int ret = -ENOMEM;
|
|
|
|
fscache_wq = alloc_workqueue("fscache", WQ_UNBOUND | WQ_FREEZABLE, 0);
|
|
if (!fscache_wq)
|
|
goto error_wq;
|
|
|
|
ret = fscache_proc_init();
|
|
if (ret < 0)
|
|
goto error_proc;
|
|
|
|
fscache_cookie_jar = kmem_cache_create("fscache_cookie_jar",
|
|
sizeof(struct fscache_cookie),
|
|
0, 0, NULL);
|
|
if (!fscache_cookie_jar) {
|
|
pr_notice("Failed to allocate a cookie jar\n");
|
|
ret = -ENOMEM;
|
|
goto error_cookie_jar;
|
|
}
|
|
|
|
pr_notice("FS-Cache loaded\n");
|
|
return 0;
|
|
|
|
error_cookie_jar:
|
|
fscache_proc_cleanup();
|
|
error_proc:
|
|
destroy_workqueue(fscache_wq);
|
|
error_wq:
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* clean up on module removal
|
|
*/
|
|
void __exit fscache_exit(void)
|
|
{
|
|
_enter("");
|
|
|
|
kmem_cache_destroy(fscache_cookie_jar);
|
|
fscache_proc_cleanup();
|
|
timer_shutdown_sync(&fscache_cookie_lru_timer);
|
|
destroy_workqueue(fscache_wq);
|
|
pr_notice("FS-Cache unloaded\n");
|
|
}
|