[PATCH 01/11] hornet: fix TOCTOU in signed program verification
Paul Moore
paul at paul-moore.com
Tue Jun 2 03:25:53 UTC 2026
On Fri, May 29, 2026 at 9:11 PM Fan Wu <wufan at kernel.org> wrote:
> On Wed, May 27, 2026 at 8:09 PM Blaise Boscaccy
> <bboscaccy at linux.microsoft.com> wrote:
> >
> > The signature verification path was vulnerable to a time-of-check vs
> > time-of-use race at both the program load and program run hook sites:
> > between the moment a map's contents were hashed for signature
> > verification and the moment the program run hook re-verified them, an
> > attacker with sufficient privileges could swap or mutate the map
> > contents.
> >
> > Close the race by snapshotting the map hashes during program load,
> > attaching them to the program, and re-verifying them from the
> > security_bpf_prog hook against prog->aux->used_maps. Because used_maps
> > is the same map set the verifier and runtime resolve against, there is
> > no longer a window in which the verified set and the executed set can
> > diverge.
> >
> > Since we are no longer targeting the fd_array passed in, drop the map
> > index data entirely and check for whether or not the set of requested
> > map hashes is a subset of prog->aux->used_maps.
> >
> > Reported-by: Eric Biggers <ebiggers at kernel.org>
> > Signed-off-by: Blaise Boscaccy <bboscaccy at linux.microsoft.com>
> > ---
> > Documentation/admin-guide/LSM/Hornet.rst | 39 +++-----
> > scripts/hornet/gen_sig.c | 17 +---
> > security/hornet/hornet.asn1 | 1 -
> > security/hornet/hornet_lsm.c | 121 +++--------------------
> > tools/testing/selftests/hornet/Makefile | 2 +-
> > 5 files changed, 35 insertions(+), 145 deletions(-)
A reminder to please trim your replies.
> > -static int hornet_verify_hashes(struct hornet_maps *maps,
> > - struct hornet_parse_context *ctx,
> > - struct bpf_prog *prog)
> > -{
> > - int map_fd;
> > - u32 i;
> > - struct bpf_map *map;
> > - int err = 0;
> > - unsigned char hash[SHA256_DIGEST_SIZE];
> > - struct hornet_prog_security_struct *security = hornet_bpf_prog_security(prog);
> > -
> > - for (i = 0; i < ctx->hash_count; i++) {
> > - if (ctx->skips[i])
> > - continue;
> > -
> > - err = copy_from_bpfptr_offset(&map_fd, maps->fd_array,
> > - ctx->indexes[i] * sizeof(map_fd),
> > - sizeof(map_fd));
> > - if (err != 0)
> > - return LSM_INT_VERDICT_FAULT;
>
> It seems this verdict is no longer used.
>
> > -
> > - CLASS(fd, f)(map_fd);
> > - if (fd_empty(f))
> > - return LSM_INT_VERDICT_FAULT;
> > - if (unlikely(fd_file(f)->f_op != &bpf_map_fops))
> > - return LSM_INT_VERDICT_FAULT;
> > -
> > - map = fd_file(f)->private_data;
> > - if (!READ_ONCE(map->frozen))
> > - return LSM_INT_VERDICT_FAULT;
> > -
> > - if (!map->ops->map_get_hash)
> > - return LSM_INT_VERDICT_FAULT;
> > -
> > - if (map->ops->map_get_hash(map, SHA256_DIGEST_SIZE, hash))
> > - return LSM_INT_VERDICT_FAULT;
> > -
> > - err = memcmp(hash, &ctx->hashes[i * SHA256_DIGEST_SIZE],
> > - SHA256_DIGEST_SIZE);
> > - if (err)
> > - return LSM_INT_VERDICT_UNEXPECTED;
>
> similar above, they should be removed for the header and for the ipe policy.
I would prefer to see LSM_INT_VERDICT_FAULT preserved as I think it is
good to have a verdict indicating a general error in the integrity
verification code, but I do agree with Fan that removing
VERDICT_UNEXPECTED is probably a good thing to do.
If Fan is insistent on removal of VERDICT_FAULT from the IPE code
that's fine, just leave it in the LSM header.
Can you get a patch out for this ASAP Blaise?
--
paul-moore.com
More information about the Linux-security-module-archive
mailing list