From: Ard Biesheuvel <ard.biesheuvel-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> To: matt.fleming-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org, x86-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org Cc: catalin.marinas-5wv7dgnIgG8@public.gmane.org, linux-efi-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org, hpa-YMNOUZJC4hwAvxtiuMwx3w@public.gmane.org, leif.lindholm-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org, roy.franz-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org, msalter-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org, Ard Biesheuvel <ard.biesheuvel-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> Subject: [PATCH 2/2] efi: implement mandatory locking for UEFI Runtime Services Date: Wed, 2 Jul 2014 12:10:02 +0200 [thread overview] Message-ID: <1404295802-28030-2-git-send-email-ard.biesheuvel@linaro.org> (raw) In-Reply-To: <1404295802-28030-1-git-send-email-ard.biesheuvel-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> According to section 7.1 of the UEFI spec, Runtime Services are not fully reentrant, and there are particular combinations of calls that need to be serialized. Signed-off-by: Ard Biesheuvel <ard.biesheuvel-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> --- drivers/firmware/efi/runtime-wrappers.c | 109 +++++++++++++++++++++++++++++--- 1 file changed, 99 insertions(+), 10 deletions(-) diff --git a/drivers/firmware/efi/runtime-wrappers.c b/drivers/firmware/efi/runtime-wrappers.c index 10daa4bbb258..6588d054af99 100644 --- a/drivers/firmware/efi/runtime-wrappers.c +++ b/drivers/firmware/efi/runtime-wrappers.c @@ -15,10 +15,50 @@ */ #include <linux/efi.h> -#include <linux/spinlock.h> /* spinlock_t */ +#include <linux/mutex.h> +#include <linux/spinlock.h> #include <asm/efi.h> /* + * According to section 7.1 of the UEFI spec, Runtime Services are not fully + * reentrant, and there are particular combinations of calls that need to be + * serialized. + * + * Table 31. Rules for Reentry Into Runtime Services + * +------------------------------------+-------------------------------+ + * | If previous call is busy in | Forbidden to call | + * +------------------------------------+-------------------------------+ + * | Any | SetVirtualAddressMap() | + * +------------------------------------+-------------------------------+ + * | ConvertPointer() | ConvertPointer() | + * +------------------------------------+-------------------------------+ + * | SetVariable() | ResetSystem() | + * | UpdateCapsule() | | + * | SetTime() | | + * | SetWakeupTime() | | + * | GetNextHighMonotonicCount() | | + * +------------------------------------+-------------------------------+ + * | GetVariable() | GetVariable() | + * | GetNextVariableName() | GetNextVariableName() | + * | SetVariable() | SetVariable() | + * | QueryVariableInfo() | QueryVariableInfo() | + * | UpdateCapsule() | UpdateCapsule() | + * | QueryCapsuleCapabilities() | QueryCapsuleCapabilities() | + * | GetNextHighMonotonicCount() | GetNextHighMonotonicCount() | + * +------------------------------------+-------------------------------+ + * | GetTime() | GetTime() | + * | SetTime() | SetTime() | + * | GetWakeupTime() | GetWakeupTime() | + * | SetWakeupTime() | SetWakeupTime() | + * +------------------------------------+-------------------------------+ + * + * The first two are disregarded here, as SetVirtualAddressMap() is called + * only once, and very early, and ConvertPointer() is not exposed at all. + */ +static DEFINE_MUTEX(var_ro_mutex); +static DEFINE_MUTEX(var_rw_mutex); + +/* * As per commit ef68c8f87ed1 ("x86: Serialize EFI time accesses on rtc_lock"), * the EFI specification requires that callers of the time related runtime * functions serialize with other CMOS accesses in the kernel, as the EFI time @@ -78,14 +118,25 @@ static efi_status_t virt_efi_get_variable(efi_char16_t *name, unsigned long *data_size, void *data) { - return efi_call_virt(get_variable, name, vendor, attr, data_size, data); + efi_status_t status; + + mutex_lock(&var_ro_mutex); + status = efi_call_virt(get_variable, name, vendor, attr, data_size, + data); + mutex_unlock(&var_ro_mutex); + return status; } static efi_status_t virt_efi_get_next_variable(unsigned long *name_size, efi_char16_t *name, efi_guid_t *vendor) { - return efi_call_virt(get_next_variable, name_size, name, vendor); + efi_status_t status; + + mutex_lock(&var_ro_mutex); + status = efi_call_virt(get_next_variable, name_size, name, vendor); + mutex_unlock(&var_ro_mutex); + return status; } static efi_status_t virt_efi_set_variable(efi_char16_t *name, @@ -94,7 +145,15 @@ static efi_status_t virt_efi_set_variable(efi_char16_t *name, unsigned long data_size, void *data) { - return efi_call_virt(set_variable, name, vendor, attr, data_size, data); + efi_status_t status; + + mutex_lock(&var_ro_mutex); + mutex_lock(&var_rw_mutex); + status = efi_call_virt(set_variable, name, vendor, attr, data_size, + data); + mutex_unlock(&var_rw_mutex); + mutex_unlock(&var_ro_mutex); + return status; } static efi_status_t virt_efi_query_variable_info(u32 attr, @@ -102,16 +161,28 @@ static efi_status_t virt_efi_query_variable_info(u32 attr, u64 *remaining_space, u64 *max_variable_size) { + efi_status_t status; + if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) return EFI_UNSUPPORTED; - return efi_call_virt(query_variable_info, attr, storage_space, - remaining_space, max_variable_size); + mutex_lock(&var_ro_mutex); + status = efi_call_virt(query_variable_info, attr, storage_space, + remaining_space, max_variable_size); + mutex_unlock(&var_ro_mutex); + return status; } static efi_status_t virt_efi_get_next_high_mono_count(u32 *count) { - return efi_call_virt(get_next_high_mono_count, count); + efi_status_t status; + + mutex_lock(&var_ro_mutex); + mutex_lock(&var_rw_mutex); + status = efi_call_virt(get_next_high_mono_count, count); + mutex_unlock(&var_rw_mutex); + mutex_unlock(&var_ro_mutex); + return status; } static void virt_efi_reset_system(int reset_type, @@ -119,17 +190,30 @@ static void virt_efi_reset_system(int reset_type, unsigned long data_size, efi_char16_t *data) { + unsigned long flags; + + mutex_lock(&var_rw_mutex); + spin_lock_irqsave(&rtc_lock, flags); __efi_call_virt(reset_system, reset_type, status, data_size, data); + spin_unlock_irqrestore(&rtc_lock, flags); + mutex_unlock(&var_rw_mutex); } static efi_status_t virt_efi_update_capsule(efi_capsule_header_t **capsules, unsigned long count, unsigned long sg_list) { + efi_status_t status; + if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) return EFI_UNSUPPORTED; - return efi_call_virt(update_capsule, capsules, count, sg_list); + mutex_lock(&var_ro_mutex); + mutex_lock(&var_rw_mutex); + status = efi_call_virt(update_capsule, capsules, count, sg_list); + mutex_unlock(&var_rw_mutex); + mutex_unlock(&var_ro_mutex); + return status; } static efi_status_t virt_efi_query_capsule_caps(efi_capsule_header_t **capsules, @@ -137,11 +221,16 @@ static efi_status_t virt_efi_query_capsule_caps(efi_capsule_header_t **capsules, u64 *max_size, int *reset_type) { + efi_status_t status; + if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) return EFI_UNSUPPORTED; - return efi_call_virt(query_capsule_caps, capsules, count, max_size, - reset_type); + mutex_lock(&var_ro_mutex); + status = efi_call_virt(query_capsule_caps, capsules, count, max_size, + reset_type); + mutex_unlock(&var_ro_mutex); + return status; } void efi_native_runtime_setup(void) -- 1.8.3.2
WARNING: multiple messages have this Message-ID (diff)
From: ard.biesheuvel@linaro.org (Ard Biesheuvel) To: linux-arm-kernel@lists.infradead.org Subject: [PATCH 2/2] efi: implement mandatory locking for UEFI Runtime Services Date: Wed, 2 Jul 2014 12:10:02 +0200 [thread overview] Message-ID: <1404295802-28030-2-git-send-email-ard.biesheuvel@linaro.org> (raw) In-Reply-To: <1404295802-28030-1-git-send-email-ard.biesheuvel@linaro.org> According to section 7.1 of the UEFI spec, Runtime Services are not fully reentrant, and there are particular combinations of calls that need to be serialized. Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> --- drivers/firmware/efi/runtime-wrappers.c | 109 +++++++++++++++++++++++++++++--- 1 file changed, 99 insertions(+), 10 deletions(-) diff --git a/drivers/firmware/efi/runtime-wrappers.c b/drivers/firmware/efi/runtime-wrappers.c index 10daa4bbb258..6588d054af99 100644 --- a/drivers/firmware/efi/runtime-wrappers.c +++ b/drivers/firmware/efi/runtime-wrappers.c @@ -15,10 +15,50 @@ */ #include <linux/efi.h> -#include <linux/spinlock.h> /* spinlock_t */ +#include <linux/mutex.h> +#include <linux/spinlock.h> #include <asm/efi.h> /* + * According to section 7.1 of the UEFI spec, Runtime Services are not fully + * reentrant, and there are particular combinations of calls that need to be + * serialized. + * + * Table 31. Rules for Reentry Into Runtime Services + * +------------------------------------+-------------------------------+ + * | If previous call is busy in | Forbidden to call | + * +------------------------------------+-------------------------------+ + * | Any | SetVirtualAddressMap() | + * +------------------------------------+-------------------------------+ + * | ConvertPointer() | ConvertPointer() | + * +------------------------------------+-------------------------------+ + * | SetVariable() | ResetSystem() | + * | UpdateCapsule() | | + * | SetTime() | | + * | SetWakeupTime() | | + * | GetNextHighMonotonicCount() | | + * +------------------------------------+-------------------------------+ + * | GetVariable() | GetVariable() | + * | GetNextVariableName() | GetNextVariableName() | + * | SetVariable() | SetVariable() | + * | QueryVariableInfo() | QueryVariableInfo() | + * | UpdateCapsule() | UpdateCapsule() | + * | QueryCapsuleCapabilities() | QueryCapsuleCapabilities() | + * | GetNextHighMonotonicCount() | GetNextHighMonotonicCount() | + * +------------------------------------+-------------------------------+ + * | GetTime() | GetTime() | + * | SetTime() | SetTime() | + * | GetWakeupTime() | GetWakeupTime() | + * | SetWakeupTime() | SetWakeupTime() | + * +------------------------------------+-------------------------------+ + * + * The first two are disregarded here, as SetVirtualAddressMap() is called + * only once, and very early, and ConvertPointer() is not exposed at all. + */ +static DEFINE_MUTEX(var_ro_mutex); +static DEFINE_MUTEX(var_rw_mutex); + +/* * As per commit ef68c8f87ed1 ("x86: Serialize EFI time accesses on rtc_lock"), * the EFI specification requires that callers of the time related runtime * functions serialize with other CMOS accesses in the kernel, as the EFI time @@ -78,14 +118,25 @@ static efi_status_t virt_efi_get_variable(efi_char16_t *name, unsigned long *data_size, void *data) { - return efi_call_virt(get_variable, name, vendor, attr, data_size, data); + efi_status_t status; + + mutex_lock(&var_ro_mutex); + status = efi_call_virt(get_variable, name, vendor, attr, data_size, + data); + mutex_unlock(&var_ro_mutex); + return status; } static efi_status_t virt_efi_get_next_variable(unsigned long *name_size, efi_char16_t *name, efi_guid_t *vendor) { - return efi_call_virt(get_next_variable, name_size, name, vendor); + efi_status_t status; + + mutex_lock(&var_ro_mutex); + status = efi_call_virt(get_next_variable, name_size, name, vendor); + mutex_unlock(&var_ro_mutex); + return status; } static efi_status_t virt_efi_set_variable(efi_char16_t *name, @@ -94,7 +145,15 @@ static efi_status_t virt_efi_set_variable(efi_char16_t *name, unsigned long data_size, void *data) { - return efi_call_virt(set_variable, name, vendor, attr, data_size, data); + efi_status_t status; + + mutex_lock(&var_ro_mutex); + mutex_lock(&var_rw_mutex); + status = efi_call_virt(set_variable, name, vendor, attr, data_size, + data); + mutex_unlock(&var_rw_mutex); + mutex_unlock(&var_ro_mutex); + return status; } static efi_status_t virt_efi_query_variable_info(u32 attr, @@ -102,16 +161,28 @@ static efi_status_t virt_efi_query_variable_info(u32 attr, u64 *remaining_space, u64 *max_variable_size) { + efi_status_t status; + if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) return EFI_UNSUPPORTED; - return efi_call_virt(query_variable_info, attr, storage_space, - remaining_space, max_variable_size); + mutex_lock(&var_ro_mutex); + status = efi_call_virt(query_variable_info, attr, storage_space, + remaining_space, max_variable_size); + mutex_unlock(&var_ro_mutex); + return status; } static efi_status_t virt_efi_get_next_high_mono_count(u32 *count) { - return efi_call_virt(get_next_high_mono_count, count); + efi_status_t status; + + mutex_lock(&var_ro_mutex); + mutex_lock(&var_rw_mutex); + status = efi_call_virt(get_next_high_mono_count, count); + mutex_unlock(&var_rw_mutex); + mutex_unlock(&var_ro_mutex); + return status; } static void virt_efi_reset_system(int reset_type, @@ -119,17 +190,30 @@ static void virt_efi_reset_system(int reset_type, unsigned long data_size, efi_char16_t *data) { + unsigned long flags; + + mutex_lock(&var_rw_mutex); + spin_lock_irqsave(&rtc_lock, flags); __efi_call_virt(reset_system, reset_type, status, data_size, data); + spin_unlock_irqrestore(&rtc_lock, flags); + mutex_unlock(&var_rw_mutex); } static efi_status_t virt_efi_update_capsule(efi_capsule_header_t **capsules, unsigned long count, unsigned long sg_list) { + efi_status_t status; + if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) return EFI_UNSUPPORTED; - return efi_call_virt(update_capsule, capsules, count, sg_list); + mutex_lock(&var_ro_mutex); + mutex_lock(&var_rw_mutex); + status = efi_call_virt(update_capsule, capsules, count, sg_list); + mutex_unlock(&var_rw_mutex); + mutex_unlock(&var_ro_mutex); + return status; } static efi_status_t virt_efi_query_capsule_caps(efi_capsule_header_t **capsules, @@ -137,11 +221,16 @@ static efi_status_t virt_efi_query_capsule_caps(efi_capsule_header_t **capsules, u64 *max_size, int *reset_type) { + efi_status_t status; + if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) return EFI_UNSUPPORTED; - return efi_call_virt(query_capsule_caps, capsules, count, max_size, - reset_type); + mutex_lock(&var_ro_mutex); + status = efi_call_virt(query_capsule_caps, capsules, count, max_size, + reset_type); + mutex_unlock(&var_ro_mutex); + return status; } void efi_native_runtime_setup(void) -- 1.8.3.2
next prev parent reply other threads:[~2014-07-02 10:10 UTC|newest] Thread overview: 28+ messages / expand[flat|nested] mbox.gz Atom feed top 2014-07-02 10:10 [PATCH 1/2] efi/arm64: fix potential NULL dereference of efi.systab Ard Biesheuvel 2014-07-02 10:10 ` Ard Biesheuvel [not found] ` <1404295802-28030-1-git-send-email-ard.biesheuvel-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> 2014-07-02 10:10 ` Ard Biesheuvel [this message] 2014-07-02 10:10 ` [PATCH 2/2] efi: implement mandatory locking for UEFI Runtime Services Ard Biesheuvel [not found] ` <1404295802-28030-2-git-send-email-ard.biesheuvel-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org> 2014-07-07 20:29 ` Matt Fleming 2014-07-07 20:29 ` Matt Fleming [not found] ` <20140707202954.GC27474-HNK1S37rvNbeXh+fF434Mdi2O/JbrIOy@public.gmane.org> 2014-07-07 20:43 ` Ard Biesheuvel 2014-07-07 20:43 ` Ard Biesheuvel [not found] ` <CAKv+Gu91CQADTQ8KMjXQPwVDvW1XkUYO2E5=Mu=aAtrB8B3q_A-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> 2014-07-08 8:54 ` Ard Biesheuvel 2014-07-08 8:54 ` Ard Biesheuvel [not found] ` <CAKv+Gu8LbfuuEYyhAeu3dUiKHqzN_UFMbOjY0agVihbmmVL9CA-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> 2014-07-08 9:29 ` Matt Fleming 2014-07-08 9:29 ` Matt Fleming [not found] ` <20140708092958.GD27474-HNK1S37rvNbeXh+fF434Mdi2O/JbrIOy@public.gmane.org> 2014-07-08 9:45 ` Ard Biesheuvel 2014-07-08 9:45 ` Ard Biesheuvel [not found] ` <CAKv+Gu9HkJgsnzUAROVwPKaHGHRU9FwAp+eOT8N8kYDR3Dda+w-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> 2014-07-08 9:52 ` Matt Fleming 2014-07-08 9:52 ` Matt Fleming 2014-07-02 10:13 ` [PATCH 1/2] efi/arm64: fix potential NULL dereference of efi.systab Ard Biesheuvel 2014-07-02 10:13 ` Ard Biesheuvel [not found] ` <CAKv+Gu-SLQC82q7Rj5ZusbFxwysy7KpRhZ=vw1ipXu9kvq46aQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> 2014-07-02 14:29 ` Mark Salter 2014-07-02 14:29 ` Mark Salter [not found] ` <1404311385.19665.15.camel-PDpCo7skNiwAicBL8TP8PQ@public.gmane.org> 2014-07-03 16:04 ` Ard Biesheuvel 2014-07-03 16:04 ` Ard Biesheuvel 2014-07-04 13:38 ` Catalin Marinas 2014-07-04 13:38 ` Catalin Marinas [not found] ` <20140704133844.GG16404-5wv7dgnIgG8@public.gmane.org> 2014-07-04 13:54 ` Ard Biesheuvel 2014-07-04 13:54 ` Ard Biesheuvel [not found] ` <CAKv+Gu_VJZuzio8oyDA4OKwaeZj3J4WY_kX4s-_zhs1rk35b7A-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org> 2014-07-04 15:32 ` Catalin Marinas 2014-07-04 15:32 ` Catalin Marinas
Reply instructions: You may reply publicly to this message via plain-text email using any one of the following methods: * Save the following mbox file, import it into your mail client, and reply-to-all from there: mbox Avoid top-posting and favor interleaved quoting: https://en.wikipedia.org/wiki/Posting_style#Interleaved_style * Reply using the --to, --cc, and --in-reply-to switches of git-send-email(1): git send-email \ --in-reply-to=1404295802-28030-2-git-send-email-ard.biesheuvel@linaro.org \ --to=ard.biesheuvel-qsej5fyqhm4dnm+yrofe0a@public.gmane.org \ --cc=catalin.marinas-5wv7dgnIgG8@public.gmane.org \ --cc=hpa-YMNOUZJC4hwAvxtiuMwx3w@public.gmane.org \ --cc=leif.lindholm-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org \ --cc=linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org \ --cc=linux-efi-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \ --cc=matt.fleming-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org \ --cc=msalter-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org \ --cc=roy.franz-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org \ --cc=x86-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org \ /path/to/YOUR_REPLY https://kernel.org/pub/software/scm/git/docs/git-send-email.html * If your mail client supports setting the In-Reply-To header via mailto: links, try the mailto: linkBe sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.