From: Mehmet Kayaalp <mkayaalp@linux.vnet.ibm.com>
To: David Howells <dhowells@redhat.com>,
David Woodhouse <dwmw2@infradead.org>,
Keyrings <keyrings@vger.kernel.org>
Cc: Linux Integrity <linux-integrity@vger.kernel.org>,
Linux Security <linux-security-module@vger.kernel.org>,
Linux Kernel <linux-kernel@vger.kernel.org>,
Mimi Zohar <zohar@linux.vnet.ibm.com>,
Stefan Berger <stefanb@linux.vnet.ibm.com>,
George Wilson <gcwilson@us.ibm.com>,
Mike Rapoport <rppt@linux.vnet.ibm.com>,
Mehmet Kayaalp <mkayaalp@linux.vnet.ibm.com>
Subject: [PATCH v6 3/4] KEYS: Support for inserting a certificate into x86 bzImage
Date: Wed, 02 May 2018 23:08:10 +0000 [thread overview]
Message-ID: <20180502230811.2751-4-mkayaalp@linux.vnet.ibm.com> (raw)
In-Reply-To: <20180502230811.2751-1-mkayaalp@linux.vnet.ibm.com>
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 <mkayaalp@linux.vnet.ibm.com>
---
scripts/insert-sys-cert.c | 257 +++++++++++++++++++++++++++++++++++++-
1 file changed, 252 insertions(+), 5 deletions(-)
diff --git a/scripts/insert-sys-cert.c b/scripts/insert-sys-cert.c
index 10a17504dc87..a3bd7ea8a436 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
@@ -370,6 +371,228 @@ 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)
+{
+ u16 boot_flag;
+ u32 magic;
+ u16 version;
+
+ if (bzimage_size < 1024) {
+ err("Invalid bzImage: File is too small\n");
+ return 0;
+ }
+
+ boot_flag = *((u16 *)&bzimage[BOOT_FLAG_O]);
+ magic = *((u32 *)&bzimage[MAGIC_O]);
+ version = *((u16 *)&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;
+}
+
+static u32 crc32(u32 seed, const char *buffer, int size)
+{
+ int i, j;
+ u32 byte, crc, mask;
+
+ crc = seed;
+ for (i = 0; i < size; i++) {
+ byte = buffer[i];
+ crc = crc ^ byte;
+ for (j = 7; j >= 0; j--) {
+ mask = -(crc & 1);
+ crc = (crc >> 1) ^ (0xEDB88320 & mask);
+ }
+ }
+ return crc;
+}
+
+/*
+ * 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) {
+ 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;
+ u32 *crc;
+
+ 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);
+
+ /* update CRC */
+ crc = (u32 *)(bzimage + bzimage_size - 4);
+ *crc = crc32(~0, bzimage, bzimage_size);
+}
+
static void print_sym(struct sym *s)
{
info("sym: %s\n", s->name);
@@ -380,18 +603,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;
@@ -399,7 +627,7 @@ int main(int argc, char **argv)
struct elf elf;
unsigned char *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;
@@ -407,6 +635,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;
@@ -415,7 +646,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);
}
@@ -424,6 +657,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);
@@ -477,7 +720,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);
@@ -511,5 +754,9 @@ int main(int argc, char **argv)
perror(vmlinux_file);
exit(EXIT_FAILURE);
}
+
+ if (bzimage)
+ repack_image(bzimage, bzimage_size, vmlinux_file, z);
+
exit(EXIT_SUCCESS);
}
--
2.17.0
WARNING: multiple messages have this Message-ID (diff)
From: Mehmet Kayaalp <mkayaalp@linux.vnet.ibm.com>
To: David Howells <dhowells@redhat.com>,
David Woodhouse <dwmw2@infradead.org>,
Keyrings <keyrings@vger.kernel.org>
Cc: Linux Integrity <linux-integrity@vger.kernel.org>,
Linux Security <linux-security-module@vger.kernel.org>,
Linux Kernel <linux-kernel@vger.kernel.org>,
Mimi Zohar <zohar@linux.vnet.ibm.com>,
Stefan Berger <stefanb@linux.vnet.ibm.com>,
George Wilson <gcwilson@us.ibm.com>,
Mike Rapoport <rppt@linux.vnet.ibm.com>,
Mehmet Kayaalp <mkayaalp@linux.vnet.ibm.com>
Subject: [PATCH v6 3/4] KEYS: Support for inserting a certificate into x86 bzImage
Date: Wed, 2 May 2018 19:08:10 -0400 [thread overview]
Message-ID: <20180502230811.2751-4-mkayaalp@linux.vnet.ibm.com> (raw)
In-Reply-To: <20180502230811.2751-1-mkayaalp@linux.vnet.ibm.com>
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 <mkayaalp@linux.vnet.ibm.com>
---
scripts/insert-sys-cert.c | 257 +++++++++++++++++++++++++++++++++++++-
1 file changed, 252 insertions(+), 5 deletions(-)
diff --git a/scripts/insert-sys-cert.c b/scripts/insert-sys-cert.c
index 10a17504dc87..a3bd7ea8a436 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
@@ -370,6 +371,228 @@ 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)
+{
+ u16 boot_flag;
+ u32 magic;
+ u16 version;
+
+ if (bzimage_size < 1024) {
+ err("Invalid bzImage: File is too small\n");
+ return 0;
+ }
+
+ boot_flag = *((u16 *)&bzimage[BOOT_FLAG_O]);
+ magic = *((u32 *)&bzimage[MAGIC_O]);
+ version = *((u16 *)&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;
+}
+
+static u32 crc32(u32 seed, const char *buffer, int size)
+{
+ int i, j;
+ u32 byte, crc, mask;
+
+ crc = seed;
+ for (i = 0; i < size; i++) {
+ byte = buffer[i];
+ crc = crc ^ byte;
+ for (j = 7; j >= 0; j--) {
+ mask = -(crc & 1);
+ crc = (crc >> 1) ^ (0xEDB88320 & mask);
+ }
+ }
+ return crc;
+}
+
+/*
+ * 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) {
+ 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;
+ u32 *crc;
+
+ 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);
+
+ /* update CRC */
+ crc = (u32 *)(bzimage + bzimage_size - 4);
+ *crc = crc32(~0, bzimage, bzimage_size);
+}
+
static void print_sym(struct sym *s)
{
info("sym: %s\n", s->name);
@@ -380,18 +603,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;
@@ -399,7 +627,7 @@ int main(int argc, char **argv)
struct elf elf;
unsigned char *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;
@@ -407,6 +635,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;
@@ -415,7 +646,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);
}
@@ -424,6 +657,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);
@@ -477,7 +720,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);
@@ -511,5 +754,9 @@ int main(int argc, char **argv)
perror(vmlinux_file);
exit(EXIT_FAILURE);
}
+
+ if (bzimage)
+ repack_image(bzimage, bzimage_size, vmlinux_file, z);
+
exit(EXIT_SUCCESS);
}
--
2.17.0
WARNING: multiple messages have this Message-ID (diff)
From: mkayaalp@linux.vnet.ibm.com (Mehmet Kayaalp)
To: linux-security-module@vger.kernel.org
Subject: [PATCH v6 3/4] KEYS: Support for inserting a certificate into x86 bzImage
Date: Wed, 2 May 2018 19:08:10 -0400 [thread overview]
Message-ID: <20180502230811.2751-4-mkayaalp@linux.vnet.ibm.com> (raw)
In-Reply-To: <20180502230811.2751-1-mkayaalp@linux.vnet.ibm.com>
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 <mkayaalp@linux.vnet.ibm.com>
---
scripts/insert-sys-cert.c | 257 +++++++++++++++++++++++++++++++++++++-
1 file changed, 252 insertions(+), 5 deletions(-)
diff --git a/scripts/insert-sys-cert.c b/scripts/insert-sys-cert.c
index 10a17504dc87..a3bd7ea8a436 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
@@ -370,6 +371,228 @@ 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)
+{
+ u16 boot_flag;
+ u32 magic;
+ u16 version;
+
+ if (bzimage_size < 1024) {
+ err("Invalid bzImage: File is too small\n");
+ return 0;
+ }
+
+ boot_flag = *((u16 *)&bzimage[BOOT_FLAG_O]);
+ magic = *((u32 *)&bzimage[MAGIC_O]);
+ version = *((u16 *)&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;
+}
+
+static u32 crc32(u32 seed, const char *buffer, int size)
+{
+ int i, j;
+ u32 byte, crc, mask;
+
+ crc = seed;
+ for (i = 0; i < size; i++) {
+ byte = buffer[i];
+ crc = crc ^ byte;
+ for (j = 7; j >= 0; j--) {
+ mask = -(crc & 1);
+ crc = (crc >> 1) ^ (0xEDB88320 & mask);
+ }
+ }
+ return crc;
+}
+
+/*
+ * 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) {
+ 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;
+ u32 *crc;
+
+ 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);
+
+ /* update CRC */
+ crc = (u32 *)(bzimage + bzimage_size - 4);
+ *crc = crc32(~0, bzimage, bzimage_size);
+}
+
static void print_sym(struct sym *s)
{
info("sym: %s\n", s->name);
@@ -380,18 +603,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;
@@ -399,7 +627,7 @@ int main(int argc, char **argv)
struct elf elf;
unsigned char *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;
@@ -407,6 +635,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;
@@ -415,7 +646,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);
}
@@ -424,6 +657,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);
@@ -477,7 +720,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);
@@ -511,5 +754,9 @@ int main(int argc, char **argv)
perror(vmlinux_file);
exit(EXIT_FAILURE);
}
+
+ if (bzimage)
+ repack_image(bzimage, bzimage_size, vmlinux_file, z);
+
exit(EXIT_SUCCESS);
}
--
2.17.0
--
To unsubscribe from this list: send the line "unsubscribe linux-security-module" in
the body of a message to majordomo at vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
next prev parent reply other threads:[~2018-05-02 23:08 UTC|newest]
Thread overview: 25+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-05-02 23:08 [PATCH v6 0/4] Certificate insertion support for x86 bzImages Mehmet Kayaalp
2018-05-02 23:08 ` Mehmet Kayaalp
2018-05-02 23:08 ` Mehmet Kayaalp
2018-05-02 23:08 ` [PATCH v6 1/4] KEYS: Insert incompressible bytes to reserve space in bzImage Mehmet Kayaalp
2018-05-02 23:08 ` Mehmet Kayaalp
2018-05-02 23:08 ` Mehmet Kayaalp
2018-05-02 23:08 ` [PATCH v6 2/4] KEYS: Add ELF class-independent certificate insertion support Mehmet Kayaalp
2018-05-02 23:08 ` Mehmet Kayaalp
2018-05-02 23:08 ` Mehmet Kayaalp
2018-05-02 23:08 ` Mehmet Kayaalp [this message]
2018-05-02 23:08 ` [PATCH v6 3/4] KEYS: Support for inserting a certificate into x86 bzImage Mehmet Kayaalp
2018-05-02 23:08 ` Mehmet Kayaalp
2018-05-02 23:08 ` [PATCH v6 4/4] KEYS: Print insert-sys-cert information to stdout instead of stderr Mehmet Kayaalp
2018-05-02 23:08 ` Mehmet Kayaalp
2018-05-02 23:08 ` Mehmet Kayaalp
2018-05-03 17:11 ` [PATCH v6 0/4] Certificate insertion support for x86 bzImages James Morris
2018-05-03 17:11 ` James Morris
2018-05-03 17:11 ` James Morris
2018-05-03 21:42 ` Mimi Zohar
2018-05-03 21:42 ` Mimi Zohar
2018-05-03 21:42 ` Mimi Zohar
2018-05-03 21:42 ` Mimi Zohar
2018-05-04 1:20 ` Mehmet Kayaalp
2018-05-04 1:20 ` Mehmet Kayaalp
2018-05-04 1:20 ` Mehmet Kayaalp
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20180502230811.2751-4-mkayaalp@linux.vnet.ibm.com \
--to=mkayaalp@linux.vnet.ibm.com \
--cc=dhowells@redhat.com \
--cc=dwmw2@infradead.org \
--cc=gcwilson@us.ibm.com \
--cc=keyrings@vger.kernel.org \
--cc=linux-integrity@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-security-module@vger.kernel.org \
--cc=rppt@linux.vnet.ibm.com \
--cc=stefanb@linux.vnet.ibm.com \
--cc=zohar@linux.vnet.ibm.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.