]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/kernel-image.c
cryptenroll: allow to use a public key on a token
[thirdparty/systemd.git] / src / shared / kernel-image.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include "fd-util.h"
4 #include "fileio.h"
5 #include "env-file.h"
6 #include "kernel-image.h"
7 #include "os-util.h"
8 #include "parse-util.h"
9 #include "pe-binary.h"
10 #include "string-table.h"
11
12 #define PE_SECTION_READ_MAX (16U*1024U)
13
14 static const char * const kernel_image_type_table[_KERNEL_IMAGE_TYPE_MAX] = {
15 [KERNEL_IMAGE_TYPE_UNKNOWN] = "unknown",
16 [KERNEL_IMAGE_TYPE_UKI] = "uki",
17 [KERNEL_IMAGE_TYPE_PE] = "pe",
18 };
19
20 DEFINE_STRING_TABLE_LOOKUP_TO_STRING(kernel_image_type, KernelImageType);
21
22 static int uki_read_pretty_name(
23 int fd,
24 const PeHeader *pe_header,
25 const IMAGE_SECTION_HEADER *sections,
26 char **ret) {
27
28 _cleanup_free_ char *pname = NULL, *name = NULL;
29 _cleanup_fclose_ FILE *f = NULL;
30 _cleanup_free_ void *osrel = NULL;
31 size_t osrel_size;
32 int r;
33
34 assert(fd >= 0);
35 assert(pe_header);
36 assert(sections || le16toh(pe_header->pe.NumberOfSections) == 0);
37 assert(ret);
38
39 r = pe_read_section_data(
40 fd,
41 pe_header,
42 sections,
43 ".osrel",
44 /* max_size=*/ PE_SECTION_READ_MAX,
45 &osrel,
46 &osrel_size);
47 if (r == -ENXIO) { /* Section not found */
48 *ret = NULL;
49 return 0;
50 }
51
52 f = fmemopen(osrel, osrel_size, "r");
53 if (!f)
54 return log_error_errno(errno, "Failed to open embedded os-release file: %m");
55
56 r = parse_env_file(
57 f, NULL,
58 "PRETTY_NAME", &pname,
59 "NAME", &name);
60 if (r < 0)
61 return log_error_errno(r, "Failed to parse embedded os-release file: %m");
62
63 /* follow the same logic as os_release_pretty_name() */
64 if (!isempty(pname))
65 *ret = TAKE_PTR(pname);
66 else if (!isempty(name))
67 *ret = TAKE_PTR(name);
68 else {
69 char *n = strdup("Linux");
70 if (!n)
71 return log_oom();
72
73 *ret = n;
74 }
75
76 return 0;
77 }
78
79 static int inspect_uki(
80 int fd,
81 const PeHeader *pe_header,
82 const IMAGE_SECTION_HEADER *sections,
83 char **ret_cmdline,
84 char **ret_uname,
85 char **ret_pretty_name) {
86
87 _cleanup_free_ char *cmdline = NULL, *uname = NULL, *pname = NULL;
88 int r;
89
90 assert(fd >= 0);
91 assert(sections || le16toh(pe_header->pe.NumberOfSections) == 0);
92
93 if (ret_cmdline) {
94 r = pe_read_section_data(fd, pe_header, sections, ".cmdline", PE_SECTION_READ_MAX, (void**) &cmdline, NULL);
95 if (r < 0 && r != -ENXIO) /* If the section doesn't exist, that's fine */
96 return r;
97 }
98
99 if (ret_uname) {
100 r = pe_read_section_data(fd, pe_header, sections, ".uname", PE_SECTION_READ_MAX, (void**) &uname, NULL);
101 if (r < 0 && r != -ENXIO) /* If the section doesn't exist, that's fine */
102 return r;
103 }
104
105 if (ret_pretty_name) {
106 r = uki_read_pretty_name(fd, pe_header, sections, &pname);
107 if (r < 0)
108 return r;
109 }
110
111 if (ret_cmdline)
112 *ret_cmdline = TAKE_PTR(cmdline);
113 if (ret_uname)
114 *ret_uname = TAKE_PTR(uname);
115 if (ret_pretty_name)
116 *ret_pretty_name = TAKE_PTR(pname);
117
118 return 0;
119 }
120
121 int inspect_kernel(
122 int dir_fd,
123 const char *filename,
124 KernelImageType *ret_type,
125 char **ret_cmdline,
126 char **ret_uname,
127 char **ret_pretty_name) {
128
129 _cleanup_free_ IMAGE_SECTION_HEADER *sections = NULL;
130 _cleanup_free_ IMAGE_DOS_HEADER *dos_header = NULL;
131 KernelImageType t = KERNEL_IMAGE_TYPE_UNKNOWN;
132 _cleanup_free_ PeHeader *pe_header = NULL;
133 _cleanup_close_ int fd = -EBADF;
134 int r;
135
136 assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
137 assert(filename);
138
139 fd = openat(dir_fd, filename, O_RDONLY|O_CLOEXEC);
140 if (fd < 0)
141 return log_error_errno(errno, "Failed to open kernel image file '%s': %m", filename);
142
143 r = pe_load_headers(fd, &dos_header, &pe_header);
144 if (r == -EBADMSG) /* not a valid PE file */
145 goto not_uki;
146 if (r < 0)
147 return log_error_errno(r, "Failed to parse kernel image file '%s': %m", filename);
148
149 r = pe_load_sections(fd, dos_header, pe_header, &sections);
150 if (r == -EBADMSG) /* not a valid PE file */
151 goto not_uki;
152 if (r < 0)
153 return log_error_errno(r, "Failed to load PE sections from kernel image file '%s': %m", filename);
154
155 if (pe_is_uki(pe_header, sections)) {
156 r = inspect_uki(fd, pe_header, sections, ret_cmdline, ret_uname, ret_pretty_name);
157 if (r < 0)
158 return r;
159
160 t = KERNEL_IMAGE_TYPE_UKI;
161 goto done;
162 } else
163 t = KERNEL_IMAGE_TYPE_PE;
164
165 not_uki:
166 if (ret_cmdline)
167 *ret_cmdline = NULL;
168 if (ret_uname)
169 *ret_uname = NULL;
170 if (ret_pretty_name)
171 *ret_pretty_name = NULL;
172
173 done:
174 if (ret_type)
175 *ret_type = t;
176
177 return 0;
178 }