:: commit a72d2fc59d3cdc773ffa86c8d41671ee71fe3951

mintsuki <mintsuki@protonmail.com> — 2023-02-06 22:58

parents: d7e827f51a

misc: Add support for enrolling config blake2b hash in executable

diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index ae7693a2..93ccd146 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -44,6 +44,15 @@ jobs:
       - name: Clean limine-version
         run: rm build/bin/limine-version
 
+      - name: Clean limine-enroll-config
+        run: rm build/bin/limine-enroll-config
+
+      - name: Build limine-enroll-config-win32
+        run: make -C build/bin CC="i686-w64-mingw32-gcc" CFLAGS="-O2 -pipe" limine-enroll-config
+
+      - name: Strip limine-enroll-config-win32
+        run: i686-w64-mingw32-strip build/bin/limine-enroll-config.exe
+
       - name: Clean limine-deploy
         run: rm build/bin/limine-deploy
 
diff --git a/GNUmakefile.in b/GNUmakefile.in
index 830f18b7..7e218548 100644
--- a/GNUmakefile.in
+++ b/GNUmakefile.in
@@ -83,7 +83,7 @@ override LIMINE_VERSION := @PACKAGE_VERSION@
 override STAGE1_FILES := $(shell find '$(call SHESCAPE,$(SRCDIR))/stage1' -type f -name '*.asm')
 
 .PHONY: all
-all: limine-version $(BUILD_UEFI_X86_64) $(BUILD_UEFI_IA32) $(BUILD_UEFI_AARCH64) $(BUILD_BIOS)
+all: limine-version limine-enroll-config $(BUILD_UEFI_X86_64) $(BUILD_UEFI_IA32) $(BUILD_UEFI_AARCH64) $(BUILD_BIOS)
 	$(MAKE) '$(call SHESCAPE,$(BINDIR))/limine-cd-efi.bin'
 
 $(call MKESCAPE,$(BINDIR))/limine-hdd.h: $(call MKESCAPE,$(BINDIR))/limine-hdd.bin
@@ -98,6 +98,10 @@ $(call MKESCAPE,$(BINDIR))/limine-version: $(call MKESCAPE,$(BINDIR))/Makefile $
 	$(SED) 's/@LIMINE_VERSION@/@PACKAGE_VERSION@/g' <'$(call SHESCAPE,$(SRCDIR))/host/limine-version.c' >'$(call SHESCAPE,$(BINDIR))/limine-version.c'
 	$(MAKE) -C '$(call SHESCAPE,$(BINDIR))' limine-version
 
+$(call MKESCAPE,$(BINDIR))/limine-enroll-config: $(call MKESCAPE,$(BINDIR))/Makefile $(call MKESCAPE,$(SRCDIR))/host/limine-enroll-config.c
+	cp '$(call SHESCAPE,$(SRCDIR))/host/limine-enroll-config.c' '$(call SHESCAPE,$(BINDIR))/'
+	$(MAKE) -C '$(call SHESCAPE,$(BINDIR))' limine-enroll-config
+
 $(call MKESCAPE,$(BINDIR))/Makefile: $(call MKESCAPE,$(SRCDIR))/host/Makefile $(call MKESCAPE,$(SRCDIR))/host/.gitignore
 	$(MKDIR_P) '$(call SHESCAPE,$(BINDIR))'
 	cp '$(call SHESCAPE,$(SRCDIR))/host/Makefile' '$(call SHESCAPE,$(SRCDIR))/host/.gitignore' '$(call SHESCAPE,$(BINDIR))/'
@@ -110,6 +114,10 @@ limine-deploy:
 limine-version:
 	$(MAKE) '$(call SHESCAPE,$(BINDIR))/limine-version'
 
+.PHONY: limine-enroll-config
+limine-enroll-config:
+	$(MAKE) '$(call SHESCAPE,$(BINDIR))/limine-enroll-config'
+
 .PHONY: clean
 clean: limine-bios-clean limine-uefi-ia32-clean limine-uefi-x86-64-clean limine-uefi-aarch64-clean
 	rm -rf '$(call SHESCAPE,$(BINDIR))' '$(call SHESCAPE,$(BUILDDIR))/stage1.stamp'
@@ -146,6 +154,7 @@ endif
 install-strip: install-data
 	$(INSTALL) -d '$(call SHESCAPE,$(DESTDIR)$(ACBINDIR))'
 	$(INSTALL_PROGRAM) -s '$(call SHESCAPE,$(BINDIR))/limine-version' '$(call SHESCAPE,$(DESTDIR)$(ACBINDIR))/'
+	$(INSTALL_PROGRAM) -s '$(call SHESCAPE,$(BINDIR))/limine-enroll-config' '$(call SHESCAPE,$(DESTDIR)$(ACBINDIR))/'
 ifneq ($(BUILD_LIMINE_DEPLOY),no)
 	$(INSTALL_PROGRAM) -s '$(call SHESCAPE,$(BINDIR))/limine-deploy' '$(call SHESCAPE,$(DESTDIR)$(ACBINDIR))/'
 endif
