• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

systemd / systemd / 22121027152

17 Feb 2026 11:25PM UTC coverage: 72.452% (-0.2%) from 72.633%
22121027152

push

github

yuwata
pe-binary: fix missing le16toh() on NumberOfSections in pe_hash/uki_hash

pe_hash() and uki_hash() pass pe_header->pe.NumberOfSections directly
to typesafe_qsort() and FOREACH_ARRAY() without le16toh(). On
big-endian (s390x), NumberOfSections=3 gets read as 0x0300 (768),
while pe_load_sections() correctly converts it and only allocates 3
sections. This makes qsort process 768 elements on a 3-element
buffer, causing a heap-buffer-overflow (confirmed with ASAN on
native s390x).

Wrap all three raw usages with le16toh() to match pe_load_sections().

3 of 4 new or added lines in 1 file covered. (75.0%)

5909 existing lines in 86 files now uncovered.

312380 of 431157 relevant lines covered (72.45%)

1145272.29 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

28.83
/src/bootctl/bootctl-set-efivar.c
1
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2

3
#include <uchar.h>
4
#include <unistd.h>
5

6
#include "alloc-util.h"
7
#include "bootctl.h"
8
#include "bootctl-set-efivar.h"
9
#include "efi-loader.h"
10
#include "efivars.h"
11
#include "log.h"
12
#include "stdio-util.h"
13
#include "time-util.h"
14
#include "utf8.h"
15
#include "virt.h"
16

17
static int parse_timeout(const char *arg1, char16_t **ret_timeout, size_t *ret_timeout_size) {
×
18
        char buf[DECIMAL_STR_MAX(usec_t)];
×
19
        usec_t timeout;
×
20
        uint64_t loader_features = 0;
×
21
        int r;
×
22

23
        assert(arg1);
×
24
        assert(ret_timeout);
×
25
        assert(ret_timeout_size);
×
26

27
        assert_cc(STRLEN("menu-force") < ELEMENTSOF(buf));
×
28
        assert_cc(STRLEN("menu-hidden") < ELEMENTSOF(buf));
×
29
        assert_cc(STRLEN("menu-disabled") < ELEMENTSOF(buf));
×
30

31
        /* Use feature EFI_LOADER_FEATURE_MENU_DISABLE as a mark that the boot loader supports the other
32
         * string values too. When unsupported, convert to the timeout with the closest meaning.
33
         */
34

35
        if (streq(arg1, "menu-force")) {
×
36
                (void) efi_loader_get_features(&loader_features);
×
37

38
                if (!(loader_features & EFI_LOADER_FEATURE_MENU_DISABLE)) {
×
39
                        log_debug("Using maximum timeout instead of '%s'.", arg1);
×
40
                        timeout = USEC_INFINITY;
×
41
                        arg1 = NULL;
×
42
                }
43

44
        } else if (streq(arg1, "menu-hidden")) {
×
45
                (void) efi_loader_get_features(&loader_features);
×
46

47
                if (!(loader_features & EFI_LOADER_FEATURE_MENU_DISABLE)) {
×
48
                        log_debug("Using zero timeout instead of '%s'.", arg1);
×
49
                        timeout = 0;
×
50
                        arg1 = NULL;  /* replace the arg by printed timeout value later */
×
51
                }
52

53
        } else if (streq(arg1, "menu-disabled")) {
×
54
                (void) efi_loader_get_features(&loader_features);
×
55

56
                if (!(loader_features & EFI_LOADER_FEATURE_MENU_DISABLE)) {
×
57
                        if (arg_graceful() == ARG_GRACEFUL_NO)
×
58
                                return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
×
59
                                                       "Loader does not support '%s'.", arg1);
60
                        log_warning("Using zero timeout instead of '%s'.", arg1);
×
61
                        timeout = 0;
×
62
                        arg1 = NULL;
×
63
                }
64

65
        } else {
66
                r = parse_time(arg1, &timeout, USEC_PER_SEC);
×
67
                if (r < 0)
×
68
                        return log_error_errno(r, "Failed to parse timeout '%s': %m", arg1);
×
69

70
                assert_cc(USEC_INFINITY > UINT32_MAX * USEC_PER_SEC);
×
71
                if (timeout > UINT32_MAX * USEC_PER_SEC && timeout != USEC_INFINITY)
×
72
                        log_debug("Timeout is too long and will be clamped to maximum timeout.");
×
73

74
                arg1 = NULL;
75
        }
76

77
        if (!arg1) {
×
78
                timeout = DIV_ROUND_UP(timeout, USEC_PER_SEC);
×
79
                xsprintf(buf, USEC_FMT, MIN(timeout, UINT32_MAX));
×
80
        }
81

82
        char16_t *encoded = utf8_to_utf16(arg1 ?: buf, SIZE_MAX);
×
83
        if (!encoded)
×
84
                return log_oom();
×
85

86
        *ret_timeout = encoded;
×
87
        *ret_timeout_size = char16_strlen(encoded) * 2 + 2;
×
88
        return 0;
×
89
}
90

