Skip to content

Commit b1e25a3

Browse files
Blaise BoscaccyKernel Patches Daemon
authored andcommitted
bpf: Add hash chain signature support for arbitrary maps
This patch introduces hash chain support for signature verification of arbitrary bpf map objects which was described here: https://lore.kernel.org/linux-security-module/[email protected]/ The UAPI is extended to allow for in-kernel checking of maps passed in via the fd_array. A hash chain is constructed from the maps, in order specified by the signature_maps field. The hash chain is terminated with the hash of the program itself. Tested-by: [email protected] Signed-off-by: Blaise Boscaccy <[email protected]>
1 parent c395c15 commit b1e25a3

File tree

3 files changed

+81
-4
lines changed

3 files changed

+81
-4
lines changed

include/uapi/linux/bpf.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1621,6 +1621,12 @@ union bpf_attr {
16211621
* verification.
16221622
*/
16231623
__s32 keyring_id;
1624+
/* Pointer to a buffer containing the maps used in the signature
1625+
* hash chain of the BPF program.
1626+
*/
1627+
__aligned_u64 signature_maps;
1628+
/* Size of the signature maps buffer. */
1629+
__u32 signature_maps_size;
16241630
};
16251631

16261632
struct { /* anonymous struct used by BPF_OBJ_* commands */

kernel/bpf/syscall.c

Lines changed: 69 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2802,14 +2802,35 @@ static bool is_perfmon_prog_type(enum bpf_prog_type prog_type)
28022802
}
28032803
}
28042804

2805+
static inline int bpf_map_get_hash(int map_fd, void *buffer)
2806+
{
2807+
struct bpf_map *map;
2808+
2809+
CLASS(fd, f)(map_fd);
2810+
map = __bpf_map_get(f);
2811+
if (IS_ERR(map))
2812+
return PTR_ERR(map);
2813+
2814+
if (!map->ops->map_get_hash)
2815+
return -EINVAL;
2816+
2817+
return map->ops->map_get_hash(map, SHA256_DIGEST_SIZE, buffer);
2818+
}
2819+
28052820
static int bpf_prog_verify_signature(struct bpf_prog *prog, union bpf_attr *attr,
28062821
bool is_kernel)
28072822
{
28082823
bpfptr_t usig = make_bpfptr(attr->signature, is_kernel);
2809-
struct bpf_dynptr_kern sig_ptr, insns_ptr;
2824+
bpfptr_t umaps;
2825+
struct bpf_dynptr_kern sig_ptr, insns_ptr, hash_ptr;
28102826
struct bpf_key *key = NULL;
28112827
void *sig;
2828+
int *maps;
2829+
int map_fd;
28122830
int err = 0;
2831+
u64 buffer[SHA256_DIGEST_SIZE * 2 / sizeof(u64)];
2832+
u64 hash[SHA256_DIGEST_SIZE / sizeof(u64)];
2833+
int n;
28132834

28142835
if (system_keyring_id_check(attr->keyring_id) == 0)
28152836
key = bpf_lookup_system_key(attr->keyring_id);
@@ -2830,16 +2851,60 @@ static int bpf_prog_verify_signature(struct bpf_prog *prog, union bpf_attr *attr
28302851
bpf_dynptr_init(&insns_ptr, prog->insnsi, BPF_DYNPTR_TYPE_LOCAL, 0,
28312852
prog->len * sizeof(struct bpf_insn));
28322853

2833-
err = bpf_verify_pkcs7_signature((struct bpf_dynptr *)&insns_ptr,
2834-
(struct bpf_dynptr *)&sig_ptr, key);
2854+
if (!attr->signature_maps_size) {
2855+
err = bpf_verify_pkcs7_signature((struct bpf_dynptr *)&insns_ptr,
2856+
(struct bpf_dynptr *)&sig_ptr, key);
2857+
} else {
2858+
bpf_dynptr_init(&hash_ptr, hash, BPF_DYNPTR_TYPE_LOCAL, 0,
2859+
sizeof(hash));
2860+
umaps = make_bpfptr(attr->signature_maps, is_kernel);
2861+
maps = kvmemdup_bpfptr(umaps, attr->signature_maps_size * sizeof(*maps));
2862+
if (IS_ERR(maps)) {
2863+
err = PTR_ERR(maps);
2864+
goto out;
2865+
}
2866+
/* Process the map array in reverse order to generate a hash chain
2867+
* h(n) = sha256(h(n + 1), sha256(map(n)))
2868+
* h(n_len) = sha256(map(n_len))
2869+
*/
2870+
for (n = attr->signature_maps_size - 1; n >= 0; n--) {
2871+
err = copy_from_bpfptr_offset(&map_fd,
2872+
make_bpfptr(attr->fd_array, is_kernel),
2873+
maps[n] * sizeof(map_fd),
2874+
sizeof(map_fd));
2875+
if (err)
2876+
goto free_maps;
2877+
2878+
if (n == attr->signature_maps_size - 1)
2879+
err = bpf_map_get_hash(map_fd, hash);
2880+
else {
2881+
memcpy(buffer, hash, sizeof(hash));
2882+
err = bpf_map_get_hash(map_fd, buffer + ARRAY_SIZE(hash));
2883+
sha256((u8 *)buffer, sizeof(buffer), (u8 *)&hash);
2884+
}
2885+
if (err)
2886+
goto free_maps;
2887+
}
2888+
/* Calculate final hash with program instructions
2889+
* f_hash = sha256(sha256(prog), h(0))
2890+
*/
2891+
sha256((u8 *)prog->insnsi, prog->len * sizeof(struct bpf_insn), (u8 *)&buffer);
2892+
memcpy(buffer + ARRAY_SIZE(hash), hash, sizeof(hash));
2893+
sha256((u8 *)buffer, sizeof(buffer), (u8 *)&hash);
2894+
err = bpf_verify_pkcs7_signature((struct bpf_dynptr *)&hash_ptr,
2895+
(struct bpf_dynptr *)&sig_ptr, key);
28352896

2897+
free_maps:
2898+
kvfree(maps);
2899+
}
2900+
out:
28362901
bpf_key_put(key);
28372902
kvfree(sig);
28382903
return err;
28392904
}
28402905

28412906
/* last field in 'union bpf_attr' used by this command */
2842-
#define BPF_PROG_LOAD_LAST_FIELD keyring_id
2907+
#define BPF_PROG_LOAD_LAST_FIELD signature_maps_size
28432908

28442909
static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr, u32 uattr_size)
28452910
{

tools/include/uapi/linux/bpf.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1621,6 +1621,12 @@ union bpf_attr {
16211621
* verification.
16221622
*/
16231623
__s32 keyring_id;
1624+
/* Pointer to a buffer containing the maps used in the signature
1625+
* hash chain of the BPF program.
1626+
*/
1627+
__aligned_u64 signature_maps;
1628+
/* Size of the signature maps buffer. */
1629+
__u32 signature_maps_size;
16241630
};
16251631

16261632
struct { /* anonymous struct used by BPF_OBJ_* commands */

0 commit comments

Comments
 (0)