Skip to content

Commit 524f41f

Browse files
committed
bpftool: Add support for signing BPF programs
Two modes of operation being added: Add two modes of operation: * For prog load, allow signing a program immediately before loading. This is essential for command-line testing and administration. bpftool prog load -S -k <private_key> -i <identity_cert> fentry_test.bpf.o * For gen skeleton, embed a pre-generated signature into the C skeleton file. This supports the use of signed programs in compiled applications. bpftool gen skeleton -S -k <private_key> -i <identity_cert> fentry_test.bpf.o Generation of the loader program and its metadata map is implemented in libbpf (bpf_obj__gen_loader). bpftool generates a skeleton that loads the program and automates the required steps: freezing the map, creating an exclusive map, loading, and running. Users can use standard libbpf APIs directly or integrate loader program generation into their own toolchains. Signed-off-by: KP Singh <[email protected]>
1 parent 2802a1c commit 524f41f

File tree

9 files changed

+367
-13
lines changed

9 files changed

+367
-13
lines changed

tools/bpf/bpftool/Documentation/bpftool-gen.rst

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ SYNOPSIS
1616

1717
**bpftool** [*OPTIONS*] **gen** *COMMAND*
1818

19-
*OPTIONS* := { |COMMON_OPTIONS| | { **-L** | **--use-loader** } }
19+
*OPTIONS* := { |COMMON_OPTIONS| [ { **-L** | **--use-loader** } ]
20+
[ { { **-S** | **--sign** } **-k** <private_key.pem> **-i** <certificate.x509> } ] }}
2021

2122
*COMMAND* := { **object** | **skeleton** | **help** }
2223

@@ -186,6 +187,19 @@ OPTIONS
186187
skeleton). A light skeleton contains a loader eBPF program. It does not use
187188
the majority of the libbpf infrastructure, and does not need libelf.
188189

190+
-S, --sign
191+
For skeletons, generate a signed skeleton. This option must be used with
192+
**-k** and **-i**. Using this flag implicitly enables **--use-loader**.
193+
See the "Signed Skeletons" section in the description of the
194+
**gen skeleton** command for more details.
195+
196+
-k <private_key.pem>
197+
Path to the private key file in PEM format, required for signing.
198+
199+
-i <certificate.x509>
200+
Path to the X.509 certificate file in PEM or DER format, required for
201+
signing.
202+
189203
EXAMPLES
190204
========
191205
**$ cat example1.bpf.c**

tools/bpf/bpftool/Documentation/bpftool-prog.rst

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@ SYNOPSIS
1616

1717
**bpftool** [*OPTIONS*] **prog** *COMMAND*
1818

19-
*OPTIONS* := { |COMMON_OPTIONS| |
20-
{ **-f** | **--bpffs** } | { **-m** | **--mapcompat** } | { **-n** | **--nomount** } |
21-
{ **-L** | **--use-loader** } }
19+
*OPTIONS* := { |COMMON_OPTIONS| [ { **-f** | **--bpffs** } ] [ { **-m** | **--mapcompat** } ]
20+
[ { **-n** | **--nomount** } ] [ { **-L** | **--use-loader** } ]
21+
[ { { **-S** | **--sign** } **-k** <private_key.pem> **-i** <certificate.x509> } ] }
2222

