Skip to content

Commit 5cb6459

Browse files
committed
libbpf: Update light skeleton for signing
* The metadata map is created with as an exclusive map (with an excl_prog_hash) This restricts map access exclusively to the signed loader program, preventing tampering by other processes. * The map is then frozen, making it read-only from userspace. * BPF_OBJ_GET_INFO_BY_ID instructs the kernel to compute the hash of the metadata map (H') and store it in bpf_map->sha. * The loader is then loaded with the signature which is then verified by the kernel. The sekeleton currently uses the session keyring (KEY_SPEC_SESSION_KEYRING) by default but this can be overridden by the user of the skeleton. loading signed programs prebuilt into the kernel are not currently supported. These can supported by enabling BPF_OBJ_GET_INFO_BY_ID to be called from the kernel. Signed-off-by: KP Singh <[email protected]>
1 parent cd53c58 commit 5cb6459

File tree

1 file changed

+71
-4
lines changed

1 file changed

+71
-4
lines changed

tools/lib/bpf/skel_internal.h

Lines changed: 71 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,15 @@
1313
#include <unistd.h>
1414
#include <sys/syscall.h>
1515
#include <sys/mman.h>
16+
#include <linux/keyctl.h>
1617
#include <stdlib.h>
1718
#include "bpf.h"
1819
#endif
1920

21+
#ifndef SHA256_DIGEST_LENGTH
22+
#define SHA256_DIGEST_LENGTH 32
23+
#endif
24+
2025
#ifndef __NR_bpf
2126
# if defined(__mips__) && defined(_ABIO32)
2227
# define __NR_bpf 4355
@@ -64,6 +69,11 @@ struct bpf_load_and_run_opts {
6469
__u32 data_sz;
6570
__u32 insns_sz;
6671
const char *errstr;
72+
void *signature;
73+
__u32 signature_sz;
74+
__s32 keyring_id;
75+
void * excl_prog_hash;
76+
__u32 excl_prog_hash_sz;
6777
};
6878

6979
long kern_sys_bpf(__u32 cmd, void *attr, __u32 attr_size);
@@ -220,14 +230,19 @@ static inline int skel_map_create(enum bpf_map_type map_type,
220230
const char *map_name,
221231
__u32 key_size,
222232
__u32 value_size,
223-
__u32 max_entries)
233+
__u32 max_entries,
234+
const void *excl_prog_hash,
235+
__u32 excl_prog_hash_sz)
224236
{
225-
const size_t attr_sz = offsetofend(union bpf_attr, map_extra);
237+
const size_t attr_sz = offsetofend(union bpf_attr, excl_prog_hash);
226238
union bpf_attr attr;
227239

228240
memset(&attr, 0, attr_sz);
229241

230242
attr.map_type = map_type;
243+
attr.excl_prog_hash = (unsigned long) excl_prog_hash;
244+
attr.excl_prog_hash_size = excl_prog_hash_sz;
245+
231246
strncpy(attr.map_name, map_name, sizeof(attr.map_name));
232247
attr.key_size = key_size;
233248
attr.value_size = value_size;
@@ -300,6 +315,34 @@ static inline int skel_link_create(int prog_fd, int target_fd,
300315
return skel_sys_bpf(BPF_LINK_CREATE, &attr, attr_sz);
301316
}
302317

318+
static inline int skel_obj_get_info_by_fd(int fd)
319+
{
320+
const size_t attr_sz = offsetofend(union bpf_attr, info);
321+
__u8 sha[SHA256_DIGEST_LENGTH];
322+
struct bpf_map_info info = {};
323+
__u32 info_len = sizeof(info);
324+
union bpf_attr attr;
325+
326+
info.hash = (long) &sha;
327+
info.hash_size = SHA256_DIGEST_LENGTH;
328+
329+
memset(&attr, 0, attr_sz);
330+
attr.info.bpf_fd = fd;
331+
attr.info.info = (long) &info;
332+
attr.info.info_len = info_len;
333+
return skel_sys_bpf(BPF_OBJ_GET_INFO_BY_FD, &attr, attr_sz);
334+
}
335+
336+
static inline int skel_map_freeze(int fd)
337+
{
338+
const size_t attr_sz = offsetofend(union bpf_attr, map_fd);
339+
union bpf_attr attr;
340+
341+
memset(&attr, 0, attr_sz);
342+
attr.map_fd = fd;
343+
344+
return skel_sys_bpf(BPF_MAP_FREEZE, &attr, attr_sz);
345+
}
303346
#ifdef __KERNEL__
304347
#define set_err
305348
#else
@@ -308,12 +351,13 @@ static inline int skel_link_create(int prog_fd, int target_fd,
308351

309352
static inline int bpf_load_and_run(struct bpf_load_and_run_opts *opts)
310353
{
311-
const size_t prog_load_attr_sz = offsetofend(union bpf_attr, fd_array);
354+
const size_t prog_load_attr_sz = offsetofend(union bpf_attr, keyring_id);
312355
const size_t test_run_attr_sz = offsetofend(union bpf_attr, test);
313356
int map_fd = -1, prog_fd = -1, key = 0, err;
314357
union bpf_attr attr;
315358

316-
err = map_fd = skel_map_create(BPF_MAP_TYPE_ARRAY, "__loader.map", 4, opts->data_sz, 1);
359+
err = map_fd = skel_map_create(BPF_MAP_TYPE_ARRAY, "__loader.map", 4, opts->data_sz, 1,
360+
opts->excl_prog_hash, opts->excl_prog_hash_sz);
317361
if (map_fd < 0) {
318362
opts->errstr = "failed to create loader map";
319363
set_err;
@@ -327,11 +371,34 @@ static inline int bpf_load_and_run(struct bpf_load_and_run_opts *opts)
327371
goto out;
328372
}
329373

374+
#ifndef __KERNEL__
375+
err = skel_map_freeze(map_fd);
376+
if (err < 0) {
377+
opts->errstr = "failed to freeze map";
378+
set_err;
379+
goto out;
380+
}
381+
err = skel_obj_get_info_by_fd(map_fd);
382+
if (err < 0) {
383+
opts->errstr = "failed to fetch obj info";
384+
set_err;
385+
goto out;
386+
}
387+
#endif
388+
330389
memset(&attr, 0, prog_load_attr_sz);
331390
attr.prog_type = BPF_PROG_TYPE_SYSCALL;
332391
attr.insns = (long) opts->insns;
333392
attr.insn_cnt = opts->insns_sz / sizeof(struct bpf_insn);
334393
attr.license = (long) "Dual BSD/GPL";
394+
#ifndef __KERNEL__
395+
attr.signature = (long) opts->signature;
396+
attr.signature_size = opts->signature_sz;
397+
#else
398+
if (opts->signature || opts->signature_sz)
399+
pr_warn("signatures are not supported from bpf_preload\n");
400+
#endif
401+
attr.keyring_id = opts->keyring_id;
335402
memcpy(attr.prog_name, "__loader.prog", sizeof("__loader.prog"));
336403
attr.fd_array = (long) &map_fd;
337404
attr.log_level = opts->ctx->log_level;

0 commit comments

Comments
 (0)