@@ -154,6 +163,7 @@ endif
 install: install-data
 	$(INSTALL) -d '$(call SHESCAPE,$(DESTDIR)$(ACBINDIR))'
 	$(INSTALL_PROGRAM) '$(call SHESCAPE,$(BINDIR))/limine-version' '$(call SHESCAPE,$(DESTDIR)$(ACBINDIR))/'
+	$(INSTALL_PROGRAM) '$(call SHESCAPE,$(BINDIR))/limine-enroll-config' '$(call SHESCAPE,$(DESTDIR)$(ACBINDIR))/'
 ifneq ($(BUILD_LIMINE_DEPLOY),no)
 	$(INSTALL_PROGRAM) '$(call SHESCAPE,$(BINDIR))/limine-deploy' '$(call SHESCAPE,$(DESTDIR)$(ACBINDIR))/'
 endif
@@ -161,6 +171,7 @@ endif
 .PHONY: uninstall
 uninstall:
 	rm -f '$(call SHESCAPE,$(DESTDIR)$(ACBINDIR))/limine-version'
+	rm -f '$(call SHESCAPE,$(DESTDIR)$(ACBINDIR))/limine-enroll-config'
 	rm -f '$(call SHESCAPE,$(DESTDIR)$(ACBINDIR))/limine-deploy'
 	rm -rf '$(call SHESCAPE,$(DESTDIR)$(ACDATAROOTDIR))/limine'
 	rm -f '$(call SHESCAPE,$(DESTDIR)$(ACINCLUDEDIR))/limine.h'
diff --git a/common/lib/config.c b/common/lib/config.c
index a53320ff..4a275f7c 100644
--- a/common/lib/config.c
+++ b/common/lib/config.c
@@ -3,10 +3,17 @@
 #include <lib/config.h>
 #include <lib/libc.h>
 #include <lib/misc.h>
+#include <lib/readline.h>
 #include <mm/pmm.h>
 #include <fs/file.h>
 #include <lib/print.h>
 #include <pxe/tftp.h>
+#include <crypt/blake2b.h>
+
+#define CONFIG_B2SUM_SIGNATURE "++CONFIG_B2SUM_SIGNATURE++"
+#define CONFIG_B2SUM_EMPTY "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
+
+const char *config_b2sum = CONFIG_B2SUM_SIGNATURE CONFIG_B2SUM_EMPTY;
 
 static bool config_get_entry_name(char *ret, size_t index, size_t limit);
 static char *config_get_entry(size_t *size, size_t index);
