From patchwork Thu Apr 18 12:54:50 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Ilias Apalodimas X-Patchwork-Id: 1925000 X-Patchwork-Delegate: xypron.glpk@gmx.de Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=linaro.org header.i=@linaro.org header.a=rsa-sha256 header.s=google header.b=NH/xWnek; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=2a01:238:438b:c500:173d:9f52:ddab:ee01; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=patchwork.ozlabs.org) Received: from phobos.denx.de (phobos.denx.de [IPv6:2a01:238:438b:c500:173d:9f52:ddab:ee01]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4VKyRm3l06z1yPv for ; Thu, 18 Apr 2024 22:55:16 +1000 (AEST) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id A888D88648; Thu, 18 Apr 2024 14:55:11 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (2048-bit key; unprotected) header.d=linaro.org header.i=@linaro.org header.b="NH/xWnek"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id 498EE8864E; Thu, 18 Apr 2024 14:55:10 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,SPF_HELO_NONE,SPF_PASS autolearn=ham autolearn_force=no version=3.4.2 Received: from mail-lf1-x12f.google.com (mail-lf1-x12f.google.com [IPv6:2a00:1450:4864:20::12f]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id BBA4B8863B for ; Thu, 18 Apr 2024 14:55:07 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=ilias.apalodimas@linaro.org Received: by mail-lf1-x12f.google.com with SMTP id 2adb3069b0e04-518b9527c60so871830e87.0 for ; Thu, 18 Apr 2024 05:55:07 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1713444907; x=1714049707; darn=lists.denx.de; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=sDcY+9C7upmKRoHndLneH5q/7nbyCu8Yr5R13Pqv7s0=; b=NH/xWnekyiY6CNz/Xb90N6cOVW/PEcYhk6ktj2fAAwfm8LCdDDUZ++66jfHNyEcGvK qYYcbl2hR0m57VE7PDPcsbZzDsV5Q9YlkxcRCzM0h49ZuwDU33r+puIuJ+N6Ak6VnOhP +2hznA3b8dcbaLTepbUQ+LzyBS3OtSbGICqrIpApfZaSx/Vk8vZpxUydRHZLkV9Th+5j ABPg5Uw35gjHzBhbmIngyQIXbaY/7gOSry9LmRMfVWVB+uLK1Dj3TTG0j+swtT1hELBJ Q7CCFk4xnLRXHV+I4GtVONPu1PQ1adRYR0apFRhMrnqJrWZIGA5jVgyFpVQmz+zMUxle QBTQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1713444907; x=1714049707; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=sDcY+9C7upmKRoHndLneH5q/7nbyCu8Yr5R13Pqv7s0=; b=cyVGFMgdgG6Rc2PV+l58S1Npqp4bWtJsYfKvYgiseBOCxlCJd1URtRQOZM4jl4TdYW E2kDw1IJgJXRiY20K9PtrqVTi9cCzOsrmxzvMh+B+7g3HdsB3vJ46WHoUdTDzTGNSXyO 8z3e1f8rUccpeUJUkHyfOEFwqIN4v+RJdO7nVuk+kqiFC7rB4W0h+UDeiLGQZZDNFUs0 hlfedZk+okkSO2FNglHKuld9Uyar5FVOTXxZDVpgI8zhSdZhqmwzxrlboaVfb7ciBAIR vt4cKTQ19XPwfjh6jcaK8BzVrNZqe+hgBm3EXQINy7APrujANqAn5LlTd6c2AHCEum7J /2SA== X-Forwarded-Encrypted: i=1; AJvYcCWlJfGRkrPA4YFq2am2imjY/hQIhY3l5VvseHSIZVRX146WJ7fyi6vsrl25Ka8+02oFz8u00TEiEp4TEatFp+rCR3xUyA== X-Gm-Message-State: AOJu0YzzG76Tz8gnJZrhY5Nw5y3HPfug9d/QRv8TzrGigPLlNIr9JK7I I32Fh7H3v947cwjo/6FGHH4y9rw7yz0FpLXwttI61/i7quffgvyy/nf1bBoUQA4= X-Google-Smtp-Source: AGHT+IFk4r6x9sG9S0lyLlT0V5TsnCC3NpX4YIkIi/ETo6X1k/u3MwDsjrzRlTUvcVIUSymeQNWe0Q== X-Received: by 2002:ac2:44cb:0:b0:515:d1a6:1b07 with SMTP id d11-20020ac244cb000000b00515d1a61b07mr2231589lfm.15.1713444906902; Thu, 18 Apr 2024 05:55:06 -0700 (PDT) Received: from hades.. (ppp176092141112.access.hol.gr. [176.92.141.112]) by smtp.gmail.com with ESMTPSA id m11-20020a1709060d8b00b00a525a18f748sm847002eji.165.2024.04.18.05.55.04 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 18 Apr 2024 05:55:06 -0700 (PDT) From: Ilias Apalodimas To: xypron.glpk@gmx.de, kettenis@openbsd.org Cc: caleb.connolly@linaro.org, sumit.garg@linaro.org, quic_llindhol@quicinc.com, ardb@kernel.org, pbrobinson@gmail.com, pjones@redhat.com, Ilias Apalodimas , Heinrich Schuchardt , Tom Rini , Masahisa Kojima , AKASHI Takahiro , Raymond Mao , Janne Grunau , Simon Glass , Matthias Schiffer , Abdellatif El Khlifi , Sughosh Ganu , Richard Henderson , Sam Edwards , Alper Nebi Yasak , Weizhao Ouyang , u-boot@lists.denx.de Subject: [PATCH v3 1/4] efi_loader: conditionally enable SetvariableRT Date: Thu, 18 Apr 2024 15:54:50 +0300 Message-Id: <20240418125456.50944-2-ilias.apalodimas@linaro.org> X-Mailer: git-send-email 2.40.1 In-Reply-To: <20240418125456.50944-1-ilias.apalodimas@linaro.org> References: <20240418125456.50944-1-ilias.apalodimas@linaro.org> MIME-Version: 1.0 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.39 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.103.8 at phobos.denx.de X-Virus-Status: Clean When we store EFI variables on file we don't allow SetVariable at runtime, since the OS doesn't know how to access or write that file. At the same time keeping the U-Boot drivers alive in runtime sections and performing writes from the firmware is dangerous -- if at all possible. For GetVariable at runtime we copy runtime variables in RAM and expose them to the OS. Add a Kconfig option and provide SetVariable at runtime using the same memory backend. The OS will be responsible for syncing the RAM contents to the file, otherwise any changes made during runtime won't persist reboots. It's worth noting that the variable store format is defined in EBBR [0] and authenticated variables are explicitly prohibited, since they have to be stored on a medium that's tamper and rollback protected. - pre-patch $~ mount | grep efiva efivarfs on /sys/firmware/efi/efivars type efivarfs (ro,nosuid,nodev,noexec,relatime) $~ efibootmgr -n 0001 Could not set BootNext: Read-only file system - post-patch $~ mount | grep efiva efivarfs on /sys/firmware/efi/efivars type efivarfs (rw,nosuid,nodev,noexec,relatime) $~ efibootmgr -n 0001 BootNext: 0001 BootCurrent: 0000 BootOrder: 0000,0001 Boot0000* debian HD(1,GPT,bdae5610-3331-4e4d-9466-acb5caf0b4a6,0x800,0x100000)/File(EFI\debian\grubaa64.efi) Boot0001* virtio 0 VenHw(e61d73b9-a384-4acc-aeab-82e828f3628b,0000000000000000)/VenHw(e61d73b9-a384-4acc-aeab-82e828f3628b,850000001f000000)/VenHw(e61d73b9-a384-4acc-aeab-82e828f3628b,1600850000000000){auto_created_boot_option} $~ efivar -p -n 8be4df61-93ca-11d2-aa0d-00e098032b8c-BootNext GUID: 8be4df61-93ca-11d2-aa0d-00e098032b8c Name: "BootNext" Attributes: Non-Volatile Boot Service Access Runtime Service Access Value: 00000000 01 00 FWTS runtime results Skipped tests are for SetVariable which is now supported 'Passed' test is for QueryVariableInfo which is not yet supported Test: UEFI miscellaneous runtime service interface tests. Test for UEFI miscellaneous runtime service interfaces 6 skipped Stress test for UEFI miscellaneous runtime service i.. 1 skipped Test GetNextHighMonotonicCount with invalid NULL par.. 1 skipped Test UEFI miscellaneous runtime services unsupported.. 1 passed Test: UEFI Runtime service variable interface tests. Test UEFI RT service get variable interface. 1 passed Test UEFI RT service get next variable name interface. 4 passed Test UEFI RT service set variable interface. 8 passed Test UEFI RT service query variable info interface. 1 skipped Test UEFI RT service variable interface stress test. 2 passed Test UEFI RT service set variable interface stress t.. 4 passed Test UEFI RT service query variable info interface s.. 1 skipped Test UEFI RT service get variable interface, invalid.. 5 passed Test UEFI RT variable services unsupported status. 1 passed, 3 skipped [0] https://arm-software.github.io/ebbr/index.html#document-chapter5-variable-storage Reviewed-by: Heinrich Schuchardt Signed-off-by: Ilias Apalodimas --- lib/efi_loader/Kconfig | 16 +++ lib/efi_loader/efi_runtime.c | 4 + lib/efi_loader/efi_variable.c | 116 ++++++++++++++++-- .../efi_selftest_variables_runtime.c | 14 ++- 4 files changed, 136 insertions(+), 14 deletions(-) diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig index e13a6f9f4c3a..cc8371a3bb4c 100644 --- a/lib/efi_loader/Kconfig +++ b/lib/efi_loader/Kconfig @@ -62,6 +62,22 @@ config EFI_VARIABLE_FILE_STORE Select this option if you want non-volatile UEFI variables to be stored as file /ubootefi.var on the EFI system partition. +config EFI_RT_VOLATILE_STORE + bool "Allow variable runtime services in volatile storage (e.g RAM)" + depends on EFI_VARIABLE_FILE_STORE + help + When EFI variables are stored on file we don't allow SetVariableRT, + since the OS doesn't know how to write that file. At he same time + we copy runtime variables in DRAM and support GetVariableRT + + Enable this option to allow SetVariableRT on the RAM backend of + the EFI variable storage. The OS will be responsible for syncing + the RAM contents to the file, otherwise any changes made during + runtime won't persist reboots. + Authenticated variables are not supported. Note that this will + violate the EFI spec since writing auth variables will return + EFI_INVALID_PARAMETER + config EFI_MM_COMM_TEE bool "UEFI variables storage service via the trusted world" depends on OPTEE diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c index a61c9a77b13f..dde083b09665 100644 --- a/lib/efi_loader/efi_runtime.c +++ b/lib/efi_loader/efi_runtime.c @@ -127,6 +127,10 @@ efi_status_t efi_init_runtime_supported(void) EFI_RT_SUPPORTED_SET_VIRTUAL_ADDRESS_MAP | EFI_RT_SUPPORTED_CONVERT_POINTER; + if (IS_ENABLED(CONFIG_EFI_RT_VOLATILE_STORE)) + rt_table->runtime_services_supported |= + EFI_RT_SUPPORTED_SET_VARIABLE; + /* * This value must be synced with efi_runtime_detach_list * as well as efi_runtime_services. diff --git a/lib/efi_loader/efi_variable.c b/lib/efi_loader/efi_variable.c index e6c1219a11c8..47bb79920575 100644 --- a/lib/efi_loader/efi_variable.c +++ b/lib/efi_loader/efi_variable.c @@ -219,17 +219,20 @@ efi_get_next_variable_name_int(efi_uintn_t *variable_name_size, return efi_get_next_variable_name_mem(variable_name_size, variable_name, vendor); } -efi_status_t efi_set_variable_int(const u16 *variable_name, - const efi_guid_t *vendor, - u32 attributes, efi_uintn_t data_size, - const void *data, bool ro_check) +/** + * setvariable_allowed() - checks defined by the UEFI spec for setvariable + * + * @variable_name: name of the variable + * @vendor: vendor GUID + * @attributes: attributes of the variable + * @data_size: size of the buffer with the variable value + * @data: buffer with the variable value + * Return: status code + */ +static efi_status_t __efi_runtime +setvariable_allowed(const u16 *variable_name, const efi_guid_t *vendor, + u32 attributes, efi_uintn_t data_size, const void *data) { - struct efi_var_entry *var; - efi_uintn_t ret; - bool append, delete; - u64 time = 0; - enum efi_auth_var_type var_type; - if (!variable_name || !*variable_name || !vendor) return EFI_INVALID_PARAMETER; @@ -261,6 +264,25 @@ efi_status_t efi_set_variable_int(const u16 *variable_name, !(attributes & EFI_VARIABLE_BOOTSERVICE_ACCESS))) return EFI_INVALID_PARAMETER; + return EFI_SUCCESS; +} + +efi_status_t efi_set_variable_int(const u16 *variable_name, + const efi_guid_t *vendor, + u32 attributes, efi_uintn_t data_size, + const void *data, bool ro_check) +{ + struct efi_var_entry *var; + efi_uintn_t ret; + bool append, delete; + u64 time = 0; + enum efi_auth_var_type var_type; + + ret = setvariable_allowed(variable_name, vendor, attributes, data_size, + data); + if (ret != EFI_SUCCESS) + return ret; + /* check if a variable exists */ var = efi_var_mem_find(vendor, variable_name, NULL); append = !!(attributes & EFI_VARIABLE_APPEND_WRITE); @@ -454,7 +476,79 @@ efi_set_variable_runtime(u16 *variable_name, const efi_guid_t *vendor, u32 attributes, efi_uintn_t data_size, const void *data) { - return EFI_UNSUPPORTED; + struct efi_var_entry *var; + efi_uintn_t ret; + bool append, delete; + u64 time = 0; + + if (!IS_ENABLED(CONFIG_EFI_RT_VOLATILE_STORE)) + return EFI_UNSUPPORTED; + + /* + * Authenticated variables are not supported. The EFI spec + * in ยง32.3.6 requires keys to be stored in non-volatile storage which + * is tamper and delete resistant. + * The rest of the checks are in setvariable_allowed() + */ + if (attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) + return EFI_INVALID_PARAMETER; + + ret = setvariable_allowed(variable_name, vendor, attributes, data_size, + data); + if (ret != EFI_SUCCESS) + return ret; + + /* check if a variable exists */ + var = efi_var_mem_find(vendor, variable_name, NULL); + append = !!(attributes & EFI_VARIABLE_APPEND_WRITE); + attributes &= ~EFI_VARIABLE_APPEND_WRITE; + delete = !append && (!data_size || !attributes); + + /* BS only variables are hidden deny writing them */ + if (!delete && !(attributes & EFI_VARIABLE_RUNTIME_ACCESS)) + return EFI_INVALID_PARAMETER; + + if (var) { + if (var->attr & EFI_VARIABLE_READ_ONLY || + !(var->attr & EFI_VARIABLE_NON_VOLATILE)) + return EFI_WRITE_PROTECTED; + + /* attributes won't be changed */ + if (!delete && (((var->attr & ~EFI_VARIABLE_READ_ONLY) != + (attributes & ~EFI_VARIABLE_READ_ONLY)))) + return EFI_INVALID_PARAMETER; + time = var->time; + } else { + if (!(attributes & EFI_VARIABLE_NON_VOLATILE)) + return EFI_INVALID_PARAMETER; + if (append && !data_size) + return EFI_SUCCESS; + if (delete) + return EFI_NOT_FOUND; + } + + if (delete) { + /* EFI_NOT_FOUND has been handled before */ + attributes = var->attr; + ret = EFI_SUCCESS; + } else if (append && var) { + u16 *old_data = (void *)((uintptr_t)var->name + + sizeof(u16) * (u16_strlen(var->name) + 1)); + + ret = efi_var_mem_ins(variable_name, vendor, attributes, + var->length, old_data, data_size, data, + time); + } else { + ret = efi_var_mem_ins(variable_name, vendor, attributes, + data_size, data, 0, NULL, time); + } + + if (ret != EFI_SUCCESS) + return ret; + /* We are always inserting new variables, get rid of the old copy */ + efi_var_mem_del(var); + + return EFI_SUCCESS; } /** diff --git a/lib/efi_selftest/efi_selftest_variables_runtime.c b/lib/efi_selftest/efi_selftest_variables_runtime.c index 4700d9424105..986924b881dd 100644 --- a/lib/efi_selftest/efi_selftest_variables_runtime.c +++ b/lib/efi_selftest/efi_selftest_variables_runtime.c @@ -62,9 +62,17 @@ static int execute(void) EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, 3, v + 4); - if (ret != EFI_UNSUPPORTED) { - efi_st_error("SetVariable failed\n"); - return EFI_ST_FAILURE; + if (IS_ENABLED(CONFIG_EFI_RT_VOLATILE_STORE)) { + /* At runtime only non-volatile variables may be set. */ + if (ret != EFI_INVALID_PARAMETER) { + efi_st_error("SetVariable failed\n"); + return EFI_ST_FAILURE; + } + } else { + if (ret != EFI_UNSUPPORTED) { + efi_st_error("SetVariable failed\n"); + return EFI_ST_FAILURE; + } } len = EFI_ST_MAX_DATA_SIZE; ret = runtime->get_variable(u"PlatformLangCodes", &guid_vendor0, From patchwork Thu Apr 18 12:54:51 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ilias Apalodimas X-Patchwork-Id: 1925001 X-Patchwork-Delegate: xypron.glpk@gmx.de Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=linaro.org header.i=@linaro.org header.a=rsa-sha256 header.s=google header.b=keTD/enx; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=2a01:238:438b:c500:173d:9f52:ddab:ee01; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=patchwork.ozlabs.org) Received: from phobos.denx.de (phobos.denx.de [IPv6:2a01:238:438b:c500:173d:9f52:ddab:ee01]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4VKyRy2bjKz1yPv for ; Thu, 18 Apr 2024 22:55:26 +1000 (AEST) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 09EDE8863B; Thu, 18 Apr 2024 14:55:16 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (2048-bit key; unprotected) header.d=linaro.org header.i=@linaro.org header.b="keTD/enx"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id EEDB58863B; Thu, 18 Apr 2024 14:55:14 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,SPF_HELO_NONE,SPF_PASS autolearn=ham autolearn_force=no version=3.4.2 Received: from mail-ej1-x62a.google.com (mail-ej1-x62a.google.com [IPv6:2a00:1450:4864:20::62a]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id 029008831A for ; Thu, 18 Apr 2024 14:55:13 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=ilias.apalodimas@linaro.org Received: by mail-ej1-x62a.google.com with SMTP id a640c23a62f3a-a526d0b2349so93491866b.3 for ; Thu, 18 Apr 2024 05:55:12 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1713444912; x=1714049712; darn=lists.denx.de; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=PG/fCLR7lE0HGFILjjYIa9AktQy4qPCNzdmMr//VU5k=; b=keTD/enxqam0wPQilvgmE4G+cXV4GsjnKdzOdkUke/mWHjGCb3exPHWWBzkE92tBFh tjAQcuG5GzGFBtg3hB2jrjStaZqMsCSjzerrGcOkGqIEoBMxW0B/dHJw3GHPkcDYEKmS bF3HPL7JTL8mq+t+XnwBbM8cVo8Lf60cHRzHIBMzx1Un3EaYS0JQkRXhj4pHVc0PZZYU GEo+AX/Q9+fwYOO3G99m6uUJn6Q8u1FK1JDWja/0lmjCksuTG/edHHFJVFO7/jpabyWY jRMvm6q3o5CEQurxojm4ihRiTFefYNuP3BrGPnBF7fy9uXFbz68O4KP0XUIZXJupzGZM pWkw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1713444912; x=1714049712; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=PG/fCLR7lE0HGFILjjYIa9AktQy4qPCNzdmMr//VU5k=; b=wRF6vbT/fUDHFHVoLCdqCFr49Js2bkAMJuO41aEZfttmnn8WLQfi/KyP99RplMmfaM RgmkyrYC03ka75ATfu08r5MXCGN9MO6JvQUp7OXzxsO6Ihp8mqx5BJaCfGOSP3LyVtU6 /ZTjdoOiMI99o2w9WTFPSddYrVjYPdgaY5b6GipEmD88Gog4WVeaZ7qG7vMPQjgy4LME lOy5Ivwef+uw7++fNPXgusV+vwkTz4CopTNi6ub6fH6q9u7GOOFZq9l2bkpo2XCOZBk2 cwTIRb5YTBzdK9RhTq7/QCJIKE+ZUVdsuBJWsInQu9JzaG5kwY9Uuqtb54OYOicWVY9V uQ4g== X-Forwarded-Encrypted: i=1; AJvYcCXHl9FpbUOO1hxtCuGuonnK2zB0X9IkXdnIajTGc11m2fU1DorRM+6jECGBKlWRgq8ociQ1cVIMgVurA51fZB3vPCloAg== X-Gm-Message-State: AOJu0YzwpfoikL8rWAVLpnR6K+ZSDAnG+XxU/C+NT/5dn4vCuvIrJx2m MxfEP4Gls2buUCgKxS6Ys1LdOKWigEIGJsO+4M4Byv/u/0yinG+DpJN4pKYOLzk= X-Google-Smtp-Source: AGHT+IEGttThkPjVmleJ4FCFd6LjqY0y704poH6n1SJ9LYdkvOrNnDsgNC3VFO7tTYfLVBilZxKm+g== X-Received: by 2002:a17:906:717:b0:a55:5516:39fa with SMTP id y23-20020a170906071700b00a55551639famr1599110ejb.64.1713444912540; Thu, 18 Apr 2024 05:55:12 -0700 (PDT) Received: from hades.. (ppp176092141112.access.hol.gr. [176.92.141.112]) by smtp.gmail.com with ESMTPSA id m11-20020a1709060d8b00b00a525a18f748sm847002eji.165.2024.04.18.05.55.09 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 18 Apr 2024 05:55:11 -0700 (PDT) From: Ilias Apalodimas To: xypron.glpk@gmx.de, kettenis@openbsd.org Cc: caleb.connolly@linaro.org, sumit.garg@linaro.org, quic_llindhol@quicinc.com, ardb@kernel.org, pbrobinson@gmail.com, pjones@redhat.com, Ilias Apalodimas , Heinrich Schuchardt , Tom Rini , Masahisa Kojima , AKASHI Takahiro , Raymond Mao , Matthias Schiffer , Janne Grunau , Simon Glass , Abdellatif El Khlifi , Sughosh Ganu , Sam Edwards , Richard Henderson , Alper Nebi Yasak , Weizhao Ouyang , u-boot@lists.denx.de Subject: [PATCH v3 2/4] efi_loader: Add OS notifications for SetVariable at runtime Date: Thu, 18 Apr 2024 15:54:51 +0300 Message-Id: <20240418125456.50944-3-ilias.apalodimas@linaro.org> X-Mailer: git-send-email 2.40.1 In-Reply-To: <20240418125456.50944-1-ilias.apalodimas@linaro.org> References: <20240418125456.50944-1-ilias.apalodimas@linaro.org> MIME-Version: 1.0 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.39 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.103.8 at phobos.denx.de X-Virus-Status: Clean Previous patches enable SetVariable at runtime using a volatile storage backend using EFI_RUNTIME_SERVICES_DATA allocared memory. Since there's no recommendation from the spec on how to notify the OS, add a volatile EFI variable that contains the filename relative to the ESP. OS'es can use that file and update it at runtime $~ efivar -p -n b2ac5fc9-92b7-4acd-aeac-11e818c3130c-RTStorageVolatile GUID: b2ac5fc9-92b7-4acd-aeac-11e818c3130c Name: "RTStorageVolatile" Attributes: Boot Service Access Runtime Service Access Value: 00000000 75 62 6f 6f 74 65 66 69 2e 76 61 72 00 |ubootefi.var. | Reviewed-by: Heinrich Schuchardt Signed-off-by: Ilias Apalodimas --- include/efi_loader.h | 4 ++++ lib/efi_loader/efi_runtime.c | 19 ++++++++++++++++--- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/include/efi_loader.h b/include/efi_loader.h index bb51c0281774..69442f4e58de 100644 --- a/include/efi_loader.h +++ b/include/efi_loader.h @@ -159,6 +159,10 @@ static inline void efi_set_bootdev(const char *dev, const char *devnr, #define EFICONFIG_AUTO_GENERATED_ENTRY_GUID \ EFI_GUID(0x8108ac4e, 0x9f11, 0x4d59, \ 0x85, 0x0e, 0xe2, 0x1a, 0x52, 0x2c, 0x59, 0xb2) +#define U_BOOT_EFI_RT_VAR_FILE_GUID \ + EFI_GUID(0xb2ac5fc9, 0x92b7, 0x4acd, \ + 0xae, 0xac, 0x11, 0xe8, 0x18, 0xc3, 0x13, 0x0c) + /* Use internal device tree when starting UEFI application */ #define EFI_FDT_USE_INTERNAL NULL diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c index dde083b09665..c8f7a88ba8db 100644 --- a/lib/efi_loader/efi_runtime.c +++ b/lib/efi_loader/efi_runtime.c @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -110,6 +111,7 @@ static __efi_runtime_data efi_uintn_t efi_descriptor_size; */ efi_status_t efi_init_runtime_supported(void) { + const efi_guid_t efi_guid_efi_rt_var_file = U_BOOT_EFI_RT_VAR_FILE_GUID; efi_status_t ret; struct efi_rt_properties_table *rt_table; @@ -127,9 +129,20 @@ efi_status_t efi_init_runtime_supported(void) EFI_RT_SUPPORTED_SET_VIRTUAL_ADDRESS_MAP | EFI_RT_SUPPORTED_CONVERT_POINTER; - if (IS_ENABLED(CONFIG_EFI_RT_VOLATILE_STORE)) - rt_table->runtime_services_supported |= - EFI_RT_SUPPORTED_SET_VARIABLE; + if (IS_ENABLED(CONFIG_EFI_RT_VOLATILE_STORE)) { + ret = efi_set_variable_int(u"RTStorageVolatile", + &efi_guid_efi_rt_var_file, + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS | + EFI_VARIABLE_READ_ONLY, + sizeof(EFI_VAR_FILE_NAME), + EFI_VAR_FILE_NAME, false); + if (ret != EFI_SUCCESS) { + log_err("Failed to set RTStorageVolatile\n"); + return ret; + } + rt_table->runtime_services_supported |= EFI_RT_SUPPORTED_SET_VARIABLE; + } /* * This value must be synced with efi_runtime_detach_list From patchwork Thu Apr 18 12:54:52 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ilias Apalodimas X-Patchwork-Id: 1925002 X-Patchwork-Delegate: xypron.glpk@gmx.de Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=linaro.org header.i=@linaro.org header.a=rsa-sha256 header.s=google header.b=ygm7qFGG; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=2a01:238:438b:c500:173d:9f52:ddab:ee01; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=patchwork.ozlabs.org) Received: from phobos.denx.de (phobos.denx.de [IPv6:2a01:238:438b:c500:173d:9f52:ddab:ee01]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4VKyS841WVz1yPv for ; Thu, 18 Apr 2024 22:55:36 +1000 (AEST) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id 66C908864B; Thu, 18 Apr 2024 14:55:22 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (2048-bit key; unprotected) header.d=linaro.org header.i=@linaro.org header.b="ygm7qFGG"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id 767AF8864A; Thu, 18 Apr 2024 14:55:21 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,SPF_HELO_NONE,SPF_PASS autolearn=ham autolearn_force=no version=3.4.2 Received: from mail-ed1-x52d.google.com (mail-ed1-x52d.google.com [IPv6:2a00:1450:4864:20::52d]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id E276188653 for ; Thu, 18 Apr 2024 14:55:18 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=ilias.apalodimas@linaro.org Received: by mail-ed1-x52d.google.com with SMTP id 4fb4d7f45d1cf-57042f84cabso1052993a12.2 for ; Thu, 18 Apr 2024 05:55:18 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1713444918; x=1714049718; darn=lists.denx.de; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=yxDBkHklVSMUxBE3DuI9GTgURirxmCYFI9fFABmIoFU=; b=ygm7qFGGEhWAGt8skrTh2p5OXgPDc2oLmBVIogOrETjOqwF1wVj2cc5NB/KO87HiXq yjG4e+xIJi8DxP3MjzNi/7O3Q5q4nRsTswlxmoop2iuJx3d4hrtptEP06C6vWmMYJ6PS FcBvgB7qTey/c02Jaz9yiGqcRnt8/dycHsVsds8tKN3H45OnGE11G6lOHSWSUpGZNite 2vQwobij0HmpsXO6Iyezfmlu7ZhMsVjKBOOUfiRWVGVL/BvFYmFIqTL1pekPFLiso2Cw psUdVTcfAF7mHIaqSlWWQBmcQwf9mokhErlC22ZvWeD+7c5R64evti0BCTvKKojlTYXZ dk2A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1713444918; x=1714049718; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=yxDBkHklVSMUxBE3DuI9GTgURirxmCYFI9fFABmIoFU=; b=k9yZXOnj1Y6i63czQFZ+SEe5QIhLAKfZqgvljqwehGHeK/71Z4oklpsyVBJR3zeKlW 213DzcOTqglT3WqHQU7B9DqQPv+qOqzhffgtoSkopT/or7fFHIt5fiMzFdkQxYfdREQb HPzmC1yQdRcfuR9ypFfBfaATuQ6Au8it9ff0S9xrP9nRuK+/oJyOX03p6rvsWcvhIh54 vcScLcCPDNqx6bb2aJbASczGeIT3A2yoeJJUh9tz6WinO2qNdavaclswLsBrPArHFWLV 8e3VpKYfSyiK1Jw5Oz9bac5uPkmG4NgXgyqOICC2nnl0RgTsU0UGbWGlc2QNhGjMZFUi xZaw== X-Forwarded-Encrypted: i=1; AJvYcCWzJl20ngjNJ0WQR+mQpLc2tYPUDM+zFtwQJHvxKPMbGWJWc3H2A6KELoxx9zW0TGKFZvnVzAtF9XYfysQGwxAX9UB4lA== X-Gm-Message-State: AOJu0YzY58NjRcq8dQ0tWr275NXgGP7rE7xLOXUVsEZsiwuJ0LLM5FwG rf3ofjLli2fh5LN/PqvKABORFKDklgE96tZslstRm8VxCpqdG8cGSr8DX1b1pN/eRDiJLUd0WPV GMqY= X-Google-Smtp-Source: AGHT+IEKH98EGBuDuwRdnghCBhlPqrYOWahc3lcPSpEiyxSsSOJZqPZihhj50vC90gcuvJnqQxfzyQ== X-Received: by 2002:a17:906:d28e:b0:a4e:21e0:2e6e with SMTP id ay14-20020a170906d28e00b00a4e21e02e6emr1809051ejb.5.1713444918376; Thu, 18 Apr 2024 05:55:18 -0700 (PDT) Received: from hades.. (ppp176092141112.access.hol.gr. [176.92.141.112]) by smtp.gmail.com with ESMTPSA id m11-20020a1709060d8b00b00a525a18f748sm847002eji.165.2024.04.18.05.55.15 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 18 Apr 2024 05:55:17 -0700 (PDT) From: Ilias Apalodimas To: xypron.glpk@gmx.de, kettenis@openbsd.org Cc: caleb.connolly@linaro.org, sumit.garg@linaro.org, quic_llindhol@quicinc.com, ardb@kernel.org, pbrobinson@gmail.com, pjones@redhat.com, Ilias Apalodimas , Heinrich Schuchardt , Tom Rini , Masahisa Kojima , AKASHI Takahiro , Raymond Mao , Simon Glass , Matthias Schiffer , Janne Grunau , Abdellatif El Khlifi , Sughosh Ganu , Richard Henderson , Sam Edwards , Alper Nebi Yasak , Weizhao Ouyang , u-boot@lists.denx.de Subject: [PATCH v3 3/4] efi_loader: add an EFI variable with the file contents Date: Thu, 18 Apr 2024 15:54:52 +0300 Message-Id: <20240418125456.50944-4-ilias.apalodimas@linaro.org> X-Mailer: git-send-email 2.40.1 In-Reply-To: <20240418125456.50944-1-ilias.apalodimas@linaro.org> References: <20240418125456.50944-1-ilias.apalodimas@linaro.org> MIME-Version: 1.0 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.39 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.103.8 at phobos.denx.de X-Virus-Status: Clean Previous patches enabled SetVariableRT using a RAM backend. Although EBBR [0] defines a variable format we can teach userspace tools and write the altered variables, it's better if we skip the ABI requirements completely. So let's add a new variable, in its own namespace called "VarToFile" which contains a binary dump of the updated RT, BS and, NV variables and will be updated when GetVariable is called. Some adjustments are needed to do that. Currently we discard BS-only variables in EBS(). We need to preserve those on the RAM backend that exposes the variables. Since BS-only variables can't appear at runtime we need to move the memory masking checks from efi_var_collect() to efi_get_next_variable_name_mem()/ efi_get_variable_mem() and do the filtering at runtime. We also need an efi_var_collect() variant available at runtime, in order to construct the "VarToFile" buffer on the fly. All users and applications (for linux) have to do when updating a variable is dd that variable in the file described by "RTStorageVolatile". Linux efivarfs uses a first 4 bytes of the output to represent attributes in little-endian format. So, storing variables works like this: $~ efibootmgr -n 0001 $~ dd if=/sys/firmware/efi/efivars/VarToFile-b2ac5fc9-92b7-4acd-aeac-11e818c3130c of=/boot/efi/ubootefi.var skip=4 bs=1 [0] https://arm-software.github.io/ebbr/index.html#document-chapter5-variable-storage Suggested-by: Ard Biesheuvel # dumping all variables to a variable Co-developed-by: Heinrich Schuchardt # contributed on efi_var_collect_mem() Signed-off-by: Heinrich Schuchardt Signed-off-by: Ilias Apalodimas --- include/efi_variable.h | 16 +++- lib/charset.c | 2 +- lib/efi_loader/efi_runtime.c | 25 +++++ lib/efi_loader/efi_var_common.c | 6 +- lib/efi_loader/efi_var_mem.c | 151 +++++++++++++++++++----------- lib/efi_loader/efi_variable.c | 6 +- lib/efi_loader/efi_variable_tee.c | 5 - 7 files changed, 146 insertions(+), 65 deletions(-) diff --git a/include/efi_variable.h b/include/efi_variable.h index 42a2b7c52bef..223bb9a4a5bd 100644 --- a/include/efi_variable.h +++ b/include/efi_variable.h @@ -271,13 +271,16 @@ const efi_guid_t *efi_auth_var_get_guid(const u16 *name); * * @variable_name_size: size of variable_name buffer in bytes * @variable_name: name of uefi variable's name in u16 + * @mask: bitmask with required attributes of variables to be collected. + * variables are only collected if all of the required + * attributes match. Use 0 to skip matching * @vendor: vendor's guid * * Return: status code */ efi_status_t __efi_runtime efi_get_next_variable_name_mem(efi_uintn_t *variable_name_size, u16 *variable_name, - efi_guid_t *vendor); + efi_guid_t *vendor, u32 mask); /** * efi_get_variable_mem() - Runtime common code across efi variable * implementations for GetVariable() from @@ -289,12 +292,15 @@ efi_get_next_variable_name_mem(efi_uintn_t *variable_name_size, u16 *variable_na * @data_size: size of the buffer to which the variable value is copied * @data: buffer to which the variable value is copied * @timep: authentication time (seconds since start of epoch) + * @mask: bitmask with required attributes of variables to be collected. + * variables are only collected if all of the required + * attributes match. Use 0 to skip matching * Return: status code */ efi_status_t __efi_runtime efi_get_variable_mem(const u16 *variable_name, const efi_guid_t *vendor, u32 *attributes, efi_uintn_t *data_size, void *data, - u64 *timep); + u64 *timep, u32 mask); /** * efi_get_variable_runtime() - runtime implementation of GetVariable() @@ -334,4 +340,10 @@ efi_get_next_variable_name_runtime(efi_uintn_t *variable_name_size, */ void efi_var_buf_update(struct efi_var_file *var_buf); +efi_status_t __efi_runtime efi_var_collect_mem(struct efi_var_file *buf, + efi_uintn_t *lenp, + u32 check_attr_mask); + +u32 efi_var_entry_len(struct efi_var_entry *var); + #endif diff --git a/lib/charset.c b/lib/charset.c index df4f04074852..182c92a50c48 100644 --- a/lib/charset.c +++ b/lib/charset.c @@ -387,7 +387,7 @@ int u16_strcasecmp(const u16 *s1, const u16 *s2) * > 0 if the first different u16 in s1 is greater than the * corresponding u16 in s2 */ -int u16_strncmp(const u16 *s1, const u16 *s2, size_t n) +int __efi_runtime u16_strncmp(const u16 *s1, const u16 *s2, size_t n) { int ret = 0; diff --git a/lib/efi_loader/efi_runtime.c b/lib/efi_loader/efi_runtime.c index c8f7a88ba8db..73831c527e00 100644 --- a/lib/efi_loader/efi_runtime.c +++ b/lib/efi_loader/efi_runtime.c @@ -130,6 +130,8 @@ efi_status_t efi_init_runtime_supported(void) EFI_RT_SUPPORTED_CONVERT_POINTER; if (IS_ENABLED(CONFIG_EFI_RT_VOLATILE_STORE)) { + u8 s = 0; + ret = efi_set_variable_int(u"RTStorageVolatile", &efi_guid_efi_rt_var_file, EFI_VARIABLE_BOOTSERVICE_ACCESS | @@ -141,6 +143,29 @@ efi_status_t efi_init_runtime_supported(void) log_err("Failed to set RTStorageVolatile\n"); return ret; } + /* + * This variable needs to be visible so users can read it, + * but the real contents are going to be filled during + * GetVariable + */ + ret = efi_set_variable_int(u"VarToFile", + &efi_guid_efi_rt_var_file, + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS | + EFI_VARIABLE_READ_ONLY, + sizeof(s), + &s, false); + if (ret != EFI_SUCCESS) { + log_err("Failed to set VarToFile\n"); + efi_set_variable_int(u"RTStorageVolatile", + &efi_guid_efi_rt_var_file, + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS | + EFI_VARIABLE_READ_ONLY, + 0, NULL, false); + + return ret; + } rt_table->runtime_services_supported |= EFI_RT_SUPPORTED_SET_VARIABLE; } diff --git a/lib/efi_loader/efi_var_common.c b/lib/efi_loader/efi_var_common.c index aa8feffd3ec1..7862f2d6ce8a 100644 --- a/lib/efi_loader/efi_var_common.c +++ b/lib/efi_loader/efi_var_common.c @@ -182,7 +182,8 @@ efi_get_variable_runtime(u16 *variable_name, const efi_guid_t *guid, { efi_status_t ret; - ret = efi_get_variable_mem(variable_name, guid, attributes, data_size, data, NULL); + ret = efi_get_variable_mem(variable_name, guid, attributes, data_size, + data, NULL, EFI_VARIABLE_RUNTIME_ACCESS); /* Remove EFI_VARIABLE_READ_ONLY flag */ if (attributes) @@ -195,7 +196,8 @@ efi_status_t __efi_runtime EFIAPI efi_get_next_variable_name_runtime(efi_uintn_t *variable_name_size, u16 *variable_name, efi_guid_t *guid) { - return efi_get_next_variable_name_mem(variable_name_size, variable_name, guid); + return efi_get_next_variable_name_mem(variable_name_size, variable_name, + guid, EFI_VARIABLE_RUNTIME_ACCESS); } /** diff --git a/lib/efi_loader/efi_var_mem.c b/lib/efi_loader/efi_var_mem.c index 6c21cec5d457..940ab6638823 100644 --- a/lib/efi_loader/efi_var_mem.c +++ b/lib/efi_loader/efi_var_mem.c @@ -61,6 +61,23 @@ efi_var_mem_compare(struct efi_var_entry *var, const efi_guid_t *guid, return match; } +/** + * efi_var_entry_len() - Get the entry len including headers & name + * + * @var: pointer to variable start + * + * Return: 8-byte aligned variable entry length + */ + +u32 __efi_runtime efi_var_entry_len(struct efi_var_entry *var) +{ + if (!var) + return 0; + + return ALIGN((sizeof(u16) * (u16_strlen(var->name) + 1)) + + var->length + sizeof(*var), 8); +} + struct efi_var_entry __efi_runtime *efi_var_mem_find(const efi_guid_t *guid, const u16 *name, struct efi_var_entry **next) @@ -184,53 +201,6 @@ u64 __efi_runtime efi_var_mem_free(void) sizeof(struct efi_var_entry); } -/** - * efi_var_mem_bs_del() - delete boot service only variables - */ -static void efi_var_mem_bs_del(void) -{ - struct efi_var_entry *var = efi_var_buf->var; - - for (;;) { - struct efi_var_entry *last; - - last = (struct efi_var_entry *) - ((uintptr_t)efi_var_buf + efi_var_buf->length); - if (var >= last) - break; - if (var->attr & EFI_VARIABLE_RUNTIME_ACCESS) { - u16 *data; - - /* skip variable */ - for (data = var->name; *data; ++data) - ; - ++data; - var = (struct efi_var_entry *) - ALIGN((uintptr_t)data + var->length, 8); - } else { - /* delete variable */ - efi_var_mem_del(var); - } - } -} - -/** - * efi_var_mem_notify_exit_boot_services() - ExitBootService callback - * - * @event: callback event - * @context: callback context - */ -static void EFIAPI -efi_var_mem_notify_exit_boot_services(struct efi_event *event, void *context) -{ - EFI_ENTRY("%p, %p", event, context); - - /* Delete boot service only variables */ - efi_var_mem_bs_del(); - - EFI_EXIT(EFI_SUCCESS); -} - /** * efi_var_mem_notify_exit_boot_services() - SetVirtualMemoryMap callback * @@ -261,11 +231,7 @@ efi_status_t efi_var_mem_init(void) efi_var_buf->magic = EFI_VAR_FILE_MAGIC; efi_var_buf->length = (uintptr_t)efi_var_buf->var - (uintptr_t)efi_var_buf; - /* crc32 for 0 bytes = 0 */ - ret = efi_create_event(EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_CALLBACK, - efi_var_mem_notify_exit_boot_services, NULL, - NULL, &event); if (ret != EFI_SUCCESS) return ret; ret = efi_create_event(EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE, TPL_CALLBACK, @@ -276,10 +242,71 @@ efi_status_t efi_var_mem_init(void) return ret; } +/** + * efi_var_collect_mem() - Copy EFI variables matching attributes mask from + * efi_var_buf + * + * @buf: buffer containing variable collection + * @lenp: buffer length + * @mask: mask of matched attributes + * + * Return: Status code + */ +efi_status_t __efi_runtime +efi_var_collect_mem(struct efi_var_file *buf, efi_uintn_t *lenp, u32 mask) +{ + static struct efi_var_file __efi_runtime_data hdr = { + .magic = EFI_VAR_FILE_MAGIC, + }; + struct efi_var_entry *last, *var, *var_to; + + hdr.length = sizeof(struct efi_var_file); + + var = efi_var_buf->var; + last = (struct efi_var_entry *) + ((uintptr_t)efi_var_buf + efi_var_buf->length); + if (buf) + var_to = buf->var; + + while (var < last) { + u32 len = efi_var_entry_len(var); + + if ((var->attr & mask) != mask) { + var = (void *)((uintptr_t)var + len); + continue; + } + + hdr.length += len; + + if (buf && hdr.length <= *lenp) { + efi_memcpy_runtime(var_to, var, len); + var_to = (void *)var_to + len; + } + var = (void *)var + len; + } + + if (!buf && hdr.length <= *lenp) { + *lenp = hdr.length; + return EFI_INVALID_PARAMETER; + } + + if (!buf || hdr.length > *lenp) { + *lenp = hdr.length; + return EFI_BUFFER_TOO_SMALL; + } + hdr.crc32 = crc32(0, (u8 *)buf->var, + hdr.length - sizeof(struct efi_var_file)); + + efi_memcpy_runtime(buf, &hdr, sizeof(hdr)); + *lenp = hdr.length; + + return EFI_SUCCESS; +} + efi_status_t __efi_runtime efi_get_variable_mem(const u16 *variable_name, const efi_guid_t *vendor, u32 *attributes, efi_uintn_t *data_size, void *data, - u64 *timep) + u64 *timep, u32 mask) { efi_uintn_t old_size; struct efi_var_entry *var; @@ -291,11 +318,22 @@ efi_get_variable_mem(const u16 *variable_name, const efi_guid_t *vendor, if (!var) return EFI_NOT_FOUND; + /* + * This function is used at runtime to dump EFI variables. + * The memory backend we keep around has BS-only variables as + * well. At runtime we filter them here + */ + if (mask && !((var->attr & mask) == mask)) + return EFI_NOT_FOUND; + if (attributes) *attributes = var->attr; if (timep) *timep = var->time; + if (!u16_strcmp(variable_name, u"VarToFile")) + return efi_var_collect_mem(data, data_size, EFI_VARIABLE_NON_VOLATILE); + old_size = *data_size; *data_size = var->length; if (old_size < var->length) @@ -315,7 +353,8 @@ efi_get_variable_mem(const u16 *variable_name, const efi_guid_t *vendor, efi_status_t __efi_runtime efi_get_next_variable_name_mem(efi_uintn_t *variable_name_size, - u16 *variable_name, efi_guid_t *vendor) + u16 *variable_name, efi_guid_t *vendor, + u32 mask) { struct efi_var_entry *var; efi_uintn_t len, old_size; @@ -324,6 +363,7 @@ efi_get_next_variable_name_mem(efi_uintn_t *variable_name_size, if (!variable_name_size || !variable_name || !vendor) return EFI_INVALID_PARAMETER; +skip: len = *variable_name_size >> 1; if (u16_strnlen(variable_name, len) == len) return EFI_INVALID_PARAMETER; @@ -347,6 +387,11 @@ efi_get_next_variable_name_mem(efi_uintn_t *variable_name_size, efi_memcpy_runtime(variable_name, var->name, *variable_name_size); efi_memcpy_runtime(vendor, &var->guid, sizeof(efi_guid_t)); + if (mask && !((var->attr & mask) == mask)) { + *variable_name_size = old_size; + goto skip; + } + return EFI_SUCCESS; } diff --git a/lib/efi_loader/efi_variable.c b/lib/efi_loader/efi_variable.c index 47bb79920575..0cbed53d1dbf 100644 --- a/lib/efi_loader/efi_variable.c +++ b/lib/efi_loader/efi_variable.c @@ -209,14 +209,16 @@ efi_get_variable_int(const u16 *variable_name, const efi_guid_t *vendor, u32 *attributes, efi_uintn_t *data_size, void *data, u64 *timep) { - return efi_get_variable_mem(variable_name, vendor, attributes, data_size, data, timep); + return efi_get_variable_mem(variable_name, vendor, attributes, data_size, + data, timep, 0); } efi_status_t __efi_runtime efi_get_next_variable_name_int(efi_uintn_t *variable_name_size, u16 *variable_name, efi_guid_t *vendor) { - return efi_get_next_variable_name_mem(variable_name_size, variable_name, vendor); + return efi_get_next_variable_name_mem(variable_name_size, variable_name, + vendor, 0); } /** diff --git a/lib/efi_loader/efi_variable_tee.c b/lib/efi_loader/efi_variable_tee.c index dde135fd9f81..4f1aa298da13 100644 --- a/lib/efi_loader/efi_variable_tee.c +++ b/lib/efi_loader/efi_variable_tee.c @@ -959,11 +959,6 @@ void efi_variables_boot_exit_notify(void) log_err("Unable to notify the MM partition for ExitBootServices\n"); free(comm_buf); - /* - * Populate the list for runtime variables. - * asking EFI_VARIABLE_RUNTIME_ACCESS is redundant, since - * efi_var_mem_notify_exit_boot_services will clean those, but that's fine - */ ret = efi_var_collect(&var_buf, &len, EFI_VARIABLE_RUNTIME_ACCESS); if (ret != EFI_SUCCESS) log_err("Can't populate EFI variables. No runtime variables will be available\n"); From patchwork Thu Apr 18 12:54:53 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ilias Apalodimas X-Patchwork-Id: 1925003 X-Patchwork-Delegate: xypron.glpk@gmx.de Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=linaro.org header.i=@linaro.org header.a=rsa-sha256 header.s=google header.b=ZeMBtFEe; dkim-atps=neutral Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.denx.de (client-ip=2a01:238:438b:c500:173d:9f52:ddab:ee01; helo=phobos.denx.de; envelope-from=u-boot-bounces@lists.denx.de; receiver=patchwork.ozlabs.org) Received: from phobos.denx.de (phobos.denx.de [IPv6:2a01:238:438b:c500:173d:9f52:ddab:ee01]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4VKySN36bvz1yPv for ; Thu, 18 Apr 2024 22:55:48 +1000 (AEST) Received: from h2850616.stratoserver.net (localhost [IPv6:::1]) by phobos.denx.de (Postfix) with ESMTP id CC96788653; Thu, 18 Apr 2024 14:55:27 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=u-boot-bounces@lists.denx.de Authentication-Results: phobos.denx.de; dkim=pass (2048-bit key; unprotected) header.d=linaro.org header.i=@linaro.org header.b="ZeMBtFEe"; dkim-atps=neutral Received: by phobos.denx.de (Postfix, from userid 109) id 55D588864A; Thu, 18 Apr 2024 14:55:26 +0200 (CEST) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on phobos.denx.de X-Spam-Level: X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,SPF_HELO_NONE,SPF_PASS autolearn=ham autolearn_force=no version=3.4.2 Received: from mail-wr1-x433.google.com (mail-wr1-x433.google.com [IPv6:2a00:1450:4864:20::433]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits)) (No client certificate requested) by phobos.denx.de (Postfix) with ESMTPS id 4265F88652 for ; Thu, 18 Apr 2024 14:55:24 +0200 (CEST) Authentication-Results: phobos.denx.de; dmarc=pass (p=none dis=none) header.from=linaro.org Authentication-Results: phobos.denx.de; spf=pass smtp.mailfrom=ilias.apalodimas@linaro.org Received: by mail-wr1-x433.google.com with SMTP id ffacd0b85a97d-349c5732fd1so669997f8f.3 for ; Thu, 18 Apr 2024 05:55:24 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; t=1713444924; x=1714049724; darn=lists.denx.de; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=sD7myUhu0NlToBzZBxJAVXRQsqlvJyrZki1WrUbboOE=; b=ZeMBtFEeWrTqTe+S+skQd1LbUrAJxg0o5Mn1TWoQN8I8hFveqITdSNrAVg5PRyGOeH M9rSAmBy4dqgNhMyT/Cb+cFGju0OkbzByavLDDTVSHbRoOqSab7e2JtYvviin4kJK6cN PbLy8f43glNAYxjHwB379dc3+WoP6XS0Rjronnx8hPXm24LgSd2j9GpBPztx6nxNd/th JQ10D9HrnZ0DICxqzDDrz94EJ3J8OP58qAIhJEp9ju9QT4gENKR98YRcWnwCGMulNbnh OnCHhvZpCH5RQagZG7JVQtb9370LaNaXaGY4fnHt6HO0AQ+3DTmiKvF6INo1NeB8ItOS fveg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1713444924; x=1714049724; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=sD7myUhu0NlToBzZBxJAVXRQsqlvJyrZki1WrUbboOE=; b=ZpFRKUFLgbcO9p+lmN3UKIwW4+o1jE4jODNibv0gAhguOuihRu5lFZzQ+6EW6Rr+AG tOU+x0PuvbH/2I/6qsz9TD+QGWEh5ncfJ5PVcvFq1BF7oi36S7ixYJyX4JmW6PugdoEJ mBP4mfDhYnmfwVbRXWD/9OHzho5dv5WGqxgsC0nQz2pHok6f3i41ia+lbJwIgneC4B/8 RHfD3fmRQz/uXog1Y3SR5JU7uvKaNUVqiR1Cr2fXkcnmcbzxadxg8Xd0C2AuAXDulthx pJ48qXb47jGa8NtD6U97SIDuTW6vT0UQvVZxWukW99kXztGzlmTdy/lFnTdVsqx6cWvw ngGA== X-Forwarded-Encrypted: i=1; AJvYcCVnbYCriRsvlt4SQ5tOWCTm5WvYUsUoAR2Ce0kRTxkpDJ0lTXRy54V5orrx6a6xgG2Eva08tJCzJaikEcwfr7gD+C3d5g== X-Gm-Message-State: AOJu0Ywnm/aBz1qdr/YWm4qtubpanCHXUx/HDHuIlXnDY8Bf+iSfaE0m +oMQORHvL4fuM1kWwhIegQ80kyqelUiMjhrVPA2TiRBe8M62TeD73A6wbGdw2g4= X-Google-Smtp-Source: AGHT+IFX5LaIgHznsrWqA2YbEZXu1VlW0jaXnuWs2HWR2nIlM3jS2/6wLlEKzaMx+U1JyNBFmJvSwQ== X-Received: by 2002:a5d:6dd2:0:b0:347:4484:4498 with SMTP id d18-20020a5d6dd2000000b0034744844498mr2151345wrz.59.1713444923747; Thu, 18 Apr 2024 05:55:23 -0700 (PDT) Received: from hades.. (ppp176092141112.access.hol.gr. [176.92.141.112]) by smtp.gmail.com with ESMTPSA id m11-20020a1709060d8b00b00a525a18f748sm847002eji.165.2024.04.18.05.55.21 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 18 Apr 2024 05:55:23 -0700 (PDT) From: Ilias Apalodimas To: xypron.glpk@gmx.de, kettenis@openbsd.org Cc: caleb.connolly@linaro.org, sumit.garg@linaro.org, quic_llindhol@quicinc.com, ardb@kernel.org, pbrobinson@gmail.com, pjones@redhat.com, Ilias Apalodimas , Tom Rini , Masahisa Kojima , AKASHI Takahiro , Raymond Mao , Simon Glass , Janne Grunau , Matthias Schiffer , Abdellatif El Khlifi , Alper Nebi Yasak , Sughosh Ganu , Sam Edwards , Richard Henderson , Weizhao Ouyang , u-boot@lists.denx.de Subject: [PATCH v3 4/4] efi_selftest: add tests for setvariableRT Date: Thu, 18 Apr 2024 15:54:53 +0300 Message-Id: <20240418125456.50944-5-ilias.apalodimas@linaro.org> X-Mailer: git-send-email 2.40.1 In-Reply-To: <20240418125456.50944-1-ilias.apalodimas@linaro.org> References: <20240418125456.50944-1-ilias.apalodimas@linaro.org> MIME-Version: 1.0 X-BeenThere: u-boot@lists.denx.de X-Mailman-Version: 2.1.39 Precedence: list List-Id: U-Boot discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: u-boot-bounces@lists.denx.de Sender: "U-Boot" X-Virus-Scanned: clamav-milter 0.103.8 at phobos.denx.de X-Virus-Status: Clean Since we support SetVariableRT now add the relevant tests - Search for the RTStorageVolatile and VarToFile variables after EBS - Try to update with invalid variales (BS, RT only) - Try to write a variable bigger than our backend storage - Write a variable that fits and check VarToFile has been updated correclty - Append to the variable and check VarToFile changes - Try to delete VarToFile which is write protected - Try to add/delete runtime variables - Verify VarToFile contains a valid file format Signed-off-by: Ilias Apalodimas --- .../efi_selftest_variables_runtime.c | 197 +++++++++++++++++- 1 file changed, 196 insertions(+), 1 deletion(-) diff --git a/lib/efi_selftest/efi_selftest_variables_runtime.c b/lib/efi_selftest/efi_selftest_variables_runtime.c index 986924b881dd..28b4e9e7afa5 100644 --- a/lib/efi_selftest/efi_selftest_variables_runtime.c +++ b/lib/efi_selftest/efi_selftest_variables_runtime.c @@ -10,6 +10,8 @@ */ #include +#include +#include #define EFI_ST_MAX_DATA_SIZE 16 #define EFI_ST_MAX_VARNAME_SIZE 40 @@ -17,6 +19,8 @@ static struct efi_boot_services *boottime; static struct efi_runtime_services *runtime; static const efi_guid_t guid_vendor0 = EFI_GLOBAL_VARIABLE_GUID; +static const efi_guid_t __efi_runtime_data efi_rt_var_guid = + U_BOOT_EFI_RT_VAR_FILE_GUID; /* * Setup unit test. @@ -41,15 +45,18 @@ static int setup(const efi_handle_t img_handle, static int execute(void) { efi_status_t ret; - efi_uintn_t len; + efi_uintn_t len, avail, append_len = 17; u32 attr; u8 v[16] = {0x5d, 0xd1, 0x5e, 0x51, 0x5a, 0x05, 0xc7, 0x0c, 0x35, 0x4a, 0xae, 0x87, 0xa5, 0xdf, 0x0f, 0x65,}; + u8 v2[CONFIG_EFI_VAR_BUF_SIZE]; u8 data[EFI_ST_MAX_DATA_SIZE]; + u8 data2[CONFIG_EFI_VAR_BUF_SIZE]; u16 varname[EFI_ST_MAX_VARNAME_SIZE]; efi_guid_t guid; u64 max_storage, rem_storage, max_size; + memset(v2, 0x1, sizeof(v2)); ret = runtime->query_variable_info(EFI_VARIABLE_BOOTSERVICE_ACCESS, &max_storage, &rem_storage, &max_size); @@ -63,11 +70,199 @@ static int execute(void) EFI_VARIABLE_RUNTIME_ACCESS, 3, v + 4); if (IS_ENABLED(CONFIG_EFI_RT_VOLATILE_STORE)) { + efi_uintn_t prev_len, delta; + struct efi_var_entry *var; + struct efi_var_file *hdr; + /* At runtime only non-volatile variables may be set. */ if (ret != EFI_INVALID_PARAMETER) { efi_st_error("SetVariable failed\n"); return EFI_ST_FAILURE; } + + /* runtime atttribute must be set */ + ret = runtime->set_variable(u"efi_st_var0", &guid_vendor0, + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_NON_VOLATILE, + 3, v + 4); + if (ret != EFI_INVALID_PARAMETER) { + efi_st_error("SetVariable failed\n"); + return EFI_ST_FAILURE; + } + + len = sizeof(data); + ret = runtime->get_variable(u"RTStorageVolatile", + &efi_rt_var_guid, + &attr, &len, data); + if (ret != EFI_SUCCESS) { + efi_st_error("GetVariable failed\n"); + return EFI_ST_FAILURE; + } + + len = sizeof(data2); + ret = runtime->get_variable(u"VarToFile", &efi_rt_var_guid, + &attr, &len, data2); + if (ret != EFI_SUCCESS) { + efi_st_error("GetVariable failed\n"); + return EFI_ST_FAILURE; + } + /* + * VarToFile size must change once a variable is inserted + * Store it now, we'll use it later + */ + prev_len = len; + ret = runtime->set_variable(u"efi_st_var0", &guid_vendor0, + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS | + EFI_VARIABLE_NON_VOLATILE, + sizeof(v2), + v2); + /* + * This will try to update VarToFile as well and must fail, + * without changing or deleting VarToFile + */ + if (ret != EFI_OUT_OF_RESOURCES) { + efi_st_error("SetVariable failed\n"); + return EFI_ST_FAILURE; + } + len = sizeof(data2); + ret = runtime->get_variable(u"VarToFile", &efi_rt_var_guid, + &attr, &len, data2); + if (ret != EFI_SUCCESS || prev_len != len) { + efi_st_error("Get/SetVariable failed\n"); + return EFI_ST_FAILURE; + } + + /* Add an 8byte aligned variable */ + ret = runtime->set_variable(u"efi_st_var0", &guid_vendor0, + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS | + EFI_VARIABLE_NON_VOLATILE, + sizeof(v), v); + if (ret != EFI_SUCCESS) { + efi_st_error("SetVariable failed\n"); + return EFI_ST_FAILURE; + } + + /* Delete it by setting the attrs to 0 */ + ret = runtime->set_variable(u"efi_st_var0", &guid_vendor0, + 0, sizeof(v), v); + if (ret != EFI_SUCCESS) { + efi_st_error("SetVariable failed\n"); + return EFI_ST_FAILURE; + } + + /* Add it back */ + ret = runtime->set_variable(u"efi_st_var0", &guid_vendor0, + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS | + EFI_VARIABLE_NON_VOLATILE, + sizeof(v), v); + if (ret != EFI_SUCCESS) { + efi_st_error("SetVariable failed\n"); + return EFI_ST_FAILURE; + } + + /* Delete it again by setting the size to 0 */ + ret = runtime->set_variable(u"efi_st_var0", &guid_vendor0, + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS | + EFI_VARIABLE_NON_VOLATILE, + 0, NULL); + if (ret != EFI_SUCCESS) { + efi_st_error("SetVariable failed\n"); + return EFI_ST_FAILURE; + } + + /* Delete it again and make sure it's not there */ + ret = runtime->set_variable(u"efi_st_var0", &guid_vendor0, + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS | + EFI_VARIABLE_NON_VOLATILE, + 0, NULL); + if (ret != EFI_NOT_FOUND) { + efi_st_error("SetVariable failed\n"); + return EFI_ST_FAILURE; + } + + /* + * Add a non-aligned variable + * VarToFile updates must include efi_st_var0 + */ + ret = runtime->set_variable(u"efi_st_var0", &guid_vendor0, + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS | + EFI_VARIABLE_NON_VOLATILE, + 9, v + 4); + if (ret != EFI_SUCCESS) { + efi_st_error("SetVariable failed\n"); + return EFI_ST_FAILURE; + } + var = efi_var_mem_find(&guid_vendor0, u"efi_st_var0", NULL); + if (!var) { + efi_st_error("GetVariable failed\n"); + return EFI_ST_FAILURE; + } + delta = efi_var_entry_len(var); + len = sizeof(data2); + ret = runtime->get_variable(u"VarToFile", &efi_rt_var_guid, + &attr, &len, data2); + if (ret != EFI_SUCCESS || prev_len + delta != len) { + efi_st_error("Get/SetVariable failed\n"); + return EFI_ST_FAILURE; + } + + /* + * Append on an existing variable must update VarToFile + * Our variable entries are 8-byte aligned. + * Adding a single byte will fit on the existing space + */ + prev_len = len; + avail = efi_var_entry_len(var) - + (sizeof(u16) * (u16_strlen(var->name) + 1) + sizeof(*var)) - + var->length; + if (avail >= append_len) + delta = 0; + else + delta = ALIGN(append_len - avail, 8); + ret = runtime->set_variable(u"efi_st_var0", &guid_vendor0, + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS | + EFI_VARIABLE_APPEND_WRITE | + EFI_VARIABLE_NON_VOLATILE, + append_len, v2); + if (ret != EFI_SUCCESS) { + efi_st_error("SetVariable failed\n"); + return EFI_ST_FAILURE; + } + len = sizeof(data2); + ret = runtime->get_variable(u"VarToFile", &efi_rt_var_guid, + &attr, &len, data2); + if (ret != EFI_SUCCESS || prev_len + delta != len) { + efi_st_error("Get/SetVariable failed\n"); + return EFI_ST_FAILURE; + } + + /* Make sure that variable contains a valid file */ + hdr = (struct efi_var_file *)data2; + if (hdr->magic != EFI_VAR_FILE_MAGIC || + len != hdr->length || + hdr->crc32 != crc32(0, (u8 *)((uintptr_t)data2 + sizeof(struct efi_var_file)), + len - sizeof(struct efi_var_file))) { + efi_st_error("VarToFile invalid header\n"); + return EFI_ST_FAILURE; + } + + /* Variables that are BS, RT and volatile are RO after EBS */ + ret = runtime->set_variable(u"VarToFile", &efi_rt_var_guid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | + EFI_VARIABLE_RUNTIME_ACCESS | + EFI_VARIABLE_NON_VOLATILE, + sizeof(v), v); + if (ret != EFI_WRITE_PROTECTED) { + efi_st_error("Get/SetVariable failed\n"); + return EFI_ST_FAILURE; + } } else { if (ret != EFI_UNSUPPORTED) { efi_st_error("SetVariable failed\n");