Skip to content

Commit 40863f4

Browse files
sinkapAlexei Starovoitov
authored andcommitted
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]> Acked-by: Quentin Monnet <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Alexei Starovoitov <[email protected]>
1 parent ea92308 commit 40863f4

File tree

9 files changed

+372
-11
lines changed

9 files changed

+372
-11
lines changed

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

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

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

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

2121
*COMMAND* := { **object** | **skeleton** | **help** }
2222

@@ -186,6 +186,17 @@ OPTIONS
186186
skeleton). A light skeleton contains a loader eBPF program. It does not use
187187
the majority of the libbpf infrastructure, and does not need libelf.
188188

189+
-S, --sign
190+
For skeletons, generate a signed skeleton. This option must be used with
191+
**-k** and **-i**. Using this flag implicitly enables **--use-loader**.
192+
193+
-k <private_key.pem>
194+
Path to the private key file in PEM format, required for signing.
195+
196+
-i <certificate.x509>
197+
Path to the X.509 certificate file in PEM or DER format, required for
198+
signing.
199+
189200
EXAMPLES
190201
========
191202
**$ cat example1.bpf.c**

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

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ SYNOPSIS
1818

1919
*OPTIONS* := { |COMMON_OPTIONS| |
2020
{ **-f** | **--bpffs** } | { **-m** | **--mapcompat** } | { **-n** | **--nomount** } |
21-
{ **-L** | **--use-loader** } }
21+
{ **-L** | **--use-loader** } | [ { **-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: 64 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,52 @@ 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+
801+
err = bpftool_prog_sign(&sopts);
802+
if (err < 0) {
803+
p_err("failed to sign program");
804+
goto out;
805+
}
806+
807+
codegen("\
808+
\n\
809+
static const char opts_sig[] __attribute__((__aligned__(8))) = \"\\\n\
810+
");
811+
print_hex((const void *)sig_buf, sopts.signature_sz);
812+
codegen("\
813+
\n\
814+
\";\n");
815+
816+
codegen("\
817+
\n\
818+
static const char opts_excl_hash[] __attribute__((__aligned__(8))) = \"\\\n\
819+
");
820+
print_hex((const void *)prog_sha, sizeof(prog_sha));
821+
codegen("\
822+
\n\
823+
\";\n");
824+
825+
codegen("\
826+
\n\
827+
opts.signature = (void *)opts_sig; \n\
828+
opts.signature_sz = sizeof(opts_sig) - 1; \n\
829+
opts.excl_prog_hash = (void *)opts_excl_hash; \n\
830+
opts.excl_prog_hash_sz = sizeof(opts_excl_hash) - 1; \n\
831+
opts.keyring_id = skel->keyring_id; \n\
832+
");
833+
}
834+
835+
codegen("\
836+
\n\
785837
opts.ctx = (struct bpf_loader_ctx *)skel; \n\
786838
opts.data_sz = sizeof(opts_data) - 1; \n\
787839
opts.data = (void *)opts_data; \n\
@@ -1240,7 +1292,7 @@ static int do_skeleton(int argc, char **argv)
12401292
err = -errno;
12411293
libbpf_strerror(err, err_buf, sizeof(err_buf));
12421294
p_err("failed to open BPF object file: %s", err_buf);
1243-
goto out;
1295+
goto out_obj;
12441296
}
12451297

12461298
bpf_object__for_each_map(map, obj) {
@@ -1355,6 +1407,13 @@ static int do_skeleton(int argc, char **argv)
13551407
printf("\t} links;\n");
13561408
}
13571409

1410+
if (sign_progs) {
1411+
codegen("\
1412+
\n\
1413+
__s32 keyring_id; \n\
1414+
");
1415+
}
1416+
13581417
if (btf) {
13591418
err = codegen_datasecs(obj, obj_name);
13601419
if (err)
@@ -1552,6 +1611,7 @@ static int do_skeleton(int argc, char **argv)
15521611
err = 0;
15531612
out:
15541613
bpf_object__close(obj);
1614+
out_obj:
15551615
if (obj_data)
15561616
munmap(obj_data, mmap_sz);
15571617
close(fd);
@@ -1930,7 +1990,7 @@ static int do_help(int argc, char **argv)
19301990
" %1$s %2$s help\n"
19311991
"\n"
19321992
" " HELP_SPEC_OPTIONS " |\n"
1933-
" {-L|--use-loader} }\n"
1993+
" {-L|--use-loader} | [ {-S|--sign } {-k} <private_key.pem> {-i} <certificate.x509> ]}\n"
19341994
"",
19351995
bin_name, "gen");
19361996

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("--sign (or -S) must be explicitly passed with -i <identity_x509_cert> and -k <private_key> to sign the 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, ...);
@@ -284,4 +293,6 @@ struct kernel_config_option {
284293
int read_kernel_config(const struct kernel_config_option *requested_options,
285294
size_t num_options, char **out_values,
286295
const char *define_prefix);
296+
int bpftool_prog_sign(struct bpf_load_and_run_opts *opts);
297+
__u32 register_session_key(const char *key_der_path);
287298
#endif

tools/bpf/bpftool/prog.c

Lines changed: 28 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,26 @@ 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+
p_err("failed to sign program");
1970+
goto out;
1971+
}
1972+
1973+
err = register_session_key(cert_path);
1974+
if (err < 0) {
1975+
p_err("failed to add session key");
1976+
goto out;
1977+
}
1978+
}
19561979
err = bpf_load_and_run(&opts);
19571980
fd_delta = count_open_fds() - fds_before;
19581981
if (err < 0 || verifier_logs) {
@@ -1961,6 +1984,7 @@ static int try_loader(struct gen_loader_opts *gen)
19611984
fprintf(stderr, "loader prog leaked %d FDs\n",
19621985
fd_delta);
19631986
}
1987+
out:
19641988
free(log_buf);
19651989
return err;
19661990
}
@@ -1988,6 +2012,9 @@ static int do_loader(int argc, char **argv)
19882012
goto err_close_obj;
19892013
}
19902014

2015+
if (sign_progs)
2016+
gen.gen_hash = true;
2017+
19912018
err = bpf_object__gen_loader(obj, &gen);
19922019
if (err)
19932020
goto err_close_obj;
@@ -2562,7 +2589,7 @@ static int do_help(int argc, char **argv)
25622589
" METRIC := { cycles | instructions | l1d_loads | llc_misses | itlb_misses | dtlb_misses }\n"
25632590
" " HELP_SPEC_OPTIONS " |\n"
25642591
" {-f|--bpffs} | {-m|--mapcompat} | {-n|--nomount} |\n"
2565-
" {-L|--use-loader} }\n"
2592+
" {-L|--use-loader} | [ {-S|--sign } {-k} <private_key.pem> {-i} <certificate.x509> ] \n"
25662593
"",
25672594
bin_name, argv[-2]);
25682595

0 commit comments

Comments
 (0)