@@ -136,6 +143,29 @@ struct macro {
 static struct macro *macros = NULL;
 
 int init_config(size_t config_size) {
+    config_b2sum += sizeof(CONFIG_B2SUM_SIGNATURE) - 1;
+
+    if (memcmp((void *)config_b2sum, CONFIG_B2SUM_EMPTY, 128) != 0) {
+        uint8_t out_buf[BLAKE2B_OUT_BYTES];
+        blake2b(out_buf, config_addr, config_size - 2);
+        uint8_t hash_buf[BLAKE2B_OUT_BYTES];
+
+        for (size_t i = 0; i < BLAKE2B_OUT_BYTES; i++) {
+            hash_buf[i] = digit_to_int(config_b2sum[i * 2]) << 4 | digit_to_int(config_b2sum[i * 2 + 1]);
+        }
+
+        if (memcmp(hash_buf, out_buf, BLAKE2B_OUT_BYTES) != 0) {
+            print("!!! CHECKSUM MISMATCH FOR CONFIG FILE !!!\n");
+            print("If you do not know what this means, ANSWER WITH 'N' NOW!\n");
+            print("Proceed with boot anyways? [y/N]: ");
+            if (getchar() != 'y') {
+                print("\n");
+                panic(true, "Checksum mismatch for config file");
+            }
+            print("\n");
+        }
+    }
+
     // add trailing newline if not present
     config_addr[config_size - 2] = '\n';
 
diff --git a/host/.gitignore b/host/.gitignore
index 9b9a44b2..059eb254 100644
--- a/host/.gitignore
+++ b/host/.gitignore
@@ -2,3 +2,5 @@ limine-deploy
 limine-deploy.exe
 limine-version
 limine-version.exe
+limine-enroll-config
+limine-enroll-config.exe
diff --git a/host/Makefile b/host/Makefile
index 1ee8b783..de20a330 100644
--- a/host/Makefile
+++ b/host/Makefile
@@ -6,7 +6,7 @@ PREFIX ?= /usr/local
 CFLAGS ?= -g -O2 -pipe -Wall -Wextra
 
 .PHONY: all
-all: limine-deploy limine-version
+all: limine-deploy limine-version limine-enroll-config
 
 .PHONY: install-data
 install-data: all
@@ -26,20 +26,26 @@ install: install-data
 	$(INSTALL) -d '$(DESTDIR)$(PREFIX)/bin'
 	$(INSTALL) limine-deploy '$(DESTDIR)$(PREFIX)/bin/'
 	$(INSTALL) limine-version '$(DESTDIR)$(PREFIX)/bin/'
+	$(INSTALL) limine-enroll-config '$(DESTDIR)$(PREFIX)/bin/'
 
 .PHONY: install-strip
 install-strip: install-data
 	$(INSTALL) -d '$(DESTDIR)$(PREFIX)/bin'
 	$(INSTALL) -s limine-deploy '$(DESTDIR)$(PREFIX)/bin/'
 	$(INSTALL) -s limine-version '$(DESTDIR)$(PREFIX)/bin/'
+	$(INSTALL) -s limine-enroll-config '$(DESTDIR)$(PREFIX)/bin/'
 
 .PHONY: clean
 clean:
 	rm -f limine-deploy limine-deploy.exe
 	rm -f limine-version limine-version.exe
+	rm -f limine-enroll-config limine-enroll-config.exe
 
 limine-deploy: limine-deploy.c limine-hdd.h
 	$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -std=c99 -D__USE_MINGW_ANSI_STDIO limine-deploy.c $(LIBS) -o $@
 
 limine-version: limine-version.c
 	$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -std=c99 -D__USE_MINGW_ANSI_STDIO limine-version.c $(LIBS) -o $@
+
+limine-enroll-config: limine-enroll-config.c
+	$(CC) $(CPPFLAGS) $(CFLAGS) $(LDFLAGS) -std=c99 -D__USE_MINGW_ANSI_STDIO limine-enroll-config.c $(LIBS) -o $@
diff --git a/host/limine-enroll-config.c b/host/limine-enroll-config.c
new file mode 100644
index 00000000..c7e0410d
--- /dev/null
+++ b/host/limine-enroll-config.c
@@ -0,0 +1,92 @@
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define CONFIG_B2SUM_SIGNATURE "++CONFIG_B2SUM_SIGNATURE++"
+
+int main(int argc, char *argv[]) {
+    int ret = 1;
+
+    char *bootloader = NULL;
+    FILE *bootloader_file = NULL;
+
+    if (argc <= 2) {
+        fprintf(stderr, "usage: %s <Limine bootloader executable> <128-byte BLAKE2B of config file>\n", argv[0]);
+        goto cleanup;
+    }
+
+    if (strlen(argv[2]) != 128) {
+        fprintf(stderr, "ERROR: BLAKE2B specified is not 128 characters long\n");
+        goto cleanup;
+    }
+
+    bootloader_file = fopen(argv[1], "r+b");
+    if (bootloader_file == NULL) {
+        perror("ERROR");
+        goto cleanup;;
+    }
+
+    if (fseek(bootloader_file, 0, SEEK_END) != 0) {
+        perror("ERROR");
+        goto cleanup;
+    }
+    size_t bootloader_size = ftell(bootloader_file);
+    rewind(bootloader_file);
+
+    bootloader = malloc(bootloader_size);
+    if (bootloader == NULL) {
+        perror("ERROR");
+        goto cleanup;
+    }
+
+    if (fread(bootloader, bootloader_size, 1, bootloader_file) != 1) {
+        perror("ERROR");
+        goto cleanup;
+    }
+
+    char *checksum_loc = NULL;
+    size_t checked_count = 0;
+    const char *config_b2sum_sign = CONFIG_B2SUM_SIGNATURE;
+    for (size_t i = 0; i < bootloader_size; i++) {
+        if (bootloader[i] != config_b2sum_sign[checked_count]) {
+            checked_count = 0;
+            continue;
+        }
+
+        checked_count++;
+
+        if (checked_count == sizeof(CONFIG_B2SUM_SIGNATURE) - 1) {
+            checksum_loc = &bootloader[i + 1];
+            break;
+        }
+    }
+
+    if (checksum_loc == NULL) {
+        fprintf(stderr, "ERROR: Checksum location not found in provided executable\n");
+        goto cleanup;
+    }
+
+    memcpy(checksum_loc, argv[2], 128);
+
+    if (fseek(bootloader_file, 0, SEEK_SET) != 0) {
+        perror("ERROR");
+        goto cleanup;
+    }
+    if (fwrite(bootloader, bootloader_size, 1, bootloader_file) != 1) {
+        perror("ERROR");
+        goto cleanup;
+    }
+
+    fprintf(stderr, "Config file BLAKE2B successfully enrolled!\n");
+    ret = 0;
+
+cleanup:
+    if (bootloader != NULL) {
+        free(bootloader);
+    }
+    if (bootloader_file != NULL) {
+        fclose(bootloader_file);
+    }
+    return ret;
+}
tab: 248 wrap: offon