1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
9 #include "alloc-util.h"
10 #include "chattr-util.h"
15 #include "memory-util.h"
16 #include "string-util.h"
17 #include "time-util.h"
23 /* Reads from efivarfs sometimes fail with EINTR. Retry that many times. */
24 #define EFI_N_RETRIES_NO_DELAY 20
25 #define EFI_N_RETRIES_TOTAL 25
26 #define EFI_RETRY_DELAY (50 * USEC_PER_MSEC)
30 uint32_t *ret_attribute
,
34 _cleanup_close_
int fd
= -EBADF
;
35 _cleanup_free_
void *buf
= NULL
;
37 usec_t begin
= 0; /* Unnecessary initialization to appease gcc */
43 const char *p
= strjoina("/sys/firmware/efi/efivars/", variable
);
45 if (!ret_value
&& !ret_size
&& !ret_attribute
) {
46 /* If caller is not interested in anything, just check if the variable exists and is
48 if (access(p
, R_OK
) < 0)
55 log_debug("Reading EFI variable %s.", p
);
56 begin
= now(CLOCK_MONOTONIC
);
59 fd
= open(p
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
);
61 return log_debug_errno(errno
, "open(\"%s\") failed: %m", p
);
63 if (fstat(fd
, &st
) < 0)
64 return log_debug_errno(errno
, "fstat(\"%s\") failed: %m", p
);
66 return log_debug_errno(SYNTHETIC_ERRNO(ENODATA
), "EFI variable %s is shorter than 4 bytes, refusing.", p
);
67 if (st
.st_size
> 4*1024*1024 + 4)
68 return log_debug_errno(SYNTHETIC_ERRNO(E2BIG
), "EFI variable %s is ridiculously large, refusing.", p
);
70 if (ret_value
|| ret_attribute
) {
71 /* The kernel ratelimits reads from the efivarfs because EFI is inefficient, and we'll
72 * occasionally fail with EINTR here. A slowdown is better than a failure for us, so
73 * retry a few times and eventually fail with -EBUSY.
75 * See https://github.com/torvalds/linux/blob/master/fs/efivarfs/file.c#L75
77 * https://github.com/torvalds/linux/commit/bef3efbeb897b56867e271cdbc5f8adaacaeb9cd.
79 for (unsigned try = 0;; try++) {
80 n
= read(fd
, &a
, sizeof(a
));
83 log_debug_errno(errno
, "Reading from \"%s\" failed: %m", p
);
86 if (try >= EFI_N_RETRIES_TOTAL
)
89 if (try >= EFI_N_RETRIES_NO_DELAY
)
90 (void) usleep_safe(EFI_RETRY_DELAY
);
93 /* Unfortunately kernel reports EOF if there's an inconsistency between efivarfs var list
94 * and what's actually stored in firmware, c.f. #34304. A zero size env var is not allowed in
95 * efi and hence the variable doesn't really exist in the backing store as long as it is zero
96 * sized, and the kernel calls this "uncommitted". Hence we translate EOF back to ENOENT here,
97 * as with kernel behavior before
98 * https://github.com/torvalds/linux/commit/3fab70c165795431f00ddf9be8b84ddd07bd1f8f
100 * If the kernel changes behaviour (to flush dentries on resume), we can drop
101 * this at some point in the future. But note that the commit is 11
102 * years old at this point so we'll need to deal with the current behaviour for
106 return log_debug_errno(SYNTHETIC_ERRNO(ENOENT
),
107 "EFI variable %s is uncommitted", p
);
110 return log_debug_errno(SYNTHETIC_ERRNO(EIO
),
111 "Read %zi bytes from EFI variable %s, expected %zu.", n
, p
, sizeof(a
));
115 buf
= malloc(st
.st_size
- 4 + 3);
119 n
= read(fd
, buf
, (size_t) st
.st_size
- 4);
121 return log_debug_errno(errno
, "Failed to read value of EFI variable %s: %m", p
);
122 assert(n
<= st
.st_size
- 4);
124 /* Always NUL-terminate (3 bytes, to properly protect UTF-16, even if truncated in the middle
126 ((char*) buf
)[n
] = 0;
127 ((char*) buf
)[n
+ 1] = 0;
128 ((char*) buf
)[n
+ 2] = 0;
130 /* Assume that the reported size is accurate */
134 usec_t end
= now(CLOCK_MONOTONIC
);
135 if (end
> begin
+ EFI_RETRY_DELAY
)
136 log_debug("Detected slow EFI variable read access on %s: %s",
137 variable
, FORMAT_TIMESPAN(end
- begin
, 1));
140 /* Note that efivarfs interestingly doesn't require ftruncate() to update an existing EFI variable
141 * with a smaller value. */
147 *ret_value
= TAKE_PTR(buf
);
155 int efi_get_variable_string(const char *variable
, char **ret
) {
156 _cleanup_free_
void *s
= NULL
;
163 r
= efi_get_variable(variable
, NULL
, &s
, &ss
);
167 x
= utf16_to_utf8(s
, ss
);
177 int efi_get_variable_path(const char *variable
, char **ret
) {
182 r
= efi_get_variable_string(variable
, ret
);
187 efi_tilt_backslashes(*ret
);
192 static int efi_verify_variable(const char *variable
, uint32_t attr
, const void *value
, size_t size
) {
193 _cleanup_free_
void *buf
= NULL
;
199 assert(value
|| size
== 0);
201 r
= efi_get_variable(variable
, &a
, &buf
, &n
);
205 return a
== attr
&& memcmp_nn(buf
, n
, value
, size
) == 0;
208 int efi_set_variable(const char *variable
, const void *value
, size_t size
) {
209 static const uint32_t attr
= EFI_VARIABLE_NON_VOLATILE
|EFI_VARIABLE_BOOTSERVICE_ACCESS
|EFI_VARIABLE_RUNTIME_ACCESS
;
214 } _packed_
* _cleanup_free_ buf
= NULL
;
215 _cleanup_close_
int fd
= -EBADF
;
216 bool saved_flags_valid
= false;
217 unsigned saved_flags
;
221 assert(value
|| size
== 0);
223 /* size 0 means removal, empty variable would not be enough for that */
224 if (size
> 0 && efi_verify_variable(variable
, attr
, value
, size
) > 0) {
225 log_debug("Variable '%s' is already in wanted state, skipping write.", variable
);
229 const char *p
= strjoina("/sys/firmware/efi/efivars/", variable
);
231 /* Newer efivarfs protects variables that are not in an allow list with FS_IMMUTABLE_FL by default,
232 * to protect them for accidental removal and modification. We are not changing these variables
233 * accidentally however, hence let's unset the bit first. */
235 r
= chattr_full(AT_FDCWD
, p
,
237 /* mask = */ FS_IMMUTABLE_FL
,
238 /* ret_previous = */ &saved_flags
,
239 /* ret_final = */ NULL
,
241 if (r
< 0 && r
!= -ENOENT
)
242 log_debug_errno(r
, "Failed to drop FS_IMMUTABLE_FL flag from '%s', ignoring: %m", p
);
244 saved_flags_valid
= r
>= 0;
255 fd
= open(p
, O_WRONLY
|O_CREAT
|O_NOCTTY
|O_CLOEXEC
, 0644);
261 buf
= malloc(sizeof(uint32_t) + size
);
268 memcpy(buf
->buf
, value
, size
);
270 r
= loop_write(fd
, buf
, sizeof(uint32_t) + size
);
274 /* For some reason efivarfs doesn't update mtime automatically. Let's do it manually then. This is
275 * useful for processes that cache EFI variables to detect when changes occurred. */
276 if (futimens(fd
, /* times = */ NULL
) < 0)
277 log_debug_errno(errno
, "Failed to update mtime/atime on %s, ignoring: %m", p
);
282 if (saved_flags_valid
) {
285 /* Restore the original flags field, just in case */
287 q
= chattr_path(p
, saved_flags
, FS_IMMUTABLE_FL
);
289 q
= chattr_fd(fd
, saved_flags
, FS_IMMUTABLE_FL
);
291 log_debug_errno(q
, "Failed to restore FS_IMMUTABLE_FL on '%s', ignoring: %m", p
);
297 int efi_set_variable_string(const char *variable
, const char *value
) {
298 _cleanup_free_ char16_t
*u16
= NULL
;
300 u16
= utf8_to_utf16(value
, SIZE_MAX
);
304 return efi_set_variable(variable
, u16
, (char16_strlen(u16
) + 1) * sizeof(char16_t
));
307 bool is_efi_boot(void) {
308 static int cache
= -1;
311 if (detect_container() > 0)
314 cache
= access("/sys/firmware/efi/", F_OK
) >= 0;
315 if (!cache
&& errno
!= ENOENT
)
316 log_debug_errno(errno
, "Unable to test whether /sys/firmware/efi/ exists, assuming EFI not available: %m");
323 static int read_flag(const char *variable
) {
324 _cleanup_free_
void *v
= NULL
;
329 if (!is_efi_boot()) /* If this is not an EFI boot, assume the queried flags are zero */
332 r
= efi_get_variable(variable
, NULL
, &v
, &s
);
343 bool is_efi_secure_boot(void) {
344 static int cache
= -1;
348 r
= read_flag(EFI_GLOBAL_VARIABLE_STR("SecureBoot"));
352 log_debug_errno(r
, "Error reading SecureBoot EFI variable, assuming not in SecureBoot mode: %m");
360 SecureBootMode
efi_get_secure_boot_mode(void) {
361 static SecureBootMode cache
= _SECURE_BOOT_INVALID
;
363 if (cache
!= _SECURE_BOOT_INVALID
)
366 int secure
= read_flag(EFI_GLOBAL_VARIABLE_STR("SecureBoot"));
368 if (secure
!= -ENOENT
)
369 log_debug_errno(secure
, "Error reading SecureBoot EFI variable, assuming not in SecureBoot mode: %m");
371 return (cache
= SECURE_BOOT_UNSUPPORTED
);
374 /* We can assume false for all these if they are abscent (AuditMode and
375 * DeployedMode may not exist on older firmware). */
376 int audit
= read_flag(EFI_GLOBAL_VARIABLE_STR("AuditMode"));
377 int deployed
= read_flag(EFI_GLOBAL_VARIABLE_STR("DeployedMode"));
378 int setup
= read_flag(EFI_GLOBAL_VARIABLE_STR("SetupMode"));
379 log_debug("Secure boot variables: SecureBoot=%d AuditMode=%d DeployedMode=%d SetupMode=%d",
380 secure
, audit
, deployed
, setup
);
382 return (cache
= decode_secure_boot_mode(secure
, audit
> 0, deployed
> 0, setup
> 0));
386 char *efi_tilt_backslashes(char *s
) {
387 return string_replace_char(s
, '\\', '/');