From 04a64fb6c7a5304048ac3def939c5de7199690d9 Mon Sep 17 00:00:00 2001 From: Gerald Yang Date: Wed, 12 Aug 2026 10:30:23 +0800 Subject: [PATCH] Pin goroutine to OS thread when reading the primary key The keyring links established by KEYCTL_LINK are per-thread, but Go may reschedule the goroutine onto a different OS thread between the link and the subsequent key read, making the read intermittently fail with permission denied: final reseal failed: cannot obtain auth key from kernel: cannot read key from kernel: cannot determine size of key payload: permission denied Wrap the link and read in runtime.LockOSThread()/UnlockOSThread() so both syscalls run on the same thread. Signed-off-by: Gerald Yang --- efibootmgr/reseal.go | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/efibootmgr/reseal.go b/efibootmgr/reseal.go index 285e3ed..dbe9223 100644 --- a/efibootmgr/reseal.go +++ b/efibootmgr/reseal.go @@ -13,6 +13,7 @@ import ( "log" "os" "path/filepath" + "runtime" "strings" "syscall" @@ -115,6 +116,16 @@ func getPrimaryKeyFromKernel() (secboot.PrimaryKey, error) { return nil, fmt.Errorf("cannot resolve devive symlink: %w", err) } + // The keyring is stored in OS thread (task_struct in linux kernel), not the process + // Link a keyring into it only takes effect for whichever thread performs the link + // and Go is free to reschedule this goroutine onto a different OS thread between + // syscalls. + // Pin the goroutine to its current thread, so both KEYCTL_LINK and the key read are + // able to access the same keyring; otherwise the read intermittently fails with + // permission denied, because it's on a thread whose keyring never got the link. + runtime.LockOSThread() + defer runtime.UnlockOSThread() + // By default, system services get their own session keyring that doesn't have // the user keyring linked to it. This means that attempting to read a key from // the user keyring will fail if the key only permits possessor read. Link the