...
...
20
qemu instead.
20
qemu instead.
21
21
22
A edk2 test branch can be found here (build with "-D QEMU_VARS=TRUE").
22
A edk2 test branch can be found here (build with "-D QEMU_VARS=TRUE").
23
https://github.com/kraxel/edk2/commits/devel/secure-boot-external-vars
23
https://github.com/kraxel/edk2/commits/devel/secure-boot-external-vars
24
24
25
The uefi-vars device must re-implement the privileged edk2 protocols
25
The uefi-vars device re-implements the privileged edk2 protocols
26
(i.e. the code running in SMM mode). The implementation is not complete
26
(i.e. the code running in SMM mode).
27
yet, specifically updating authenticated variables is not implemented.
28
These variables are simply read-only for now.
29
27
30
But there is enough functionality working that it is possible to run
28
v2 changes:
31
guests, including guests in secure boot mode, so I'm sending this out
29
- fully implement authenticated variables.
32
for feedback (before tackling the remaining 20% which evidently will
30
- various cleanups and fixes.
33
need 80% of the time ;)
34
35
Because the guest can not write to authenticated variables (yet) it can
36
not enroll secure boot keys itself, this must be done on the host. The
37
virt-firmware tools (https://gitlab.com/kraxel/virt-firmware) can be
38
used for that:
39
40
virt-fw-vars --enroll-redhat --secure-boot --output-json uefivars.json
41
31
42
enjoy & take care,
32
enjoy & take care,
43
Gerd
33
Gerd
44
34
45
Gerd Hoffmann (16):
35
Gerd Hoffmann (21):
46
hw/uefi: add include/hw/uefi/var-service-api.h
36
hw/uefi: add include/hw/uefi/var-service-api.h
47
hw/uefi: add include/hw/uefi/var-service-edk2.h
37
hw/uefi: add include/hw/uefi/var-service-edk2.h
48
hw/uefi: add include/hw/uefi/var-service.h
38
hw/uefi: add include/hw/uefi/var-service.h
49
hw/uefi: add var-service-guid.c
39
hw/uefi: add var-service-guid.c
50
hw/uefi: add var-service-core.c
40
hw/uefi: add var-service-utils.c
51
hw/uefi: add var-service-vars.c
41
hw/uefi: add var-service-vars.c
52
hw/uefi: add var-service-auth.c
42
hw/uefi: add var-service-auth.c
53
hw/uefi: add var-service-policy.c
43
hw/uefi: add var-service-policy.c
54
hw/uefi: add support for storing persistent variables on disk
44
hw/uefi: add var-service-core.c
45
hw/uefi: add var-service-pkcs7.c
46
hw/uefi: add var-service-pkcs7-stub.c
47
hw/uefi: add var-service-siglist.c
48
hw/uefi: add var-service-json.c + qapi for NV vars.
55
hw/uefi: add trace-events
49
hw/uefi: add trace-events
56
hw/uefi: add to Kconfig
50
hw/uefi: add UEFI_VARS to Kconfig
57
hw/uefi: add to meson
51
hw/uefi: add to meson
58
hw/uefi: add uefi-vars-sysbus device
52
hw/uefi: add uefi-vars-sysbus device
59
hw/uefi: add uefi-vars-isa device
53
hw/uefi: add uefi-vars-isa device
60
hw/arm: add uefi variable support to virt machine type
54
hw/arm: add uefi variable support to virt machine type
61
docs: add uefi variable service documentation and TODO list.
55
docs: add uefi variable service documentation
56
hw/uefi: add MAINTAINERS entry
62
57
63
include/hw/arm/virt.h | 2 +
58
include/hw/arm/virt.h | 2 +
64
include/hw/uefi/var-service-api.h | 40 ++
59
include/hw/uefi/var-service-api.h | 40 ++
65
include/hw/uefi/var-service-edk2.h | 184 +++++++++
60
include/hw/uefi/var-service-edk2.h | 227 +++++++++
66
include/hw/uefi/var-service.h | 119 ++++++
61
include/hw/uefi/var-service.h | 186 ++++++++
67
hw/arm/virt.c | 41 ++
62
hw/arm/virt.c | 41 ++
68
hw/uefi/var-service-auth.c | 91 +++++
63
hw/uefi/var-service-auth.c | 361 ++++++++++++++
69
hw/uefi/var-service-core.c | 350 +++++++++++++++++
64
hw/uefi/var-service-core.c | 237 ++++++++++
70
hw/uefi/var-service-guid.c | 61 +++
65
hw/uefi/var-service-guid.c | 99 ++++
71
hw/uefi/var-service-isa.c | 88 +++++
66
hw/uefi/var-service-isa.c | 91 ++++
72
hw/uefi/var-service-json.c | 194 ++++++++++
67
hw/uefi/var-service-json.c | 242 ++++++++++
73
hw/uefi/var-service-policy.c | 390 +++++++++++++++++++
68
hw/uefi/var-service-pkcs7-stub.c | 16 +
74
hw/uefi/var-service-sysbus.c | 87 +++++
69
hw/uefi/var-service-pkcs7.c | 436 +++++++++++++++++
75
hw/uefi/var-service-vars.c | 602 +++++++++++++++++++++++++++++
70
hw/uefi/var-service-policy.c | 370 +++++++++++++++
71
hw/uefi/var-service-siglist.c | 212 +++++++++
72
hw/uefi/var-service-sysbus.c | 90 ++++
73
hw/uefi/var-service-utils.c | 241 ++++++++++
74
hw/uefi/var-service-vars.c | 725 +++++++++++++++++++++++++++++
75
MAINTAINERS | 6 +
76
docs/devel/index-internals.rst | 1 +
76
docs/devel/index-internals.rst | 1 +
77
docs/devel/uefi-vars.rst | 66 ++++
77
docs/devel/uefi-vars.rst | 66 +++
78
hw/Kconfig | 1 +
78
hw/Kconfig | 1 +
79
hw/meson.build | 1 +
79
hw/meson.build | 1 +
80
hw/uefi/Kconfig | 9 +
80
hw/uefi/Kconfig | 9 +
81
hw/uefi/TODO.md | 17 +
81
hw/uefi/LIMITATIONS.md | 7 +
82
hw/uefi/meson.build | 18 +
82
hw/uefi/meson.build | 24 +
83
hw/uefi/trace-events | 16 +
83
hw/uefi/trace-events | 17 +
84
meson.build | 1 +
84
meson.build | 1 +
85
qapi/meson.build | 1 +
85
qapi/meson.build | 1 +
86
qapi/qapi-schema.json | 1 +
86
qapi/qapi-schema.json | 1 +
87
qapi/uefi.json | 40 ++
87
qapi/uefi.json | 45 ++
88
25 files changed, 2421 insertions(+)
88
30 files changed, 3796 insertions(+)
89
create mode 100644 include/hw/uefi/var-service-api.h
89
create mode 100644 include/hw/uefi/var-service-api.h
90
create mode 100644 include/hw/uefi/var-service-edk2.h
90
create mode 100644 include/hw/uefi/var-service-edk2.h
91
create mode 100644 include/hw/uefi/var-service.h
91
create mode 100644 include/hw/uefi/var-service.h
92
create mode 100644 hw/uefi/var-service-auth.c
92
create mode 100644 hw/uefi/var-service-auth.c
93
create mode 100644 hw/uefi/var-service-core.c
93
create mode 100644 hw/uefi/var-service-core.c
94
create mode 100644 hw/uefi/var-service-guid.c
94
create mode 100644 hw/uefi/var-service-guid.c
95
create mode 100644 hw/uefi/var-service-isa.c
95
create mode 100644 hw/uefi/var-service-isa.c
96
create mode 100644 hw/uefi/var-service-json.c
96
create mode 100644 hw/uefi/var-service-json.c
97
create mode 100644 hw/uefi/var-service-pkcs7-stub.c
98
create mode 100644 hw/uefi/var-service-pkcs7.c
97
create mode 100644 hw/uefi/var-service-policy.c
99
create mode 100644 hw/uefi/var-service-policy.c
100
create mode 100644 hw/uefi/var-service-siglist.c
98
create mode 100644 hw/uefi/var-service-sysbus.c
101
create mode 100644 hw/uefi/var-service-sysbus.c
102
create mode 100644 hw/uefi/var-service-utils.c
99
create mode 100644 hw/uefi/var-service-vars.c
103
create mode 100644 hw/uefi/var-service-vars.c
100
create mode 100644 docs/devel/uefi-vars.rst
104
create mode 100644 docs/devel/uefi-vars.rst
101
create mode 100644 hw/uefi/Kconfig
105
create mode 100644 hw/uefi/Kconfig
102
create mode 100644 hw/uefi/TODO.md
106
create mode 100644 hw/uefi/LIMITATIONS.md
103
create mode 100644 hw/uefi/meson.build
107
create mode 100644 hw/uefi/meson.build
104
create mode 100644 hw/uefi/trace-events
108
create mode 100644 hw/uefi/trace-events
105
create mode 100644 qapi/uefi.json
109
create mode 100644 qapi/uefi.json
106
110
107
--
111
--
108
2.41.0
112
2.47.1
diff view generated by jsdifflib
1
This file defines the register interface of the uefi-vars device.
1
This file defines the register interface of the uefi-vars device.
2
It's only a handful of registers: magic value, command and status
2
It's only a handful of registers: magic value, command and status
3
registers, location and size of the communication buffer.
3
registers, location and size of the communication buffer.
4
4
5
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
5
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
6
Reviewed-by: Laszlo Ersek <lersek@redhat.com>
6
---
7
---
7
include/hw/uefi/var-service-api.h | 40 +++++++++++++++++++++++++++++++
8
include/hw/uefi/var-service-api.h | 40 +++++++++++++++++++++++++++++++
8
1 file changed, 40 insertions(+)
9
1 file changed, 40 insertions(+)
9
create mode 100644 include/hw/uefi/var-service-api.h
10
create mode 100644 include/hw/uefi/var-service-api.h
10
11
...
...
53
+#define UEFI_VARS_STS_ERR_BAD_BUFFER_SIZE 0x12
54
+#define UEFI_VARS_STS_ERR_BAD_BUFFER_SIZE 0x12
54
+
55
+
55
+
56
+
56
+#endif /* QEMU_UEFI_VAR_SERVICE_API_H */
57
+#endif /* QEMU_UEFI_VAR_SERVICE_API_H */
57
--
58
--
58
2.41.0
59
2.47.1
diff view generated by jsdifflib
1
A bunch of #defines and structs copied over from edk2,
1
A bunch of #defines and structs copied over from edk2,
2
mostly needed to decode and encode the messages in the
2
mostly needed to decode and encode the messages in the
3
communication buffer.
3
communication buffer.
4
4
5
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
5
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
6
---
6
---
7
include/hw/uefi/var-service-edk2.h | 184 +++++++++++++++++++++++++++++
7
include/hw/uefi/var-service-edk2.h | 227 +++++++++++++++++++++++++++++
8
1 file changed, 184 insertions(+)
8
1 file changed, 227 insertions(+)
9
create mode 100644 include/hw/uefi/var-service-edk2.h
9
create mode 100644 include/hw/uefi/var-service-edk2.h
10
10
11
diff --git a/include/hw/uefi/var-service-edk2.h b/include/hw/uefi/var-service-edk2.h
11
diff --git a/include/hw/uefi/var-service-edk2.h b/include/hw/uefi/var-service-edk2.h
12
new file mode 100644
12
new file mode 100644
13
index XXXXXXX..XXXXXXX
13
index XXXXXXX..XXXXXXX
...
...
37
+#define EFI_WRITE_PROTECTED ENCODE_ERROR(8)
37
+#define EFI_WRITE_PROTECTED ENCODE_ERROR(8)
38
+#define EFI_OUT_OF_RESOURCES ENCODE_ERROR(9)
38
+#define EFI_OUT_OF_RESOURCES ENCODE_ERROR(9)
39
+#define EFI_NOT_FOUND ENCODE_ERROR(14)
39
+#define EFI_NOT_FOUND ENCODE_ERROR(14)
40
+#define EFI_ACCESS_DENIED ENCODE_ERROR(15)
40
+#define EFI_ACCESS_DENIED ENCODE_ERROR(15)
41
+#define EFI_ALREADY_STARTED ENCODE_ERROR(20)
41
+#define EFI_ALREADY_STARTED ENCODE_ERROR(20)
42
+#define EFI_SECURITY_VIOLATION ENCODE_ERROR(26)
42
+
43
+
43
+#define EFI_VARIABLE_NON_VOLATILE 0x01
44
+#define EFI_VARIABLE_NON_VOLATILE 0x01
44
+#define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x02
45
+#define EFI_VARIABLE_BOOTSERVICE_ACCESS 0x02
45
+#define EFI_VARIABLE_RUNTIME_ACCESS 0x04
46
+#define EFI_VARIABLE_RUNTIME_ACCESS 0x04
46
+#define EFI_VARIABLE_HARDWARE_ERROR_RECORD 0x08
47
+#define EFI_VARIABLE_HARDWARE_ERROR_RECORD 0x08
47
+#define EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS 0x10 // deprecated
48
+#define EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS 0x10 /* deprecated */
48
+#define EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS 0x20
49
+#define EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS 0x20
49
+#define EFI_VARIABLE_APPEND_WRITE 0x40
50
+#define EFI_VARIABLE_APPEND_WRITE 0x40
50
+
51
+
51
+/* SecureBootEnable */
52
+/* SecureBootEnable */
52
+#define SECURE_BOOT_ENABLE 1
53
+#define SECURE_BOOT_ENABLE 1
...
...
194
+ uint8_t value;
195
+ uint8_t value;
195
+ uint8_t padding;
196
+ uint8_t padding;
196
+ /* Name */
197
+ /* Name */
197
+};
198
+};
198
+
199
+
200
+/* --- variable authentication --------------------------------------- */
201
+
202
+#define WIN_CERT_TYPE_EFI_GUID 0x0EF1
203
+
204
+typedef struct efi_time efi_time;
205
+typedef struct efi_siglist efi_siglist;
206
+typedef struct variable_auth_2 variable_auth_2;
207
+
208
+/* EFI_TIME */
209
+struct efi_time {
210
+ uint16_t year;
211
+ uint8_t month;
212
+ uint8_t day;
213
+ uint8_t hour;
214
+ uint8_t minute;
215
+ uint8_t second;
216
+ uint8_t pad1;
217
+ uint32_t nanosecond;
218
+ int16_t timezone;
219
+ uint8_t daylight;
220
+ uint8_t pad2;
221
+};
222
+
223
+/* EFI_SIGNATURE_LIST */
224
+struct efi_siglist {
225
+ QemuUUID guid_type;
226
+ uint32_t siglist_size;
227
+ uint32_t header_size;
228
+ uint32_t sig_size;
229
+};
230
+
231
+/* EFI_VARIABLE_AUTHENTICATION_2 */
232
+struct variable_auth_2 {
233
+ struct efi_time timestamp;
234
+
235
+ /* WIN_CERTIFICATE_UEFI_GUID */
236
+ uint32_t hdr_length;
237
+ uint16_t hdr_revision;
238
+ uint16_t hdr_cert_type;
239
+ QemuUUID guid_cert_type;
240
+ uint8_t cert_data[];
241
+};
199
+
242
+
200
+#endif /* QEMU_UEFI_VAR_SERVICE_EDK2_H */
243
+#endif /* QEMU_UEFI_VAR_SERVICE_EDK2_H */
201
--
244
--
202
2.41.0
245
2.47.1
diff view generated by jsdifflib
1
Add state structs and function declarations for the uefi-vars device.
1
Add state structs and function declarations for the uefi-vars device.
2
2
3
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
3
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
4
---
4
---
5
include/hw/uefi/var-service.h | 119 ++++++++++++++++++++++++++++++++++
5
include/hw/uefi/var-service.h | 186 ++++++++++++++++++++++++++++++++++
6
1 file changed, 119 insertions(+)
6
1 file changed, 186 insertions(+)
7
create mode 100644 include/hw/uefi/var-service.h
7
create mode 100644 include/hw/uefi/var-service.h
8
8
9
diff --git a/include/hw/uefi/var-service.h b/include/hw/uefi/var-service.h
9
diff --git a/include/hw/uefi/var-service.h b/include/hw/uefi/var-service.h
10
new file mode 100644
10
new file mode 100644
11
index XXXXXXX..XXXXXXX
11
index XXXXXXX..XXXXXXX
...
...
29
+
29
+
30
+typedef struct uefi_variable uefi_variable;
30
+typedef struct uefi_variable uefi_variable;
31
+typedef struct uefi_var_policy uefi_var_policy;
31
+typedef struct uefi_var_policy uefi_var_policy;
32
+typedef struct uefi_vars_state uefi_vars_state;
32
+typedef struct uefi_vars_state uefi_vars_state;
33
+
33
+
34
+typedef struct uefi_vars_cert uefi_vars_cert;
35
+typedef struct uefi_vars_hash uefi_vars_hash;
36
+typedef struct uefi_vars_siglist uefi_vars_siglist;
37
+
34
+struct uefi_variable {
38
+struct uefi_variable {
35
+ QemuUUID guid;
39
+ QemuUUID guid;
36
+ uint16_t *name;
40
+ uint16_t *name;
37
+ uint32_t name_size;
41
+ uint32_t name_size;
38
+ uint32_t attributes;
42
+ uint32_t attributes;
39
+ void *data;
43
+ void *data;
40
+ uint32_t data_size;
44
+ uint32_t data_size;
45
+ efi_time time;
46
+ void *digest;
47
+ uint32_t digest_size;
41
+ QTAILQ_ENTRY(uefi_variable) next;
48
+ QTAILQ_ENTRY(uefi_variable) next;
42
+};
49
+};
43
+
50
+
44
+struct uefi_var_policy {
51
+struct uefi_var_policy {
45
+ variable_policy_entry *entry;
52
+ variable_policy_entry *entry;
46
+ uint32_t entry_size;
53
+ uint32_t entry_size;
47
+ uint16_t *name;
54
+ uint16_t *name;
48
+ uint32_t name_size;
55
+ uint32_t name_size;
56
+
57
+ /* number of hashmarks (wildcard character) in name */
49
+ uint32_t hashmarks;
58
+ uint32_t hashmarks;
59
+
50
+ QTAILQ_ENTRY(uefi_var_policy) next;
60
+ QTAILQ_ENTRY(uefi_var_policy) next;
51
+};
61
+};
52
+
62
+
53
+struct uefi_vars_state {
63
+struct uefi_vars_state {
54
+ MemoryRegion mr;
64
+ MemoryRegion mr;
...
...
68
+
78
+
69
+ /* storage accounting */
79
+ /* storage accounting */
70
+ uint64_t max_storage;
80
+ uint64_t max_storage;
71
+ uint64_t used_storage;
81
+ uint64_t used_storage;
72
+
82
+
83
+ /* config options */
73
+ char *jsonfile;
84
+ char *jsonfile;
74
+ int jsonfd;
85
+ int jsonfd;
86
+ bool force_secure_boot;
87
+ bool disable_custom_mode;
88
+};
89
+
90
+struct uefi_vars_cert {
91
+ QTAILQ_ENTRY(uefi_vars_cert) next;
92
+ QemuUUID owner;
93
+ uint64_t size;
94
+ uint8_t data[];
95
+};
96
+
97
+struct uefi_vars_hash {
98
+ QTAILQ_ENTRY(uefi_vars_hash) next;
99
+ QemuUUID owner;
100
+ uint8_t data[];
101
+};
102
+
103
+struct uefi_vars_siglist {
104
+ QTAILQ_HEAD(, uefi_vars_cert) x509;
105
+ QTAILQ_HEAD(, uefi_vars_hash) sha256;
75
+};
106
+};
76
+
107
+
77
+/* vars-service-guid.c */
108
+/* vars-service-guid.c */
78
+extern QemuUUID EfiGlobalVariable;
109
+extern const QemuUUID EfiGlobalVariable;
79
+extern QemuUUID EfiImageSecurityDatabase;
110
+extern const QemuUUID EfiImageSecurityDatabase;
80
+extern QemuUUID EfiCustomModeEnable;
111
+extern const QemuUUID EfiCustomModeEnable;
81
+extern QemuUUID EfiSecureBootEnableDisable;
112
+extern const QemuUUID EfiSecureBootEnableDisable;
82
+extern QemuUUID EfiSmmVariableProtocolGuid;
113
+
83
+extern QemuUUID VarCheckPolicyLibMmiHandlerGuid;
114
+extern const QemuUUID EfiCertSha256Guid;
84
+extern QemuUUID EfiEndOfDxeEventGroupGuid;
115
+extern const QemuUUID EfiCertSha384Guid;
85
+extern QemuUUID EfiEventReadyToBootGuid;
116
+extern const QemuUUID EfiCertSha512Guid;
86
+extern QemuUUID EfiEventExitBootServicesGuid;
117
+extern const QemuUUID EfiCertRsa2048Guid;
87
+
118
+extern const QemuUUID EfiCertX509Guid;
88
+/* vars-service-core.c */
119
+extern const QemuUUID EfiCertTypePkcs7Guid;
89
+extern const VMStateDescription vmstate_uefi_vars;
120
+
121
+extern const QemuUUID EfiSmmVariableProtocolGuid;
122
+extern const QemuUUID VarCheckPolicyLibMmiHandlerGuid;
123
+
124
+extern const QemuUUID EfiEndOfDxeEventGroupGuid;
125
+extern const QemuUUID EfiEventReadyToBootGuid;
126
+extern const QemuUUID EfiEventExitBootServicesGuid;
127
+
128
+/* vars-service-utils.c */
129
+gboolean uefi_str_is_valid(const uint16_t *str, size_t len,
130
+ gboolean must_be_null_terminated);
90
+size_t uefi_strlen(const uint16_t *str, size_t len);
131
+size_t uefi_strlen(const uint16_t *str, size_t len);
132
+gboolean uefi_str_equal_ex(const uint16_t *a, size_t alen,
133
+ const uint16_t *b, size_t blen,
134
+ gboolean wildcards_in_a);
91
+gboolean uefi_str_equal(const uint16_t *a, size_t alen,
135
+gboolean uefi_str_equal(const uint16_t *a, size_t alen,
92
+ const uint16_t *b, size_t blen);
136
+ const uint16_t *b, size_t blen);
93
+char *uefi_ucs2_to_ascii(const uint16_t *ucs2, uint64_t ucs2_size);
137
+char *uefi_ucs2_to_ascii(const uint16_t *ucs2, uint64_t ucs2_size);
138
+int uefi_time_compare(efi_time *a, efi_time *b);
94
+void uefi_trace_variable(const char *action, QemuUUID guid,
139
+void uefi_trace_variable(const char *action, QemuUUID guid,
95
+ const uint16_t *name, uint64_t name_size);
140
+ const uint16_t *name, uint64_t name_size);
96
+void uefi_trace_status(const char *action, efi_status status);
141
+void uefi_trace_status(const char *action, efi_status status);
142
+
143
+/* vars-service-core.c */
144
+extern const VMStateDescription vmstate_uefi_vars;
97
+void uefi_vars_init(Object *obj, uefi_vars_state *uv);
145
+void uefi_vars_init(Object *obj, uefi_vars_state *uv);
98
+void uefi_vars_realize(uefi_vars_state *uv, Error **errp);
146
+void uefi_vars_realize(uefi_vars_state *uv, Error **errp);
99
+void uefi_vars_hard_reset(uefi_vars_state *uv);
147
+void uefi_vars_hard_reset(uefi_vars_state *uv);
100
+
148
+
101
+/* vars-service-json.c */
149
+/* vars-service-json.c */
...
...
116
+void uefi_vars_clear_all(uefi_vars_state *uv);
164
+void uefi_vars_clear_all(uefi_vars_state *uv);
117
+void uefi_vars_update_storage(uefi_vars_state *uv);
165
+void uefi_vars_update_storage(uefi_vars_state *uv);
118
+uint32_t uefi_vars_mm_vars_proto(uefi_vars_state *uv);
166
+uint32_t uefi_vars_mm_vars_proto(uefi_vars_state *uv);
119
+
167
+
120
+/* vars-service-auth.c */
168
+/* vars-service-auth.c */
169
+bool uefi_vars_is_sb_pk(uefi_variable *var);
170
+bool uefi_vars_is_sb_any(uefi_variable *var);
171
+efi_status uefi_vars_check_auth_2(uefi_vars_state *uv, uefi_variable *var,
172
+ mm_variable_access *va, void *data);
173
+efi_status uefi_vars_check_secure_boot(uefi_vars_state *uv, uefi_variable *var);
121
+void uefi_vars_auth_init(uefi_vars_state *uv);
174
+void uefi_vars_auth_init(uefi_vars_state *uv);
175
+
176
+/* vars-service-pkcs7.c */
177
+efi_status uefi_vars_check_pkcs7_2(uefi_variable *siglist,
178
+ void **digest, uint32_t *digest_size,
179
+ mm_variable_access *va, void *data);
180
+
181
+/* vars-service-siglist.c */
182
+void uefi_vars_siglist_init(uefi_vars_siglist *siglist);
183
+void uefi_vars_siglist_free(uefi_vars_siglist *siglist);
184
+void uefi_vars_siglist_parse(uefi_vars_siglist *siglist,
185
+ void *data, uint64_t size);
186
+uint64_t uefi_vars_siglist_blob_size(uefi_vars_siglist *siglist);
187
+void uefi_vars_siglist_blob_generate(uefi_vars_siglist *siglist,
188
+ void *data, uint64_t size);
122
+
189
+
123
+/* vars-service-policy.c */
190
+/* vars-service-policy.c */
124
+extern const VMStateDescription vmstate_uefi_var_policy;
191
+extern const VMStateDescription vmstate_uefi_var_policy;
125
+efi_status uefi_vars_policy_check(uefi_vars_state *uv,
192
+efi_status uefi_vars_policy_check(uefi_vars_state *uv,
126
+ uefi_variable *var,
193
+ uefi_variable *var,
...
...
130
+ variable_policy_entry *pe);
197
+ variable_policy_entry *pe);
131
+uint32_t uefi_vars_mm_check_policy_proto(uefi_vars_state *uv);
198
+uint32_t uefi_vars_mm_check_policy_proto(uefi_vars_state *uv);
132
+
199
+
133
+#endif /* QEMU_UEFI_VAR_SERVICE_H */
200
+#endif /* QEMU_UEFI_VAR_SERVICE_H */
134
--
201
--
135
2.41.0
202
2.47.1
diff view generated by jsdifflib
1
Add variables for a bunch of GUIDs we will need.
1
Add variables for a bunch of UEFI GUIDs we will need.
2
2
3
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
3
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
4
---
4
---
5
hw/uefi/var-service-guid.c | 61 ++++++++++++++++++++++++++++++++++++++
5
hw/uefi/var-service-guid.c | 99 ++++++++++++++++++++++++++++++++++++++
6
1 file changed, 61 insertions(+)
6
1 file changed, 99 insertions(+)
7
create mode 100644 hw/uefi/var-service-guid.c
7
create mode 100644 hw/uefi/var-service-guid.c
8
8
9
diff --git a/hw/uefi/var-service-guid.c b/hw/uefi/var-service-guid.c
9
diff --git a/hw/uefi/var-service-guid.c b/hw/uefi/var-service-guid.c
10
new file mode 100644
10
new file mode 100644
11
index XXXXXXX..XXXXXXX
11
index XXXXXXX..XXXXXXX
...
...
17
+ *
17
+ *
18
+ * uefi vars device - GUIDs
18
+ * uefi vars device - GUIDs
19
+ */
19
+ */
20
+
20
+
21
+#include "qemu/osdep.h"
21
+#include "qemu/osdep.h"
22
+#include "sysemu/dma.h"
22
+#include "system/dma.h"
23
+
23
+
24
+#include "hw/uefi/var-service.h"
24
+#include "hw/uefi/var-service.h"
25
+
25
+
26
+/* variable namespaces */
26
+/* variable namespaces */
27
+
27
+
28
+QemuUUID EfiGlobalVariable = {
28
+const QemuUUID EfiGlobalVariable = {
29
+ .data = UUID_LE(0x8be4df61, 0x93ca, 0x11d2, 0xaa, 0x0d,
29
+ .data = UUID_LE(0x8be4df61, 0x93ca, 0x11d2, 0xaa, 0x0d,
30
+ 0x00, 0xe0, 0x98, 0x03, 0x2b, 0x8c)
30
+ 0x00, 0xe0, 0x98, 0x03, 0x2b, 0x8c)
31
+};
31
+};
32
+
32
+
33
+QemuUUID EfiImageSecurityDatabase = {
33
+const QemuUUID EfiImageSecurityDatabase = {
34
+ .data = UUID_LE(0xd719b2cb, 0x3d3a, 0x4596, 0xa3, 0xbc,
34
+ .data = UUID_LE(0xd719b2cb, 0x3d3a, 0x4596, 0xa3, 0xbc,
35
+ 0xda, 0xd0, 0x0e, 0x67, 0x65, 0x6f)
35
+ 0xda, 0xd0, 0x0e, 0x67, 0x65, 0x6f)
36
+};
36
+};
37
+
37
+
38
+QemuUUID EfiCustomModeEnable = {
38
+const QemuUUID EfiCustomModeEnable = {
39
+ .data = UUID_LE(0xc076ec0c, 0x7028, 0x4399, 0xa0, 0x72,
39
+ .data = UUID_LE(0xc076ec0c, 0x7028, 0x4399, 0xa0, 0x72,
40
+ 0x71, 0xee, 0x5c, 0x44, 0x8b, 0x9f)
40
+ 0x71, 0xee, 0x5c, 0x44, 0x8b, 0x9f)
41
+};
41
+};
42
+
42
+
43
+QemuUUID EfiSecureBootEnableDisable = {
43
+const QemuUUID EfiSecureBootEnableDisable = {
44
+ .data = UUID_LE(0xf0a30bc7, 0xaf08, 0x4556, 0x99, 0xc4,
44
+ .data = UUID_LE(0xf0a30bc7, 0xaf08, 0x4556, 0x99, 0xc4,
45
+ 0x0, 0x10, 0x9, 0xc9, 0x3a, 0x44)
45
+ 0x0, 0x10, 0x9, 0xc9, 0x3a, 0x44)
46
+};
46
+};
47
+
47
+
48
+/* protocols */
48
+/* signatures */
49
+
49
+
50
+QemuUUID EfiSmmVariableProtocolGuid = {
50
+const QemuUUID EfiCertSha256Guid = {
51
+ .data = UUID_LE(0xc1c41626, 0x504c, 0x4092, 0xac, 0xa9,
52
+ 0x41, 0xf9, 0x36, 0x93, 0x43, 0x28)
53
+};
54
+
55
+const QemuUUID EfiCertSha384Guid = {
56
+ .data = UUID_LE(0xff3e5307, 0x9fd0, 0x48c9, 0x85, 0xf1,
57
+ 0x8a, 0xd5, 0x6c, 0x70, 0x1e, 0x1)
58
+};
59
+
60
+const QemuUUID EfiCertSha512Guid = {
61
+ .data = UUID_LE(0x93e0fae, 0xa6c4, 0x4f50, 0x9f, 0x1b,
62
+ 0xd4, 0x1e, 0x2b, 0x89, 0xc1, 0x9a)
63
+};
64
+
65
+const QemuUUID EfiCertRsa2048Guid = {
66
+ .data = UUID_LE(0x3c5766e8, 0x269c, 0x4e34, 0xaa, 0x14,
67
+ 0xed, 0x77, 0x6e, 0x85, 0xb3, 0xb6)
68
+};
69
+
70
+const QemuUUID EfiCertX509Guid = {
71
+ .data = UUID_LE(0xa5c059a1, 0x94e4, 0x4aa7, 0x87, 0xb5,
72
+ 0xab, 0x15, 0x5c, 0x2b, 0xf0, 0x72)
73
+};
74
+
75
+const QemuUUID EfiCertTypePkcs7Guid = {
76
+ .data = UUID_LE(0x4aafd29d, 0x68df, 0x49ee, 0x8a, 0xa9,
77
+ 0x34, 0x7d, 0x37, 0x56, 0x65, 0xa7)
78
+};
79
+
80
+/*
81
+ * mm_header.guid values that the guest DXE/BDS phases use for
82
+ * sending requests to management mode
83
+ */
84
+
85
+const QemuUUID EfiSmmVariableProtocolGuid = {
51
+ .data = UUID_LE(0xed32d533, 0x99e6, 0x4209, 0x9c, 0xc0,
86
+ .data = UUID_LE(0xed32d533, 0x99e6, 0x4209, 0x9c, 0xc0,
52
+ 0x2d, 0x72, 0xcd, 0xd9, 0x98, 0xa7)
87
+ 0x2d, 0x72, 0xcd, 0xd9, 0x98, 0xa7)
53
+};
88
+};
54
+
89
+
55
+QemuUUID VarCheckPolicyLibMmiHandlerGuid = {
90
+const QemuUUID VarCheckPolicyLibMmiHandlerGuid = {
56
+ .data = UUID_LE(0xda1b0d11, 0xd1a7, 0x46c4, 0x9d, 0xc9,
91
+ .data = UUID_LE(0xda1b0d11, 0xd1a7, 0x46c4, 0x9d, 0xc9,
57
+ 0xf3, 0x71, 0x48, 0x75, 0xc6, 0xeb)
92
+ 0xf3, 0x71, 0x48, 0x75, 0xc6, 0xeb)
58
+};
93
+};
59
+
94
+
60
+/* events */
95
+/*
96
+ * mm_header.guid values that the guest DXE/BDS phases use for
97
+ * reporting event groups being signaled to management mode
98
+ */
61
+
99
+
62
+QemuUUID EfiEndOfDxeEventGroupGuid = {
100
+const QemuUUID EfiEndOfDxeEventGroupGuid = {
63
+ .data = UUID_LE(0x02CE967A, 0xDD7E, 0x4FFC, 0x9E, 0xE7,
101
+ .data = UUID_LE(0x02ce967a, 0xdd7e, 0x4FFc, 0x9e, 0xe7,
64
+ 0x81, 0x0C, 0xF0, 0x47, 0x08, 0x80)
102
+ 0x81, 0x0c, 0xF0, 0x47, 0x08, 0x80)
65
+};
103
+};
66
+
104
+
67
+QemuUUID EfiEventReadyToBootGuid = {
105
+const QemuUUID EfiEventReadyToBootGuid = {
68
+ .data = UUID_LE(0x7CE88FB3, 0x4BD7, 0x4679, 0x87, 0xA8,
106
+ .data = UUID_LE(0x7ce88Fb3, 0x4bd7, 0x4679, 0x87, 0xa8,
69
+ 0xA8, 0xD8, 0xDE, 0xE5, 0x0D, 0x2B)
107
+ 0xa8, 0xd8, 0xde, 0xe5, 0x0d, 0x2b)
70
+};
108
+};
71
+
109
+
72
+QemuUUID EfiEventExitBootServicesGuid = {
110
+const QemuUUID EfiEventExitBootServicesGuid = {
73
+ .data = UUID_LE(0x27ABF055, 0xB1B8, 0x4C26, 0x80, 0x48,
111
+ .data = UUID_LE(0x27abF055, 0xb1b8, 0x4c26, 0x80, 0x48,
74
+ 0x74, 0x8F, 0x37, 0xBA, 0xA2, 0xDF)
112
+ 0x74, 0x8F, 0x37, 0xba, 0xa2, 0xdF)
75
+};
113
+};
76
--
114
--
77
2.41.0
115
2.47.1
diff view generated by jsdifflib
New patch
1
Add utility functions. Helpers for UEFI (ucs2) string handling.
2
Helpers for readable trace messages. Compare UEFI time stamps.
1
3
4
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
5
---
6
hw/uefi/var-service-utils.c | 241 ++++++++++++++++++++++++++++++++++++
7
1 file changed, 241 insertions(+)
8
create mode 100644 hw/uefi/var-service-utils.c
9
10
diff --git a/hw/uefi/var-service-utils.c b/hw/uefi/var-service-utils.c
11
new file mode 100644
12
index XXXXXXX..XXXXXXX
13
--- /dev/null
14
+++ b/hw/uefi/var-service-utils.c
15
@@ -XXX,XX +XXX,XX @@
16
+/*
17
+ * SPDX-License-Identifier: GPL-2.0-or-later
18
+ *
19
+ * uefi vars device - helper functions for ucs2 strings and tracing
20
+ */
21
+#include "qemu/osdep.h"
22
+#include "system/dma.h"
23
+
24
+#include "hw/uefi/var-service.h"
25
+
26
+#include "trace/trace-hw_uefi.h"
27
+
28
+/* ------------------------------------------------------------------ */
29
+
30
+/*
31
+ * string helper functions.
32
+ *
33
+ * Most of the time uefi ucs2 strings are NULL-terminated, except
34
+ * sometimes when they are not (for example in variable policies).
35
+ */
36
+
37
+gboolean uefi_str_is_valid(const uint16_t *str, size_t len,
38
+ gboolean must_be_null_terminated)
39
+{
40
+ size_t pos = 0;
41
+
42
+ for (;;) {
43
+ if (pos == len) {
44
+ if (must_be_null_terminated) {
45
+ return false;
46
+ } else {
47
+ return true;
48
+ }
49
+ }
50
+ switch (str[pos]) {
51
+ case 0:
52
+ /* end of string */
53
+ return true;
54
+ case 0xd800 ... 0xdfff:
55
+ /* reject surrogates */
56
+ return false;
57
+ default:
58
+ /* char is good, check next */
59
+ break;
60
+ }
61
+ pos++;
62
+ }
63
+}
64
+
65
+size_t uefi_strlen(const uint16_t *str, size_t len)
66
+{
67
+ size_t pos = 0;
68
+
69
+ for (;;) {
70
+ if (pos == len) {
71
+ return pos;
72
+ }
73
+ if (str[pos] == 0) {
74
+ return pos;
75
+ }
76
+ pos++;
77
+ }
78
+}
79
+
80
+gboolean uefi_str_equal_ex(const uint16_t *a, size_t alen,
81
+ const uint16_t *b, size_t blen,
82
+ gboolean wildcards_in_a)
83
+{
84
+ size_t pos = 0;
85
+
86
+ alen = alen / 2;
87
+ blen = blen / 2;
88
+ for (;;) {
89
+ if (pos == alen && pos == blen) {
90
+ return true;
91
+ }
92
+ if (pos == alen && b[pos] == 0) {
93
+ return true;
94
+ }
95
+ if (pos == blen && a[pos] == 0) {
96
+ return true;
97
+ }
98
+ if (pos == alen || pos == blen) {
99
+ return false;
100
+ }
101
+ if (a[pos] == 0 && b[pos] == 0) {
102
+ return true;
103
+ }
104
+
105
+ if (wildcards_in_a && a[pos] == '#') {
106
+ if (!isxdigit(b[pos])) {
107
+ return false;
108
+ }
109
+ } else {
110
+ if (a[pos] != b[pos]) {
111
+ return false;
112
+ }
113
+ }
114
+ pos++;
115
+ }
116
+}
117
+
118
+gboolean uefi_str_equal(const uint16_t *a, size_t alen,
119
+ const uint16_t *b, size_t blen)
120
+{
121
+ return uefi_str_equal_ex(a, alen, b, blen, false);
122
+}
123
+
124
+char *uefi_ucs2_to_ascii(const uint16_t *ucs2, uint64_t ucs2_size)
125
+{
126
+ char *str = g_malloc0(ucs2_size / 2 + 1);
127
+ int i;
128
+
129
+ for (i = 0; i * 2 < ucs2_size; i++) {
130
+ if (ucs2[i] == 0) {
131
+ break;
132
+ }
133
+ if (ucs2[i] < 128) {
134
+ str[i] = ucs2[i];
135
+ } else {
136
+ str[i] = '?';
137
+ }
138
+ }
139
+ str[i] = 0;
140
+ return str;
141
+}
142
+
143
+/* ------------------------------------------------------------------ */
144
+/* time helper functions */
145
+
146
+int uefi_time_compare(efi_time *a, efi_time *b)
147
+{
148
+ if (a->year < b->year) {
149
+ return -1;
150
+ }
151
+ if (a->year > b->year) {
152
+ return 1;
153
+ }
154
+
155
+ if (a->month < b->month) {
156
+ return -1;
157
+ }
158
+ if (a->month > b->month) {
159
+ return 1;
160
+ }
161
+
162
+ if (a->day < b->day) {
163
+ return -1;
164
+ }
165
+ if (a->day > b->day) {
166
+ return 1;
167
+ }
168
+
169
+ if (a->hour < b->hour) {
170
+ return -1;
171
+ }
172
+ if (a->hour > b->hour) {
173
+ return 1;
174
+ }
175
+
176
+ if (a->minute < b->minute) {
177
+ return -1;
178
+ }
179
+ if (a->minute > b->minute) {
180
+ return 1;
181
+ }
182
+
183
+ if (a->second < b->second) {
184
+ return -1;
185
+ }
186
+ if (a->second > b->second) {
187
+ return 1;
188
+ }
189
+
190
+ if (a->nanosecond < b->nanosecond) {
191
+ return -1;
192
+ }
193
+ if (a->nanosecond > b->nanosecond) {
194
+ return 1;
195
+ }
196
+
197
+ return 0;
198
+}
199
+
200
+/* ------------------------------------------------------------------ */
201
+/* tracing helper functions */
202
+
203
+void uefi_trace_variable(const char *action, QemuUUID guid,
204
+ const uint16_t *name, uint64_t name_size)
205
+{
206
+ QemuUUID be = qemu_uuid_bswap(guid);
207
+ char *str_uuid = qemu_uuid_unparse_strdup(&be);
208
+ char *str_name = uefi_ucs2_to_ascii(name, name_size);
209
+
210
+ trace_uefi_variable(action, str_name, name_size, str_uuid);
211
+
212
+ g_free(str_name);
213
+ g_free(str_uuid);
214
+}
215
+
216
+void uefi_trace_status(const char *action, efi_status status)
217
+{
218
+ switch (status) {
219
+ case EFI_SUCCESS:
220
+ trace_uefi_status(action, "success");
221
+ break;
222
+ case EFI_INVALID_PARAMETER:
223
+ trace_uefi_status(action, "invalid parameter");
224
+ break;
225
+ case EFI_UNSUPPORTED:
226
+ trace_uefi_status(action, "unsupported");
227
+ break;
228
+ case EFI_BAD_BUFFER_SIZE:
229
+ trace_uefi_status(action, "bad buffer size");
230
+ break;
231
+ case EFI_BUFFER_TOO_SMALL:
232
+ trace_uefi_status(action, "buffer too small");
233
+ break;
234
+ case EFI_WRITE_PROTECTED:
235
+ trace_uefi_status(action, "write protected");
236
+ break;
237
+ case EFI_OUT_OF_RESOURCES:
238
+ trace_uefi_status(action, "out of resources");
239
+ break;
240
+ case EFI_NOT_FOUND:
241
+ trace_uefi_status(action, "not found");
242
+ break;
243
+ case EFI_ACCESS_DENIED:
244
+ trace_uefi_status(action, "access denied");
245
+ break;
246
+ case EFI_ALREADY_STARTED:
247
+ trace_uefi_status(action, "already started");
248
+ break;
249
+ case EFI_SECURITY_VIOLATION:
250
+ trace_uefi_status(action, "security violation");
251
+ break;
252
+ default:
253
+ trace_uefi_status(action, "unknown error");
254
+ break;
255
+ }
256
+}
257
--
258
2.47.1
diff view generated by jsdifflib
1
This is the uefi variable service (EfiSmmVariableProtocol),
1
This is the uefi variable service (EfiSmmVariableProtocol), providing
2
providing functions for reading and writing variables.
2
functions for listing, reading and updating variables.
3
3
4
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
4
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
5
---
5
---
6
hw/uefi/var-service-vars.c | 602 +++++++++++++++++++++++++++++++++++++
6
hw/uefi/var-service-vars.c | 725 +++++++++++++++++++++++++++++++++++++
7
1 file changed, 602 insertions(+)
7
1 file changed, 725 insertions(+)
8
create mode 100644 hw/uefi/var-service-vars.c
8
create mode 100644 hw/uefi/var-service-vars.c
9
9
10
diff --git a/hw/uefi/var-service-vars.c b/hw/uefi/var-service-vars.c
10
diff --git a/hw/uefi/var-service-vars.c b/hw/uefi/var-service-vars.c
11
new file mode 100644
11
new file mode 100644
12
index XXXXXXX..XXXXXXX
12
index XXXXXXX..XXXXXXX
...
...
17
+ * SPDX-License-Identifier: GPL-2.0-or-later
17
+ * SPDX-License-Identifier: GPL-2.0-or-later
18
+ *
18
+ *
19
+ * uefi vars device - EfiSmmVariableProtocol implementation
19
+ * uefi vars device - EfiSmmVariableProtocol implementation
20
+ */
20
+ */
21
+#include "qemu/osdep.h"
21
+#include "qemu/osdep.h"
22
+#include "sysemu/dma.h"
22
+#include "qemu/error-report.h"
23
+#include "system/dma.h"
23
+#include "migration/vmstate.h"
24
+#include "migration/vmstate.h"
24
+
25
+
25
+#include "hw/uefi/var-service.h"
26
+#include "hw/uefi/var-service.h"
26
+#include "hw/uefi/var-service-api.h"
27
+#include "hw/uefi/var-service-api.h"
27
+#include "hw/uefi/var-service-edk2.h"
28
+#include "hw/uefi/var-service-edk2.h"
28
+
29
+
29
+#include "trace/trace-hw_uefi.h"
30
+#include "trace/trace-hw_uefi.h"
31
+
32
+#define EFI_VARIABLE_ATTRIBUTE_SUPPORTED \
33
+ (EFI_VARIABLE_NON_VOLATILE | \
34
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | \
35
+ EFI_VARIABLE_RUNTIME_ACCESS | \
36
+ EFI_VARIABLE_HARDWARE_ERROR_RECORD | \
37
+ EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS | \
38
+ EFI_VARIABLE_APPEND_WRITE)
39
+
40
+
41
+const VMStateDescription vmstate_uefi_time = {
42
+ .name = "uefi-time",
43
+ .fields = (VMStateField[]) {
44
+ VMSTATE_UINT16(year, efi_time),
45
+ VMSTATE_UINT8(month, efi_time),
46
+ VMSTATE_UINT8(day, efi_time),
47
+ VMSTATE_UINT8(hour, efi_time),
48
+ VMSTATE_UINT8(minute, efi_time),
49
+ VMSTATE_UINT8(second, efi_time),
50
+ VMSTATE_UINT32(nanosecond, efi_time),
51
+ VMSTATE_END_OF_LIST()
52
+ },
53
+};
30
+
54
+
31
+const VMStateDescription vmstate_uefi_variable = {
55
+const VMStateDescription vmstate_uefi_variable = {
32
+ .name = "uefi-variable",
56
+ .name = "uefi-variable",
33
+ .fields = (VMStateField[]) {
57
+ .fields = (VMStateField[]) {
34
+ VMSTATE_UINT8_ARRAY_V(guid.data, uefi_variable, sizeof(QemuUUID), 0),
58
+ VMSTATE_UINT8_ARRAY_V(guid.data, uefi_variable, sizeof(QemuUUID), 0),
35
+ VMSTATE_UINT32(name_size, uefi_variable),
59
+ VMSTATE_UINT32(name_size, uefi_variable),
36
+ VMSTATE_UINT32(data_size, uefi_variable),
60
+ VMSTATE_UINT32(data_size, uefi_variable),
37
+ VMSTATE_UINT32(attributes, uefi_variable),
61
+ VMSTATE_UINT32(attributes, uefi_variable),
38
+ VMSTATE_VBUFFER_ALLOC_UINT32(name, uefi_variable, 0, NULL, name_size),
62
+ VMSTATE_VBUFFER_ALLOC_UINT32(name, uefi_variable, 0, NULL, name_size),
39
+ VMSTATE_VBUFFER_ALLOC_UINT32(data, uefi_variable, 0, NULL, data_size),
63
+ VMSTATE_VBUFFER_ALLOC_UINT32(data, uefi_variable, 0, NULL, data_size),
64
+ VMSTATE_STRUCT(time, uefi_variable, 0, vmstate_uefi_time, efi_time),
40
+ VMSTATE_END_OF_LIST()
65
+ VMSTATE_END_OF_LIST()
41
+ },
66
+ },
42
+};
67
+};
43
+
68
+
44
+uefi_variable *uefi_vars_find_variable(uefi_vars_state *uv, QemuUUID guid,
69
+uefi_variable *uefi_vars_find_variable(uefi_vars_state *uv, QemuUUID guid,
...
...
50
+ if (!uefi_str_equal(var->name, var->name_size,
75
+ if (!uefi_str_equal(var->name, var->name_size,
51
+ name, name_size)) {
76
+ name, name_size)) {
52
+ continue;
77
+ continue;
53
+ }
78
+ }
54
+ if (!qemu_uuid_is_equal(&var->guid, &guid)) {
79
+ if (!qemu_uuid_is_equal(&var->guid, &guid)) {
80
+ continue;
81
+ }
82
+ if (!var->data_size) {
83
+ /* in process of being created/updated */
55
+ continue;
84
+ continue;
56
+ }
85
+ }
57
+ return var;
86
+ return var;
58
+ }
87
+ }
59
+ return NULL;
88
+ return NULL;
...
...
70
+ var->name = g_malloc(name_size);
99
+ var->name = g_malloc(name_size);
71
+ memcpy(var->name, name, name_size);
100
+ memcpy(var->name, name, name_size);
72
+ var->name_size = name_size;
101
+ var->name_size = name_size;
73
+ var->attributes = attributes;
102
+ var->attributes = attributes;
74
+
103
+
104
+ var->attributes &= ~EFI_VARIABLE_APPEND_WRITE;
105
+
75
+ QTAILQ_INSERT_TAIL(&uv->variables, var, next);
106
+ QTAILQ_INSERT_TAIL(&uv->variables, var, next);
76
+ return var;
107
+ return var;
77
+}
108
+}
78
+
109
+
79
+static void del_variable(uefi_vars_state *uv, uefi_variable *var)
110
+static void del_variable(uefi_vars_state *uv, uefi_variable *var)
...
...
83
+ }
114
+ }
84
+
115
+
85
+ QTAILQ_REMOVE(&uv->variables, var, next);
116
+ QTAILQ_REMOVE(&uv->variables, var, next);
86
+ g_free(var->data);
117
+ g_free(var->data);
87
+ g_free(var->name);
118
+ g_free(var->name);
119
+ g_free(var->digest);
88
+ g_free(var);
120
+ g_free(var);
89
+}
121
+}
90
+
122
+
91
+static size_t variable_size(uefi_variable *var)
123
+static size_t variable_size(uefi_variable *var)
92
+{
124
+{
93
+ size_t size;
125
+ size_t size;
94
+
126
+
95
+ size = sizeof(*var);
127
+ size = sizeof(*var);
96
+ size += var->name_size;
128
+ size += var->name_size;
97
+ size += var->data_size;
129
+ size += var->data_size;
130
+ size += var->digest_size;
98
+ return size;
131
+ return size;
99
+}
132
+}
100
+
133
+
101
+void uefi_vars_set_variable(uefi_vars_state *uv, QemuUUID guid,
134
+void uefi_vars_set_variable(uefi_vars_state *uv, QemuUUID guid,
102
+ const uint16_t *name, uint64_t name_size,
135
+ const uint16_t *name, uint64_t name_size,
...
...
151
+ QTAILQ_FOREACH(var, &uv->variables, next) {
184
+ QTAILQ_FOREACH(var, &uv->variables, next) {
152
+ uv->used_storage += variable_size(var);
185
+ uv->used_storage += variable_size(var);
153
+ }
186
+ }
154
+}
187
+}
155
+
188
+
156
+static efi_status check_secure_boot(uefi_vars_state *uv, uefi_variable *var)
157
+{
158
+ static const uint16_t pk[] = { 'P', 'K', 0 };
159
+ static const uint16_t kek[] = { 'K', 'E', 'K', 0 };
160
+ static const uint16_t db[] = { 'd', 'b', 0 };
161
+ static const uint16_t dbx[] = { 'd', 'b', 'x', 0 };
162
+
163
+ /* TODO (reject for now) */
164
+ if (qemu_uuid_is_equal(&var->guid, &EfiGlobalVariable) &&
165
+ uefi_str_equal(var->name, var->name_size, pk, sizeof(pk))) {
166
+ return EFI_WRITE_PROTECTED;
167
+ }
168
+ if (qemu_uuid_is_equal(&var->guid, &EfiGlobalVariable) &&
169
+ uefi_str_equal(var->name, var->name_size, kek, sizeof(kek))) {
170
+ return EFI_WRITE_PROTECTED;
171
+ }
172
+
173
+ if (qemu_uuid_is_equal(&var->guid, &EfiImageSecurityDatabase) &&
174
+ uefi_str_equal(var->name, var->name_size, db, sizeof(db))) {
175
+ return EFI_WRITE_PROTECTED;
176
+ }
177
+ if (qemu_uuid_is_equal(&var->guid, &EfiImageSecurityDatabase) &&
178
+ uefi_str_equal(var->name, var->name_size, dbx, sizeof(dbx))) {
179
+ return EFI_WRITE_PROTECTED;
180
+ }
181
+
182
+ return EFI_SUCCESS;
183
+}
184
+
185
+static gboolean check_access(uefi_vars_state *uv, uefi_variable *var)
189
+static gboolean check_access(uefi_vars_state *uv, uefi_variable *var)
186
+{
190
+{
187
+ if (!uv->exit_boot_service) {
191
+ if (!uv->exit_boot_service) {
188
+ if (!(var->attributes & EFI_VARIABLE_BOOTSERVICE_ACCESS)) {
192
+ if (!(var->attributes & EFI_VARIABLE_BOOTSERVICE_ACCESS)) {
189
+ return false;
193
+ return false;
...
...
203
+
207
+
204
+ if (old_var) {
208
+ if (old_var) {
205
+ if (!check_access(uv, old_var)) {
209
+ if (!check_access(uv, old_var)) {
206
+ return EFI_ACCESS_DENIED;
210
+ return EFI_ACCESS_DENIED;
207
+ }
211
+ }
208
+ if (old_var->attributes &
209
+ (EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS |
210
+ EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)) {
211
+ /* TODO (reject for now) */
212
+ return EFI_WRITE_PROTECTED;
213
+ }
214
+ }
212
+ }
215
+
213
+
216
+ if (new_var) {
214
+ if (new_var) {
215
+ if (new_var->attributes & ~EFI_VARIABLE_ATTRIBUTE_SUPPORTED) {
216
+ return EFI_UNSUPPORTED;
217
+ }
217
+ if (!check_access(uv, new_var)) {
218
+ if (!check_access(uv, new_var)) {
218
+ return EFI_ACCESS_DENIED;
219
+ return EFI_ACCESS_DENIED;
219
+ }
220
+ }
220
+ }
221
+ }
221
+
222
+
...
...
226
+ }
227
+ }
227
+
228
+
228
+ if (new_var) {
229
+ if (new_var) {
229
+ /* create + update */
230
+ /* create + update */
230
+ status = uefi_vars_policy_check(uv, new_var, old_var == NULL);
231
+ status = uefi_vars_policy_check(uv, new_var, old_var == NULL);
231
+ } else if (old_var) {
232
+ } else {
232
+ /* delete */
233
+ /* delete */
234
+ g_assert(old_var);
233
+ status = uefi_vars_policy_check(uv, old_var, false);
235
+ status = uefi_vars_policy_check(uv, old_var, false);
234
+ }
236
+ }
235
+ if (status != EFI_SUCCESS) {
237
+ if (status != EFI_SUCCESS) {
236
+ return status;
238
+ return status;
237
+ }
239
+ }
238
+
240
+
239
+ status = check_secure_boot(uv, new_var ?: old_var);
241
+ status = uefi_vars_check_secure_boot(uv, new_var ?: old_var);
240
+ if (status != EFI_SUCCESS) {
242
+ if (status != EFI_SUCCESS) {
241
+ return status;
243
+ return status;
242
+ }
244
+ }
243
+
245
+
244
+ return EFI_SUCCESS;
246
+ return EFI_SUCCESS;
247
+}
248
+
249
+static void append_write(uefi_variable *old_var,
250
+ uefi_variable *new_var)
251
+{
252
+ uefi_vars_siglist siglist;
253
+ uint64_t size;
254
+ void *data;
255
+
256
+ uefi_vars_siglist_init(&siglist);
257
+ uefi_vars_siglist_parse(&siglist, old_var->data, old_var->data_size);
258
+ uefi_vars_siglist_parse(&siglist, new_var->data, new_var->data_size);
259
+
260
+ size = uefi_vars_siglist_blob_size(&siglist);
261
+ data = g_malloc(size);
262
+ uefi_vars_siglist_blob_generate(&siglist, data, size);
263
+
264
+ g_free(new_var->data);
265
+ new_var->data = data;
266
+ new_var->data_size = size;
267
+
268
+ uefi_vars_siglist_free(&siglist);
245
+}
269
+}
246
+
270
+
247
+static size_t uefi_vars_mm_error(mm_header *mhdr, mm_variable *mvar,
271
+static size_t uefi_vars_mm_error(mm_header *mhdr, mm_variable *mvar,
248
+ uint64_t status)
272
+ uint64_t status)
249
+{
273
+{
...
...
256
+{
280
+{
257
+ mm_variable_access *va = func;
281
+ mm_variable_access *va = func;
258
+ uint16_t *name;
282
+ uint16_t *name;
259
+ void *data;
283
+ void *data;
260
+ uefi_variable *var;
284
+ uefi_variable *var;
261
+ size_t length;
285
+ uint64_t length;
262
+
286
+
263
+ length = sizeof(*mvar) + sizeof(*va);
287
+ length = sizeof(*mvar) + sizeof(*va);
264
+ if (mhdr->length < length) {
288
+ if (mhdr->length < length) {
265
+ return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE);
289
+ return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE);
266
+ }
290
+ }
...
...
269
+ va->data_size > uv->max_storage) {
293
+ va->data_size > uv->max_storage) {
270
+ return uefi_vars_mm_error(mhdr, mvar, EFI_OUT_OF_RESOURCES);
294
+ return uefi_vars_mm_error(mhdr, mvar, EFI_OUT_OF_RESOURCES);
271
+ }
295
+ }
272
+
296
+
273
+ name = func + sizeof(*va);
297
+ name = func + sizeof(*va);
274
+ length += va->name_size;
298
+ if (uadd64_overflow(length, va->name_size, &length)) {
275
+ if (mhdr->length < length) {
299
+ return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE);
276
+ return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE);
300
+ }
301
+ if (mhdr->length < length) {
302
+ return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE);
303
+ }
304
+
305
+ if (!uefi_str_is_valid(name, va->name_size, true)) {
306
+ return uefi_vars_mm_error(mhdr, mvar, EFI_INVALID_PARAMETER);
277
+ }
307
+ }
278
+
308
+
279
+ uefi_trace_variable(__func__, va->guid, name, va->name_size);
309
+ uefi_trace_variable(__func__, va->guid, name, va->name_size);
280
+
310
+
281
+ var = uefi_vars_find_variable(uv, va->guid, name, va->name_size);
311
+ var = uefi_vars_find_variable(uv, va->guid, name, va->name_size);
...
...
287
+ if (!check_access(uv, var)) {
317
+ if (!check_access(uv, var)) {
288
+ return uefi_vars_mm_error(mhdr, mvar, EFI_ACCESS_DENIED);
318
+ return uefi_vars_mm_error(mhdr, mvar, EFI_ACCESS_DENIED);
289
+ }
319
+ }
290
+
320
+
291
+ data = func + sizeof(*va) + va->name_size;
321
+ data = func + sizeof(*va) + va->name_size;
292
+ length += var->data_size;
322
+ if (uadd64_overflow(length, va->data_size, &length)) {
323
+ return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE);
324
+ }
293
+ if (uv->buf_size < length) {
325
+ if (uv->buf_size < length) {
294
+ return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE);
326
+ return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE);
295
+ }
327
+ }
296
+
328
+
297
+ va->attributes = var->attributes;
329
+ va->attributes = var->attributes;
298
+ va->data_size = var->data_size;
330
+ if (va->data_size < var->data_size) {
299
+ memcpy(data, var->data, var->data_size);
331
+ va->data_size = var->data_size;
300
+ mvar->status = EFI_SUCCESS;
332
+ length -= va->data_size;
333
+ mvar->status = EFI_BUFFER_TOO_SMALL;
334
+ } else {
335
+ va->data_size = var->data_size;
336
+ memcpy(data, var->data, var->data_size);
337
+ mvar->status = EFI_SUCCESS;
338
+ }
301
+ return length;
339
+ return length;
302
+}
340
+}
303
+
341
+
304
+static size_t
342
+static size_t
305
+uefi_vars_mm_get_next_variable(uefi_vars_state *uv, mm_header *mhdr,
343
+uefi_vars_mm_get_next_variable(uefi_vars_state *uv, mm_header *mhdr,
306
+ mm_variable *mvar, void *func)
344
+ mm_variable *mvar, void *func)
307
+{
345
+{
308
+ mm_next_variable *nv = func;
346
+ mm_next_variable *nv = func;
309
+ uefi_variable *var;
347
+ uefi_variable *var;
310
+ uint16_t *name;
348
+ uint16_t *name;
311
+ size_t length;
349
+ uint64_t length;
312
+
350
+
313
+ length = sizeof(*mvar) + sizeof(*nv);
351
+ length = sizeof(*mvar) + sizeof(*nv);
314
+ if (mhdr->length < length) {
352
+ if (mhdr->length < length) {
315
+ return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE);
353
+ return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE);
316
+ }
354
+ }
317
+
355
+
318
+ if (nv->name_size > uv->max_storage) {
356
+ if (nv->name_size > uv->max_storage) {
319
+ return uefi_vars_mm_error(mhdr, mvar, EFI_OUT_OF_RESOURCES);
357
+ return uefi_vars_mm_error(mhdr, mvar, EFI_OUT_OF_RESOURCES);
320
+ }
358
+ }
321
+
359
+
322
+ name = func + sizeof(*nv);
360
+ name = func + sizeof(*nv);
323
+ length += nv->name_size;
361
+ if (uadd64_overflow(length, nv->name_size, &length)) {
324
+ if (mhdr->length < length) {
362
+ return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE);
325
+ return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE);
363
+ }
364
+ if (mhdr->length < length) {
365
+ return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE);
366
+ }
367
+
368
+ if (!uefi_str_is_valid(name, nv->name_size, true)) {
369
+ return uefi_vars_mm_error(mhdr, mvar, EFI_INVALID_PARAMETER);
326
+ }
370
+ }
327
+
371
+
328
+ if (uefi_strlen(name, nv->name_size) == 0) {
372
+ if (uefi_strlen(name, nv->name_size) == 0) {
329
+ /* empty string -> first */
373
+ /* empty string -> first */
330
+ var = QTAILQ_FIRST(&uv->variables);
374
+ var = QTAILQ_FIRST(&uv->variables);
...
...
354
+ memcpy(name, var->name, var->name_size);
398
+ memcpy(name, var->name, var->name_size);
355
+ mvar->status = EFI_SUCCESS;
399
+ mvar->status = EFI_SUCCESS;
356
+ return length;
400
+ return length;
357
+}
401
+}
358
+
402
+
403
+static bool uefi_vars_mm_digest_compare(uefi_variable *old_var,
404
+ uefi_variable *new_var)
405
+{
406
+ if (!old_var->digest ||
407
+ !new_var->digest ||
408
+ !old_var->digest_size ||
409
+ !new_var->digest_size) {
410
+ /* should not happen */
411
+ trace_uefi_vars_security_violation("inconsistent authvar digest state");
412
+ return false;
413
+ }
414
+ if (old_var->digest_size != new_var->digest_size) {
415
+ trace_uefi_vars_security_violation("authvar digest size mismatch");
416
+ return false;
417
+ }
418
+ if (memcmp(old_var->digest, new_var->digest,
419
+ old_var->digest_size) != 0) {
420
+ trace_uefi_vars_security_violation("authvar digest data mismatch");
421
+ return false;
422
+ }
423
+ return true;
424
+}
425
+
359
+static size_t uefi_vars_mm_set_variable(uefi_vars_state *uv, mm_header *mhdr,
426
+static size_t uefi_vars_mm_set_variable(uefi_vars_state *uv, mm_header *mhdr,
360
+ mm_variable *mvar, void *func)
427
+ mm_variable *mvar, void *func)
361
+{
428
+{
362
+ mm_variable_access *va = func;
429
+ mm_variable_access *va = func;
363
+ uint32_t attributes = 0;
430
+ uint32_t attributes = 0;
364
+ uint16_t *name;
431
+ uint16_t *name;
365
+ void *data;
432
+ void *data;
366
+ uefi_variable *old_var, *new_var;
433
+ uefi_variable *old_var, *new_var;
367
+ size_t length, new_storage;
434
+ uint64_t length;
435
+ size_t new_storage;
368
+ efi_status status;
436
+ efi_status status;
369
+
437
+
370
+ length = sizeof(*mvar) + sizeof(*va);
438
+ length = sizeof(*mvar) + sizeof(*va);
371
+ if (mhdr->length < length) {
439
+ if (mhdr->length < length) {
372
+ return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE);
440
+ return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE);
...
...
376
+ va->data_size > uv->max_storage) {
444
+ va->data_size > uv->max_storage) {
377
+ return uefi_vars_mm_error(mhdr, mvar, EFI_OUT_OF_RESOURCES);
445
+ return uefi_vars_mm_error(mhdr, mvar, EFI_OUT_OF_RESOURCES);
378
+ }
446
+ }
379
+
447
+
380
+ name = func + sizeof(*va);
448
+ name = func + sizeof(*va);
381
+ length += va->name_size;
449
+ if (uadd64_overflow(length, va->name_size, &length)) {
450
+ return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE);
451
+ }
382
+ if (mhdr->length < length) {
452
+ if (mhdr->length < length) {
383
+ return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE);
453
+ return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE);
384
+ }
454
+ }
385
+
455
+
386
+ data = func + sizeof(*va) + va->name_size;
456
+ data = func + sizeof(*va) + va->name_size;
387
+ length += va->data_size;
457
+ if (uadd64_overflow(length, va->data_size, &length)) {
458
+ return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE);
459
+ }
388
+ if (mhdr->length < length) {
460
+ if (mhdr->length < length) {
389
+ return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE);
461
+ return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE);
390
+ }
462
+ }
391
+
463
+
392
+ g_assert(va->name_size < G_MAXUINT32);
464
+ g_assert(va->name_size < G_MAXUINT32);
393
+ g_assert(va->data_size < G_MAXUINT32);
465
+ g_assert(va->data_size < G_MAXUINT32);
466
+
467
+ if (!uefi_str_is_valid(name, va->name_size, true)) {
468
+ return uefi_vars_mm_error(mhdr, mvar, EFI_INVALID_PARAMETER);
469
+ }
394
+
470
+
395
+ uefi_trace_variable(__func__, va->guid, name, va->name_size);
471
+ uefi_trace_variable(__func__, va->guid, name, va->name_size);
396
+
472
+
397
+ old_var = uefi_vars_find_variable(uv, va->guid, name, va->name_size);
473
+ old_var = uefi_vars_find_variable(uv, va->guid, name, va->name_size);
398
+ if (va->data_size) {
474
+ if (va->data_size) {
399
+ new_var = add_variable(uv, va->guid, name, va->name_size,
475
+ new_var = add_variable(uv, va->guid, name, va->name_size,
400
+ va->attributes);
476
+ va->attributes);
401
+ new_var->data = g_malloc(va->data_size);
477
+ if (va->attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) {
402
+ memcpy(new_var->data, data, va->data_size);
478
+ /* not implemented (deprecated in uefi spec) */
403
+ new_var->data_size = va->data_size;
479
+ warn_report("%s: AUTHENTICATED_WRITE_ACCESS", __func__);
480
+ mvar->status = EFI_UNSUPPORTED;
481
+ goto rollback;
482
+ } else if (va->attributes &
483
+ EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) {
484
+ status = uefi_vars_check_auth_2(uv, new_var, va, data);
485
+ if (status != EFI_SUCCESS) {
486
+ mvar->status = status;
487
+ goto rollback;
488
+ }
489
+ if (old_var && new_var) {
490
+ if (uefi_time_compare(&old_var->time, &new_var->time) > 0) {
491
+ trace_uefi_vars_security_violation("time check failed");
492
+ mvar->status = EFI_SECURITY_VIOLATION;
493
+ goto rollback;
494
+ }
495
+ if (old_var->digest_size || new_var->digest_size) {
496
+ if (!uefi_vars_mm_digest_compare(old_var, new_var)) {
497
+ mvar->status = EFI_SECURITY_VIOLATION;
498
+ goto rollback;
499
+ }
500
+ }
501
+ }
502
+ } else {
503
+ new_var->data = g_malloc(va->data_size);
504
+ memcpy(new_var->data, data, va->data_size);
505
+ new_var->data_size = va->data_size;
506
+ }
507
+ if (!new_var->data) {
508
+ /* we land here when deleting authenticated variables */
509
+ del_variable(uv, new_var);
510
+ new_var = NULL;
511
+ }
404
+ } else {
512
+ } else {
405
+ new_var = NULL;
513
+ new_var = NULL;
406
+ }
514
+ }
407
+
515
+
408
+ if (!old_var && !new_var) {
516
+ if (!old_var && !new_var) {
...
...
416
+ if (status != EFI_SUCCESS) {
524
+ if (status != EFI_SUCCESS) {
417
+ mvar->status = status;
525
+ mvar->status = status;
418
+ goto rollback;
526
+ goto rollback;
419
+ }
527
+ }
420
+
528
+
529
+ if (va->attributes & EFI_VARIABLE_APPEND_WRITE && old_var && new_var) {
530
+ /* merge signature databases */
531
+ if (!uefi_vars_is_sb_any(new_var)) {
532
+ mvar->status = EFI_UNSUPPORTED;
533
+ goto rollback;
534
+ }
535
+ append_write(old_var, new_var);
536
+ }
537
+
421
+ /* check storage space */
538
+ /* check storage space */
422
+ new_storage = uv->used_storage;
539
+ new_storage = uv->used_storage;
423
+ if (old_var) {
540
+ if (old_var) {
424
+ new_storage -= variable_size(old_var);
541
+ new_storage -= variable_size(old_var);
425
+ }
542
+ }
...
...
441
+
558
+
442
+ if (attributes & EFI_VARIABLE_NON_VOLATILE) {
559
+ if (attributes & EFI_VARIABLE_NON_VOLATILE) {
443
+ uefi_vars_json_save(uv);
560
+ uefi_vars_json_save(uv);
444
+ }
561
+ }
445
+
562
+
563
+ if (new_var && uefi_vars_is_sb_pk(new_var)) {
564
+ uefi_vars_auth_init(uv);
565
+ }
566
+
446
+ mvar->status = EFI_SUCCESS;
567
+ mvar->status = EFI_SUCCESS;
447
+ return sizeof(*mvar);
568
+ return sizeof(*mvar);
448
+
569
+
449
+rollback:
570
+rollback:
450
+ del_variable(uv, new_var);
571
+ del_variable(uv, new_var);
...
...
453
+
574
+
454
+static size_t uefi_vars_mm_variable_info(uefi_vars_state *uv, mm_header *mhdr,
575
+static size_t uefi_vars_mm_variable_info(uefi_vars_state *uv, mm_header *mhdr,
455
+ mm_variable *mvar, void *func)
576
+ mm_variable *mvar, void *func)
456
+{
577
+{
457
+ mm_variable_info *vi = func;
578
+ mm_variable_info *vi = func;
458
+ size_t length;
579
+ uint64_t length;
459
+
580
+
460
+ length = sizeof(*mvar) + sizeof(*vi);
581
+ length = sizeof(*mvar) + sizeof(*vi);
461
+ if (uv->buf_size < length) {
582
+ if (uv->buf_size < length) {
462
+ return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE);
583
+ return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE);
463
+ }
584
+ }
...
...
474
+static size_t
595
+static size_t
475
+uefi_vars_mm_get_payload_size(uefi_vars_state *uv, mm_header *mhdr,
596
+uefi_vars_mm_get_payload_size(uefi_vars_state *uv, mm_header *mhdr,
476
+ mm_variable *mvar, void *func)
597
+ mm_variable *mvar, void *func)
477
+{
598
+{
478
+ mm_get_payload_size *ps = func;
599
+ mm_get_payload_size *ps = func;
479
+ size_t length;
600
+ uint64_t length;
480
+
601
+
481
+ length = sizeof(*mvar) + sizeof(*ps);
602
+ length = sizeof(*mvar) + sizeof(*ps);
482
+ if (uv->buf_size < length) {
603
+ if (uv->buf_size < length) {
483
+ return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE);
604
+ return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE);
484
+ }
605
+ }
...
...
493
+ mm_variable *mvar, void *func)
614
+ mm_variable *mvar, void *func)
494
+{
615
+{
495
+ mm_lock_variable *lv = func;
616
+ mm_lock_variable *lv = func;
496
+ variable_policy_entry *pe;
617
+ variable_policy_entry *pe;
497
+ uint16_t *name, *dest;
618
+ uint16_t *name, *dest;
498
+ size_t length;
619
+ uint64_t length;
499
+
620
+
500
+ length = sizeof(*mvar) + sizeof(*lv);
621
+ length = sizeof(*mvar) + sizeof(*lv);
501
+ if (mhdr->length < length) {
622
+ if (mhdr->length < length) {
502
+ return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE);
623
+ return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE);
503
+ }
624
+ }
504
+
625
+
505
+ name = func + sizeof(*lv);
626
+ name = func + sizeof(*lv);
506
+ length += lv->name_size;
627
+ if (uadd64_overflow(length, lv->name_size, &length)) {
628
+ return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE);
629
+ }
507
+ if (mhdr->length < length) {
630
+ if (mhdr->length < length) {
508
+ return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE);
631
+ return uefi_vars_mm_error(mhdr, mvar, EFI_BAD_BUFFER_SIZE);
509
+ }
632
+ }
510
+
633
+
511
+ uefi_trace_variable(__func__, lv->guid, name, lv->name_size);
634
+ uefi_trace_variable(__func__, lv->guid, name, lv->name_size);
...
...
549
+ "init-runtime-cache-contect",
672
+ "init-runtime-cache-contect",
550
+ "sync-runtime-cache",
673
+ "sync-runtime-cache",
551
+ "get-runtime-cache-info",
674
+ "get-runtime-cache-info",
552
+ };
675
+ };
553
+ const char *fname;
676
+ const char *fname;
554
+ size_t length;
677
+ uint64_t length;
555
+
678
+
556
+ mm_header *mhdr = (mm_header *) uv->buffer;
679
+ mm_header *mhdr = (mm_header *) uv->buffer;
557
+ mm_variable *mvar = (mm_variable *) (uv->buffer + sizeof(*mhdr));
680
+ mm_variable *mvar = (mm_variable *) (uv->buffer + sizeof(*mhdr));
558
+ void *func = (uv->buffer + sizeof(*mhdr) + sizeof(*mvar));
681
+ void *func = (uv->buffer + sizeof(*mhdr) + sizeof(*mvar));
559
+
682
+
...
...
614
+
737
+
615
+ uefi_trace_status(__func__, mvar->status);
738
+ uefi_trace_status(__func__, mvar->status);
616
+ return UEFI_VARS_STS_SUCCESS;
739
+ return UEFI_VARS_STS_SUCCESS;
617
+}
740
+}
618
--
741
--
619
2.41.0
742
2.47.1
diff view generated by jsdifflib
1
This implements authenticated variable handling (AuthVariableLib in edk2).
1
This implements authenticated variable handling (see AuthVariableLib in
2
edk2).
2
3
3
For now this implements the bare minimum to make secure boot work,
4
The by far most common use case for auth variables is secure boot. The
4
by initializing the 'SecureBoot' variable.
5
secure boot certificate databases ('PK', 'KEK', 'db' and 'dbx') are
5
6
authenticated variables, with update rules being specified in the UEFI
6
Support for authenticated variable updates is not implemented yet, for
7
specification.
7
now they are read-only so the guest can neither provision secure boot
8
keys nor update the 'dbx' database.
9
8
10
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
9
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
11
---
10
---
12
hw/uefi/var-service-auth.c | 91 ++++++++++++++++++++++++++++++++++++++
11
hw/uefi/var-service-auth.c | 361 +++++++++++++++++++++++++++++++++++++
13
1 file changed, 91 insertions(+)
12
1 file changed, 361 insertions(+)
14
create mode 100644 hw/uefi/var-service-auth.c
13
create mode 100644 hw/uefi/var-service-auth.c
15
14
16
diff --git a/hw/uefi/var-service-auth.c b/hw/uefi/var-service-auth.c
15
diff --git a/hw/uefi/var-service-auth.c b/hw/uefi/var-service-auth.c
17
new file mode 100644
16
new file mode 100644
18
index XXXXXXX..XXXXXXX
17
index XXXXXXX..XXXXXXX
...
...
24
+ *
23
+ *
25
+ * uefi vars device - AuthVariableLib
24
+ * uefi vars device - AuthVariableLib
26
+ */
25
+ */
27
+
26
+
28
+#include "qemu/osdep.h"
27
+#include "qemu/osdep.h"
29
+#include "sysemu/dma.h"
28
+#include "qemu/error-report.h"
29
+#include "system/dma.h"
30
+
30
+
31
+#include "hw/uefi/var-service.h"
31
+#include "hw/uefi/var-service.h"
32
+
32
+
33
+static const uint16_t name_pk[] = { 'P', 'K',
33
+static const uint16_t name_pk[] = u"PK";
34
+ 0 };
34
+static const uint16_t name_kek[] = u"KEK";
35
+static const uint16_t name_setup_mode[] = { 'S', 'e', 't', 'u', 'p',
35
+static const uint16_t name_db[] = u"db";
36
+ 'M', 'o', 'd', 'e',
36
+static const uint16_t name_dbx[] = u"dbx";
37
+ 0 };
37
+static const uint16_t name_setup_mode[] = u"SetupMode";
38
+static const uint16_t name_sb[] = { 'S', 'e', 'c', 'u', 'r', 'e',
38
+static const uint16_t name_sigs_support[] = u"SignatureSupport";
39
+ 'B', 'o', 'o', 't',
39
+static const uint16_t name_sb[] = u"SecureBoot";
40
+ 0 };
40
+static const uint16_t name_sb_enable[] = u"SecureBootEnable";
41
+static const uint16_t name_sb_enable[] = { 'S', 'e', 'c', 'u', 'r', 'e',
41
+static const uint16_t name_custom_mode[] = u"CustomMode";
42
+ 'B', 'o', 'o', 't',
42
+static const uint16_t name_vk[] = u"VendorKeys";
43
+ 'E', 'n', 'a', 'b', 'l', 'e',
43
+static const uint16_t name_vk_nv[] = u"VendorKeysNv";
44
+ 0 };
44
+
45
+static const uint16_t name_custom_mode[] = { 'C', 'u', 's', 't', 'o', 'm',
45
+static const uint32_t sigdb_attrs =
46
+ 'M', 'o', 'd', 'e',
46
+ EFI_VARIABLE_NON_VOLATILE |
47
+ 0 };
47
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
48
+ EFI_VARIABLE_RUNTIME_ACCESS |
49
+ EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
50
+
51
+static void set_secure_boot(uefi_vars_state *uv, uint8_t sb)
52
+{
53
+ uefi_vars_set_variable(uv, EfiGlobalVariable,
54
+ name_sb, sizeof(name_sb),
55
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
56
+ EFI_VARIABLE_RUNTIME_ACCESS,
57
+ &sb, sizeof(sb));
58
+}
59
+
60
+static void set_secure_boot_enable(uefi_vars_state *uv, uint8_t sbe)
61
+{
62
+ uefi_vars_set_variable(uv, EfiSecureBootEnableDisable,
63
+ name_sb_enable, sizeof(name_sb_enable),
64
+ EFI_VARIABLE_NON_VOLATILE |
65
+ EFI_VARIABLE_BOOTSERVICE_ACCESS,
66
+ &sbe, sizeof(sbe));
67
+}
68
+
69
+static void set_setup_mode(uefi_vars_state *uv, uint8_t sm)
70
+{
71
+ uefi_vars_set_variable(uv, EfiGlobalVariable,
72
+ name_setup_mode, sizeof(name_setup_mode),
73
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
74
+ EFI_VARIABLE_RUNTIME_ACCESS,
75
+ &sm, sizeof(sm));
76
+}
77
+
78
+static void set_custom_mode(uefi_vars_state *uv, uint8_t cm)
79
+{
80
+ uefi_vars_set_variable(uv, EfiCustomModeEnable,
81
+ name_custom_mode, sizeof(name_custom_mode),
82
+ EFI_VARIABLE_NON_VOLATILE |
83
+ EFI_VARIABLE_BOOTSERVICE_ACCESS,
84
+ &cm, sizeof(cm));
85
+}
86
+
87
+static void set_signature_support(uefi_vars_state *uv)
88
+{
89
+ QemuUUID sigs_support[5];
90
+
91
+ sigs_support[0] = EfiCertSha256Guid;
92
+ sigs_support[1] = EfiCertSha384Guid;
93
+ sigs_support[2] = EfiCertSha512Guid;
94
+ sigs_support[3] = EfiCertRsa2048Guid;
95
+ sigs_support[4] = EfiCertX509Guid;
96
+
97
+ uefi_vars_set_variable(uv, EfiGlobalVariable,
98
+ name_sigs_support, sizeof(name_sigs_support),
99
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
100
+ EFI_VARIABLE_RUNTIME_ACCESS,
101
+ sigs_support, sizeof(sigs_support));
102
+}
103
+
104
+static bool setup_mode_is_active(uefi_vars_state *uv)
105
+{
106
+ uefi_variable *var;
107
+ uint8_t *value;
108
+
109
+ var = uefi_vars_find_variable(uv, EfiGlobalVariable,
110
+ name_setup_mode, sizeof(name_setup_mode));
111
+ if (var) {
112
+ value = var->data;
113
+ if (value[0] == SETUP_MODE) {
114
+ return true;
115
+ }
116
+ }
117
+ return false;
118
+}
119
+
120
+static bool custom_mode_is_active(uefi_vars_state *uv)
121
+{
122
+ uefi_variable *var;
123
+ uint8_t *value;
124
+
125
+ var = uefi_vars_find_variable(uv, EfiCustomModeEnable,
126
+ name_custom_mode, sizeof(name_custom_mode));
127
+ if (var) {
128
+ value = var->data;
129
+ if (value[0] == CUSTOM_SECURE_BOOT_MODE) {
130
+ return true;
131
+ }
132
+ }
133
+ return false;
134
+}
135
+
136
+bool uefi_vars_is_sb_pk(uefi_variable *var)
137
+{
138
+ if (qemu_uuid_is_equal(&var->guid, &EfiGlobalVariable) &&
139
+ uefi_str_equal(var->name, var->name_size, name_pk, sizeof(name_pk))) {
140
+ return true;
141
+ }
142
+ return false;
143
+}
144
+
145
+static bool uefi_vars_is_sb_kek(uefi_variable *var)
146
+{
147
+ if (qemu_uuid_is_equal(&var->guid, &EfiGlobalVariable) &&
148
+ uefi_str_equal(var->name, var->name_size, name_kek, sizeof(name_kek))) {
149
+ return true;
150
+ }
151
+ return false;
152
+}
153
+
154
+static bool uefi_vars_is_sb_db(uefi_variable *var)
155
+{
156
+ if (!qemu_uuid_is_equal(&var->guid, &EfiImageSecurityDatabase)) {
157
+ return false;
158
+ }
159
+ if (uefi_str_equal(var->name, var->name_size, name_db, sizeof(name_db))) {
160
+ return true;
161
+ }
162
+ if (uefi_str_equal(var->name, var->name_size, name_dbx, sizeof(name_dbx))) {
163
+ return true;
164
+ }
165
+ return false;
166
+}
167
+
168
+bool uefi_vars_is_sb_any(uefi_variable *var)
169
+{
170
+ if (uefi_vars_is_sb_pk(var) ||
171
+ uefi_vars_is_sb_kek(var) ||
172
+ uefi_vars_is_sb_db(var)) {
173
+ return true;
174
+ }
175
+ return false;
176
+}
177
+
178
+static uefi_variable *uefi_vars_find_siglist(uefi_vars_state *uv,
179
+ uefi_variable *var)
180
+{
181
+ if (uefi_vars_is_sb_pk(var)) {
182
+ return uefi_vars_find_variable(uv, EfiGlobalVariable,
183
+ name_pk, sizeof(name_pk));
184
+ }
185
+ if (uefi_vars_is_sb_kek(var)) {
186
+ return uefi_vars_find_variable(uv, EfiGlobalVariable,
187
+ name_pk, sizeof(name_pk));
188
+ }
189
+ if (uefi_vars_is_sb_db(var)) {
190
+ return uefi_vars_find_variable(uv, EfiGlobalVariable,
191
+ name_kek, sizeof(name_kek));
192
+ }
193
+
194
+ return NULL;
195
+}
196
+
197
+static efi_status uefi_vars_check_auth_2_sb(uefi_vars_state *uv,
198
+ uefi_variable *var,
199
+ mm_variable_access *va,
200
+ void *data,
201
+ uint64_t data_offset)
202
+{
203
+ variable_auth_2 *auth = data;
204
+ uefi_variable *siglist;
205
+
206
+ if (custom_mode_is_active(uv)) {
207
+ /* no authentication in custom mode */
208
+ return EFI_SUCCESS;
209
+ }
210
+
211
+ if (setup_mode_is_active(uv) && !uefi_vars_is_sb_pk(var)) {
212
+ /* no authentication in setup mode (except PK) */
213
+ return EFI_SUCCESS;
214
+ }
215
+
216
+ if (auth->hdr_length == 24) {
217
+ /* no signature (auth->cert_data is empty) */
218
+ return EFI_SECURITY_VIOLATION;
219
+ }
220
+
221
+ siglist = uefi_vars_find_siglist(uv, var);
222
+ if (!siglist && setup_mode_is_active(uv) && uefi_vars_is_sb_pk(var)) {
223
+ /* check PK is self-signed */
224
+ uefi_variable tmp = {
225
+ .guid = EfiGlobalVariable,
226
+ .name = (uint16_t *)name_pk,
227
+ .name_size = sizeof(name_pk),
228
+ .attributes = sigdb_attrs,
229
+ .data = data + data_offset,
230
+ .data_size = va->data_size - data_offset,
231
+ };
232
+ return uefi_vars_check_pkcs7_2(&tmp, NULL, NULL, va, data);
233
+ }
234
+
235
+ return uefi_vars_check_pkcs7_2(siglist, NULL, NULL, va, data);
236
+}
237
+
238
+efi_status uefi_vars_check_auth_2(uefi_vars_state *uv, uefi_variable *var,
239
+ mm_variable_access *va, void *data)
240
+{
241
+ variable_auth_2 *auth = data;
242
+ uint64_t data_offset;
243
+ efi_status status;
244
+
245
+ if (va->data_size < sizeof(*auth)) {
246
+ return EFI_SECURITY_VIOLATION;
247
+ }
248
+ if (uadd64_overflow(sizeof(efi_time), auth->hdr_length, &data_offset)) {
249
+ return EFI_SECURITY_VIOLATION;
250
+ }
251
+ if (va->data_size < data_offset) {
252
+ return EFI_SECURITY_VIOLATION;
253
+ }
254
+
255
+ if (auth->hdr_revision != 0x0200 ||
256
+ auth->hdr_cert_type != WIN_CERT_TYPE_EFI_GUID ||
257
+ !qemu_uuid_is_equal(&auth->guid_cert_type, &EfiCertTypePkcs7Guid)) {
258
+ return EFI_UNSUPPORTED;
259
+ }
260
+
261
+ if (uefi_vars_is_sb_any(var)) {
262
+ /* secure boot variables */
263
+ status = uefi_vars_check_auth_2_sb(uv, var, va, data, data_offset);
264
+ if (status != EFI_SUCCESS) {
265
+ return status;
266
+ }
267
+ } else {
268
+ /* other authenticated variables */
269
+ status = uefi_vars_check_pkcs7_2(NULL,
270
+ &var->digest, &var->digest_size,
271
+ va, data);
272
+ if (status != EFI_SUCCESS) {
273
+ return status;
274
+ }
275
+ }
276
+
277
+ /* checks passed, set variable data */
278
+ var->time = auth->timestamp;
279
+ if (va->data_size - data_offset > 0) {
280
+ var->data = g_malloc(va->data_size - data_offset);
281
+ memcpy(var->data, data + data_offset, va->data_size - data_offset);
282
+ var->data_size = va->data_size - data_offset;
283
+ }
284
+
285
+ return EFI_SUCCESS;
286
+}
287
+
288
+efi_status uefi_vars_check_secure_boot(uefi_vars_state *uv, uefi_variable *var)
289
+{
290
+ uint8_t *value = var->data;
291
+
292
+ if (uefi_vars_is_sb_any(var)) {
293
+ if (var->attributes != sigdb_attrs) {
294
+ return EFI_INVALID_PARAMETER;
295
+ }
296
+ }
297
+
298
+ /* reject SecureBootEnable updates if force_secure_boot is set */
299
+ if (qemu_uuid_is_equal(&var->guid, &EfiSecureBootEnableDisable) &&
300
+ uefi_str_equal(var->name, var->name_size,
301
+ name_sb_enable, sizeof(name_sb_enable)) &&
302
+ uv->force_secure_boot &&
303
+ value[0] != SECURE_BOOT_ENABLE) {
304
+ return EFI_WRITE_PROTECTED;
305
+ }
306
+
307
+ /* reject CustomMode updates if disable_custom_mode is set */
308
+ if (qemu_uuid_is_equal(&var->guid, &EfiCustomModeEnable) &&
309
+ uefi_str_equal(var->name, var->name_size,
310
+ name_custom_mode, sizeof(name_custom_mode)) &&
311
+ uv->disable_custom_mode) {
312
+ return EFI_WRITE_PROTECTED;
313
+ }
314
+
315
+ return EFI_SUCCESS;
316
+}
48
+
317
+
49
+/* AuthVariableLibInitialize */
318
+/* AuthVariableLibInitialize */
50
+void uefi_vars_auth_init(uefi_vars_state *uv)
319
+void uefi_vars_auth_init(uefi_vars_state *uv)
51
+{
320
+{
52
+ uefi_variable *pk_var, *sbe_var;;
321
+ uefi_variable *pk_var, *sbe_var;
53
+ uint8_t platform_mode, sb, sbe, custom_mode;
322
+ uint8_t platform_mode, sb, sbe, vk;
54
+
323
+
55
+ /* SetupMode */
324
+ /* SetupMode */
56
+ pk_var = uefi_vars_find_variable(uv, EfiGlobalVariable,
325
+ pk_var = uefi_vars_find_variable(uv, EfiGlobalVariable,
57
+ name_pk, sizeof(name_pk));
326
+ name_pk, sizeof(name_pk));
58
+ if (!pk_var) {
327
+ if (!pk_var) {
59
+ platform_mode = SETUP_MODE;
328
+ platform_mode = SETUP_MODE;
60
+ } else {
329
+ } else {
61
+ platform_mode = USER_MODE;
330
+ platform_mode = USER_MODE;
62
+ }
331
+ }
63
+ uefi_vars_set_variable(uv, EfiGlobalVariable,
332
+ set_setup_mode(uv, platform_mode);
64
+ name_setup_mode, sizeof(name_setup_mode),
333
+
65
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
334
+ /* SignatureSupport */
66
+ EFI_VARIABLE_RUNTIME_ACCESS,
335
+ set_signature_support(uv);
67
+ &platform_mode, sizeof(platform_mode));
68
+
69
+ /* TODO: SignatureSupport */
70
+
336
+
71
+ /* SecureBootEnable */
337
+ /* SecureBootEnable */
72
+ sbe = SECURE_BOOT_DISABLE;
338
+ sbe = SECURE_BOOT_DISABLE;
73
+ sbe_var = uefi_vars_find_variable(uv, EfiSecureBootEnableDisable,
339
+ sbe_var = uefi_vars_find_variable(uv, EfiSecureBootEnableDisable,
74
+ name_sb_enable, sizeof(name_sb_enable));
340
+ name_sb_enable, sizeof(name_sb_enable));
75
+ if (sbe_var) {
341
+ if (sbe_var) {
76
+ if (platform_mode == USER_MODE) {
342
+ if (platform_mode == USER_MODE) {
77
+ sbe = ((uint8_t*)sbe_var->data)[0];
343
+ sbe = ((uint8_t *)sbe_var->data)[0];
78
+ }
344
+ }
79
+ } else if (platform_mode == USER_MODE) {
345
+ } else if (platform_mode == USER_MODE) {
80
+ sbe = SECURE_BOOT_ENABLE;
346
+ sbe = SECURE_BOOT_ENABLE;
81
+ uefi_vars_set_variable(uv, EfiSecureBootEnableDisable,
347
+ set_secure_boot_enable(uv, sbe);
82
+ name_sb_enable, sizeof(name_sb_enable),
348
+ }
83
+ EFI_VARIABLE_NON_VOLATILE |
349
+
84
+ EFI_VARIABLE_BOOTSERVICE_ACCESS,
350
+ if (uv->force_secure_boot && sbe != SECURE_BOOT_ENABLE) {
85
+ &sbe, sizeof(sbe));
351
+ sbe = SECURE_BOOT_ENABLE;
352
+ set_secure_boot_enable(uv, sbe);
86
+ }
353
+ }
87
+
354
+
88
+ /* SecureBoot */
355
+ /* SecureBoot */
89
+ if ((sbe == SECURE_BOOT_ENABLE) && (platform_mode == USER_MODE)) {
356
+ if ((sbe == SECURE_BOOT_ENABLE) && (platform_mode == USER_MODE)) {
90
+ sb = SECURE_BOOT_MODE_ENABLE;
357
+ sb = SECURE_BOOT_MODE_ENABLE;
91
+ } else {
358
+ } else {
92
+ sb = SECURE_BOOT_MODE_DISABLE;
359
+ sb = SECURE_BOOT_MODE_DISABLE;
93
+ }
360
+ }
94
+ uefi_vars_set_variable(uv, EfiGlobalVariable,
361
+ set_secure_boot(uv, sb);
95
+ name_sb, sizeof(name_sb),
362
+
363
+ /* CustomMode */
364
+ set_custom_mode(uv, STANDARD_SECURE_BOOT_MODE);
365
+
366
+ vk = 0;
367
+ uefi_vars_set_variable(uv, EfiGlobalVariable,
368
+ name_vk_nv, sizeof(name_vk_nv),
369
+ EFI_VARIABLE_NON_VOLATILE |
370
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
371
+ EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS,
372
+ &vk, sizeof(vk));
373
+ uefi_vars_set_variable(uv, EfiGlobalVariable,
374
+ name_vk, sizeof(name_vk),
96
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
375
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
97
+ EFI_VARIABLE_RUNTIME_ACCESS,
376
+ EFI_VARIABLE_RUNTIME_ACCESS,
98
+ &sb, sizeof(sb));
377
+ &vk, sizeof(vk));
99
+
378
+
100
+ /* CustomMode */
379
+ /* flush to disk */
101
+ custom_mode = STANDARD_SECURE_BOOT_MODE;
380
+ uefi_vars_json_save(uv);
102
+ uefi_vars_set_variable(uv, EfiCustomModeEnable,
103
+ name_custom_mode, sizeof(name_custom_mode),
104
+ EFI_VARIABLE_NON_VOLATILE |
105
+ EFI_VARIABLE_BOOTSERVICE_ACCESS,
106
+ &custom_mode, sizeof(custom_mode));
107
+
108
+ /* TODO: certdb */
109
+ /* TODO: certdbv */
110
+ /* TODO: VendorKeysNv */
111
+ /* TODO: VendorKeys */
112
+}
381
+}
113
--
382
--
114
2.41.0
383
2.47.1
diff view generated by jsdifflib
1
Implement variable policies (Edk2VariablePolicyProtocol).
1
Implement variable policies (Edk2VariablePolicyProtocol).
2
2
3
This protocol allows to define restrictions for variables.
3
This EFI protocol allows to define restrictions for variables.
4
It also allows to lock down variables (disallow write access).
4
It also allows to lock down variables (disallow write access).
5
5
6
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
6
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
7
---
7
---
8
hw/uefi/var-service-policy.c | 390 +++++++++++++++++++++++++++++++++++
8
hw/uefi/var-service-policy.c | 370 +++++++++++++++++++++++++++++++++++
9
1 file changed, 390 insertions(+)
9
1 file changed, 370 insertions(+)
10
create mode 100644 hw/uefi/var-service-policy.c
10
create mode 100644 hw/uefi/var-service-policy.c
11
11
12
diff --git a/hw/uefi/var-service-policy.c b/hw/uefi/var-service-policy.c
12
diff --git a/hw/uefi/var-service-policy.c b/hw/uefi/var-service-policy.c
13
new file mode 100644
13
new file mode 100644
14
index XXXXXXX..XXXXXXX
14
index XXXXXXX..XXXXXXX
...
...
22
+ *
22
+ *
23
+ * variable policy specs:
23
+ * variable policy specs:
24
+ * https://github.com/tianocore/edk2/blob/master/MdeModulePkg/Library/VariablePolicyLib/ReadMe.md
24
+ * https://github.com/tianocore/edk2/blob/master/MdeModulePkg/Library/VariablePolicyLib/ReadMe.md
25
+ */
25
+ */
26
+#include "qemu/osdep.h"
26
+#include "qemu/osdep.h"
27
+#include "sysemu/dma.h"
27
+#include "system/dma.h"
28
+#include "migration/vmstate.h"
28
+#include "migration/vmstate.h"
29
+
29
+
30
+#include "hw/uefi/var-service.h"
30
+#include "hw/uefi/var-service.h"
31
+#include "hw/uefi/var-service-api.h"
31
+#include "hw/uefi/var-service-api.h"
32
+#include "hw/uefi/var-service-edk2.h"
32
+#include "hw/uefi/var-service-edk2.h"
...
...
83
+ if (pe->lock_policy_type) {
83
+ if (pe->lock_policy_type) {
84
+ fprintf(stderr, " lock policy type %d\n", pe->lock_policy_type);
84
+ fprintf(stderr, " lock policy type %d\n", pe->lock_policy_type);
85
+ }
85
+ }
86
+}
86
+}
87
+
87
+
88
+static gboolean wildcard_strcmp(uefi_var_policy *pol,
88
+static gboolean wildcard_str_equal(uefi_var_policy *pol,
89
+ uefi_variable *var)
89
+ uefi_variable *var)
90
+{
90
+{
91
+ size_t pos = 0;
91
+ return uefi_str_equal_ex(pol->name, pol->name_size,
92
+ size_t plen = pol->name_size / 2;
92
+ var->name, var->name_size,
93
+ size_t vlen = var->name_size / 2;
93
+ true);
94
+
95
+ if (plen == 0) {
96
+ return true;
97
+ }
98
+
99
+ for (;;) {
100
+ if (pos == plen && pos == vlen) {
101
+ return true;
102
+ }
103
+ if (pos == plen || pos == vlen) {
104
+ return false;
105
+ }
106
+ if (pol->name[pos] == 0 && var->name[pos] == 0) {
107
+ return true;
108
+ }
109
+
110
+ if (pol->name[pos] == '#') {
111
+ if (!isxdigit(var->name[pos])) {
112
+ return false;
113
+ }
114
+ } else {
115
+ if (pol->name[pos] != var->name[pos]) {
116
+ return false;
117
+ }
118
+ }
119
+
120
+ pos++;
121
+ }
122
+}
94
+}
123
+
95
+
124
+static uefi_var_policy *find_policy(uefi_vars_state *uv, QemuUUID guid,
96
+static uefi_var_policy *find_policy(uefi_vars_state *uv, QemuUUID guid,
125
+ uint16_t *name, uint64_t name_size)
97
+ uint16_t *name, uint64_t name_size)
126
+{
98
+{
...
...
146
+
118
+
147
+ QTAILQ_FOREACH(pol, &uv->var_policies, next) {
119
+ QTAILQ_FOREACH(pol, &uv->var_policies, next) {
148
+ if (!qemu_uuid_is_equal(&pol->entry->namespace, &var->guid)) {
120
+ if (!qemu_uuid_is_equal(&pol->entry->namespace, &var->guid)) {
149
+ continue;
121
+ continue;
150
+ }
122
+ }
151
+ if (!wildcard_strcmp(pol, var)) {
123
+ if (!wildcard_str_equal(pol, var)) {
152
+ continue;
124
+ continue;
153
+ }
125
+ }
154
+ return pol;
126
+ return pol;
155
+ }
127
+ }
156
+ return NULL;
128
+ return NULL;
...
...
317
+ mm_check_policy *mchk,
289
+ mm_check_policy *mchk,
318
+ void *func)
290
+ void *func)
319
+{
291
+{
320
+ variable_policy_entry *pe = func;
292
+ variable_policy_entry *pe = func;
321
+ uefi_var_policy *pol;
293
+ uefi_var_policy *pol;
322
+ size_t length;
294
+ uint64_t length;
323
+
295
+
324
+ length = sizeof(*mchk) + pe->size;
296
+ if (uadd64_overflow(sizeof(*mchk), pe->size, &length)) {
297
+ return uefi_vars_mm_policy_error(mhdr, mchk, EFI_BAD_BUFFER_SIZE);
298
+ }
325
+ if (mhdr->length < length) {
299
+ if (mhdr->length < length) {
326
+ return uefi_vars_mm_policy_error(mhdr, mchk, EFI_BAD_BUFFER_SIZE);
300
+ return uefi_vars_mm_policy_error(mhdr, mchk, EFI_BAD_BUFFER_SIZE);
327
+ }
301
+ }
328
+ if (pe->size < sizeof(*pe)) {
302
+ if (pe->size < sizeof(*pe)) {
329
+ return uefi_vars_mm_policy_error(mhdr, mchk, EFI_BAD_BUFFER_SIZE);
303
+ return uefi_vars_mm_policy_error(mhdr, mchk, EFI_BAD_BUFFER_SIZE);
...
...
338
+ }
312
+ }
339
+
313
+
340
+ /* check space for minimum string length */
314
+ /* check space for minimum string length */
341
+ if (pe->size < (size_t)pe->offset_to_name) {
315
+ if (pe->size < (size_t)pe->offset_to_name) {
342
+ return uefi_vars_mm_policy_error(mhdr, mchk, EFI_BAD_BUFFER_SIZE);
316
+ return uefi_vars_mm_policy_error(mhdr, mchk, EFI_BAD_BUFFER_SIZE);
317
+ }
318
+
319
+ if (!uefi_str_is_valid((void *)pe + pe->offset_to_name,
320
+ pe->size - pe->offset_to_name,
321
+ false)) {
322
+ return uefi_vars_mm_policy_error(mhdr, mchk, EFI_INVALID_PARAMETER);
343
+ }
323
+ }
344
+
324
+
345
+ pol = find_policy(uv, pe->namespace,
325
+ pol = find_policy(uv, pe->namespace,
346
+ (void *)pe + pe->offset_to_name,
326
+ (void *)pe + pe->offset_to_name,
347
+ pe->size - pe->offset_to_name);
327
+ pe->size - pe->offset_to_name);
...
...
404
+
384
+
405
+ uefi_trace_status(__func__, mchk->result);
385
+ uefi_trace_status(__func__, mchk->result);
406
+ return UEFI_VARS_STS_SUCCESS;
386
+ return UEFI_VARS_STS_SUCCESS;
407
+}
387
+}
408
--
388
--
409
2.41.0
389
2.47.1
410
390
411
391
diff view generated by jsdifflib
1
This is the core code for guest <-> host communication. This accepts
1
This is the core code for guest <-> host communication. This accepts
2
request messages from the guest, dispatches them to the service called,
2
request messages from the guest, dispatches them to the service called,
3
and sends back the response message.
3
and sends back the response message.
4
4
5
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
5
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
6
---
6
---
7
hw/uefi/var-service-core.c | 350 +++++++++++++++++++++++++++++++++++++
7
hw/uefi/var-service-core.c | 237 +++++++++++++++++++++++++++++++++++++
8
1 file changed, 350 insertions(+)
8
1 file changed, 237 insertions(+)
9
create mode 100644 hw/uefi/var-service-core.c
9
create mode 100644 hw/uefi/var-service-core.c
10
10
11
diff --git a/hw/uefi/var-service-core.c b/hw/uefi/var-service-core.c
11
diff --git a/hw/uefi/var-service-core.c b/hw/uefi/var-service-core.c
12
new file mode 100644
12
new file mode 100644
13
index XXXXXXX..XXXXXXX
13
index XXXXXXX..XXXXXXX
...
...
18
+ * SPDX-License-Identifier: GPL-2.0-or-later
18
+ * SPDX-License-Identifier: GPL-2.0-or-later
19
+ *
19
+ *
20
+ * uefi vars device
20
+ * uefi vars device
21
+ */
21
+ */
22
+#include "qemu/osdep.h"
22
+#include "qemu/osdep.h"
23
+#include "sysemu/dma.h"
23
+#include "system/dma.h"
24
+#include "migration/vmstate.h"
24
+#include "migration/vmstate.h"
25
+
25
+
26
+#include "hw/uefi/var-service.h"
26
+#include "hw/uefi/var-service.h"
27
+#include "hw/uefi/var-service-api.h"
27
+#include "hw/uefi/var-service-api.h"
28
+#include "hw/uefi/var-service-edk2.h"
28
+#include "hw/uefi/var-service-edk2.h"
...
...
68
+ vmstate_uefi_var_policy, uefi_var_policy, next),
68
+ vmstate_uefi_var_policy, uefi_var_policy, next),
69
+ VMSTATE_END_OF_LIST()
69
+ VMSTATE_END_OF_LIST()
70
+ },
70
+ },
71
+};
71
+};
72
+
72
+
73
+size_t uefi_strlen(const uint16_t *str, size_t len)
74
+{
75
+ size_t pos = 0;
76
+
77
+ for (;;) {
78
+ if (pos == len) {
79
+ return pos;
80
+ }
81
+ if (str[pos] == 0) {
82
+ return pos;
83
+ }
84
+ pos++;
85
+ }
86
+}
87
+
88
+gboolean uefi_str_equal(const uint16_t *a, size_t alen,
89
+ const uint16_t *b, size_t blen)
90
+{
91
+ size_t pos = 0;
92
+
93
+ alen = alen / 2;
94
+ blen = blen / 2;
95
+ for (;;) {
96
+ if (pos == alen && pos == blen) {
97
+ return true;
98
+ }
99
+ if (pos == alen && b[pos] == 0) {
100
+ return true;
101
+ }
102
+ if (pos == blen && a[pos] == 0) {
103
+ return true;
104
+ }
105
+ if (pos == alen || pos == blen) {
106
+ return false;
107
+ }
108
+ if (a[pos] == 0 && b[pos] == 0) {
109
+ return true;
110
+ }
111
+ if (a[pos] != b[pos]) {
112
+ return false;
113
+ }
114
+ pos++;
115
+ }
116
+}
117
+
118
+char *uefi_ucs2_to_ascii(const uint16_t *ucs2, uint64_t ucs2_size)
119
+{
120
+ char *str = g_malloc0(ucs2_size / 2 + 1);
121
+ int i;
122
+
123
+ for (i = 0; i * 2 < ucs2_size; i++) {
124
+ if (ucs2[i] == 0) {
125
+ break;
126
+ }
127
+ if (ucs2[i] < 128) {
128
+ str[i] = ucs2[i];
129
+ } else {
130
+ str[i] = '?';
131
+ }
132
+ }
133
+ str[i] = 0;
134
+ return str;
135
+}
136
+
137
+void uefi_trace_variable(const char *action, QemuUUID guid,
138
+ const uint16_t *name, uint64_t name_size)
139
+{
140
+ QemuUUID be = qemu_uuid_bswap(guid);
141
+ char *str_uuid = qemu_uuid_unparse_strdup(&be);
142
+ char *str_name = uefi_ucs2_to_ascii(name, name_size);
143
+
144
+ trace_uefi_variable(action, str_name, name_size, str_uuid);
145
+
146
+ g_free(str_name);
147
+ g_free(str_uuid);
148
+}
149
+
150
+void uefi_trace_status(const char *action, efi_status status)
151
+{
152
+ switch (status) {
153
+ case EFI_SUCCESS:
154
+ trace_uefi_status(action, "success");
155
+ break;
156
+ case EFI_INVALID_PARAMETER:
157
+ trace_uefi_status(action, "invalid parameter");
158
+ break;
159
+ case EFI_UNSUPPORTED:
160
+ trace_uefi_status(action, "unsupported");
161
+ break;
162
+ case EFI_BAD_BUFFER_SIZE:
163
+ trace_uefi_status(action, "bad buffer size");
164
+ break;
165
+ case EFI_BUFFER_TOO_SMALL:
166
+ trace_uefi_status(action, "buffer too small");
167
+ break;
168
+ case EFI_WRITE_PROTECTED:
169
+ trace_uefi_status(action, "write protected");
170
+ break;
171
+ case EFI_OUT_OF_RESOURCES:
172
+ trace_uefi_status(action, "out of resources");
173
+ break;
174
+ case EFI_NOT_FOUND:
175
+ trace_uefi_status(action, "not found");
176
+ break;
177
+ case EFI_ACCESS_DENIED:
178
+ trace_uefi_status(action, "access denied");
179
+ break;
180
+ case EFI_ALREADY_STARTED:
181
+ trace_uefi_status(action, "already started");
182
+ break;
183
+ default:
184
+ trace_uefi_status(action, "unknown error");
185
+ break;
186
+ }
187
+}
188
+
189
+static uint32_t uefi_vars_cmd_mm(uefi_vars_state *uv)
73
+static uint32_t uefi_vars_cmd_mm(uefi_vars_state *uv)
190
+{
74
+{
191
+ hwaddr dma;
75
+ hwaddr dma;
192
+ mm_header *mhdr;
76
+ mm_header *mhdr;
193
+ uint32_t size, retval;
77
+ uint64_t size;
78
+ uint32_t retval;
194
+
79
+
195
+ dma = uv->buf_addr_lo | ((hwaddr)uv->buf_addr_hi << 32);
80
+ dma = uv->buf_addr_lo | ((hwaddr)uv->buf_addr_hi << 32);
196
+ mhdr = (mm_header *) uv->buffer;
81
+ mhdr = (mm_header *) uv->buffer;
197
+
82
+
198
+ if (!uv->buffer || uv->buf_size < sizeof(*mhdr)) {
83
+ if (!uv->buffer || uv->buf_size < sizeof(*mhdr)) {
...
...
202
+ /* read header */
87
+ /* read header */
203
+ dma_memory_read(&address_space_memory, dma,
88
+ dma_memory_read(&address_space_memory, dma,
204
+ uv->buffer, sizeof(*mhdr),
89
+ uv->buffer, sizeof(*mhdr),
205
+ MEMTXATTRS_UNSPECIFIED);
90
+ MEMTXATTRS_UNSPECIFIED);
206
+
91
+
207
+ size = sizeof(*mhdr) + mhdr->length;
92
+ if (uadd64_overflow(sizeof(*mhdr), mhdr->length, &size)) {
93
+ return UEFI_VARS_STS_ERR_BAD_BUFFER_SIZE;
94
+ }
208
+ if (uv->buf_size < size) {
95
+ if (uv->buf_size < size) {
209
+ return UEFI_VARS_STS_ERR_BAD_BUFFER_SIZE;
96
+ return UEFI_VARS_STS_ERR_BAD_BUFFER_SIZE;
210
+ }
97
+ }
211
+
98
+
212
+ /* read buffer (excl header) */
99
+ /* read buffer (excl header) */
...
...
363
+{
250
+{
364
+ uefi_vars_json_init(uv, errp);
251
+ uefi_vars_json_init(uv, errp);
365
+ uefi_vars_json_load(uv, errp);
252
+ uefi_vars_json_load(uv, errp);
366
+}
253
+}
367
--
254
--
368
2.41.0
255
2.47.1
diff view generated by jsdifflib
New patch
1
This implements pkcs7 signature verification using gnutls.
2
Needed to check authenticated variable updates.
1
3
4
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
5
---
6
hw/uefi/var-service-pkcs7.c | 436 ++++++++++++++++++++++++++++++++++++
7
1 file changed, 436 insertions(+)
8
create mode 100644 hw/uefi/var-service-pkcs7.c
9
10
diff --git a/hw/uefi/var-service-pkcs7.c b/hw/uefi/var-service-pkcs7.c
11
new file mode 100644
12
index XXXXXXX..XXXXXXX
13
--- /dev/null
14
+++ b/hw/uefi/var-service-pkcs7.c
15
@@ -XXX,XX +XXX,XX @@
16
+/*
17
+ * SPDX-License-Identifier: GPL-2.0-or-later
18
+ *
19
+ * uefi vars device - pkcs7 verification
20
+ */
21
+#include "qemu/osdep.h"
22
+#include "qemu/error-report.h"
23
+#include "system/dma.h"
24
+
25
+#include <gnutls/gnutls.h>
26
+#include <gnutls/pkcs7.h>
27
+#include <gnutls/crypto.h>
28
+
29
+#include "hw/uefi/var-service.h"
30
+
31
+#define AUTHVAR_DIGEST_ALGO GNUTLS_DIG_SHA256
32
+#define AUTHVAR_DIGEST_SIZE 32
33
+
34
+/*
35
+ * Replicate the signed data for signature verification.
36
+ */
37
+static gnutls_datum_t *build_signed_data(mm_variable_access *va, void *data)
38
+{
39
+ variable_auth_2 *auth = data;
40
+ uint64_t data_offset = sizeof(efi_time) + auth->hdr_length;
41
+ uint16_t *name = (void *)va + sizeof(mm_variable_access);
42
+ gnutls_datum_t *sdata;
43
+ uint64_t pos = 0;
44
+
45
+ sdata = g_new(gnutls_datum_t, 1);
46
+ sdata->size = (va->name_size - 2
47
+ + sizeof(QemuUUID)
48
+ + sizeof(va->attributes)
49
+ + sizeof(auth->timestamp)
50
+ + va->data_size - data_offset);
51
+ sdata->data = g_malloc(sdata->size);
52
+
53
+ /* Variable Name (without terminating \0) */
54
+ memcpy(sdata->data + pos, name, va->name_size - 2);
55
+ pos += va->name_size - 2;
56
+
57
+ /* Variable Namespace Guid */
58
+ memcpy(sdata->data + pos, &va->guid, sizeof(va->guid));
59
+ pos += sizeof(va->guid);
60
+
61
+ /* Attributes */
62
+ memcpy(sdata->data + pos, &va->attributes, sizeof(va->attributes));
63
+ pos += sizeof(va->attributes);
64
+
65
+ /* TimeStamp */
66
+ memcpy(sdata->data + pos, &auth->timestamp, sizeof(auth->timestamp));
67
+ pos += sizeof(auth->timestamp);
68
+
69
+ /* Variable Content */
70
+ memcpy(sdata->data + pos, data + data_offset, va->data_size - data_offset);
71
+ pos += va->data_size - data_offset;
72
+
73
+ assert(pos == sdata->size);
74
+ return sdata;
75
+}
76
+
77
+/*
78
+ * See WrapPkcs7Data() in edk2.
79
+ *
80
+ * UEFI spec allows pkcs7 signatures being used without the envelope which
81
+ * identifies them as pkcs7 signatures. openssl and gnutls will not parse them
82
+ * without the envelope though. So add it if needed.
83
+ */
84
+static void wrap_pkcs7(gnutls_datum_t *pkcs7)
85
+{
86
+ static uint8_t signed_data_oid[9] = {
87
+ 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02
88
+ };
89
+ gnutls_datum_t wrap;
90
+
91
+ if (pkcs7->data[4] == 0x06 &&
92
+ pkcs7->data[5] == 0x09 &&
93
+ memcmp(pkcs7->data + 6, signed_data_oid, sizeof(signed_data_oid)) == 0 &&
94
+ pkcs7->data[15] == 0x0a &&
95
+ pkcs7->data[16] == 0x82) {
96
+ return;
97
+ }
98
+
99
+ wrap.size = pkcs7->size + 19;
100
+ wrap.data = g_malloc(wrap.size);
101
+
102
+ wrap.data[0] = 0x30;
103
+ wrap.data[1] = 0x82;
104
+ wrap.data[2] = (wrap.size - 4) >> 8;
105
+ wrap.data[3] = (wrap.size - 4) & 0xff;
106
+ wrap.data[4] = 0x06;
107
+ wrap.data[5] = 0x09;
108
+ memcpy(wrap.data + 6, signed_data_oid, sizeof(signed_data_oid));
109
+
110
+ wrap.data[15] = 0xa0;
111
+ wrap.data[16] = 0x82;
112
+ wrap.data[17] = pkcs7->size >> 8;
113
+ wrap.data[18] = pkcs7->size & 0xff;
114
+ memcpy(wrap.data + 19, pkcs7->data, pkcs7->size);
115
+
116
+ g_free(pkcs7->data);
117
+ *pkcs7 = wrap;
118
+}
119
+
120
+static gnutls_datum_t *build_pkcs7(void *data)
121
+{
122
+ variable_auth_2 *auth = data;
123
+ gnutls_datum_t *pkcs7;
124
+
125
+ pkcs7 = g_new(gnutls_datum_t, 1);
126
+ pkcs7->size = auth->hdr_length - 24;
127
+ pkcs7->data = g_malloc(pkcs7->size);
128
+ memcpy(pkcs7->data, data + 16 + 24, pkcs7->size);
129
+
130
+ wrap_pkcs7(pkcs7);
131
+
132
+ return pkcs7;
133
+}
134
+
135
+/*
136
+ * Read UEFI signature database, store x509 all certificates found in
137
+ * gnutls_x509_trust_list_t.
138
+ */
139
+static gnutls_x509_trust_list_t build_trust_list_sb(uefi_variable *var)
140
+{
141
+ gnutls_x509_trust_list_t tlist;
142
+ gnutls_datum_t cert_data;
143
+ gnutls_x509_crt_t cert;
144
+ uefi_vars_siglist siglist;
145
+ uefi_vars_cert *c;
146
+ int rc;
147
+
148
+ rc = gnutls_x509_trust_list_init(&tlist, 0);
149
+ if (rc < 0) {
150
+ warn_report("gnutls_x509_trust_list_init error: %s",
151
+ gnutls_strerror(rc));
152
+ return NULL;
153
+ }
154
+
155
+ uefi_vars_siglist_init(&siglist);
156
+ uefi_vars_siglist_parse(&siglist, var->data, var->data_size);
157
+
158
+ QTAILQ_FOREACH(c, &siglist.x509, next) {
159
+ cert_data.size = c->size;
160
+ cert_data.data = c->data;
161
+
162
+ rc = gnutls_x509_crt_init(&cert);
163
+ if (rc < 0) {
164
+ warn_report("gnutls_x509_crt_init error: %s", gnutls_strerror(rc));
165
+ break;
166
+ }
167
+ rc = gnutls_x509_crt_import(cert, &cert_data, GNUTLS_X509_FMT_DER);
168
+ if (rc < 0) {
169
+ warn_report("gnutls_x509_crt_import error: %s",
170
+ gnutls_strerror(rc));
171
+ gnutls_x509_crt_deinit(cert);
172
+ break;
173
+ }
174
+ rc = gnutls_x509_trust_list_add_cas(tlist, &cert, 1, 0);
175
+ if (rc < 0) {
176
+ warn_report("gnutls_x509_crt_import error: %s",
177
+ gnutls_strerror(rc));
178
+ gnutls_x509_crt_deinit(cert);
179
+ break;
180
+ }
181
+ }
182
+
183
+ uefi_vars_siglist_free(&siglist);
184
+
185
+ return tlist;
186
+}
187
+
188
+static int build_digest_authvar(gnutls_x509_crt_t signer,
189
+ gnutls_x509_crt_t root,
190
+ uint8_t *hash_digest)
191
+{
192
+ char *cn;
193
+ size_t cn_size = 0;
194
+ uint8_t fp[AUTHVAR_DIGEST_SIZE];
195
+ size_t fp_size = sizeof(fp);
196
+ gnutls_hash_hd_t hash;
197
+ int rc;
198
+
199
+ /* get signer CN */
200
+ rc = gnutls_x509_crt_get_dn_by_oid(signer, GNUTLS_OID_X520_COMMON_NAME,
201
+ 0, 0, NULL, &cn_size);
202
+ if (rc != GNUTLS_E_SHORT_MEMORY_BUFFER) {
203
+ warn_report("gnutls_x509_crt_get_dn_by_oid error #1: %s",
204
+ gnutls_strerror(rc));
205
+ return rc;
206
+ }
207
+
208
+ cn = g_malloc(cn_size);
209
+ rc = gnutls_x509_crt_get_dn_by_oid(signer, GNUTLS_OID_X520_COMMON_NAME,
210
+ 0, 0, cn, &cn_size);
211
+ if (rc < 0) {
212
+ warn_report("gnutls_x509_crt_get_dn_by_oid error #2: %s",
213
+ gnutls_strerror(rc));
214
+ goto err;
215
+ }
216
+
217
+ /* get root certificate fingerprint */
218
+ rc = gnutls_x509_crt_get_fingerprint(root, AUTHVAR_DIGEST_ALGO,
219
+ fp, &fp_size);
220
+ if (rc < 0) {
221
+ warn_report("gnutls_x509_crt_get_fingerprint error: %s",
222
+ gnutls_strerror(rc));
223
+ goto err;
224
+ }
225
+
226
+ /* digest both items */
227
+ rc = gnutls_hash_init(&hash, AUTHVAR_DIGEST_ALGO);
228
+ if (rc < 0) {
229
+ warn_report("gnutls_hash_init error: %s",
230
+ gnutls_strerror(rc));
231
+ goto err;
232
+ }
233
+ rc = gnutls_hash(hash, cn, cn_size);
234
+ if (rc < 0) {
235
+ warn_report("gnutls_hash error: %s",
236
+ gnutls_strerror(rc));
237
+ goto err;
238
+ }
239
+ rc = gnutls_hash(hash, fp, fp_size);
240
+ if (rc < 0) {
241
+ warn_report("gnutls_hash error: %s",
242
+ gnutls_strerror(rc));
243
+ goto err;
244
+ }
245
+ gnutls_hash_deinit(hash, hash_digest);
246
+
247
+ return 0;
248
+
249
+err:
250
+ g_free(cn);
251
+ return rc;
252
+}
253
+
254
+/*
255
+ * uefi spec 2.9, section 8.2.2
256
+ *
257
+ * For EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS variables which are
258
+ * NOT secure boot variables we should track the root certificate of the trust
259
+ * chain, and the subject CN of the signer certificate.
260
+ *
261
+ * So we'll go store a digest of these two items so we can verify this. Also
262
+ * create a gnutls_x509_trust_list_t with the root certificate, so
263
+ * gnutls_pkcs7_verify() will pass (assuming the signature is otherwise
264
+ * correct).
265
+ */
266
+static gnutls_x509_trust_list_t build_trust_list_authvar(gnutls_pkcs7_t pkcs7,
267
+ uint8_t *hash_digest)
268
+{
269
+ gnutls_datum_t signer_data = { 0 };
270
+ gnutls_datum_t root_data = { 0 };
271
+ gnutls_x509_crt_t signer = NULL;
272
+ gnutls_x509_crt_t root = NULL;
273
+ gnutls_x509_trust_list_t tlist = NULL;
274
+ int n, rc;
275
+
276
+ n = gnutls_pkcs7_get_crt_count(pkcs7);
277
+
278
+ /* first is signer certificate */
279
+ rc = gnutls_pkcs7_get_crt_raw2(pkcs7, 0, &signer_data);
280
+ if (rc < 0) {
281
+ warn_report("gnutls_pkcs7_get_crt_raw2(0) error: %s",
282
+ gnutls_strerror(rc));
283
+ goto done;
284
+ }
285
+ rc = gnutls_x509_crt_init(&signer);
286
+ if (rc < 0) {
287
+ warn_report("gnutls_x509_crt_init error: %s", gnutls_strerror(rc));
288
+ goto done;
289
+ }
290
+ rc = gnutls_x509_crt_import(signer, &signer_data, GNUTLS_X509_FMT_DER);
291
+ if (rc < 0) {
292
+ warn_report("gnutls_x509_crt_import error: %s",
293
+ gnutls_strerror(rc));
294
+ gnutls_x509_crt_deinit(signer);
295
+ goto done;
296
+ }
297
+
298
+ /* last is root-of-trust certificate (can be identical to signer) */
299
+ rc = gnutls_pkcs7_get_crt_raw2(pkcs7, n - 1, &root_data);
300
+ if (rc < 0) {
301
+ warn_report("gnutls_pkcs7_get_crt_raw2(%d) error: %s",
302
+ n - 1, gnutls_strerror(rc));
303
+ goto done;
304
+ }
305
+ rc = gnutls_x509_crt_init(&root);
306
+ if (rc < 0) {
307
+ warn_report("gnutls_x509_crt_init error: %s", gnutls_strerror(rc));
308
+ goto done;
309
+ }
310
+ rc = gnutls_x509_crt_import(root, &root_data, GNUTLS_X509_FMT_DER);
311
+ if (rc < 0) {
312
+ warn_report("gnutls_x509_crt_import error: %s",
313
+ gnutls_strerror(rc));
314
+ goto done;
315
+ }
316
+
317
+ /* calc digest for signer CN + root cert */
318
+ rc = build_digest_authvar(signer, root, hash_digest);
319
+ if (rc < 0) {
320
+ goto done;
321
+ }
322
+
323
+ /* add root to trust list */
324
+ rc = gnutls_x509_trust_list_init(&tlist, 0);
325
+ if (rc < 0) {
326
+ warn_report("gnutls_x509_trust_list_init error: %s",
327
+ gnutls_strerror(rc));
328
+ goto done;
329
+ }
330
+ rc = gnutls_x509_trust_list_add_cas(tlist, &root, 1, 0);
331
+ if (rc < 0) {
332
+ warn_report("gnutls_x509_crt_import error: %s",
333
+ gnutls_strerror(rc));
334
+ gnutls_x509_trust_list_deinit(tlist, 1);
335
+ tlist = NULL;
336
+ goto done;
337
+ } else {
338
+ /* ownership passed to tlist */
339
+ root = NULL;
340
+ }
341
+
342
+done:
343
+ if (signer_data.data) {
344
+ gnutls_free(signer_data.data);
345
+ }
346
+ if (root_data.data) {
347
+ gnutls_free(root_data.data);
348
+ }
349
+ if (signer) {
350
+ gnutls_x509_crt_deinit(signer);
351
+ }
352
+ if (root) {
353
+ gnutls_x509_crt_deinit(root);
354
+ }
355
+ return tlist;
356
+}
357
+
358
+static void free_datum(gnutls_datum_t *ptr)
359
+{
360
+ if (!ptr) {
361
+ return;
362
+ }
363
+ g_free(ptr->data);
364
+ g_free(ptr);
365
+}
366
+
367
+static void gnutls_log_stderr(int level, const char *msg)
368
+{
369
+ if (strncmp(msg, "ASSERT:", 7) == 0) {
370
+ return;
371
+ }
372
+ fprintf(stderr, " %d: %s", level, msg);
373
+}
374
+
375
+/*
376
+ * pkcs7 signature verification (EFI_VARIABLE_AUTHENTICATION_2).
377
+ */
378
+efi_status uefi_vars_check_pkcs7_2(uefi_variable *siglist,
379
+ void **digest, uint32_t *digest_size,
380
+ mm_variable_access *va, void *data)
381
+{
382
+ gnutls_x509_trust_list_t tlist = NULL;
383
+ gnutls_datum_t *signed_data = NULL;
384
+ gnutls_datum_t *pkcs7_data = NULL;
385
+ gnutls_pkcs7_t pkcs7 = NULL;
386
+ efi_status status = EFI_SECURITY_VIOLATION;
387
+ int rc;
388
+
389
+ if (0) {
390
+ /* gnutls debug logging */
391
+ static bool first = true;
392
+
393
+ if (first) {
394
+ first = false;
395
+ gnutls_global_set_log_function(gnutls_log_stderr);
396
+ gnutls_global_set_log_level(99);
397
+ }
398
+ }
399
+
400
+ signed_data = build_signed_data(va, data);
401
+ pkcs7_data = build_pkcs7(data);
402
+
403
+ rc = gnutls_pkcs7_init(&pkcs7);
404
+ if (rc < 0) {
405
+ warn_report("gnutls_pkcs7_init error: %s", gnutls_strerror(rc));
406
+ goto out;
407
+ }
408
+
409
+ rc = gnutls_pkcs7_import(pkcs7, pkcs7_data, GNUTLS_X509_FMT_DER);
410
+ if (rc < 0) {
411
+ warn_report("gnutls_pkcs7_import error: %s", gnutls_strerror(rc));
412
+ goto out;
413
+ }
414
+
415
+ if (siglist) {
416
+ /* secure boot variables */
417
+ tlist = build_trust_list_sb(siglist);
418
+ } else if (digest && digest_size) {
419
+ /* other authenticated variables */
420
+ *digest_size = AUTHVAR_DIGEST_SIZE;
421
+ *digest = g_malloc(*digest_size);
422
+ tlist = build_trust_list_authvar(pkcs7, *digest);
423
+ } else {
424
+ /* should not happen */
425
+ goto out;
426
+ }
427
+
428
+ rc = gnutls_pkcs7_verify(pkcs7, tlist,
429
+ NULL, 0,
430
+ 0, signed_data,
431
+ GNUTLS_VERIFY_DISABLE_TIME_CHECKS |
432
+ GNUTLS_VERIFY_DISABLE_TRUSTED_TIME_CHECKS);
433
+ if (rc < 0) {
434
+ warn_report("gnutls_pkcs7_verify error: %s", gnutls_strerror(rc));
435
+ goto out;
436
+ }
437
+
438
+ /* check passed */
439
+ status = EFI_SUCCESS;
440
+
441
+out:
442
+ free_datum(signed_data);
443
+ free_datum(pkcs7_data);
444
+ if (tlist) {
445
+ gnutls_x509_trust_list_deinit(tlist, 1);
446
+ }
447
+ if (pkcs7) {
448
+ gnutls_pkcs7_deinit(pkcs7);
449
+ }
450
+ return status;
451
+}
452
--
453
2.47.1
diff view generated by jsdifflib
New patch
1
pkcs7 stub which is used in case gnutls is not available.
1
2
3
It throws EFI_WRITE_PROTECTED errors unconditionally, so all
4
authenticated variables are readonly for the guest.
5
6
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
7
---
8
hw/uefi/var-service-pkcs7-stub.c | 16 ++++++++++++++++
9
1 file changed, 16 insertions(+)
10
create mode 100644 hw/uefi/var-service-pkcs7-stub.c
11
12
diff --git a/hw/uefi/var-service-pkcs7-stub.c b/hw/uefi/var-service-pkcs7-stub.c
13
new file mode 100644
14
index XXXXXXX..XXXXXXX
15
--- /dev/null
16
+++ b/hw/uefi/var-service-pkcs7-stub.c
17
@@ -XXX,XX +XXX,XX @@
18
+/*
19
+ * SPDX-License-Identifier: GPL-2.0-or-later
20
+ *
21
+ * uefi vars device - pkcs7 stubs
22
+ */
23
+#include "qemu/osdep.h"
24
+#include "system/dma.h"
25
+
26
+#include "hw/uefi/var-service.h"
27
+
28
+efi_status uefi_vars_check_pkcs7_2(uefi_variable *siglist,
29
+ void **digest, uint32_t *digest_size,
30
+ mm_variable_access *va, void *data)
31
+{
32
+ return EFI_WRITE_PROTECTED;
33
+}
34
--
35
2.47.1
diff view generated by jsdifflib
New patch
1
Functions to serialize and de-serialize EFI signature databases. This
2
is needed to merge signature databases (happens in practice when
3
appending dbx updates) and also to extract the certificates for
4
pkcs7 signature verification.
1
5
6
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
7
---
8
hw/uefi/var-service-siglist.c | 212 ++++++++++++++++++++++++++++++++++
9
1 file changed, 212 insertions(+)
10
create mode 100644 hw/uefi/var-service-siglist.c
11
12
diff --git a/hw/uefi/var-service-siglist.c b/hw/uefi/var-service-siglist.c
13
new file mode 100644
14
index XXXXXXX..XXXXXXX
15
--- /dev/null
16
+++ b/hw/uefi/var-service-siglist.c
17
@@ -XXX,XX +XXX,XX @@
18
+/*
19
+ * SPDX-License-Identifier: GPL-2.0-or-later
20
+ *
21
+ * uefi vars device - parse and generate efi signature databases
22
+ */
23
+
24
+#include "qemu/osdep.h"
25
+#include "qemu/error-report.h"
26
+#include "system/dma.h"
27
+
28
+#include "hw/uefi/var-service.h"
29
+
30
+/*
31
+ * Add x509 certificate to list (with duplicate check).
32
+ */
33
+static void uefi_vars_siglist_add_x509(uefi_vars_siglist *siglist,
34
+ QemuUUID *owner,
35
+ void *data, uint64_t size)
36
+{
37
+ uefi_vars_cert *c;
38
+
39
+ QTAILQ_FOREACH(c, &siglist->x509, next) {
40
+ if (c->size != size) {
41
+ continue;
42
+ }
43
+ if (memcmp(c->data, data, size) != 0) {
44
+ continue;
45
+ }
46
+ return;
47
+ }
48
+
49
+ c = g_malloc(sizeof(*c) + size);
50
+ c->owner = *owner;
51
+ c->size = size;
52
+ memcpy(c->data, data, size);
53
+ QTAILQ_INSERT_TAIL(&siglist->x509, c, next);
54
+}
55
+
56
+/*
57
+ * Add sha256 hash to list (with duplicate check).
58
+ */
59
+static void uefi_vars_siglist_add_sha256(uefi_vars_siglist *siglist,
60
+ QemuUUID *owner,
61
+ void *data)
62
+{
63
+ uefi_vars_hash *h;
64
+
65
+ QTAILQ_FOREACH(h, &siglist->sha256, next) {
66
+ if (memcmp(h->data, data, 32) != 0) {
67
+ continue;
68
+ }
69
+ return;
70
+ }
71
+
72
+ h = g_malloc(sizeof(*h) + 32);
73
+ h->owner = *owner;
74
+ memcpy(h->data, data, 32);
75
+ QTAILQ_INSERT_TAIL(&siglist->sha256, h, next);
76
+}
77
+
78
+void uefi_vars_siglist_init(uefi_vars_siglist *siglist)
79
+{
80
+ memset(siglist, 0, sizeof(*siglist));
81
+ QTAILQ_INIT(&siglist->x509);
82
+ QTAILQ_INIT(&siglist->sha256);
83
+}
84
+
85
+void uefi_vars_siglist_free(uefi_vars_siglist *siglist)
86
+{
87
+ uefi_vars_cert *c, *cs;
88
+ uefi_vars_hash *h, *hs;
89
+
90
+ QTAILQ_FOREACH_SAFE(c, &siglist->x509, next, cs) {
91
+ QTAILQ_REMOVE(&siglist->x509, c, next);
92
+ g_free(c);
93
+ }
94
+ QTAILQ_FOREACH_SAFE(h, &siglist->sha256, next, hs) {
95
+ QTAILQ_REMOVE(&siglist->sha256, h, next);
96
+ g_free(h);
97
+ }
98
+}
99
+
100
+/*
101
+ * Parse UEFI signature list.
102
+ */
103
+void uefi_vars_siglist_parse(uefi_vars_siglist *siglist,
104
+ void *data, uint64_t size)
105
+{
106
+ efi_siglist *efilist;
107
+ uint64_t start;
108
+
109
+ while (size) {
110
+ if (size < sizeof(*efilist)) {
111
+ break;
112
+ }
113
+ efilist = data;
114
+ if (size < efilist->siglist_size) {
115
+ break;
116
+ }
117
+
118
+ if (uadd64_overflow(sizeof(*efilist), efilist->header_size, &start)) {
119
+ break;
120
+ }
121
+ if (efilist->sig_size <= sizeof(QemuUUID)) {
122
+ break;
123
+ }
124
+
125
+ if (qemu_uuid_is_equal(&efilist->guid_type, &EfiCertX509Guid)) {
126
+ if (start + efilist->sig_size != efilist->siglist_size) {
127
+ break;
128
+ }
129
+ uefi_vars_siglist_add_x509(siglist,
130
+ (QemuUUID *)(data + start),
131
+ data + start + sizeof(QemuUUID),
132
+ efilist->sig_size - sizeof(QemuUUID));
133
+
134
+ } else if (qemu_uuid_is_equal(&efilist->guid_type, &EfiCertSha256Guid)) {
135
+ if (efilist->sig_size != sizeof(QemuUUID) + 32) {
136
+ break;
137
+ }
138
+ if (start + efilist->sig_size > efilist->siglist_size) {
139
+ break;
140
+ }
141
+ while (start <= efilist->siglist_size - efilist->sig_size) {
142
+ uefi_vars_siglist_add_sha256(siglist,
143
+ (QemuUUID *)(data + start),
144
+ data + start + sizeof(QemuUUID));
145
+ start += efilist->sig_size;
146
+ }
147
+
148
+ } else {
149
+ QemuUUID be = qemu_uuid_bswap(efilist->guid_type);
150
+ char *str_uuid = qemu_uuid_unparse_strdup(&be);
151
+ warn_report("%s: unknown type (%s)", __func__, str_uuid);
152
+ g_free(str_uuid);
153
+ }
154
+
155
+ data += efilist->siglist_size;
156
+ size -= efilist->siglist_size;
157
+ }
158
+}
159
+
160
+uint64_t uefi_vars_siglist_blob_size(uefi_vars_siglist *siglist)
161
+{
162
+ uefi_vars_cert *c;
163
+ uefi_vars_hash *h;
164
+ uint64_t size = 0;
165
+
166
+ QTAILQ_FOREACH(c, &siglist->x509, next) {
167
+ size += sizeof(efi_siglist) + sizeof(QemuUUID) + c->size;
168
+ }
169
+
170
+ if (!QTAILQ_EMPTY(&siglist->sha256)) {
171
+ size += sizeof(efi_siglist);
172
+ QTAILQ_FOREACH(h, &siglist->sha256, next) {
173
+ size += sizeof(QemuUUID) + 32;
174
+ }
175
+ }
176
+
177
+ return size;
178
+}
179
+
180
+/*
181
+ * Generate UEFI signature list.
182
+ */
183
+void uefi_vars_siglist_blob_generate(uefi_vars_siglist *siglist,
184
+ void *data, uint64_t size)
185
+{
186
+ uefi_vars_cert *c;
187
+ uefi_vars_hash *h;
188
+ efi_siglist *efilist;
189
+ uint64_t pos = 0, start;
190
+ uint32_t i;
191
+
192
+ QTAILQ_FOREACH(c, &siglist->x509, next) {
193
+ efilist = data + pos;
194
+ efilist->guid_type = EfiCertX509Guid;
195
+ efilist->sig_size = sizeof(QemuUUID) + c->size;
196
+ efilist->header_size = 0;
197
+
198
+ start = pos + sizeof(efi_siglist);
199
+ memcpy(data + start,
200
+ &c->owner, sizeof(QemuUUID));
201
+ memcpy(data + start + sizeof(QemuUUID),
202
+ c->data, c->size);
203
+
204
+ efilist->siglist_size = sizeof(efi_siglist) + efilist->sig_size;
205
+ pos += efilist->siglist_size;
206
+ }
207
+
208
+ if (!QTAILQ_EMPTY(&siglist->sha256)) {
209
+ efilist = data + pos;
210
+ efilist->guid_type = EfiCertSha256Guid;
211
+ efilist->sig_size = sizeof(QemuUUID) + 32;
212
+ efilist->header_size = 0;
213
+
214
+ i = 0;
215
+ start = pos + sizeof(efi_siglist);
216
+ QTAILQ_FOREACH(h, &siglist->sha256, next) {
217
+ memcpy(data + start + efilist->sig_size * i,
218
+ &h->owner, sizeof(QemuUUID));
219
+ memcpy(data + start + efilist->sig_size * i + sizeof(QemuUUID),
220
+ h->data, 32);
221
+ i++;
222
+ }
223
+
224
+ efilist->siglist_size = sizeof(efi_siglist) + efilist->sig_size * i;
225
+ pos += efilist->siglist_size;
226
+ }
227
+
228
+ assert(pos == size);
229
+}
230
--
231
2.47.1
diff view generated by jsdifflib
1
Define qapi schema for the uefi variable store state.
1
Define qapi schema for the uefi variable store state.
2
2
3
Use it and the generated visitor helper functions to
3
Use it and the generated visitor helper functions to store persistent
4
store persistent variables in JSON format on disk.
4
(EFI_VARIABLE_NON_VOLATILE) variables in JSON format on disk.
5
5
6
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
6
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
7
---
7
---
8
hw/uefi/var-service-json.c | 194 +++++++++++++++++++++++++++++++++++++
8
hw/uefi/var-service-json.c | 242 +++++++++++++++++++++++++++++++++++++
9
qapi/meson.build | 1 +
9
qapi/meson.build | 1 +
10
qapi/qapi-schema.json | 1 +
10
qapi/qapi-schema.json | 1 +
11
qapi/uefi.json | 40 ++++++++
11
qapi/uefi.json | 45 +++++++
12
4 files changed, 236 insertions(+)
12
4 files changed, 289 insertions(+)
13
create mode 100644 hw/uefi/var-service-json.c
13
create mode 100644 hw/uefi/var-service-json.c
14
create mode 100644 qapi/uefi.json
14
create mode 100644 qapi/uefi.json
15
15
16
diff --git a/hw/uefi/var-service-json.c b/hw/uefi/var-service-json.c
16
diff --git a/hw/uefi/var-service-json.c b/hw/uefi/var-service-json.c
17
new file mode 100644
17
new file mode 100644
...
...
29
+ * - https://gitlab.com/kraxel/virt-firmware
29
+ * - https://gitlab.com/kraxel/virt-firmware
30
+ * - https://github.com/awslabs/python-uefivars
30
+ * - https://github.com/awslabs/python-uefivars
31
+ */
31
+ */
32
+#include "qemu/osdep.h"
32
+#include "qemu/osdep.h"
33
+#include "qemu/cutils.h"
33
+#include "qemu/cutils.h"
34
+#include "sysemu/dma.h"
34
+#include "qemu/error-report.h"
35
+#include "system/dma.h"
35
+
36
+
36
+#include "hw/uefi/var-service.h"
37
+#include "hw/uefi/var-service.h"
37
+
38
+
38
+#include "qapi/dealloc-visitor.h"
39
+#include "qapi/dealloc-visitor.h"
39
+#include "qapi/qobject-input-visitor.h"
40
+#include "qapi/qobject-input-visitor.h"
40
+#include "qapi/qobject-output-visitor.h"
41
+#include "qapi/qobject-output-visitor.h"
41
+#include "qapi/qmp/qobject.h"
42
+#include "qapi/qmp/qobject.h"
42
+#include "qapi/qmp/qjson.h"
43
+#include "qapi/qmp/qjson.h"
43
+#include "qapi/qapi-types-uefi.h"
44
+#include "qapi/qapi-types-uefi.h"
44
+#include "qapi/qapi-visit-uefi.h"
45
+#include "qapi/qapi-visit-uefi.h"
45
+
46
+
46
+static UefiVarStore *uefi_vars_to_qapi(uefi_vars_state *uv)
47
+static char *generate_hexstr(void *data, size_t len)
47
+{
48
+{
48
+ static const char hex[] = {
49
+ static const char hex[] = {
49
+ '0', '1', '2', '3', '4', '5', '6', '7',
50
+ '0', '1', '2', '3', '4', '5', '6', '7',
50
+ '8', '9', 'a', 'b', 'c', 'd', 'e', 'f',
51
+ '8', '9', 'a', 'b', 'c', 'd', 'e', 'f',
51
+ };
52
+ };
53
+ uint8_t *src = data;
54
+ char *dest;
55
+ size_t i;
56
+
57
+ dest = g_malloc(len * 2 + 1);
58
+ for (i = 0; i < len * 2;) {
59
+ dest[i++] = hex[*src >> 4];
60
+ dest[i++] = hex[*src & 15];
61
+ src++;
62
+ }
63
+ dest[i++] = 0;
64
+
65
+ return dest;
66
+}
67
+
68
+static UefiVarStore *uefi_vars_to_qapi(uefi_vars_state *uv)
69
+{
52
+ UefiVarStore *vs;
70
+ UefiVarStore *vs;
53
+ UefiVariableList **tail;
71
+ UefiVariableList **tail;
54
+ UefiVariable *v;
72
+ UefiVariable *v;
55
+ QemuUUID be;
73
+ QemuUUID be;
56
+ uefi_variable *var;
74
+ uefi_variable *var;
57
+ uint8_t *data;
58
+ unsigned int i;
59
+
75
+
60
+ vs = g_new0(UefiVarStore, 1);
76
+ vs = g_new0(UefiVarStore, 1);
61
+ vs->version = 2;
77
+ vs->version = 2;
62
+ tail = &vs->variables;
78
+ tail = &vs->variables;
63
+
79
+
...
...
70
+ be = qemu_uuid_bswap(var->guid);
86
+ be = qemu_uuid_bswap(var->guid);
71
+ v->guid = qemu_uuid_unparse_strdup(&be);
87
+ v->guid = qemu_uuid_unparse_strdup(&be);
72
+ v->name = uefi_ucs2_to_ascii(var->name, var->name_size);
88
+ v->name = uefi_ucs2_to_ascii(var->name, var->name_size);
73
+ v->attr = var->attributes;
89
+ v->attr = var->attributes;
74
+
90
+
75
+ v->data = g_malloc(var->data_size * 2 + 1);
91
+ v->data = generate_hexstr(var->data, var->data_size);
76
+ data = var->data;
92
+
77
+ for (i = 0; i < var->data_size * 2;) {
93
+ if (var->attributes &
78
+ v->data[i++] = hex[*data >> 4];
94
+ EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) {
79
+ v->data[i++] = hex[*data & 15];
95
+ v->time = generate_hexstr(&var->time, sizeof(var->time));
80
+ data++;
96
+ if (var->digest && var->digest_size) {
81
+ }
97
+ v->digest = generate_hexstr(var->digest, var->digest_size);
82
+ v->data[i++] = 0;
98
+ }
99
+ }
83
+
100
+
84
+ QAPI_LIST_APPEND(tail, v);
101
+ QAPI_LIST_APPEND(tail, v);
85
+ }
102
+ }
86
+ return vs;
103
+ return vs;
87
+}
104
+}
...
...
91
+ switch (c) {
108
+ switch (c) {
92
+ case '0' ... '9': return c - '0';
109
+ case '0' ... '9': return c - '0';
93
+ case 'a' ... 'f': return c - 'a' + 0xa;
110
+ case 'a' ... 'f': return c - 'a' + 0xa;
94
+ case 'A' ... 'F': return c - 'A' + 0xA;
111
+ case 'A' ... 'F': return c - 'A' + 0xA;
95
+ default: return 0;
112
+ default: return 0;
113
+ }
114
+}
115
+
116
+static void parse_hexstr(void *dest, char *src, int len)
117
+{
118
+ uint8_t *data = dest;
119
+ size_t i;
120
+
121
+ for (i = 0; i < len; i += 2) {
122
+ *(data++) =
123
+ parse_hexchar(src[i]) << 4 |
124
+ parse_hexchar(src[i + 1]);
96
+ }
125
+ }
97
+}
126
+}
98
+
127
+
99
+static void uefi_vars_from_qapi(uefi_vars_state *uv, UefiVarStore *vs)
128
+static void uefi_vars_from_qapi(uefi_vars_state *uv, UefiVarStore *vs)
100
+{
129
+{
...
...
121
+ }
150
+ }
122
+
151
+
123
+ len = strlen(v->data);
152
+ len = strlen(v->data);
124
+ var->data_size = len / 2;
153
+ var->data_size = len / 2;
125
+ var->data = data = g_malloc(var->data_size);
154
+ var->data = data = g_malloc(var->data_size);
126
+ for (i = 0; i < len; i += 2) {
155
+ parse_hexstr(var->data, v->data, len);
127
+ *(data++) =
156
+
128
+ parse_hexchar(v->data[i]) << 4 |
157
+ if (v->time && strlen(v->time) == 32) {
129
+ parse_hexchar(v->data[i + 1]);
158
+ parse_hexstr(&var->time, v->time, 32);
159
+ }
160
+
161
+ if (v->digest) {
162
+ len = strlen(v->digest);
163
+ var->digest_size = len / 2;
164
+ var->digest = g_malloc(var->digest_size);
165
+ parse_hexstr(var->digest, v->digest, len);
130
+ }
166
+ }
131
+
167
+
132
+ QTAILQ_INSERT_TAIL(&uv->variables, var, next);
168
+ QTAILQ_INSERT_TAIL(&uv->variables, var, next);
133
+ }
169
+ }
134
+}
170
+}
...
...
161
+}
197
+}
162
+
198
+
163
+void uefi_vars_json_save(uefi_vars_state *uv)
199
+void uefi_vars_json_save(uefi_vars_state *uv)
164
+{
200
+{
165
+ GString *gstr;
201
+ GString *gstr;
202
+ int rc;
166
+
203
+
167
+ if (uv->jsonfd == -1) {
204
+ if (uv->jsonfd == -1) {
168
+ return;
205
+ return;
169
+ }
206
+ }
170
+
207
+
171
+ gstr = uefi_vars_to_json(uv);
208
+ gstr = uefi_vars_to_json(uv);
172
+
209
+
173
+ lseek(uv->jsonfd, 0, SEEK_SET);
210
+ lseek(uv->jsonfd, 0, SEEK_SET);
174
+ write(uv->jsonfd, gstr->str, gstr->len);
211
+ rc = write(uv->jsonfd, gstr->str, gstr->len);
175
+ ftruncate(uv->jsonfd, gstr->len);
212
+ if (rc != gstr->len) {
213
+ warn_report("%s: write error", __func__);
214
+ }
215
+ rc = ftruncate(uv->jsonfd, gstr->len);
216
+ if (rc != 0) {
217
+ warn_report("%s: ftruncate error", __func__);
218
+ }
176
+ fsync(uv->jsonfd);
219
+ fsync(uv->jsonfd);
177
+
220
+
178
+ g_string_free(gstr, true);
221
+ g_string_free(gstr, true);
179
+}
222
+}
180
+
223
+
...
...
183
+ UefiVarStore *vs;
226
+ UefiVarStore *vs;
184
+ QObject *qobj;
227
+ QObject *qobj;
185
+ Visitor *v;
228
+ Visitor *v;
186
+ char *str;
229
+ char *str;
187
+ size_t len;
230
+ size_t len;
231
+ int rc;
188
+
232
+
189
+ if (uv->jsonfd == -1) {
233
+ if (uv->jsonfd == -1) {
190
+ return;
234
+ return;
191
+ }
235
+ }
192
+
236
+
...
...
195
+ return;
239
+ return;
196
+ }
240
+ }
197
+
241
+
198
+ str = g_malloc(len + 1);
242
+ str = g_malloc(len + 1);
199
+ lseek(uv->jsonfd, 0, SEEK_SET);
243
+ lseek(uv->jsonfd, 0, SEEK_SET);
200
+ read(uv->jsonfd, str, len);
244
+ rc = read(uv->jsonfd, str, len);
245
+ if (rc != len) {
246
+ warn_report("%s: read error", __func__);
247
+ }
201
+ str[len] = 0;
248
+ str[len] = 0;
202
+
249
+
203
+ qobj = qobject_from_json(str, errp);
250
+ qobj = qobject_from_json(str, errp);
204
+ v = qobject_input_visitor_new(qobj);
251
+ v = qobject_input_visitor_new(qobj);
205
+ visit_type_UefiVarStore(v, NULL, &vs, errp);
252
+ visit_type_UefiVarStore(v, NULL, &vs, errp);
206
+ visit_free(v);
253
+ visit_free(v);
207
+
254
+
208
+ if (!(*errp)) {
255
+ if (!(*errp)) {
209
+ uefi_vars_from_qapi(uv, vs);
256
+ uefi_vars_from_qapi(uv, vs);
257
+ uefi_vars_update_storage(uv);
210
+ }
258
+ }
211
+
259
+
212
+ qapi_free_UefiVarStore(vs);
260
+ qapi_free_UefiVarStore(vs);
213
+ qobject_unref(qobj);
261
+ qobject_unref(qobj);
214
+ g_free(str);
262
+ g_free(str);
215
+}
263
+}
216
diff --git a/qapi/meson.build b/qapi/meson.build
264
diff --git a/qapi/meson.build b/qapi/meson.build
217
index XXXXXXX..XXXXXXX 100644
265
index XXXXXXX..XXXXXXX 100644
218
--- a/qapi/meson.build
266
--- a/qapi/meson.build
219
+++ b/qapi/meson.build
267
+++ b/qapi/meson.build
220
@@ -XXX,XX +XXX,XX @@ if have_system
268
@@ -XXX,XX +XXX,XX @@ if have_system
221
'rdma',
269
'pci',
222
'rocker',
270
'rocker',
223
'tpm',
271
'tpm',
224
+ 'uefi',
272
+ 'uefi',
225
]
273
]
226
endif
274
endif
227
if have_system or have_tools
275
if have_system or have_tools
228
diff --git a/qapi/qapi-schema.json b/qapi/qapi-schema.json
276
diff --git a/qapi/qapi-schema.json b/qapi/qapi-schema.json
229
index XXXXXXX..XXXXXXX 100644
277
index XXXXXXX..XXXXXXX 100644
230
--- a/qapi/qapi-schema.json
278
--- a/qapi/qapi-schema.json
231
+++ b/qapi/qapi-schema.json
279
+++ b/qapi/qapi-schema.json
232
@@ -XXX,XX +XXX,XX @@
280
@@ -XXX,XX +XXX,XX @@
233
{ 'include': 'virtio.json' }
281
{ 'include': 'vfio.json' }
234
{ 'include': 'cryptodev.json' }
282
{ 'include': 'cryptodev.json' }
235
{ 'include': 'cxl.json' }
283
{ 'include': 'cxl.json' }
236
+{ 'include': 'uefi.json' }
284
+{ 'include': 'uefi.json' }
237
diff --git a/qapi/uefi.json b/qapi/uefi.json
285
diff --git a/qapi/uefi.json b/qapi/uefi.json
238
new file mode 100644
286
new file mode 100644
...
...
255
+#
303
+#
256
+# @attr: variable attributes
304
+# @attr: variable attributes
257
+#
305
+#
258
+# @data: variable content (base64)
306
+# @data: variable content (base64)
259
+#
307
+#
260
+# Since: 9.0
308
+# @time: variable modification time (EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS).
309
+#
310
+# @digest: variable certificate digest (EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS).
311
+#
312
+# Since: 10.0
261
+##
313
+##
262
+{ 'struct' : 'UefiVariable',
314
+{ 'struct' : 'UefiVariable',
263
+ 'data' : { 'guid' : 'str',
315
+ 'data' : { 'guid' : 'str',
264
+ 'name' : 'str',
316
+ 'name' : 'str',
265
+ 'attr' : 'int',
317
+ 'attr' : 'int',
266
+ 'data' : 'str',
318
+ 'data' : 'str',
267
+ '*time' : 'str'}}
319
+ '*time' : 'str',
320
+ '*digest' : 'str'}}
268
+
321
+
269
+##
322
+##
270
+# @UefiVarStore:
323
+# @UefiVarStore:
271
+#
324
+#
272
+# UEFI Variable Store
325
+# UEFI Variable Store
273
+#
326
+#
274
+# @version: 2
327
+# @version: 2
275
+#
328
+#
276
+# @variables: list of uefi variables
329
+# @variables: list of uefi variables
277
+#
330
+#
278
+# Since: 9.0
331
+# Since: 10.0
279
+##
332
+##
280
+{ 'struct' : 'UefiVarStore',
333
+{ 'struct' : 'UefiVarStore',
281
+ 'data' : { 'version' : 'int',
334
+ 'data' : { 'version' : 'int',
282
+ 'variables' : [ 'UefiVariable' ] }}
335
+ 'variables' : [ 'UefiVariable' ] }}
283
--
336
--
284
2.41.0
337
2.47.1
diff view generated by jsdifflib
1
Add trace events for debugging and trouble shooting.
2
1
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
3
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2
---
4
---
3
hw/uefi/trace-events | 16 ++++++++++++++++
5
hw/uefi/trace-events | 17 +++++++++++++++++
4
1 file changed, 16 insertions(+)
6
1 file changed, 17 insertions(+)
5
create mode 100644 hw/uefi/trace-events
7
create mode 100644 hw/uefi/trace-events
6
8
7
diff --git a/hw/uefi/trace-events b/hw/uefi/trace-events
9
diff --git a/hw/uefi/trace-events b/hw/uefi/trace-events
8
new file mode 100644
10
new file mode 100644
9
index XXXXXXX..XXXXXXX
11
index XXXXXXX..XXXXXXX
10
--- /dev/null
12
--- /dev/null
11
+++ b/hw/uefi/trace-events
13
+++ b/hw/uefi/trace-events
12
@@ -XXX,XX +XXX,XX @@
14
@@ -XXX,XX +XXX,XX @@
13
+# device
15
+# device
14
+uefi_reg_read(uint64_t addr, unsigned size) "addr 0x%lx, size %d"
16
+uefi_reg_read(uint64_t addr, unsigned size) "addr 0x%" PRIx64 ", size %u"
15
+uefi_reg_write(uint64_t addr, uint64_t val, unsigned size) "addr 0x%lx, val 0x%lx, size %d"
17
+uefi_reg_write(uint64_t addr, uint64_t val, unsigned size) "addr 0x%" PRIx64 ", val 0x%" PRIx64 ", size %d"
16
+uefi_hard_reset(void) ""
18
+uefi_hard_reset(void) ""
17
+
19
+
18
+# generic uefi
20
+# generic uefi
19
+uefi_variable(const char *context, const char *name, uint64_t size, const char *uuid) "context %s, name %s, size %ld, uuid %s"
21
+uefi_variable(const char *context, const char *name, uint64_t size, const char *uuid) "context %s, name %s, size %" PRIu64 ", uuid %s"
20
+uefi_status(const char *context, const char *name) "context %s, status %s"
22
+uefi_status(const char *context, const char *name) "context %s, status %s"
21
+uefi_event(const char *name) "event %s"
23
+uefi_event(const char *name) "event %s"
22
+
24
+
23
+# variable protocol
25
+# variable protocol
24
+uefi_vars_proto_cmd(const char *cmd) "cmd %s"
26
+uefi_vars_proto_cmd(const char *cmd) "cmd %s"
27
+uefi_vars_security_violation(const char *reason) "reason %s"
25
+
28
+
26
+# variable policy protocol
29
+# variable policy protocol
27
+uefi_vars_policy_cmd(const char *cmd) "cmd %s"
30
+uefi_vars_policy_cmd(const char *cmd) "cmd %s"
28
+uefi_vars_policy_deny(const char *reason) "reason %s"
31
+uefi_vars_policy_deny(const char *reason) "reason %s"
29
--
32
--
30
2.41.0
33
2.47.1
diff view generated by jsdifflib
1
Add UEFI_VARS config option, enable by default for x86_64 and aarch64.
2
1
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
3
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2
---
4
---
3
hw/Kconfig | 1 +
5
hw/Kconfig | 1 +
4
hw/uefi/Kconfig | 3 +++
6
hw/uefi/Kconfig | 3 +++
5
2 files changed, 4 insertions(+)
7
2 files changed, 4 insertions(+)
...
...
25
@@ -XXX,XX +XXX,XX @@
27
@@ -XXX,XX +XXX,XX @@
26
+config UEFI_VARS
28
+config UEFI_VARS
27
+    bool
29
+    bool
28
+ default y if X86_64 || AARCH64
30
+ default y if X86_64 || AARCH64
29
--
31
--
30
2.41.0
32
2.47.1
diff view generated by jsdifflib
1
Wire up uefi-vars in the build system.
1
Wire up uefi-vars in the build system.
2
2
3
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
3
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
4
---
4
---
5
hw/meson.build | 1 +
5
hw/meson.build | 1 +
6
hw/uefi/meson.build | 12 ++++++++++++
6
hw/uefi/meson.build | 18 ++++++++++++++++++
7
meson.build | 1 +
7
meson.build | 1 +
8
3 files changed, 14 insertions(+)
8
3 files changed, 20 insertions(+)
9
create mode 100644 hw/uefi/meson.build
9
create mode 100644 hw/uefi/meson.build
10
10
11
diff --git a/hw/meson.build b/hw/meson.build
11
diff --git a/hw/meson.build b/hw/meson.build
12
index XXXXXXX..XXXXXXX 100644
12
index XXXXXXX..XXXXXXX 100644
13
--- a/hw/meson.build
13
--- a/hw/meson.build
...
...
25
index XXXXXXX..XXXXXXX
25
index XXXXXXX..XXXXXXX
26
--- /dev/null
26
--- /dev/null
27
+++ b/hw/uefi/meson.build
27
+++ b/hw/uefi/meson.build
28
@@ -XXX,XX +XXX,XX @@
28
@@ -XXX,XX +XXX,XX @@
29
+uefi_vars_ss = ss.source_set()
29
+uefi_vars_ss = ss.source_set()
30
+uefi_vars_ss.add(when: 'CONFIG_UEFI_VARS',
30
+if (config_all_devices.has_key('CONFIG_UEFI_VARS'))
31
+ if_true: files('var-service-core.c',
31
+ uefi_vars_ss.add(files('var-service-core.c',
32
+ 'var-service-json.c',
32
+ 'var-service-json.c',
33
+ 'var-service-vars.c',
33
+ 'var-service-vars.c',
34
+ 'var-service-auth.c',
34
+ 'var-service-auth.c',
35
+ 'var-service-guid.c',
35
+ 'var-service-guid.c',
36
+ 'var-service-policy.c'))
36
+ 'var-service-utils.c',
37
+ 'var-service-policy.c'))
38
+ uefi_vars_ss.add(when: gnutls,
39
+ if_true: files('var-service-pkcs7.c'),
40
+ if_false: files('var-service-pkcs7-stub.c'))
41
+ uefi_vars_ss.add(files('var-service-siglist.c'))
42
+endif
37
+
43
+
38
+modules += { 'hw-uefi' : {
44
+modules += { 'hw-uefi' : {
39
+ 'vars' : uefi_vars_ss,
45
+ 'vars' : uefi_vars_ss,
40
+}}
46
+}}
41
diff --git a/meson.build b/meson.build
47
diff --git a/meson.build b/meson.build
...
...
49
+ 'hw/uefi',
55
+ 'hw/uefi',
50
'hw/ufs',
56
'hw/ufs',
51
'hw/usb',
57
'hw/usb',
52
'hw/vfio',
58
'hw/vfio',
53
--
59
--
54
2.41.0
60
2.47.1
diff view generated by jsdifflib
1
This adds sysbus bindings for the variable service.
1
This adds sysbus bindings for the variable service.
2
2
3
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
3
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
4
---
4
---
5
hw/uefi/var-service-sysbus.c | 87 ++++++++++++++++++++++++++++++++++++
5
hw/uefi/var-service-sysbus.c | 90 ++++++++++++++++++++++++++++++++++++
6
hw/uefi/meson.build | 3 +-
6
hw/uefi/meson.build | 3 +-
7
2 files changed, 89 insertions(+), 1 deletion(-)
7
2 files changed, 92 insertions(+), 1 deletion(-)
8
create mode 100644 hw/uefi/var-service-sysbus.c
8
create mode 100644 hw/uefi/var-service-sysbus.c
9
9
10
diff --git a/hw/uefi/var-service-sysbus.c b/hw/uefi/var-service-sysbus.c
10
diff --git a/hw/uefi/var-service-sysbus.c b/hw/uefi/var-service-sysbus.c
11
new file mode 100644
11
new file mode 100644
12
index XXXXXXX..XXXXXXX
12
index XXXXXXX..XXXXXXX
...
...
42
+ vmstate_uefi_vars, uefi_vars_state),
42
+ vmstate_uefi_vars, uefi_vars_state),
43
+ VMSTATE_END_OF_LIST()
43
+ VMSTATE_END_OF_LIST()
44
+ }
44
+ }
45
+};
45
+};
46
+
46
+
47
+static Property uefi_vars_sysbus_properties[] = {
47
+static const Property uefi_vars_sysbus_properties[] = {
48
+ DEFINE_PROP_SIZE("size", uefi_vars_sysbus_state, state.max_storage,
48
+ DEFINE_PROP_SIZE("size", uefi_vars_sysbus_state, state.max_storage,
49
+ 256 * 1024),
49
+ 256 * 1024),
50
+ DEFINE_PROP_STRING("jsonfile", uefi_vars_sysbus_state, state.jsonfile),
50
+ DEFINE_PROP_STRING("jsonfile", uefi_vars_sysbus_state, state.jsonfile),
51
+ DEFINE_PROP_END_OF_LIST(),
51
+ DEFINE_PROP_BOOL("force-secure-boot", uefi_vars_sysbus_state,
52
+ state.force_secure_boot, false),
53
+ DEFINE_PROP_BOOL("disable-custom-mode", uefi_vars_sysbus_state,
54
+ state.disable_custom_mode, false),
52
+};
55
+};
53
+
56
+
54
+static void uefi_vars_sysbus_init(Object *obj)
57
+static void uefi_vars_sysbus_init(Object *obj)
55
+{
58
+{
56
+ uefi_vars_sysbus_state *uv = UEFI_VARS_SYSBUS(obj);
59
+ uefi_vars_sysbus_state *uv = UEFI_VARS_SYSBUS(obj);
...
...
77
+static void uefi_vars_sysbus_class_init(ObjectClass *klass, void *data)
80
+static void uefi_vars_sysbus_class_init(ObjectClass *klass, void *data)
78
+{
81
+{
79
+ DeviceClass *dc = DEVICE_CLASS(klass);
82
+ DeviceClass *dc = DEVICE_CLASS(klass);
80
+
83
+
81
+ dc->realize = uefi_vars_sysbus_realize;
84
+ dc->realize = uefi_vars_sysbus_realize;
82
+ dc->reset = uefi_vars_sysbus_reset;
83
+ dc->vmsd = &vmstate_uefi_vars_sysbus;
85
+ dc->vmsd = &vmstate_uefi_vars_sysbus;
86
+ device_class_set_legacy_reset(dc, uefi_vars_sysbus_reset);
84
+ device_class_set_props(dc, uefi_vars_sysbus_properties);
87
+ device_class_set_props(dc, uefi_vars_sysbus_properties);
85
+ set_bit(DEVICE_CATEGORY_MISC, dc->categories);
88
+ set_bit(DEVICE_CATEGORY_MISC, dc->categories);
86
+}
89
+}
87
+
90
+
88
+static const TypeInfo uefi_vars_sysbus_info = {
91
+static const TypeInfo uefi_vars_sysbus_info = {
...
...
102
+type_init(uefi_vars_sysbus_register_types)
105
+type_init(uefi_vars_sysbus_register_types)
103
diff --git a/hw/uefi/meson.build b/hw/uefi/meson.build
106
diff --git a/hw/uefi/meson.build b/hw/uefi/meson.build
104
index XXXXXXX..XXXXXXX 100644
107
index XXXXXXX..XXXXXXX 100644
105
--- a/hw/uefi/meson.build
108
--- a/hw/uefi/meson.build
106
+++ b/hw/uefi/meson.build
109
+++ b/hw/uefi/meson.build
107
@@ -XXX,XX +XXX,XX @@ uefi_vars_ss.add(when: 'CONFIG_UEFI_VARS',
110
@@ -XXX,XX +XXX,XX @@ if (config_all_devices.has_key('CONFIG_UEFI_VARS'))
108
'var-service-vars.c',
111
'var-service-auth.c',
109
'var-service-auth.c',
112
'var-service-guid.c',
110
'var-service-guid.c',
113
'var-service-utils.c',
111
- 'var-service-policy.c'))
114
- 'var-service-policy.c'))
112
+ 'var-service-policy.c',
115
+ 'var-service-policy.c',
113
+ 'var-service-sysbus.c'))
116
+ 'var-service-sysbus.c'))
114
117
uefi_vars_ss.add(when: gnutls,
115
modules += { 'hw-uefi' : {
118
if_true: files('var-service-pkcs7.c'),
116
'vars' : uefi_vars_ss,
119
if_false: files('var-service-pkcs7-stub.c'))
117
--
120
--
118
2.41.0
121
2.47.1
diff view generated by jsdifflib
1
This adds isa bindings for the variable service.
1
This adds isa bindings for the variable service.
2
2
3
Usage: qemu-system-x86_64 -device uefi-vars-isa,jsonfile=/path/to/uefivars.json
3
Usage: qemu-system-x86_64 -device uefi-vars-isa,jsonfile=/path/to/uefivars.json
4
4
5
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
5
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
6
---
6
---
7
hw/uefi/var-service-isa.c | 88 +++++++++++++++++++++++++++++++++++++++
7
hw/uefi/var-service-isa.c | 91 +++++++++++++++++++++++++++++++++++++++
8
hw/uefi/Kconfig | 6 +++
8
hw/uefi/Kconfig | 6 +++
9
hw/uefi/meson.build | 5 +++
9
hw/uefi/meson.build | 5 +++
10
3 files changed, 99 insertions(+)
10
3 files changed, 102 insertions(+)
11
create mode 100644 hw/uefi/var-service-isa.c
11
create mode 100644 hw/uefi/var-service-isa.c
12
12
13
diff --git a/hw/uefi/var-service-isa.c b/hw/uefi/var-service-isa.c
13
diff --git a/hw/uefi/var-service-isa.c b/hw/uefi/var-service-isa.c
14
new file mode 100644
14
new file mode 100644
15
index XXXXXXX..XXXXXXX
15
index XXXXXXX..XXXXXXX
...
...
45
+ vmstate_uefi_vars, uefi_vars_state),
45
+ vmstate_uefi_vars, uefi_vars_state),
46
+ VMSTATE_END_OF_LIST()
46
+ VMSTATE_END_OF_LIST()
47
+ }
47
+ }
48
+};
48
+};
49
+
49
+
50
+static Property uefi_vars_isa_properties[] = {
50
+static const Property uefi_vars_isa_properties[] = {
51
+ DEFINE_PROP_SIZE("size", uefi_vars_isa_state, state.max_storage,
51
+ DEFINE_PROP_SIZE("size", uefi_vars_isa_state, state.max_storage,
52
+ 256 * 1024),
52
+ 256 * 1024),
53
+ DEFINE_PROP_STRING("jsonfile", uefi_vars_isa_state, state.jsonfile),
53
+ DEFINE_PROP_STRING("jsonfile", uefi_vars_isa_state, state.jsonfile),
54
+ DEFINE_PROP_END_OF_LIST(),
54
+ DEFINE_PROP_BOOL("force-secure-boot", uefi_vars_isa_state,
55
+ state.force_secure_boot, false),
56
+ DEFINE_PROP_BOOL("disable-custom-mode", uefi_vars_isa_state,
57
+ state.disable_custom_mode, false),
55
+};
58
+};
56
+
59
+
57
+static void uefi_vars_isa_init(Object *obj)
60
+static void uefi_vars_isa_init(Object *obj)
58
+{
61
+{
59
+ uefi_vars_isa_state *uv = UEFI_VARS_ISA(obj);
62
+ uefi_vars_isa_state *uv = UEFI_VARS_ISA(obj);
...
...
80
+static void uefi_vars_isa_class_init(ObjectClass *klass, void *data)
83
+static void uefi_vars_isa_class_init(ObjectClass *klass, void *data)
81
+{
84
+{
82
+ DeviceClass *dc = DEVICE_CLASS(klass);
85
+ DeviceClass *dc = DEVICE_CLASS(klass);
83
+
86
+
84
+ dc->realize = uefi_vars_isa_realize;
87
+ dc->realize = uefi_vars_isa_realize;
85
+ dc->reset = uefi_vars_isa_reset;
86
+ dc->vmsd = &vmstate_uefi_vars_isa;
88
+ dc->vmsd = &vmstate_uefi_vars_isa;
89
+ device_class_set_legacy_reset(dc, uefi_vars_isa_reset);
87
+ device_class_set_props(dc, uefi_vars_isa_properties);
90
+ device_class_set_props(dc, uefi_vars_isa_properties);
88
+ set_bit(DEVICE_CATEGORY_MISC, dc->categories);
91
+ set_bit(DEVICE_CATEGORY_MISC, dc->categories);
89
+}
92
+}
90
+
93
+
91
+static const TypeInfo uefi_vars_isa_info = {
94
+static const TypeInfo uefi_vars_isa_info = {
...
...
120
+ depends on ISA_BUS
123
+ depends on ISA_BUS
121
diff --git a/hw/uefi/meson.build b/hw/uefi/meson.build
124
diff --git a/hw/uefi/meson.build b/hw/uefi/meson.build
122
index XXXXXXX..XXXXXXX 100644
125
index XXXXXXX..XXXXXXX 100644
123
--- a/hw/uefi/meson.build
126
--- a/hw/uefi/meson.build
124
+++ b/hw/uefi/meson.build
127
+++ b/hw/uefi/meson.build
125
@@ -XXX,XX +XXX,XX @@ uefi_vars_ss.add(when: 'CONFIG_UEFI_VARS',
128
@@ -XXX,XX +XXX,XX @@ if (config_all_devices.has_key('CONFIG_UEFI_VARS'))
126
'var-service-policy.c',
129
uefi_vars_ss.add(files('var-service-siglist.c'))
127
'var-service-sysbus.c'))
130
endif
128
131
129
+uefi_vars_isa_ss = ss.source_set()
132
+uefi_vars_isa_ss = ss.source_set()
130
+uefi_vars_isa_ss.add(when: 'CONFIG_UEFI_VARS_ISA',
133
+uefi_vars_isa_ss.add(when: 'CONFIG_UEFI_VARS_ISA',
131
+ if_true: files('var-service-isa.c'))
134
+ if_true: files('var-service-isa.c'))
132
+
135
+
133
modules += { 'hw-uefi' : {
136
modules += { 'hw-uefi' : {
134
'vars' : uefi_vars_ss,
137
'vars' : uefi_vars_ss,
135
+ 'vars-isa' : uefi_vars_isa_ss,
138
+ 'vars-isa' : uefi_vars_isa_ss,
136
}}
139
}}
137
--
140
--
138
2.41.0
141
2.47.1
diff view generated by jsdifflib
...
...
20
+ VIRT_UEFI_VARS,
20
+ VIRT_UEFI_VARS,
21
VIRT_LOWMEMMAP_LAST,
21
VIRT_LOWMEMMAP_LAST,
22
};
22
};
23
23
24
@@ -XXX,XX +XXX,XX @@ struct VirtMachineState {
24
@@ -XXX,XX +XXX,XX @@ struct VirtMachineState {
25
bool ras;
26
bool mte;
25
bool mte;
27
bool dtb_randomness;
26
bool dtb_randomness;
27
bool second_ns_uart_present;
28
+ bool uefi_vars;
28
+ bool uefi_vars;
29
OnOffAuto acpi;
29
OnOffAuto acpi;
30
VirtGICType gic_version;
30
VirtGICType gic_version;
31
VirtIOMMUType iommu;
31
VirtIOMMUType iommu;
32
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
32
diff --git a/hw/arm/virt.c b/hw/arm/virt.c
...
...
37
#include "hw/intc/arm_gicv3_common.h"
37
#include "hw/intc/arm_gicv3_common.h"
38
#include "hw/intc/arm_gicv3_its_common.h"
38
#include "hw/intc/arm_gicv3_its_common.h"
39
#include "hw/irq.h"
39
#include "hw/irq.h"
40
+#include "hw/uefi/var-service-api.h"
40
+#include "hw/uefi/var-service-api.h"
41
#include "kvm_arm.h"
41
#include "kvm_arm.h"
42
#include "hvf_arm.h"
42
#include "hw/firmware/smbios.h"
43
#include "hw/firmware/smbios.h"
43
#include "qapi/visitor.h"
44
@@ -XXX,XX +XXX,XX @@ static const MemMapEntry base_memmap[] = {
44
@@ -XXX,XX +XXX,XX @@ static const MemMapEntry base_memmap[] = {
45
[VIRT_NVDIMM_ACPI] = { 0x09090000, NVDIMM_ACPI_IO_LEN},
45
[VIRT_NVDIMM_ACPI] = { 0x09090000, NVDIMM_ACPI_IO_LEN},
46
[VIRT_PVTIME] = { 0x090a0000, 0x00010000 },
46
[VIRT_PVTIME] = { 0x090a0000, 0x00010000 },
47
[VIRT_SECURE_GPIO] = { 0x090b0000, 0x00001000 },
47
[VIRT_SECURE_GPIO] = { 0x090b0000, 0x00001000 },
48
+ [VIRT_UEFI_VARS] = { 0x090c0000, 0x00000010 },
48
+ [VIRT_UEFI_VARS] = { 0x090c0000, 0x00000010 },
...
...
115
+ virt_set_uefi_vars);
115
+ virt_set_uefi_vars);
116
}
116
}
117
117
118
static void virt_instance_init(Object *obj)
118
static void virt_instance_init(Object *obj)
119
--
119
--
120
2.41.0
120
2.47.1
diff view generated by jsdifflib
1
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
1
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2
---
2
---
3
docs/devel/index-internals.rst | 1 +
3
docs/devel/index-internals.rst | 1 +
4
docs/devel/uefi-vars.rst | 66 ++++++++++++++++++++++++++++++++++
4
docs/devel/uefi-vars.rst | 66 ++++++++++++++++++++++++++++++++++
5
hw/uefi/TODO.md | 17 +++++++++
5
hw/uefi/LIMITATIONS.md | 7 ++++
6
3 files changed, 84 insertions(+)
6
3 files changed, 74 insertions(+)
7
create mode 100644 docs/devel/uefi-vars.rst
7
create mode 100644 docs/devel/uefi-vars.rst
8
create mode 100644 hw/uefi/TODO.md
8
create mode 100644 hw/uefi/LIMITATIONS.md
9
9
10
diff --git a/docs/devel/index-internals.rst b/docs/devel/index-internals.rst
10
diff --git a/docs/devel/index-internals.rst b/docs/devel/index-internals.rst
11
index XXXXXXX..XXXXXXX 100644
11
index XXXXXXX..XXXXXXX 100644
12
--- a/docs/devel/index-internals.rst
12
--- a/docs/devel/index-internals.rst
13
+++ b/docs/devel/index-internals.rst
13
+++ b/docs/devel/index-internals.rst
14
@@ -XXX,XX +XXX,XX @@ Details about QEMU's various subsystems including how to add features to them.
14
@@ -XXX,XX +XXX,XX @@ Details about QEMU's various subsystems including how to add features to them.
15
s390-cpu-topology
15
s390-cpu-topology
16
s390-dasd-ipl
16
s390-dasd-ipl
17
tracing
17
tracing
18
+ uefi-vars
18
+ uefi-vars
19
vfio-migration
19
vfio-iommufd
20
writing-monitor-commands
20
writing-monitor-commands
21
virtio-backends
21
virtio-backends
22
diff --git a/docs/devel/uefi-vars.rst b/docs/devel/uefi-vars.rst
22
diff --git a/docs/devel/uefi-vars.rst b/docs/devel/uefi-vars.rst
23
new file mode 100644
23
new file mode 100644
24
index XXXXXXX..XXXXXXX
24
index XXXXXXX..XXXXXXX
...
...
30
+==============
30
+==============
31
+
31
+
32
+Guest UEFI variable management
32
+Guest UEFI variable management
33
+==============================
33
+==============================
34
+
34
+
35
+Traditional approach for UEFI Variable storage in qemu guests is to
35
+The traditional approach for UEFI Variable storage in qemu guests is
36
+work as close as possible to physical hardware. That means provide
36
+to work as close as possible to physical hardware. That means
37
+pflash as storage and leave the management of variables and flash to
37
+providing pflash as storage and leaving the management of variables
38
+the guest.
38
+and flash to the guest.
39
+
39
+
40
+Secure boot support comes with the requirement that the UEFI variable
40
+Secure boot support comes with the requirement that the UEFI variable
41
+storage must be protected against direct access by the OS. All update
41
+storage must be protected against direct access by the OS. All update
42
+requests must pass the sanity checks. (Parts of) the firmware must
42
+requests must pass the sanity checks. (Parts of) the firmware must
43
+run with a higher priviledge level than the OS so this can be enforced
43
+run with a higher privilege level than the OS so this can be enforced
44
+by the firmware. On x86 this has been implemented using System
44
+by the firmware. On x86 this has been implemented using System
45
+Management Mode (SMM) in qemu and kvm, which again is the same
45
+Management Mode (SMM) in qemu and kvm, which again is the same
46
+approach taken by physical hardware. Only priviedged code running in
46
+approach taken by physical hardware. Only privileged code running in
47
+SMM mode is allowed to access flash storage.
47
+SMM mode is allowed to access flash storage.
48
+
48
+
49
+Communication with the firmware code running in SMM mode works by
49
+Communication with the firmware code running in SMM mode works by
50
+serializing the requests to a shared buffer, then trapping into SMM
50
+serializing the requests to a shared buffer, then trapping into SMM
51
+mode via SMI. The SMM code processes the request, stores the reply in
51
+mode via SMI. The SMM code processes the request, stores the reply in
52
+the same buffer and returns.
52
+the same buffer and returns.
53
+
53
+
54
+Host UEFI variable service
54
+Host UEFI variable service
55
+==========================
55
+==========================
56
+
56
+
57
+Instead of running the priviledged code inside the guest we can run it
57
+Instead of running the privileged code inside the guest we can run it
58
+on the host. The serialization protocol cen be reused. The
58
+on the host. The serialization protocol can be reused. The
59
+communication with the host uses a virtual device, which essentially
59
+communication with the host uses a virtual device, which essentially
60
+allows to configure the shared buffer location and size and to trap to
60
+configures the shared buffer location and size, and traps to the host
61
+the host to process the requests.
61
+to process the requests.
62
+
62
+
63
+The ``uefi-vars`` device implements the UEFI virtual device. It comes
63
+The ``uefi-vars`` device implements the UEFI virtual device. It comes
64
+in ``uefi-vars-isa`` and ``uefi-vars-sysbus`` flavours. The device
64
+in ``uefi-vars-isa`` and ``uefi-vars-sysbus`` flavours. The device
65
+reimplements the handlers needed, specifically
65
+reimplements the handlers needed, specifically
66
+``EfiSmmVariableProtocol`` and ``VarCheckPolicyLibMmiHandler``. It
66
+``EfiSmmVariableProtocol`` and ``VarCheckPolicyLibMmiHandler``. It
67
+also consumes events (``EfiEndOfDxeEventGroup``,
67
+also consumes events (``EfiEndOfDxeEventGroup``,
68
+``EfiEventReadyToBoot`` and ``EfiEventExitBootServices``).
68
+``EfiEventReadyToBoot`` and ``EfiEventExitBootServices``).
69
+
69
+
70
+The advantage of the approach is that we do not need a special
70
+The advantage of the approach is that we do not need a special
71
+prividge level for the firmware to protect itself, i.e. it does not
71
+privilege level for the firmware to protect itself, i.e. it does not
72
+depend on SMM emulation on x64, which allows to remove a bunch of
72
+depend on SMM emulation on x64, which allows the removal of a bunch of
73
+complex code for SMM emulation from the linux kernel
73
+complex code for SMM emulation from the linux kernel
74
+(CONFIG_KVM_SMM=n). It also allows to support secure boot on arm
74
+(CONFIG_KVM_SMM=n). It also allows support for secure boot on arm
75
+without implementing secure world (el3) emulation in kvm.
75
+without implementing secure world (el3) emulation in kvm.
76
+
76
+
77
+Of course there are also downsides. The added device increases the
77
+Of course there are also downsides. The added device increases the
78
+attack surface of the host, and we are adding some code duplication
78
+attack surface of the host, and we are adding some code duplication
79
+because we have to reimplement some edk2 functionality in qemu.
79
+because we have to reimplement some edk2 functionality in qemu.
...
...
89
+-------------------------
89
+-------------------------
90
+
90
+
91
+.. code::
91
+.. code::
92
+
92
+
93
+ qemu-system-aarch64 -M virt,x-uefi-vars=on
93
+ qemu-system-aarch64 -M virt,x-uefi-vars=on
94
diff --git a/hw/uefi/TODO.md b/hw/uefi/TODO.md
94
diff --git a/hw/uefi/LIMITATIONS.md b/hw/uefi/LIMITATIONS.md
95
new file mode 100644
95
new file mode 100644
96
index XXXXXXX..XXXXXXX
96
index XXXXXXX..XXXXXXX
97
--- /dev/null
97
--- /dev/null
98
+++ b/hw/uefi/TODO.md
98
+++ b/hw/uefi/LIMITATIONS.md
99
@@ -XXX,XX +XXX,XX @@
99
@@ -XXX,XX +XXX,XX @@
100
+
101
+uefi variable service - todo list
102
+---------------------------------
103
+
104
+* implement reading/writing variable update time.
105
+* implement authenticated variable updates.
106
+ - used for 'dbx' updates.
107
+
108
+known issues and limitations
100
+known issues and limitations
109
+----------------------------
101
+----------------------------
110
+
102
+
111
+* secure boot variables are read-only
112
+ - due to auth vars not being implemented yet.
113
+* works only on little endian hosts
103
+* works only on little endian hosts
114
+ - accessing structs in guest ram is done without endian conversion.
104
+ - accessing structs in guest ram is done without endian conversion.
115
+* works only for 64-bit guests
105
+* works only for 64-bit guests
116
+ - UINTN is mapped to uint64_t, for 32-bit guests that would be uint32_t
106
+ - UINTN is mapped to uint64_t, for 32-bit guests that would be uint32_t
117
--
107
--
118
2.41.0
108
2.47.1
diff view generated by jsdifflib
New patch
1
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
2
---
3
MAINTAINERS | 6 ++++++
4
1 file changed, 6 insertions(+)
1
5
6
diff --git a/MAINTAINERS b/MAINTAINERS
7
index XXXXXXX..XXXXXXX 100644
8
--- a/MAINTAINERS
9
+++ b/MAINTAINERS
10
@@ -XXX,XX +XXX,XX @@ F: hw/hyperv/hv-balloon*.h
11
F: include/hw/hyperv/dynmem-proto.h
12
F: include/hw/hyperv/hv-balloon.h
13
14
+UEFI variable service
15
+M: Gerd Hoffmann <kraxel@redhat.com>
16
+S: Maintained
17
+F: hw/uefi/
18
+F: include/hw/uefi/
19
+
20
Subsystems
21
----------
22
Overall Audio backends
23
--
24
2.47.1
diff view generated by jsdifflib