2323
*COMMANDS* :=
2424
{ **show** | **list** | **dump xlated** | **dump jited** | **pin** | **load** |
@@ -248,6 +248,18 @@ OPTIONS
248248
creating the maps, and loading the programs (see **bpftool prog tracelog**
249249
as a way to dump those messages).
250250

251+
-S, --sign
252+
Enable signing of the BPF program before loading. This option must be
253+
used with **-k** and **-i**. Using this flag implicitly enables
254+
**--use-loader**.
255+
256+
-k <private_key.pem>
257+
Path to the private key file in PEM format, required when signing.
258+
259+
-i <certificate.x509>
260+
Path to the X.509 certificate file in PEM or DER format, required when
261+
signing.
262+
251263
EXAMPLES
252264
========
253265
**# bpftool prog show**

tools/bpf/bpftool/Makefile

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -130,8 +130,8 @@ include $(FEATURES_DUMP)
130130
endif
131131
endif
132132

133-
LIBS = $(LIBBPF) -lelf -lz
134-
LIBS_BOOTSTRAP = $(LIBBPF_BOOTSTRAP) -lelf -lz
133+
LIBS = $(LIBBPF) -lelf -lz -lcrypto
134+
LIBS_BOOTSTRAP = $(LIBBPF_BOOTSTRAP) -lelf -lz -lcrypto
135135

136136
ifeq ($(feature-libelf-zstd),1)
137137
LIBS += -lzstd
@@ -194,7 +194,7 @@ endif
194194

195195
BPFTOOL_BOOTSTRAP := $(BOOTSTRAP_OUTPUT)bpftool
196196

197-
BOOTSTRAP_OBJS = $(addprefix $(BOOTSTRAP_OUTPUT),main.o common.o json_writer.o gen.o btf.o)
197+
BOOTSTRAP_OBJS = $(addprefix $(BOOTSTRAP_OUTPUT),main.o common.o json_writer.o gen.o btf.o sign.o)
198198
$(BOOTSTRAP_OBJS): $(LIBBPF_BOOTSTRAP)
199199

200200
OBJS = $(patsubst %.c,$(OUTPUT)%.o,$(SRCS)) $(OUTPUT)disasm.o

tools/bpf/bpftool/cgroup.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22
// Copyright (C) 2017 Facebook
33
// Author: Roman Gushchin <[email protected]>
44

5+
#undef GCC_VERSION
6+
#ifndef _GNU_SOURCE
7+
#define _GNU_SOURCE
8+
#endif
59
#define _XOPEN_SOURCE 500
610
#include <errno.h>
711
#include <fcntl.h>

tools/bpf/bpftool/gen.c

Lines changed: 56 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -688,10 +688,17 @@ static void codegen_destroy(struct bpf_object *obj, const char *obj_name)
688688
static int gen_trace(struct bpf_object *obj, const char *obj_name, const char *header_guard)
689689
{
690690
DECLARE_LIBBPF_OPTS(gen_loader_opts, opts);
691+
struct bpf_load_and_run_opts sopts = {};
692+
char sig_buf[MAX_SIG_SIZE];
693+
__u8 prog_sha[SHA256_DIGEST_LENGTH];
691694
struct bpf_map *map;
695+
692696
char ident[256];
693697
int err = 0;
694698

699+
if (sign_progs)
700+
opts.gen_hash = true;
701+
695702
err = bpf_object__gen_loader(obj, &opts);
696703
if (err)
697704
return err;
@@ -701,6 +708,7 @@ static int gen_trace(struct bpf_object *obj, const char *obj_name, const char *h
701708
p_err("failed to load object file");
702709
goto out;
703710
}
711+
704712
/* If there was no error during load then gen_loader_opts
705713
* are populated with the loader program.
706714
*/
@@ -780,8 +788,51 @@ static int gen_trace(struct bpf_object *obj, const char *obj_name, const char *h
780788
print_hex(opts.insns, opts.insns_sz);
781789
codegen("\
782790
\n\
783-
\"; \n\
784-
\n\
791+
\";\n");
792+
793+
if (sign_progs) {
794+
sopts.insns = opts.insns;
795+
sopts.insns_sz = opts.insns_sz;
796+
sopts.excl_prog_hash = prog_sha;
797+
sopts.excl_prog_hash_sz = sizeof(prog_sha);
798+
sopts.signature = sig_buf;
799+
sopts.signature_sz = MAX_SIG_SIZE;
800+
sopts.keyring_id = KEY_SPEC_SESSION_KEYRING;
801+
802+
err = bpftool_prog_sign(&sopts);
803+
if (err < 0)
804+
return err;
805+
806+
codegen("\
807+
\n\
808+
static const char opts_sig[] __attribute__((__aligned__(8))) = \"\\\n\
809+
");
810+
print_hex((const void *)sig_buf, sopts.signature_sz);
811+
codegen("\
812+
\n\
813+
\";\n");
814+
815+
codegen("\
816+
\n\
817+
static const char opts_excl_hash[] __attribute__((__aligned__(8))) = \"\\\n\
818+
");
819+
print_hex((const void *)prog_sha, sizeof(prog_sha));
820+
codegen("\
821+
\n\
822+
\";\n");
823+
824+
codegen("\
825+
\n\
826+
opts.signature = (void *)opts_sig; \n\
827+
opts.signature_sz = sizeof(opts_sig) - 1; \n\
828+
opts.excl_prog_hash = (void *)opts_excl_hash; \n\
829+
opts.excl_prog_hash_sz = sizeof(opts_excl_hash) - 1; \n\
830+
opts.keyring_id = KEY_SPEC_SESSION_KEYRING; \n\
831+
");
832+
}
833+
834+
codegen("\
835+
\n\
785836
opts.ctx = (struct bpf_loader_ctx *)skel; \n\
786837
opts.data_sz = sizeof(opts_data) - 1; \n\
787838
opts.data = (void *)opts_data; \n\
@@ -1240,7 +1291,7 @@ static int do_skeleton(int argc, char **argv)
12401291
err = -errno;
12411292
libbpf_strerror(err, err_buf, sizeof(err_buf));
12421293
p_err("failed to open BPF object file: %s", err_buf);
1243-
goto out;
1294+
goto out_obj;
12441295
}
12451296

12461297
bpf_object__for_each_map(map, obj) {
@@ -1552,6 +1603,7 @@ static int do_skeleton(int argc, char **argv)
15521603
err = 0;
15531604
out:
15541605
bpf_object__close(obj);
1606+
out_obj:
15551607
if (obj_data)
15561608
munmap(obj_data, mmap_sz);
15571609
close(fd);
@@ -1930,7 +1982,7 @@ static int do_help(int argc, char **argv)
19301982
" %1$s %2$s help\n"
19311983
"\n"
19321984
" " HELP_SPEC_OPTIONS " |\n"
1933-
" {-L|--use-loader} }\n"
1985+
" {-L|--use-loader} | [ {-S|--sign } {-k} <private_key.pem> {-i} <certificate.x509> ]}\n"
19341986
"",
19351987
bin_name, "gen");
19361988

tools/bpf/bpftool/main.c

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ bool relaxed_maps;
3333
bool use_loader;
3434
struct btf *base_btf;
3535
struct hashmap *refs_table;
36+
bool sign_progs;
37+
const char *private_key_path;
38+
const char *cert_path;
3639

3740
static void __noreturn clean_and_exit(int i)
3841
{
@@ -448,6 +451,7 @@ int main(int argc, char **argv)
448451
{ "nomount", no_argument, NULL, 'n' },
449452
{ "debug", no_argument, NULL, 'd' },
450453
{ "use-loader", no_argument, NULL, 'L' },
454+
{ "sign", no_argument, NULL, 'S' },
451455
{ "base-btf", required_argument, NULL, 'B' },
452456
{ 0 }
453457
};
@@ -474,7 +478,7 @@ int main(int argc, char **argv)
474478
bin_name = "bpftool";
475479

476480
opterr = 0;
477-
while ((opt = getopt_long(argc, argv, "VhpjfLmndB:l",
481+
while ((opt = getopt_long(argc, argv, "VhpjfLmndSi:k:B:l",
478482
options, NULL)) >= 0) {
479483
switch (opt) {
480484
case 'V':
@@ -520,6 +524,16 @@ int main(int argc, char **argv)
520524
case 'L':
521525
use_loader = true;
522526
break;
527+
case 'S':
528+
sign_progs = true;
529+
use_loader = true;
530+
break;
531+
case 'k':
532+
private_key_path = optarg;
533+
break;
534+
case 'i':
535+
cert_path = optarg;
536+
break;
523537
default:
524538
p_err("unrecognized option '%s'", argv[optind - 1]);
525539
if (json_output)
@@ -534,6 +548,16 @@ int main(int argc, char **argv)
534548
if (argc < 0)
535549
usage();
536550

551+
if (sign_progs && (private_key_path == NULL || cert_path == NULL)) {
552+
p_err("-i <identity_x509_cert> and -k <private> key must be supplied with -S for signing");
553+
return -EINVAL;
554+
}
555+
556+
if (!sign_progs && (private_key_path != NULL || cert_path != NULL)) {
557+
p_err("-i <identity_x509_cert> and -k <private> also need --sign to be used for sign programs");
558+
return -EINVAL;
559+
}
560+
537561
if (version_requested)
538562
ret = do_version(argc, argv);
539563
else

tools/bpf/bpftool/main.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,14 @@
66

77
/* BFD and kernel.h both define GCC_VERSION, differently */
88
#undef GCC_VERSION
9+
#ifndef _GNU_SOURCE
10+
#define _GNU_SOURCE
11+
#endif
912
#include <stdbool.h>
1013
#include <stdio.h>
14+
#include <errno.h>
1115
#include <stdlib.h>
16+
#include <bpf/skel_internal.h>
1217
#include <linux/bpf.h>
1318
#include <linux/compiler.h>
1419
#include <linux/kernel.h>
@@ -52,6 +57,7 @@ static inline void *u64_to_ptr(__u64 ptr)
5257
})
5358

5459
#define ERR_MAX_LEN 1024
60+
#define MAX_SIG_SIZE 4096
5561

5662
#define BPF_TAG_FMT "%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx"
5763

@@ -85,6 +91,9 @@ extern bool relaxed_maps;
8591
extern bool use_loader;
8692
extern struct btf *base_btf;
8793
extern struct hashmap *refs_table;
94+
extern bool sign_progs;
95+
extern const char *private_key_path;
96+
extern const char *cert_path;
8897

8998
void __printf(1, 2) p_err(const char *fmt, ...);
9099
void __printf(1, 2) p_info(const char *fmt, ...);
@@ -275,4 +284,6 @@ int pathname_concat(char *buf, int buf_sz, const char *path,
275284
/* print netfilter bpf_link info */
276285
void netfilter_dump_plain(const struct bpf_link_info *info);
277286
void netfilter_dump_json(const struct bpf_link_info *info, json_writer_t *wtr);
287+
int bpftool_prog_sign(struct bpf_load_and_run_opts *opts);
288+
__u32 register_session_key(const char *key_der_path);
278289
#endif

tools/bpf/bpftool/prog.c

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include <linux/err.h>
2424
#include <linux/perf_event.h>
2525
#include <linux/sizes.h>
26+
#include <linux/keyctl.h>
2627

2728
#include <bpf/bpf.h>
2829
#include <bpf/btf.h>
@@ -1930,6 +1931,8 @@ static int try_loader(struct gen_loader_opts *gen)
19301931
{
19311932
struct bpf_load_and_run_opts opts = {};
19321933
struct bpf_loader_ctx *ctx;
1934+
char sig_buf[MAX_SIG_SIZE];
1935+
__u8 prog_sha[SHA256_DIGEST_LENGTH];
19331936
int ctx_sz = sizeof(*ctx) + 64 * max(sizeof(struct bpf_map_desc),
19341937
sizeof(struct bpf_prog_desc));
19351938
int log_buf_sz = (1u << 24) - 1;
@@ -1953,6 +1956,24 @@ static int try_loader(struct gen_loader_opts *gen)
19531956
opts.insns = gen->insns;
19541957
opts.insns_sz = gen->insns_sz;
19551958
fds_before = count_open_fds();
1959+
1960+
if (sign_progs) {
1961+
opts.excl_prog_hash = prog_sha;
1962+
opts.excl_prog_hash_sz = sizeof(prog_sha);
1963+
opts.signature = sig_buf;
1964+
opts.signature_sz = MAX_SIG_SIZE;
1965+
opts.keyring_id = KEY_SPEC_SESSION_KEYRING;
1966+
1967+
err = bpftool_prog_sign(&opts);
1968+
if (err < 0)
1969+
return err;
1970+
1971+
err = register_session_key(cert_path);
1972+
if (err < 0) {
1973+
p_err("failed to add session key");
1974+
goto out;
1975+
}
1976+
}
19561977
err = bpf_load_and_run(&opts);
19571978
fd_delta = count_open_fds() - fds_before;
19581979
if (err < 0 || verifier_logs) {
@@ -1961,6 +1982,7 @@ static int try_loader(struct gen_loader_opts *gen)
19611982
fprintf(stderr, "loader prog leaked %d FDs\n",
19621983
fd_delta);
19631984
}
1985+
out:
19641986
free(log_buf);
19651987
return err;
19661988
}
@@ -1988,6 +2010,9 @@ static int do_loader(int argc, char **argv)
19882010
goto err_close_obj;
19892011
}
19902012

2013+
if (sign_progs)
2014+
gen.gen_hash = true;
2015+
19912016
err = bpf_object__gen_loader(obj, &gen);
19922017
if (err)
19932018
goto err_close_obj;
@@ -2562,7 +2587,7 @@ static int do_help(int argc, char **argv)
25622587
" METRIC := { cycles | instructions | l1d_loads | llc_misses | itlb_misses | dtlb_misses }\n"
25632588
" " HELP_SPEC_OPTIONS " |\n"
25642589
" {-f|--bpffs} | {-m|--mapcompat} | {-n|--nomount} |\n"
2565-
" {-L|--use-loader} }\n"
2590+
" {-L|--use-loader} | [ {-S|--sign } {-k} <private_key.pem> {-i} <certificate.x509> ] \n"
25662591
"",
25672592
bin_name, argv[-2]);
25682593

0 commit comments

Comments
 (0)