1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
6 #include "kernel-image.h"
8 #include "parse-util.h"
10 #include "string-table.h"
12 #define PE_SECTION_READ_MAX (16U*1024U)
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",
20 DEFINE_STRING_TABLE_LOOKUP_TO_STRING(kernel_image_type
, KernelImageType
);
22 static int uki_read_pretty_name(
24 const PeHeader
*pe_header
,
25 const IMAGE_SECTION_HEADER
*sections
,
28 _cleanup_free_
char *pname
= NULL
, *name
= NULL
;
29 _cleanup_fclose_
FILE *f
= NULL
;
30 _cleanup_free_
void *osrel
= NULL
;
36 assert(sections
|| le16toh(pe_header
->pe
.NumberOfSections
) == 0);
39 r
= pe_read_section_data(
44 /* max_size=*/ PE_SECTION_READ_MAX
,
47 if (r
== -ENXIO
) { /* Section not found */
52 f
= fmemopen(osrel
, osrel_size
, "r");
54 return log_error_errno(errno
, "Failed to open embedded os-release file: %m");
58 "PRETTY_NAME", &pname
,
61 return log_error_errno(r
, "Failed to parse embedded os-release file: %m");
63 /* follow the same logic as os_release_pretty_name() */
65 *ret
= TAKE_PTR(pname
);
66 else if (!isempty(name
))
67 *ret
= TAKE_PTR(name
);
69 char *n
= strdup("Linux");
79 static int inspect_uki(
81 const PeHeader
*pe_header
,
82 const IMAGE_SECTION_HEADER
*sections
,
85 char **ret_pretty_name
) {
87 _cleanup_free_
char *cmdline
= NULL
, *uname
= NULL
, *pname
= NULL
;
91 assert(sections
|| le16toh(pe_header
->pe
.NumberOfSections
) == 0);
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 */
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 */
105 if (ret_pretty_name
) {
106 r
= uki_read_pretty_name(fd
, pe_header
, sections
, &pname
);
112 *ret_cmdline
= TAKE_PTR(cmdline
);
114 *ret_uname
= TAKE_PTR(uname
);
116 *ret_pretty_name
= TAKE_PTR(pname
);
123 const char *filename
,
124 KernelImageType
*ret_type
,
127 char **ret_pretty_name
) {
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
;
136 assert(dir_fd
>= 0 || dir_fd
== AT_FDCWD
);
139 fd
= openat(dir_fd
, filename
, O_RDONLY
|O_CLOEXEC
);
141 return log_error_errno(errno
, "Failed to open kernel image file '%s': %m", filename
);
143 r
= pe_load_headers(fd
, &dos_header
, &pe_header
);
144 if (r
== -EBADMSG
) /* not a valid PE file */
147 return log_error_errno(r
, "Failed to parse kernel image file '%s': %m", filename
);
149 r
= pe_load_sections(fd
, dos_header
, pe_header
, §ions
);
150 if (r
== -EBADMSG
) /* not a valid PE file */
153 return log_error_errno(r
, "Failed to load PE sections from kernel image file '%s': %m", filename
);
155 if (pe_is_uki(pe_header
, sections
)) {
156 r
= inspect_uki(fd
, pe_header
, sections
, ret_cmdline
, ret_uname
, ret_pretty_name
);
160 t
= KERNEL_IMAGE_TYPE_UKI
;
163 t
= KERNEL_IMAGE_TYPE_PE
;
171 *ret_pretty_name
= NULL
;