build: compile kernel archives for the selected architecture and iOS version

This commit is contained in:
bluseliu50 committed 2026-10-26 14:43:27 +08:00
1 parent f66b8b8fe6
commit 2d5a60af86
11 files changed
+152 -52

No files matched your search

+16
View File
@@ -0,0 +1,16 @@
diff --git a/pexpert/pexpert/arm64/BCM2837.h b/pexpert/pexpert/arm64/BCM2837.h
index 9c140d76..5a5574ea 100644
--- a/pexpert/pexpert/arm64/BCM2837.h
+++ b/pexpert/pexpert/arm64/BCM2837.h
@@ -18,6 +18,11 @@
#define __ARM_DEBUG__ 7
#define __ARM64_PMAP_SUBPAGE_L1__ 1
+/* Native ARMv8.1+ targets select PAN explicitly; the original A53 target has none. */
+#if defined(XNU_NATIVE_PAN) && XNU_NATIVE_PAN
+#define __ARM_PAN_AVAILABLE__ 1
+#endif
+
/*
* arm64e on a non-Apple ARMv8.3 CPU: pointer authentication uses the
* architectural key registers (see HAS_NATIVE_PAC in arm64/pac_asm.h).
@@ -0,0 +1,40 @@
diff --git a/osfmk/prng/prng_random.c b/osfmk/prng/prng_random.c
index 504b3fa7..3cda99ff 100644
--- a/osfmk/prng/prng_random.c
+++ b/osfmk/prng/prng_random.c
@@ -502,3 +502,35 @@ random_bool_gen_bits(struct bool_gen * bg, unsigned int * buffer, unsigned int c
}
return rbits;
}
+
+/* Internal source-provider verification; no replacement callbacks or skipped POST. */
+#if defined(XNU_SOURCE_CORECRYPTO14)
+#include <kern/startup.h>
+#include <mach/kmod.h>
+#include <mach-o/loader.h>
+
+extern struct mach_header_64 _mh_execute_header;
+extern kern_return_t corecrypto_kext_start(kmod_info_t *, void *);
+SECURITY_READ_ONLY_LATE(kern_return_t) source_corecrypto14_status = KERN_FAILURE;
+
+static void
+source_corecrypto14_bootstrap(void)
+{
+ static kmod_info_t info = {
+ .info_version = KMOD_INFO_VERSION,
+ .name = "source-corecrypto14-evaluation",
+ .version = "14.0",
+ };
+ uint32_t mode = 0;
+
+ if (PE_parse_boot_argn("fips_mode", &mode, sizeof(mode)) && mode != 0) {
+ panic("source corecrypto verification requires complete default POST");
+ }
+ info.address = (vm_address_t)&_mh_execute_header;
+ source_corecrypto14_status = corecrypto_kext_start(&info, NULL);
+ if (source_corecrypto14_status != KERN_SUCCESS) {
+ panic("source corecrypto initialization failed: %d", source_corecrypto14_status);
+ }
+}
+STARTUP(EARLY_BOOT, STARTUP_RANK_FIRST, source_corecrypto14_bootstrap);
+#endif
@@ -0,0 +1,29 @@
diff --git a/bsd/kern/source_pthread_bootstrap.c b/bsd/kern/source_pthread_bootstrap.c
new file mode 100644
index 00000000..86a48e9c
--- /dev/null
+++ b/bsd/kern/source_pthread_bootstrap.c
@@ -0,0 +1,23 @@
+/* SPDX-License-Identifier: BSD-2-Clause-Patent */
+#include <kern/startup.h>
+#include <kern/debug.h>
+#include <libkern/section_keywords.h>
+#include <mach/kmod.h>
+
+extern kern_return_t pthread_start(kmod_info_t *, void *);
+SECURITY_READ_ONLY_LATE(kern_return_t) source_pthread_status = KERN_FAILURE;
+
+static void
+source_pthread_bootstrap(void)
+{
+ static kmod_info_t info = {
+ .info_version = KMOD_INFO_VERSION,
+ .name = "source-libpthread",
+ .version = "519.120.4",
+ };
+ source_pthread_status = pthread_start(&info, NULL);
+ if (source_pthread_status != KERN_SUCCESS) {
+ panic("source libpthread registration failed: %d", source_pthread_status);
+ }
+}
+STARTUP(EARLY_BOOT, STARTUP_RANK_SECOND, source_pthread_bootstrap);
@@ -0,0 +1,7 @@
CONFIG_XNU_BUILD_ARCHIVES=y
CONFIG_XNU_SOURCE_CORECRYPTO14=y
CONFIG_XNU_SOURCE_PTHREAD=y
CONFIG_XNU_ARM_DT_PLATFORM=y
CONFIG_XNU_ARMCPU=y
CONFIG_XNU_NATIVE_ARCH_TIMER=y
CONFIG_XNU_NATIVE_PAN=y
+3
View File
@@ -25,3 +25,6 @@
../../../../../patches/xnu-12377/public-pmap-without-monitor.patch
../../../../../patches/xnu-12377/optional-kernel-support-archive.patch
../../../../../patches/xnu-12377/public-missing-definitions.patch
../../../../../patches/xnu-12377/source-corecrypto14-bootstrap.patch
../../../../../patches/xnu-12377/source-pthread-bootstrap.patch
../../../../../patches/xnu-12377/native-arm-pan.patch
+4 -15
View File
@@ -4,9 +4,10 @@ import argparse
import json
import tomllib
from pathlib import Path
import struct
import subprocess
from kernel_target import TRIPLE, check_object
ROOT = Path(__file__).resolve().parents[1]
parser = argparse.ArgumentParser(description=__doc__)
catalog = {entry['id']: entry for entry in tomllib.loads((ROOT / 'components.toml').read_text())['component']
@@ -103,20 +104,8 @@ result = subprocess.run(command, cwd=record['directory'], stdout=subprocess.PIPE
(out / 'compile.log').write_text(result.stdout)
if result.returncode:
raise SystemExit(result.stdout[-3500:])
data = destination.read_bytes()
magic, cpu, subtype, kind, count, size = struct.unpack_from('<6I', data)
if (magic, cpu, subtype, kind) != (0xfeedfacf, 0x100000c, 0, 1):
raise SystemExit('Unexpected platform object architecture')
offset = 32
deployment = None
for _ in range(count):
cmd, length = struct.unpack_from('<II', data, offset)
if cmd == 0x32:
deployment = struct.unpack_from('<II', data, offset + 8)
offset += length
if deployment != (2, 0x110000):
raise SystemExit(f'Unexpected platform deployment {deployment}')
check_object(destination.read_bytes(), component)
archive = out / ('lib' + identifier + '.a')
archive.unlink(missing_ok=True)
subprocess.run(['xcrun', 'ar', 'rcs', archive, destination], check=True)
print(f'{identifier}: -Werror build and actual ARM64/iOS 17 object audit passed')
print(f'{identifier}: -Werror build and {TRIPLE} object audit passed')
+4 -16
View File
@@ -11,12 +11,12 @@ import json
from pathlib import Path
import platform
import subprocess
import struct
import sys
ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT / 'scripts'))
import pbxproj
from kernel_target import TRIPLE, check_object
from xnu_symbols import kernel_names
SOURCE = ROOT / 'refer/corecrypto-2023'
REVISION = '11fba65b12d8830630e248dfa8344caf8b065f26'
@@ -74,7 +74,7 @@ for header in SOURCE.glob('*/corecrypto/*.h'):
link.symlink_to(header)
sdk = subprocess.check_output(['xcrun', '--sdk', 'iphoneos', '--show-sdk-path'], text=True).strip()
framework = ROOT / '.cache/fakeroot/System/Library/Frameworks/Kernel.framework/Versions/A'
command = ['xcrun', '--sdk', 'iphoneos', 'clang', '-target', 'arm64-apple-ios17.0', '-isysroot', sdk,
command = ['xcrun', '--sdk', 'iphoneos', 'clang', '-target', TRIPLE, '-isysroot', sdk,
'-mkernel', '-ffreestanding', '-fno-builtin', '-fno-stack-check', '-std=gnu99', '-fblocks', '-O2',
'-fno-vectorize', '-fno-slp-vectorize', '-mno-implicit-float',
'-DKERNEL=1', '-DKERNEL_PRIVATE=1', '-DBUILDKERNEL=1', '-DCC_USE_ASM=0', '-DNDEBUG=1',
@@ -114,7 +114,7 @@ with concurrent.futures.ThreadPoolExecutor(max_workers=4) as executor:
failed = [result for result in results if result['exit_code']]
report = {'source_url': 'https://github.com/ONLYA/corecrypto-2023', 'source_revision': REVISION,
'provenance': 'Third-party source snapshot; not authenticated against an Apple archive',
'module_version': '14.0', 'target': 'arm64-apple-ios17.0', 'assembly_enabled': False,
'module_version': '14.0', 'target': TRIPLE, 'assembly_enabled': False,
'compiled_sources': len(results), 'failures': len(failed), 'objects': results,
'kernel_provider_registered': False, 'crypto_selftests_passed': False}
(OUT / f'build-report{variant}.json').write_text(json.dumps(report, indent=2) + '\n')
@@ -124,19 +124,7 @@ for result in failed[:8]:
if failed:
sys.exit(1)
for result in results:
data = (object_dir / result['object']).read_bytes()
magic, cpu, subtype, kind, count, size = struct.unpack_from('<6I', data)
if (magic, cpu, subtype, kind) != (0xfeedfacf, 0x100000c, 0, 1):
raise SystemExit(f'Wrong object architecture: {result["object"]}')
offset = 32
deployment = None
for _ in range(count):
cmd, length = struct.unpack_from('<II', data, offset)
if cmd == 0x32:
deployment = struct.unpack_from('<II', data, offset + 8)
offset += length
if deployment != (2, 0x110000):
raise SystemExit(f'Wrong deployment: {result["object"]}: {deployment}')
check_object((object_dir / result['object']).read_bytes(), result['object'])
archive = OUT / f'libcorecrypto_kernel_noasm{variant}.a'
archive.unlink(missing_ok=True)
subprocess.run(['xcrun', 'ar', 'rcs', archive, *[object_dir / result['object'] for result in results]], check=True)
+11 -18
View File
@@ -1,21 +1,26 @@
#!/usr/bin/env python3
"""Build the matching Darwin 23 pthread kernel component and its real registration."""
"""Build the pthread kernel component of the selected OS profile and its real registration."""
import json
import os
import shutil
from pathlib import Path
import struct
import subprocess
import sys
ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT / 'scripts'))
from kernel_target import TRIPLE, check_object
from xnu_symbols import kernel_names
SOURCE = ROOT / 'refer/libpthread'
REVISION = 'c0e60fb5ecfc54cf379c261d3f9572cc22ded891'
# The OS profile pins the source; without it, the Darwin 23 revision.
REVISION = os.environ.get('UNIXNU_LIBPTHREAD_COMMIT', 'c0e60fb5ecfc54cf379c261d3f9572cc22ded891')
if subprocess.check_output(['git', '-C', SOURCE, 'rev-parse', 'HEAD'], text=True).strip() != REVISION:
raise SystemExit('Unexpected libpthread source revision')
if subprocess.check_output(['git', '-C', SOURCE, 'status', '--porcelain'], text=True):
raise SystemExit('The libpthread reference must remain immutable')
WORK = ROOT / '.cache/libpthread-work'
if WORK.exists() and subprocess.check_output(['git', '-C', WORK, 'rev-parse', 'HEAD'], text=True).strip() != REVISION:
shutil.rmtree(WORK)
if not WORK.exists():
subprocess.run(['git', 'clone', '--shared', SOURCE, WORK], check=True)
for patch in sorted((ROOT / 'patches/libpthread').glob('*.patch')):
@@ -47,7 +52,7 @@ def compile_one(source, destination, namespace=None):
index += 1
else:
framework = ROOT / '.cache/fakeroot/System/Library/Frameworks/Kernel.framework/Versions/A'
command = ['xcrun', '--sdk', 'iphoneos', 'clang', '-target', 'arm64-apple-ios17.0',
command = ['xcrun', '--sdk', 'iphoneos', 'clang', '-target', TRIPLE,
'-isysroot', sdk, '-mkernel', '-ffreestanding', '-fno-builtin', '-fno-stack-check',
'-std=gnu11', '-fblocks', '-O2', '-mno-implicit-float',
'-DKERNEL=1', '-DKERNEL_PRIVATE=1', '-DXNU_KERNEL_PRIVATE=1',
@@ -62,19 +67,7 @@ def compile_one(source, destination, namespace=None):
destination.with_suffix('.log').write_text(result.stdout)
if result.returncode:
raise SystemExit(result.stdout[-4500:])
data = destination.read_bytes()
if struct.unpack_from('<4I', data) != (0xfeedfacf, 0x100000c, 0, 1):
raise SystemExit('Unexpected pthread object architecture')
offset = 32
deployment = None
for _ in range(struct.unpack_from('<I', data, 16)[0]):
cmd, length = struct.unpack_from('<II', data, offset)
if cmd == 0x32:
deployment = struct.unpack_from('<II', data, offset + 8)
offset += length
if deployment != (2, 0x110000):
raise SystemExit(f'Unexpected pthread deployment: {deployment}')
check_object(destination.read_bytes(), destination.name)
def names(path, mode, global_only=True):
result = subprocess.check_output(['xcrun', 'nm', *(['-g'] if global_only else []), mode, '-j', path], text=True)
@@ -100,7 +93,7 @@ imports = set().union(*(names(path, '-u') for path in objects)) - definitions
# The component is statically linked: os_log's DSO identity is the real
# executable Mach-O header, synthesized by the Mach-O executable linker.
missing = sorted(imports - kernel_names - {'___dso_handle'})
report = {'revision': REVISION, 'sources': 3, 'ordinary_arm64_ios17_audited': True,
report = {'revision': REVISION, 'sources': 3, 'target': TRIPLE, 'target_audited': True,
'namespace_collisions_isolated': sorted(collisions), 'missing_kernel_names': missing,
'linker_synthesized_symbols': ['___dso_handle'],
'registration_observed': False}
+32
View File
@@ -0,0 +1,32 @@
"""Target of objects linked into the kernel: architecture and iOS deployment of the kernel build.
The kernel build exports UNIXNU_XNU_ARCH and UNIXNU_IOS_VERSION from the selected profiles. Without them
the arm64 iOS 17.0 target is used.
"""
import os
import struct
ARCH = os.environ.get('UNIXNU_XNU_ARCH', 'arm64')
IOS_VERSION = os.environ.get('UNIXNU_IOS_VERSION', '17.0')
TRIPLE = f'{ARCH}-apple-ios{IOS_VERSION}'
_major, _minor = (IOS_VERSION.split('.') + ['0'])[:2]
DEPLOYMENT = (2, int(_major) << 16 | int(_minor) << 8)
_SUBTYPES = {'arm64': 0, 'arm64e': 2}
if ARCH not in _SUBTYPES:
raise SystemExit(f'Unsupported kernel architecture {ARCH}')
SUBTYPE = _SUBTYPES[ARCH]
def check_object(data, what):
"""Refuse a relocatable object whose architecture or deployment differs from the kernel target."""
magic, cpu, subtype, kind, count = struct.unpack_from('<5I', data)
if (magic, cpu, subtype & 0xff, kind) != (0xfeedfacf, 0x100000c, SUBTYPE, 1):
raise SystemExit(f'{what}: not an {ARCH} object')
offset, deployment = 32, None
for _ in range(count):
command, length = struct.unpack_from('<II', data, offset)
if command == 0x32:
deployment = struct.unpack_from('<II', data, offset + 8)
offset += length
if deployment != DEPLOYMENT:
raise SystemExit(f'{what}: deployment {deployment}, expected {DEPLOYMENT}')
+5 -2
View File
@@ -12,12 +12,15 @@ import json
from pathlib import Path
import struct
from kernel_target import ARCH, SUBTYPE
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('kernel', type=Path)
args = parser.parse_args()
data = bytearray(args.kernel.read_bytes())
if struct.unpack_from('<4I', data) != (0xfeedfacf, 0x100000c, 0, 2):
raise SystemExit('Expected a source-built ordinary ARM64 MH_EXECUTE kernel')
magic, cpu, subtype, kind = struct.unpack_from('<4I', data)
if (magic, cpu, subtype & 0xff, kind) != (0xfeedfacf, 0x100000c, SUBTYPE, 2):
raise SystemExit(f'Expected a source-built {ARCH} MH_EXECUTE kernel')
if b'_source_corecrypto14_bootstrap\0' not in data:
raise SystemExit('Input does not contain the explicit source-provider bootstrap')
offset = 32
+1 -1
View File
@@ -23,7 +23,7 @@ def xnu_env(ctx):
def version_env(modules, ctx=None):
"""Source versions of the Apple references, from feeds.toml, for the kernel scripts."""
env = {}
for name, prefix in (('xnu', 'XNU'), ('libplatform', 'LIBPLATFORM'), ('libdispatch', 'LIBDISPATCH'), ('AvailabilityVersions', 'AVAILABILITYVERSIONS')):
for name, prefix in (('xnu', 'XNU'), ('libplatform', 'LIBPLATFORM'), ('libdispatch', 'LIBDISPATCH'), ('AvailabilityVersions', 'AVAILABILITYVERSIONS'), ('libpthread', 'LIBPTHREAD')):
module = modules.get(('refer', name))
entry = module.source if module and module.source else {}
if entry.get('ref'):