[PATCH] crypto: asymmetric_keys - fix OOB read in pefile_parse_binary

Fabrice Derepas <[email protected]>
Newsgroups org.kernel.vger.linux-crypto,org.infradead.lists.kexec,org.kernel.vger.keyrings,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
pefile_parse_binary() reads the size field of the certificate table's
data-directory entry, which sits at fixed index 4 of the PE optional
header's data directory:

	ctx->certs_size = ddir->certs.size;

but nothing ensures index 4 is present. n_data_dirents (the untrusted
NumberOfRvaAndSizes) is only upper-bounded against header_size and may be
0, and header_size need only satisfy cursor < header_size < datalen. A
crafted PE with n_data_dirents = 0 and a tiny header_size therefore causes
the ddir->certs.size read to land past the end of the image (CWE-125). The
chkaddr() that bounds the certificate blob runs only after this read.

verify_pefile_signature() is reached from kexec_file_load() (the
lockdown/secure-boot enforced PE-image signature path), and the image is
parsed before its signature is checked. The trigger needs CAP_SYS_BOOT and
the access is out-of-bounds read only (no write).

Require the certificate table's data-directory entry (index 4) to be
present; the existing upper-bound check then keeps ddir->certs within
[cursor, header_size).

Fixes: 26d1164be37f ("pefile: Parse a PE binary to find a key and a signature contained therein")
Assisted-by: copilot-cli:claude-opus-4-6 frama-c
Signed-off-by: Fabrice Derepas <[email protected]>
---
Reproduced under KASAN (CONFIG_KASAN_GENERIC, x86-64) with a KUnit case that
builds a crafted PE (valid MZ/PE/PE32 magics, data_dirs = 0, header_size just
past the optional header) and calls verify_pefile_signature() with a NULL
keyring -- the parse runs before any signature check. On an unpatched kernel:

    BUG: KASAN: slab-out-of-bounds in verify_pefile_signature+0x1d6/0x950
    Read of size 4 ... in pefile_parse_binary() (inlined)

With this patch the crafted image is rejected (-ELIBBAD) before the read and
the case passes with no KASAN report. The test is not included here; happy to
submit it separately.

 crypto/asymmetric_keys/verify_pefile.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/crypto/asymmetric_keys/verify_pefile.c b/crypto/asymmetric_keys/verify_pefile.c
index cec99db..e7f8bdb 100644
--- a/crypto/asymmetric_keys/verify_pefile.c
+++ b/crypto/asymmetric_keys/verify_pefile.c
@@ -87,6 +87,10 @@ static int pefile_parse_binary(const void *pebuf, unsigned int pelen,
 	if (ctx->n_data_dirents > (ctx->header_size - cursor) / sizeof(*dde))
 		return -ELIBBAD;
 
+	/* The certificate table entry is at fixed index 4 of the data directory. */
+	if (ctx->n_data_dirents <= 4)
+		return -ELIBBAD;
+
 	ddir = pebuf + cursor;
 	cursor += sizeof(*dde) * ctx->n_data_dirents;
 
base-commit: 3d6d817622b0a9721e3cc404df3469171582be13
-- 
2.53.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.