mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-09-18 23:09:29 +02:00
efivarfs: Rate limit statfs() handler
Ravi reports that statfs() may be called by unprivileged users on the
efivarfs mount point, which may result in a flood of calls to the
QueryVariableInfo() runtime service. These calls are disproportionately
costly on x86 systems where the variable store is backed by SMM, as each
SMM entry requires a rendez-vous of all the CPUs.
So rate limit the calls to QueryVariableInfo() at twice per second, and
return the most recently obtained value for calls that are elided.
Cc: <stable@vger.kernel.org>
Reported-by: Ravi Bangoria <ravi.bangoria@amd.com>
Fixes: d86ff3333c ("efivarfs: expose used and total size")
Reviewed-by: Anisse Astier <anisse@astier.eu>
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
This commit is contained in:
+24
-6
@@ -89,12 +89,30 @@ static int efivarfs_statfs(struct dentry *dentry, struct kstatfs *buf)
|
||||
/* Some UEFI firmware does not implement QueryVariableInfo() */
|
||||
storage_space = remaining_space = 0;
|
||||
if (efi_rt_services_supported(EFI_RT_SUPPORTED_QUERY_VARIABLE_INFO)) {
|
||||
status = efivar_query_variable_info(attr, &storage_space,
|
||||
&remaining_space,
|
||||
&max_variable_size);
|
||||
if (status != EFI_SUCCESS && status != EFI_UNSUPPORTED)
|
||||
pr_warn_ratelimited("query_variable_info() failed: 0x%lx\n",
|
||||
status);
|
||||
static DEFINE_RATELIMIT_STATE(_rs, 2 * HZ, 5);
|
||||
static u64 storage, remaining;
|
||||
static DEFINE_SPINLOCK(lock);
|
||||
|
||||
if (!__ratelimit(&_rs)) {
|
||||
ratelimit_set_flags(&_rs, RATELIMIT_MSG_ON_RELEASE);
|
||||
|
||||
spin_lock(&lock);
|
||||
storage_space = storage;
|
||||
remaining_space = remaining;
|
||||
spin_unlock(&lock);
|
||||
} else {
|
||||
status = efivar_query_variable_info(attr, &storage_space,
|
||||
&remaining_space,
|
||||
&max_variable_size);
|
||||
if (status != EFI_SUCCESS && status != EFI_UNSUPPORTED)
|
||||
pr_warn("query_variable_info() failed: 0x%lx\n",
|
||||
status);
|
||||
|
||||
spin_lock(&lock);
|
||||
storage = storage_space;
|
||||
remaining = remaining_space;
|
||||
spin_unlock(&lock);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user