91
static int parse_loader_entry_target_arg(const char *arg1, char16_t **ret_target, size_t *ret_target_size) {
5✔
92
        char16_t *encoded = NULL;
5✔
93
        int r;
5✔
94

95
        assert(arg1);
5✔
96
        assert(ret_target);
5✔
97
        assert(ret_target_size);
5✔
98

99
        if (streq(arg1, "@current")) {
5✔
100
                r = efi_get_variable(EFI_LOADER_VARIABLE_STR("LoaderEntrySelected"), NULL, (void *) ret_target, ret_target_size);
×
101
                if (r < 0)
×
102
                        return log_error_errno(r, "Failed to get EFI variable 'LoaderEntrySelected': %m");
×
103

104
        } else if (streq(arg1, "@oneshot")) {
5✔
105
                r = efi_get_variable(EFI_LOADER_VARIABLE_STR("LoaderEntryOneShot"), NULL, (void *) ret_target, ret_target_size);
×
106
                if (r < 0)
×
107
                        return log_error_errno(r, "Failed to get EFI variable 'LoaderEntryOneShot': %m");
×
108

109
        } else if (streq(arg1, "@default")) {
5✔
110
                r = efi_get_variable(EFI_LOADER_VARIABLE_STR("LoaderEntryDefault"), NULL, (void *) ret_target, ret_target_size);
×
111
                if (r < 0)
×
112
                        return log_error_errno(r, "Failed to get EFI variable 'LoaderEntryDefault': %m");
×
113

114
        } else if (streq(arg1, "@sysfail")) {
5✔
115
                r = efi_get_variable(EFI_LOADER_VARIABLE_STR("LoaderEntrySysFail"), NULL, (void *) ret_target, ret_target_size);
×
116
                if (r < 0)
×
117
                        return log_error_errno(r, "Failed to get EFI variable 'LoaderEntrySysFail': %m");
×
118

119
        } else if (arg1[0] == '@' && !streq(arg1, "@saved"))
5✔
120
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Unsupported special entry identifier: %s", arg1);
×
121
        else {
122
                encoded = utf8_to_utf16(arg1, SIZE_MAX);
5✔
123
                if (!encoded)
5✔
124
                        return log_oom();
×
125

126
                *ret_target = encoded;
5✔
127
                *ret_target_size = char16_strlen(encoded) * 2 + 2;
5✔
128
        }
129

130
        return 0;
131
}
132

133
int verb_set_efivar(int argc, char *argv[], void *userdata) {
5✔
134
        int r;
5✔
135

136
        /* Note: changing EFI variables is the primary purpose of these verbs, hence unlike in the other
137
         * verbs that might touch EFI variables where we skip things gracefully, here we fail loudly if we
138
         * are not run on EFI or EFI variable modifications were turned off. */
139

140
        if (arg_touch_variables < 0) {
5✔
141
                if (arg_root)
5✔
142
                        return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
×
143
                                               "Acting on %s, refusing EFI variable setup.",
144
                                               arg_image ? "image" : "root directory");
145

146
                if (detect_container() > 0)
5✔
147
                        return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
×
148
                                               "'%s' operation not supported in a container.",
149
                                               argv[0]);
150
                if (!is_efi_boot())
5✔
151
                        return log_error_errno(SYNTHETIC_ERRNO(EOPNOTSUPP),
×
152
                                               "Not booted with UEFI.");
153

154
                if (access(EFIVAR_PATH(EFI_LOADER_VARIABLE_STR("LoaderInfo")), F_OK) < 0) {
5✔
155
                        if (errno == ENOENT) {
×
156
                                log_error_errno(errno, "Not booted with a supported boot loader.");
×
157
                                return -EOPNOTSUPP;
×
158
                        }
159

160
                        return log_error_errno(errno, "Failed to detect whether boot loader supports '%s' operation: %m", argv[0]);
×
161
                }
162

163
        } else if (!arg_touch_variables)
×
164
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
165
                                       "'%s' operation cannot be combined with --variables=no.",
166
                                       argv[0]);
167

168
        const char *variable;
5✔
169
        int (* arg_parser)(const char *, char16_t **, size_t *);
5✔
170

171
        if (streq(argv[0], "set-default")) {
5✔
172
                variable = EFI_LOADER_VARIABLE_STR("LoaderEntryDefault");
173
                arg_parser = parse_loader_entry_target_arg;
174
        } else if (streq(argv[0], "set-preferred")) {
×
175
                variable = EFI_LOADER_VARIABLE_STR("LoaderEntryPreferred");
176
                arg_parser = parse_loader_entry_target_arg;
177
        } else if (streq(argv[0], "set-sysfail")) {
×
178
                variable = EFI_LOADER_VARIABLE_STR("LoaderEntrySysFail");
179
                arg_parser = parse_loader_entry_target_arg;
180
        } else if (streq(argv[0], "set-oneshot")) {
×
181
                variable = EFI_LOADER_VARIABLE_STR("LoaderEntryOneShot");
182
                arg_parser = parse_loader_entry_target_arg;
183
        } else if (streq(argv[0], "set-timeout")) {
×
184
                variable = EFI_LOADER_VARIABLE_STR("LoaderConfigTimeout");
185
                arg_parser = parse_timeout;
UNCOV
186
        } else if (streq(argv[0], "set-timeout-oneshot")) {
×
187
                variable = EFI_LOADER_VARIABLE_STR("LoaderConfigTimeoutOneShot");
188
                arg_parser = parse_timeout;
189
        } else
190
                assert_not_reached();
×
191

192
        if (isempty(argv[1])) {
5✔
UNCOV
193
                r = efi_set_variable(variable, NULL, 0);
×
UNCOV
194
                if (r < 0 && r != -ENOENT)
×
UNCOV
195
                        return log_error_errno(r, "Failed to remove EFI variable '%s': %m", variable);
×
196
        } else {
197
                _cleanup_free_ char16_t *value = NULL;
5✔
198
                size_t value_size = 0;
5✔
199

200
                r = arg_parser(argv[1], &value, &value_size);
5✔
201
                if (r < 0)
5✔
202
                        return r;
203
                r = efi_set_variable(variable, value, value_size);
5✔
204
                if (r < 0)
5✔
UNCOV
205
                        return log_error_errno(r, "Failed to update EFI variable '%s': %m", variable);
×
206
        }
207

208
        return 0;
209
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc