2016-11-22 04:16:43

by Mehmet Kayaalp

[permalink] [raw]
Subject:

>From e8196ab86d10c24a9ebc87a1007a4047dc77bab8 Mon Sep 17 00:00:00 2001
From: Mehmet Kayaalp <[email protected]>
Date: Mon, 21 Nov 2016 15:46:20 -0500
Subject: [PATCH v3 0/4] Certificate insertion support for x86 bzImages

These patches add support for modifying the reserved space for extra
certificates in a compressed bzImage in x86. This allows separating the
system keyring certificate from the kernel build process. After the kernel
image is distributed, the insert-sys-cert script can be used to insert the
certificate for x86.

Changes:

v3:
* Rewrote 1/4 to insert incompressible bytes are at build time. Previous
solution required changes to <arch>/boot/Makefile's for modifying the
vmlinux file after linking, and did not work well with cross compilation.
* Added 2/4 for ELF class-independent processing of vmlinux file, in case the
script was compiled for 64-bit and the kernel was compiled for 32-bit.
* Reordered 3/4, added x86 bzImage boot version (>=2.08) verification.

v2:
* Rebased arch/boot/x86/Makefile patch (removed in v3)

Mehmet Kayaalp (4):
KEYS: Insert incompressible bytes to reserve space in bzImage
KEYS: Add ELF class-independent certificate insertion support
KEYS: Support for inserting a certificate into x86 bzImage
KEYS: Print insert-sys-cert information to stdout instead of stderr

certs/Makefile | 21 +-
certs/system_certificates.S | 2 +-
scripts/Makefile | 1 +
scripts/insert-sys-cert.c | 455 +++++++++++++++++++++++++++++++++-----------
4 files changed, 362 insertions(+), 117 deletions(-)

--
2.7.4


2016-11-22 04:16:45

by Mehmet Kayaalp

[permalink] [raw]
Subject: [PATCH 2/4] KEYS: Add ELF class-independent certificate insertion support

Use ELF class-independent GElf API for processing the kernel binary.

Signed-off-by: Mehmet Kayaalp <[email protected]>
---
scripts/Makefile | 1 +
scripts/insert-sys-cert.c | 215 +++++++++++++++++++++++-----------------------
2 files changed, 109 insertions(+), 107 deletions(-)

diff --git a/scripts/Makefile b/scripts/Makefile
index 1d80897..5633f2c 100644
--- a/scripts/Makefile
+++ b/scripts/Makefile
@@ -25,6 +25,7 @@ HOSTCFLAGS_sortextable.o = -I$(srctree)/tools/include
HOSTCFLAGS_asn1_compiler.o = -I$(srctree)/include
HOSTLOADLIBES_sign-file = -lcrypto
HOSTLOADLIBES_extract-cert = -lcrypto
+HOSTLOADLIBES_insert-sys-cert = -lelf

always := $(hostprogs-y) $(hostprogs-m)

diff --git a/scripts/insert-sys-cert.c b/scripts/insert-sys-cert.c
index 8902836..c4c6205 100644
--- a/scripts/insert-sys-cert.c
+++ b/scripts/insert-sys-cert.c
@@ -24,7 +24,7 @@
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
-#include <elf.h>
+#include <gelf.h>

#define CERT_SYM "system_extra_cert"
#define USED_SYM "system_extra_cert_used"
@@ -34,18 +34,6 @@
#define warn(format, args...) fprintf(stdout, "WARNING: " format, ## args)
#define err(format, args...) fprintf(stderr, "ERROR: " format, ## args)

