From c9f158361cba8218a45fdc0ccb9a14ba05ddac3a Mon Sep 17 00:00:00 2001 From: Richard Qin Date: Wed, 13 May 2026 15:54:04 +0800 Subject: feat: add KASLR configuration options and implement LZ4 compression in pack_image script --- na/scripts/Kconfig.mk | 17 ++++ na/scripts/pack_image.py | 227 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 244 insertions(+) create mode 100644 na/scripts/pack_image.py (limited to 'na/scripts') diff --git a/na/scripts/Kconfig.mk b/na/scripts/Kconfig.mk index ee2d9de..c979e76 100644 --- a/na/scripts/Kconfig.mk +++ b/na/scripts/Kconfig.mk @@ -49,7 +49,10 @@ CONFIG_KERNEL_STACK_SIZE ?= 8192 # --- Security / Hardening ------------------------------------------- CONFIG_KASLR ?= y +CONFIG_KASLR_POLICY_ID ?= 0 +CONFIG_KASLR_LOG_LEVEL ?= 1 CONFIG_STACK_CANARY ?= y +CONFIG_KERNEL_COMPRESSED ?= y # --- Debug ----------------------------------------------------------- CONFIG_DEBUG ?= y @@ -98,6 +101,8 @@ KCPPFLAGS += -DCONFIG_KERNEL_STACK_SIZE=$(CONFIG_KERNEL_STACK_SIZE) ifeq ($(CONFIG_KASLR),y) KCPPFLAGS += -DCONFIG_KASLR=1 endif +KCPPFLAGS += -DCONFIG_KASLR_POLICY_ID=$(CONFIG_KASLR_POLICY_ID) +KCPPFLAGS += -DCONFIG_KASLR_LOG_LEVEL=$(CONFIG_KASLR_LOG_LEVEL) ifeq ($(CONFIG_STACK_CANARY),y) KCPPFLAGS += -DCONFIG_STACK_CANARY=1 endif @@ -113,6 +118,9 @@ endif ifeq ($(CONFIG_KLOG),y) KCPPFLAGS += -DCONFIG_KLOG=1 endif +ifeq ($(CONFIG_KERNEL_COMPRESSED),y) +KCPPFLAGS += -DCONFIG_KERNEL_COMPRESSED=1 +endif # ------------------------------------------------------------------ # §5 Generate autoconf.h (analogous to Linux's include/generated/autoconf.h) @@ -147,6 +155,8 @@ define generate-autoconf @echo "" >> $(AUTOCONF_H) @echo "/* Security */" >> $(AUTOCONF_H) $(if $(filter y,$(CONFIG_KASLR)), @echo "#define CONFIG_KASLR 1" >> $(AUTOCONF_H)) + @echo "#define CONFIG_KASLR_POLICY_ID $(CONFIG_KASLR_POLICY_ID)" >> $(AUTOCONF_H) + @echo "#define CONFIG_KASLR_LOG_LEVEL $(CONFIG_KASLR_LOG_LEVEL)" >> $(AUTOCONF_H) $(if $(filter y,$(CONFIG_STACK_CANARY)), @echo "#define CONFIG_STACK_CANARY 1" >> $(AUTOCONF_H)) @echo "" >> $(AUTOCONF_H) @echo "/* Debug */" >> $(AUTOCONF_H) @@ -154,6 +164,7 @@ define generate-autoconf $(if $(filter y,$(CONFIG_DEBUG_LOCKS)), @echo "#define CONFIG_DEBUG_LOCKS 1" >> $(AUTOCONF_H)) $(if $(filter y,$(CONFIG_SELFTEST)), @echo "#define CONFIG_SELFTEST 1" >> $(AUTOCONF_H)) $(if $(filter y,$(CONFIG_KLOG)), @echo "#define CONFIG_KLOG 1" >> $(AUTOCONF_H)) + $(if $(filter y,$(CONFIG_KERNEL_COMPRESSED)), @echo "#define CONFIG_KERNEL_COMPRESSED 1" >> $(AUTOCONF_H)) endef # ------------------------------------------------------------------ @@ -179,11 +190,14 @@ savedefconfig: @echo "CONFIG_MAX_ORDER = $(CONFIG_MAX_ORDER)" >> .config @echo "CONFIG_KERNEL_STACK_SIZE = $(CONFIG_KERNEL_STACK_SIZE)" >> .config @echo "CONFIG_KASLR = $(CONFIG_KASLR)" >> .config + @echo "CONFIG_KASLR_POLICY_ID = $(CONFIG_KASLR_POLICY_ID)" >> .config + @echo "CONFIG_KASLR_LOG_LEVEL = $(CONFIG_KASLR_LOG_LEVEL)" >> .config @echo "CONFIG_STACK_CANARY = $(CONFIG_STACK_CANARY)" >> .config @echo "CONFIG_DEBUG = $(CONFIG_DEBUG)" >> .config @echo "CONFIG_DEBUG_LOCKS = $(CONFIG_DEBUG_LOCKS)" >> .config @echo "CONFIG_SELFTEST = $(CONFIG_SELFTEST)" >> .config @echo "CONFIG_KLOG = $(CONFIG_KLOG)" >> .config + @echo "CONFIG_KERNEL_COMPRESSED = $(CONFIG_KERNEL_COMPRESSED)" >> .config # 'make showconfig' — print effective configuration showconfig: @@ -201,9 +215,12 @@ showconfig: @echo " MAX_ORDER = $(CONFIG_MAX_ORDER)" @echo " KERNEL_STACK_SIZE = $(CONFIG_KERNEL_STACK_SIZE)" @echo " KASLR = $(CONFIG_KASLR)" + @echo " KASLR_POLICY_ID = $(CONFIG_KASLR_POLICY_ID)" + @echo " KASLR_LOG_LEVEL = $(CONFIG_KASLR_LOG_LEVEL)" @echo " STACK_CANARY = $(CONFIG_STACK_CANARY)" @echo " DEBUG = $(CONFIG_DEBUG)" @echo " DEBUG_LOCKS = $(CONFIG_DEBUG_LOCKS)" @echo " SELFTEST = $(CONFIG_SELFTEST)" @echo " KLOG = $(CONFIG_KLOG)" + @echo " KERNEL_COMPRESSED = $(CONFIG_KERNEL_COMPRESSED)" @echo "========================================" diff --git a/na/scripts/pack_image.py b/na/scripts/pack_image.py new file mode 100644 index 0000000..dc5c6db --- /dev/null +++ b/na/scripts/pack_image.py @@ -0,0 +1,227 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (C) 2026 Richard Qin + +import argparse +import struct +import sys + +MAGIC = 0x4C554D45434F4D50 # "LUMECOMP" +COMP_NONE = 0 +COMP_LZ4 = 1 + +HDR_FMT = " int: + for b in data: + crc ^= b + for _ in range(8): + mask = -(crc & 1) & 0xFFFFFFFF + crc = ((crc >> 1) ^ (0xEDB88320 & mask)) & 0xFFFFFFFF + return crc + + +def crc32_ieee(data: bytes) -> int: + crc = 0xFFFFFFFF + crc = crc32_update(crc, data) + return (crc ^ 0xFFFFFFFF) & 0xFFFFFFFF + + +def lz4_compress(data: bytes) -> bytes: + n = len(data) + if n == 0: + return b"" + + min_match = 4 + hash_log = 16 + hash_size = 1 << hash_log + max_offset = 65535 + + def hash4(b0, b1, b2, b3): + v = b0 | (b1 << 8) | (b2 << 16) | (b3 << 24) + return (v * 2654435761) & (hash_size - 1) + + htab = [-1] * hash_size + out = bytearray() + anchor = 0 + i = 0 + + while i + min_match <= n: + h = hash4(data[i], data[i + 1], data[i + 2], data[i + 3]) + ref = htab[h] + htab[h] = i + + if ref >= 0 and i - ref <= max_offset and data[ref:ref + min_match] == data[i:i + min_match]: + match_len = min_match + while i + match_len < n and data[ref + match_len] == data[i + match_len]: + match_len += 1 + + lit_len = i - anchor + token = (15 if lit_len >= 15 else lit_len) << 4 + match_field = match_len - min_match + token |= 15 if match_field >= 15 else match_field + out.append(token) + + if lit_len >= 15: + l = lit_len - 15 + while l >= 255: + out.append(255) + l -= 255 + out.append(l) + + out.extend(data[anchor:i]) + + offset = i - ref + out.append(offset & 0xFF) + out.append((offset >> 8) & 0xFF) + + if match_field >= 15: + l = match_field - 15 + while l >= 255: + out.append(255) + l -= 255 + out.append(l) + + i += match_len + anchor = i + continue + + i += 1 + + lit_len = n - anchor + token = (15 if lit_len >= 15 else lit_len) << 4 + out.append(token) + if lit_len >= 15: + l = lit_len - 15 + while l >= 255: + out.append(255) + l -= 255 + out.append(l) + out.extend(data[anchor:]) + return bytes(out) + + +def get_header_offset(data: bytes) -> int: + if len(data) < HDR_OFFSET + HDR_SIZE: + return -1 + if data[HDR_OFFSET:HDR_OFFSET + 8] != struct.pack("= e_shnum: + continue + str_off = e_shoff + sh_link * e_shentsize + (sname, stype, sflags, saddr, soff, ssize, slink, sinfo, + salign, sentsz), _ = read_struct("= link_base: + payload_offset = (bss_end - link_base + 7) & ~7 + + header[4] = comp + header[6] = uncompressed_size + header[7] = compressed_size + header[8] = 0 # load_phys_base auto + header[11] = payload_offset + header[12] = 0 + header[13] = crc32_ieee(payload) if payload else 0 + + header_bytes = struct.pack(HDR_FMT, *header) + header[12] = crc32_ieee(header_bytes) + + out = bytearray(raw) + struct.pack_into(HDR_FMT, out, hdr_off, *header) + if payload: + if payload_offset > len(out): + out.extend(b"\x00" * (payload_offset - len(out))) + out.extend(payload) + + with open(args.output, "wb") as f: + f.write(out) + + return 0 + + +if __name__ == "__main__": + try: + sys.exit(main()) + except Exception as e: + print("pack_image: " + str(e), file=sys.stderr) + sys.exit(1) -- cgit v1.2.3