-#if UINTPTR_MAX == 0xffffffff
-#define CURRENT_ELFCLASS ELFCLASS32
-#define Elf_Ehdr Elf32_Ehdr
-#define Elf_Shdr Elf32_Shdr
-#define Elf_Sym Elf32_Sym
-#else
-#define CURRENT_ELFCLASS ELFCLASS64
-#define Elf_Ehdr Elf64_Ehdr
-#define Elf_Shdr Elf64_Shdr
-#define Elf_Sym Elf64_Sym
-#endif
-
static unsigned char endianness(void)
{
uint16_t two_byte = 0x00FF;
@@ -65,22 +53,17 @@ struct sym {
int size;
};

-static unsigned long get_offset_from_address(Elf_Ehdr *hdr, unsigned long addr)
+static unsigned long get_offset_from_address(Elf *elf, unsigned long addr)
{
- Elf_Shdr *x;
- unsigned int i, num_sections;
-
- x = (void *)hdr + hdr->e_shoff;
- if (hdr->e_shnum == SHN_UNDEF)
- num_sections = x[0].sh_size;
- else
- num_sections = hdr->e_shnum;
-
- for (i = 1; i < num_sections; i++) {
- unsigned long start = x[i].sh_addr;
- unsigned long end = start + x[i].sh_size;
- unsigned long offset = x[i].sh_offset;
-
+ Elf_Scn *scn = NULL;
+ GElf_Shdr shdr;
+ unsigned long start, end, offset;
+
+ while ((scn = elf_nextscn(elf, scn)) != NULL) {
+ gelf_getshdr(scn, &shdr);
+ start = shdr.sh_addr;
+ end = start + shdr.sh_size;
+ offset = shdr.sh_offset;
if (addr >= start && addr <= end)
return addr - start + offset;
}
@@ -90,7 +73,7 @@ static unsigned long get_offset_from_address(Elf_Ehdr *hdr, unsigned long addr)

#define LINE_SIZE 100

-static void get_symbol_from_map(Elf_Ehdr *hdr, FILE *f, char *name,
+static void get_symbol_from_map(Elf *elf, void *base, FILE *f, char *name,
struct sym *s)
{
char l[LINE_SIZE];
@@ -125,76 +108,65 @@ static void get_symbol_from_map(Elf_Ehdr *hdr, FILE *f, char *name,
s->address = strtoul(l, NULL, 16);
if (s->address == 0)
return;
- s->offset = get_offset_from_address(hdr, s->address);
+ s->offset = get_offset_from_address(elf, s->address);
s->name = name;
- s->content = (void *)hdr + s->offset;
-}
-
-static Elf_Sym *find_elf_symbol(Elf_Ehdr *hdr, Elf_Shdr *symtab, char *name)
-{
- Elf_Sym *sym, *symtab_start;
- char *strtab, *symname;
- unsigned int link;
- Elf_Shdr *x;
- int i, n;
-
- x = (void *)hdr + hdr->e_shoff;
- link = symtab->sh_link;
- symtab_start = (void *)hdr + symtab->sh_offset;
- n = symtab->sh_size / symtab->sh_entsize;
- strtab = (void *)hdr + x[link].sh_offset;
-
- for (i = 0; i < n; i++) {
- sym = &symtab_start[i];
- symname = strtab + sym->st_name;
- if (strcmp(symname, name) == 0)
- return sym;
- }
- err("Unable to find symbol: %s\n", name);
- return NULL;
+ s->content = (void *)base + s->offset;
}

-static void get_symbol_from_table(Elf_Ehdr *hdr, Elf_Shdr *symtab,
+static void get_symbol_from_table(Elf *elf, Elf_Scn *symtab, void *base,
char *name, struct sym *s)
{
- Elf_Shdr *sec;
- int secndx;
- Elf_Sym *elf_sym;
- Elf_Shdr *x;
+ GElf_Shdr shdr;
+ Elf_Data *data;
+ int count;
+ int i;
+ GElf_Sym sym;
+ char *symname;
+ int found = 0;
+ size_t secndx;
+ Elf_Scn *sec;
+
+ gelf_getshdr(symtab, &shdr);
+ data = elf_getdata(symtab, NULL);
+ count = shdr.sh_size / shdr.sh_entsize;
+
+ for (i = 0; i < count; i++) {
+ gelf_getsym(data, i, &sym);
+ symname = elf_strptr(elf, shdr.sh_link, sym.st_name);
+ if (strcmp(symname, name) == 0) {
+ found = 1;
+ break;
+ }
+ }

- x = (void *)hdr + hdr->e_shoff;
s->size = 0;
s->address = 0;
s->offset = 0;
- elf_sym = find_elf_symbol(hdr, symtab, name);
- if (!elf_sym)
+ if (!found)
return;
- secndx = elf_sym->st_shndx;
+ secndx = sym.st_shndx;
if (!secndx)
return;
- sec = &x[secndx];
- s->size = elf_sym->st_size;
- s->address = elf_sym->st_value;
- s->offset = s->address - sec->sh_addr
- + sec->sh_offset;
+ sec = elf_getscn(elf, secndx);
+ gelf_getshdr(sec, &shdr);
+ s->size = sym.st_size;
+ s->address = sym.st_value;
+ s->offset = s->address - shdr.sh_addr
+ + shdr.sh_offset;
s->name = name;
- s->content = (void *)hdr + s->offset;
+ s->content = base + s->offset;
}

-static Elf_Shdr *get_symbol_table(Elf_Ehdr *hdr)
+static Elf_Scn *get_symbol_table(Elf *elf)
{
- Elf_Shdr *x;
- unsigned int i, num_sections;
-
- x = (void *)hdr + hdr->e_shoff;
- if (hdr->e_shnum == SHN_UNDEF)
- num_sections = x[0].sh_size;
- else
- num_sections = hdr->e_shnum;
+ Elf_Scn *scn = NULL;
+ GElf_Shdr shdr;

- for (i = 1; i < num_sections; i++)
- if (x[i].sh_type == SHT_SYMTAB)
- return &x[i];
+ while ((scn = elf_nextscn(elf, scn)) != NULL) {
+ gelf_getshdr(scn, &shdr);
+ if (shdr.sh_type == SHT_SYMTAB)
+ return scn;
+ }
return NULL;
}

@@ -206,6 +178,7 @@ static void *map_file(char *file_name, int *size)

fd = open(file_name, O_RDWR);
if (fd < 0) {
+ err("Open failed\n");
perror(file_name);
return NULL;
}
@@ -257,7 +230,7 @@ static char *read_file(char *file_name, int *size)
return buf;
}

-static void print_sym(Elf_Ehdr *hdr, struct sym *s)
+static void print_sym(struct sym *s)
{
info("sym: %s\n", s->name);
info("addr: 0x%lx\n", s->address);
@@ -277,14 +250,15 @@ int main(int argc, char **argv)
char *cert_file = NULL;
int vmlinux_size;
int cert_size;
- Elf_Ehdr *hdr;
+ char *vmlinux;
char *cert;
FILE *system_map;
- unsigned long *lsize;
int *used;
int opt;
- Elf_Shdr *symtab = NULL;
struct sym cert_sym, lsize_sym, used_sym;
+ Elf *elf;
+ GElf_Ehdr hdr_s, *hdr;
+ Elf_Scn *symtab = NULL;

while ((opt = getopt(argc, argv, "b:c:s:")) != -1) {
switch (opt) {
@@ -311,12 +285,24 @@ int main(int argc, char **argv)
if (!cert)
exit(EXIT_FAILURE);

- hdr = map_file(vmlinux_file, &vmlinux_size);
- if (!hdr)
+ vmlinux = map_file(vmlinux_file, &vmlinux_size);
+ if (!vmlinux)
exit(EXIT_FAILURE);

- if (vmlinux_size < sizeof(*hdr)) {
- err("Invalid ELF file.\n");
+ if (elf_version(EV_CURRENT) == EV_NONE) {
+ err("Init libelf failed.\n");
+ exit(EXIT_FAILURE);
+ }
+
+ elf = elf_memory(vmlinux, vmlinux_size);
+ if (elf == NULL) {
+ err("Unable to read Elf: %s\n", elf_errmsg(elf_errno()));
+ exit(EXIT_FAILURE);
+ }
+
+ hdr = gelf_getehdr(elf, &hdr_s);
+ if (hdr == NULL) {
+ err("Unable to read Elf_hdr: %s\n", elf_errmsg(elf_errno()));
exit(EXIT_FAILURE);
}

@@ -328,11 +314,6 @@ int main(int argc, char **argv)
exit(EXIT_FAILURE);
}

- if (hdr->e_ident[EI_CLASS] != CURRENT_ELFCLASS) {
- err("ELF class mismatch.\n");
- exit(EXIT_FAILURE);
- }
-
if (hdr->e_ident[EI_DATA] != endianness()) {
err("ELF endian mismatch.\n");
exit(EXIT_FAILURE);
@@ -343,7 +324,7 @@ int main(int argc, char **argv)
exit(EXIT_FAILURE);
}

- symtab = get_symbol_table(hdr);
+ symtab = get_symbol_table(elf);
if (!symtab) {
warn("Could not find the symbol table.\n");
if (!system_map_file) {
@@ -357,27 +338,32 @@ int main(int argc, char **argv)
perror(system_map_file);
exit(EXIT_FAILURE);
}
- get_symbol_from_map(hdr, system_map, CERT_SYM, &cert_sym);
- get_symbol_from_map(hdr, system_map, USED_SYM, &used_sym);
- get_symbol_from_map(hdr, system_map, LSIZE_SYM, &lsize_sym);
+ get_symbol_from_map(elf, vmlinux, system_map,
+ CERT_SYM, &cert_sym);
+ get_symbol_from_map(elf, vmlinux, system_map,
+ USED_SYM, &used_sym);
+ get_symbol_from_map(elf, vmlinux, system_map,
+ LSIZE_SYM, &lsize_sym);
cert_sym.size = used_sym.address - cert_sym.address;
} else {
info("Symbol table found.\n");
if (system_map_file)
warn("System.map is ignored.\n");
- get_symbol_from_table(hdr, symtab, CERT_SYM, &cert_sym);
- get_symbol_from_table(hdr, symtab, USED_SYM, &used_sym);
- get_symbol_from_table(hdr, symtab, LSIZE_SYM, &lsize_sym);
+ get_symbol_from_table(elf, symtab, vmlinux,
+ CERT_SYM, &cert_sym);
+ get_symbol_from_table(elf, symtab, vmlinux,
+ USED_SYM, &used_sym);
+ get_symbol_from_table(elf, symtab, vmlinux,
+ LSIZE_SYM, &lsize_sym);
}

if (!cert_sym.offset || !lsize_sym.offset || !used_sym.offset)
exit(EXIT_FAILURE);

- print_sym(hdr, &cert_sym);
- print_sym(hdr, &used_sym);
- print_sym(hdr, &lsize_sym);
+ print_sym(&cert_sym);
+ print_sym(&used_sym);
+ print_sym(&lsize_sym);

- lsize = (unsigned long *)lsize_sym.content;
used = (int *)used_sym.content;

if (cert_sym.size < cert_size) {
@@ -400,11 +386,26 @@ int main(int argc, char **argv)
memset(cert_sym.content + cert_size,
0, cert_sym.size - cert_size);

- *lsize = *lsize + cert_size - *used;
+ if (hdr->e_ident[EI_CLASS] == ELFCLASS64) {
+ uint64_t *lsize;
+
+ lsize = (uint64_t *)lsize_sym.content;
+ *lsize = *lsize + cert_size - *used;
+ } else {
+ uint32_t *lsize;
+
+ lsize = (uint32_t *)lsize_sym.content;
+ *lsize = *lsize + cert_size - *used;
+ }
*used = cert_size;
info("Inserted the contents of %s into %lx.\n", cert_file,
cert_sym.address);
info("Used %d bytes out of %d bytes reserved.\n", *used,
cert_sym.size);
+ if (munmap(vmlinux, vmlinux_size) == -1) {
+ perror(vmlinux_file);
+ exit(EXIT_FAILURE);
+ }
+
exit(EXIT_SUCCESS);
}
--
2.7.4

2016-11-22 04:16:42

by Mehmet Kayaalp

[permalink] [raw]
Subject: [PATCH 1/4] KEYS: Insert incompressible bytes to reserve space in bzImage

Include a random filled binary in vmlinux at the space reserved with
CONFIG_SYSTEM_EXTRA_CERTIFICATE. This results in an uncompressed reserved
area inside the bzImage as well, so that it can be replaced with an actual
certificate later (after the bzImage is distributed).

Signed-off-by: Mehmet Kayaalp <[email protected]>
---
certs/Makefile | 21 ++++++++++++++++++---
certs/system_certificates.S | 2 +-
2 files changed, 19 insertions(+), 4 deletions(-)

diff --git a/certs/Makefile b/certs/Makefile
index 2773c4a..294c8bf 100644
--- a/certs/Makefile
+++ b/certs/Makefile
@@ -9,7 +9,12 @@ ifeq ($(CONFIG_SYSTEM_TRUSTED_KEYRING),y)
$(eval $(call config_filename,SYSTEM_TRUSTED_KEYS))

# GCC doesn't include .incbin files in -MD generated dependencies (PR#66871)
-$(obj)/system_certificates.o: $(obj)/x509_certificate_list
+ifeq ($(CONFIG_SYSTEM_EXTRA_CERTIFICATE),y)
+system_certs_incbin = $(obj)/x509_certificate_list $(obj)/extra_cert_placeholder
+else
+system_certs_incbin = $(obj)/x509_certificate_list
+endif
+$(obj)/system_certificates.o: $(system_certs_incbin)

# Cope with signing_key.x509 existing in $(srctree) not $(objtree)
AFLAGS_system_certificates.o := -I$(srctree)
@@ -17,12 +22,22 @@ AFLAGS_system_certificates.o := -I$(srctree)
quiet_cmd_extract_certs = EXTRACT_CERTS $(patsubst "%",%,$(2))
cmd_extract_certs = scripts/extract-cert $(2) $@ || ( rm $@; exit 1)

-targets += x509_certificate_list
+targets += $(system_certs_incbin)
$(obj)/x509_certificate_list: scripts/extract-cert $(SYSTEM_TRUSTED_KEYS_SRCPREFIX)$(SYSTEM_TRUSTED_KEYS_FILENAME) FORCE
$(call if_changed,extract_certs,$(SYSTEM_TRUSTED_KEYS_SRCPREFIX)$(CONFIG_SYSTEM_TRUSTED_KEYS))
+
+ifeq ($(CONFIG_SYSTEM_EXTRA_CERTIFICATE),y)
+# Generate incompressible bytes. Use seed to make it reproducible
+quiet_cmd_placeholder = EXTRA_CERT_PLACEHOLDER
+ cmd_placeholder = perl -e 'srand(0); printf("%c", int(rand(256))) for (1..$(2))' > $@
+
+$(obj)/extra_cert_placeholder: FORCE
+ $(call if_changed,placeholder,$(CONFIG_SYSTEM_EXTRA_CERTIFICATE_SIZE))
+endif
+
endif

-clean-files := x509_certificate_list .x509.list
+clean-files := $(system_certs_incbin) .x509.list

ifeq ($(CONFIG_MODULE_SIG),y)
###############################################################################
diff --git a/certs/system_certificates.S b/certs/system_certificates.S
index c9ceb71..02b9222 100644
--- a/certs/system_certificates.S
+++ b/certs/system_certificates.S
@@ -17,7 +17,7 @@ __cert_list_end:
.globl VMLINUX_SYMBOL(system_extra_cert)
.size system_extra_cert, CONFIG_SYSTEM_EXTRA_CERTIFICATE_SIZE
VMLINUX_SYMBOL(system_extra_cert):
- .fill CONFIG_SYSTEM_EXTRA_CERTIFICATE_SIZE, 1, 0
+ .incbin "certs/extra_cert_placeholder"

.align 4
.globl VMLINUX_SYMBOL(system_extra_cert_used)
--
2.7.4

2016-11-22 04:17:17

by Mehmet Kayaalp

[permalink] [raw]
Subject: [PATCH 3/4] KEYS: Support for inserting a certificate into x86 bzImage

The config option SYSTEM_EXTRA_CERTIFICATE (introduced in c4c361059585)
reserves space in vmlinux file, which is compressed to create the
self-extracting bzImage. This patch adds the capability of extracting the
vmlinux, inserting the certificate, and repackaging the result into a
bzImage.

It only works if the resulting compressed vmlinux is smaller than the
original. Otherwise re-linking would be required. To make the reserved
space allocate actual space in bzImage, incompressible bytes are
inserted into the vmlinux as a placeholder for the extra certificate.
After receiving a bzImage that is created this way, the actual
certificate can be inserted into the bzImage:

scripts/insert-sys-cert -s <System.map> -z <bzImage> -c <certfile>

Signed-off-by: Mehmet Kayaalp <[email protected]>
---
scripts/insert-sys-cert.c | 238 +++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 233 insertions(+), 5 deletions(-)

diff --git a/scripts/insert-sys-cert.c b/scripts/insert-sys-cert.c
index c4c6205..3d9018f 100644
--- a/scripts/insert-sys-cert.c
+++ b/scripts/insert-sys-cert.c
@@ -7,7 +7,8 @@
* This software may be used and distributed according to the terms
* of the GNU General Public License, incorporated herein by reference.
*
- * Usage: insert-sys-cert [-s <System.map> -b <vmlinux> -c <certfile>
+ * Usage: insert-sys-cert [-s <System.map>] -b <vmlinux> -c <certfile>
+ * [-s <System.map>] -z <bzImage> -c <certfile>
*/

#define _GNU_SOURCE
@@ -230,6 +231,210 @@ static char *read_file(char *file_name, int *size)
return buf;
}

+#define BOOT_FLAG 0xAA55
+#define MAGIC 0x53726448
+
+#define BOOT_FLAG_O 0x1FE
+#define MAGIC_O 0x202
+#define VERSION_O 0x206
+#define SETUP_SECTS_O 0x1F1
+#define PAYLOAD_OFFSET_O 0x248
+#define PAYLOAD_LENGTH_O 0x24C
+
+static int image_supported(char *bzimage, int bzimage_size)
+{
+ uint16_t boot_flag;
+ uint32_t magic;
+ uint16_t version;
+
+ if (bzimage_size < 1024) {
+ err("Invalid bzImage: File is too small\n");
+ return 0;
+ }
+
+ boot_flag = *((uint16_t *)&bzimage[BOOT_FLAG_O]);
+ magic = *((uint32_t *)&bzimage[MAGIC_O]);
+ version = *((uint16_t *)&bzimage[VERSION_O]);
+
+ if (boot_flag != BOOT_FLAG || magic != MAGIC) {
+ err("Invalid bzImage: Magic mismatch\n");
+ return 0;
+ }
+
+ if (version < 0x208) {
+ err("Invalid bzImage: Boot version <2.08 not supported\n");
+ return 0;
+ }
+
+ return 1;
+}
+
+static void get_payload_info(char *bzimage, int *offset, int *size)
+{
+ unsigned int system_offset;
+ unsigned char setup_sectors;
+
+ setup_sectors = bzimage[SETUP_SECTS_O] + 1;
+ system_offset = setup_sectors * 512;
+ *offset = system_offset + *((int *)&bzimage[PAYLOAD_OFFSET_O]);
+ *size = *((int *)&bzimage[PAYLOAD_LENGTH_O]);
+}
+
+static void update_payload_info(char *bzimage, int new_size)
+{
+ int offset, size;
+
+ get_payload_info(bzimage, &offset, &size);
+ *((int *)&bzimage[PAYLOAD_LENGTH_O]) = new_size;
+ if (new_size < size)
+ memset(bzimage + offset + new_size, 0, size - new_size);
+}
+
+struct zipper {
+ unsigned char pattern[10];
+ int length;
+ char *command;
+ char *compress;
+};
+
+struct zipper zippers[] = {
+ {{0x7F, 'E', 'L', 'F'},
+ 4, "cat", "cat"},
+ {{0x1F, 0x8B},
+ 2, "gunzip", "gzip -n -f -9"},
+ {{0xFD, '7', 'z', 'X', 'Z', 0},
+ 6, "unxz", "xz"},
+ {{'B', 'Z', 'h'},
+ 3, "bunzip2", "bzip2 -9"},
+ {{0xFF, 'L', 'Z', 'M', 'A', 0},
+ 6, "unlzma", "lzma -9"},
+ {{0xD3, 'L', 'Z', 'O', 0, '\r', '\n', 0x20, '\n'},
+ 9, "lzop -d", "lzop -9"}
+};
+
+static struct zipper *get_zipper(char *p)
+{
+ int i;
+
+ for (i = 0; i < sizeof(zippers)/sizeof(struct zipper); i++) {
+ if (memcmp(p, zippers[i].pattern, zippers[i].length) == 0)
+ return &zippers[i];
+ }
+ return NULL;
+}
+
+/*
+ * This only works for x86 bzImage
+ */
+static void extract_vmlinux(char *bzimage, int bzimage_size,
+ char **file, struct zipper **zipper)
+{
+ int r;
+ char src[15] = "vmlinux-XXXXXX";
+ char dest[15] = "vmlinux-XXXXXX";
+ char cmd[100];
+ int src_fd, dest_fd;
+ int offset, size;
+ struct zipper *z;
+
+ if (!image_supported(bzimage, bzimage_size))
+ return;
+
+ get_payload_info(bzimage, &offset, &size);
+ z = get_zipper(bzimage + offset);
+ if (z == NULL) {
+ err("Unable to determine the compression of vmlinux\n");
+ return;
+ }
+
+ src_fd = mkstemp(src);
+ if (src_fd == -1) {
+ perror("Could not create temp file");
+ return;
+ }
+
+ r = write(src_fd, bzimage + offset, size);
+ if (r != size) {
+ perror("Could not write vmlinux");
+ return;
+ }
+ dest_fd = mkstemp(dest);
+ if (dest_fd == -1) {
+ perror("Could not create temp file");
+ return;
+ }
+
+ snprintf(cmd, sizeof(cmd), "%s <%s >%s", z->command, src, dest);
+ info("Executing: %s\n", cmd);
+ r = system(cmd);
+ if (r != 0)
+ warn("Possible errors when extracting\n");
+
+ r = remove(src);
+ if (r != 0)
+ perror(src);
+
+ *file = strdup(dest);
+ *zipper = z;
+}
+
+static void repack_image(char *bzimage, int bzimage_size,
+ char *vmlinux_file, struct zipper *z)
+{
+ char tmp[15] = "vmlinux-XXXXXX";
+ char cmd[100];
+ int fd;
+ struct stat st;
+ int new_size;
+ int r;
+ int offset, size;
+
+ get_payload_info(bzimage, &offset, &size);
+
+ fd = mkstemp(tmp);
+ if (fd == -1) {
+ perror("Could not create temp file");
+ return;
+ }
+ snprintf(cmd, sizeof(cmd), "%s <%s >%s",
+ z->compress, vmlinux_file, tmp);
+
+ info("Executing: %s\n", cmd);
+ r = system(cmd);
+ if (r != 0)
+ warn("Possible errors when compressing\n");
+
+ r = remove(vmlinux_file);
+ if (r != 0)
+ perror(vmlinux_file);
+
+ if (fstat(fd, &st)) {
+ perror("Could not determine file size");
+ close(fd);
+
+ }
+ new_size = st.st_size;
+ if (new_size > size) {
+ err("Increase in compressed size is not supported.\n");
+ err("Old size was %d, new size is %d\n", size, new_size);
+ exit(EXIT_FAILURE);
+ }
+
+ r = read(fd, bzimage + offset, new_size);
+ if (r != new_size)
+ perror(tmp);
+
+ r = remove(tmp);
+ if (r != 0)
+ perror(tmp);
+
+ /* x86 specific patching of bzimage */
+ update_payload_info(bzimage, new_size);
+
+ /* TODO: update CRC */
+
+}
+
static void print_sym(struct sym *s)
{
info("sym: %s\n", s->name);
@@ -240,18 +445,23 @@ static void print_sym(struct sym *s)

static void print_usage(char *e)
{
- printf("Usage %s [-s <System.map>] -b <vmlinux> -c <certfile>\n", e);
+ printf("Usage: %s [-s <System.map>] -b <vmlinux> -c <certfile>\n", e);
+ printf(" %s [-s <System.map>] -z <bzImage> -c <certfile>\n", e);
}

int main(int argc, char **argv)
{
char *system_map_file = NULL;
char *vmlinux_file = NULL;
+ char *bzimage_file = NULL;
char *cert_file = NULL;
int vmlinux_size;
+ int bzimage_size;
int cert_size;
char *vmlinux;
char *cert;
+ char *bzimage = NULL;
+ struct zipper *z = NULL;
FILE *system_map;
int *used;
int opt;
@@ -260,7 +470,7 @@ int main(int argc, char **argv)
GElf_Ehdr hdr_s, *hdr;
Elf_Scn *symtab = NULL;

- while ((opt = getopt(argc, argv, "b:c:s:")) != -1) {
+ while ((opt = getopt(argc, argv, "b:z:c:s:")) != -1) {
switch (opt) {
case 's':
system_map_file = optarg;
@@ -268,6 +478,9 @@ int main(int argc, char **argv)
case 'b':
vmlinux_file = optarg;
break;
+ case 'z':
+ bzimage_file = optarg;
+ break;
case 'c':
cert_file = optarg;
break;
@@ -276,7 +489,9 @@ int main(int argc, char **argv)
}
}

- if (!vmlinux_file || !cert_file) {
+ if (!cert_file ||
+ (!vmlinux_file && !bzimage_file) ||
+ (vmlinux_file && bzimage_file)) {
print_usage(argv[0]);
exit(EXIT_FAILURE);
}
@@ -285,6 +500,16 @@ int main(int argc, char **argv)
if (!cert)
exit(EXIT_FAILURE);

+ if (bzimage_file) {
+ bzimage = map_file(bzimage_file, &bzimage_size);
+ if (!bzimage)
+ exit(EXIT_FAILURE);
+
+ extract_vmlinux(bzimage, bzimage_size, &vmlinux_file, &z);
+ if (!vmlinux_file)
+ exit(EXIT_FAILURE);
+ }
+
vmlinux = map_file(vmlinux_file, &vmlinux_size);
if (!vmlinux)
exit(EXIT_FAILURE);
@@ -372,7 +597,7 @@ int main(int argc, char **argv)
}

/* If the existing cert is the same, don't overwrite */
- if (cert_size == *used &&
+ if (cert_size > 0 && cert_size == *used &&
strncmp(cert_sym.content, cert, cert_size) == 0) {
warn("Certificate was already inserted.\n");
exit(EXIT_SUCCESS);
@@ -407,5 +632,8 @@ int main(int argc, char **argv)
exit(EXIT_FAILURE);
}

+ if (bzimage)
+ repack_image(bzimage, bzimage_size, vmlinux_file, z);
+
exit(EXIT_SUCCESS);
}
--
2.7.4

2016-11-22 04:17:31

by Mehmet Kayaalp

[permalink] [raw]
Subject: [PATCH 4/4] KEYS: Print insert-sys-cert information to stdout instead of stderr

Detailed INFO output should go to stdout instead of stderr.

Signed-off-by: Mehmet Kayaalp <[email protected]>
---
scripts/insert-sys-cert.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/scripts/insert-sys-cert.c b/scripts/insert-sys-cert.c
index 3d9018f..0516b2e 100644
--- a/scripts/insert-sys-cert.c
+++ b/scripts/insert-sys-cert.c
@@ -31,7 +31,7 @@
#define USED_SYM "system_extra_cert_used"
#define LSIZE_SYM "system_certificate_list_size"

-#define info(format, args...) fprintf(stderr, "INFO: " format, ## args)
+#define info(format, args...) fprintf(stdout, "INFO: " format, ## args)
#define warn(format, args...) fprintf(stdout, "WARNING: " format, ## args)
#define err(format, args...) fprintf(stderr, "ERROR: " format, ## args)

--
2.7.4

2016-11-25 09:06:49

by David Howells

[permalink] [raw]
Subject: Re: [PATCH 1/4] KEYS: Insert incompressible bytes to reserve space in bzImage

Mehmet Kayaalp <[email protected]> wrote:

> Include a random filled binary in vmlinux at the space reserved with
> CONFIG_SYSTEM_EXTRA_CERTIFICATE. This results in an uncompressed reserved
> area inside the bzImage as well, so that it can be replaced with an actual
> certificate later (after the bzImage is distributed).

You haven't said *why* you need an incompressible buffer. I presume it's
something to do with the decompression wrapper.

David

2016-11-25 19:49:06

by Mehmet Kayaalp

[permalink] [raw]
Subject: Re: [PATCH 1/4] KEYS: Insert incompressible bytes to reserve space in bzImage


> On Nov 25, 2016, at 4:06 AM, David Howells <[email protected]> wrote:
>
> Mehmet Kayaalp <[email protected]> wrote:
>
>> Include a random filled binary in vmlinux at the space reserved with
>> CONFIG_SYSTEM_EXTRA_CERTIFICATE. This results in an uncompressed reserved
>> area inside the bzImage as well, so that it can be replaced with an actual
>> certificate later (after the bzImage is distributed).
>
> You haven't said *why* you need an incompressible buffer. I presume it's
> something to do with the decompression wrapper.
>

After you replace zeroes with a certificate and compress again, the image size
increases. Then, repackaging the bzImage becomes difficult.

>From the commit message of 3/4:

> This patch adds the capability of extracting the
> vmlinux, inserting the certificate, and repackaging the result into a
> bzImage.
>
> It only works if the resulting compressed vmlinux is smaller than the
> original. Otherwise re-linking would be required. To make the reserved
> space allocate actual space in bzImage, incompressible bytes are
> inserted into the vmlinux as a placeholder for the extra certificate.

Mehmet