* [RFC bpf-next 0/2] bpf: sign bpf programs @ 2021-10-12 19:00 Matteo Croce 2021-10-12 19:00 ` [RFC bpf-next 1/2] bpf: add signature to eBPF instructions Matteo Croce 2021-10-12 19:00 ` [RFC bpf-next 2/2] bpftool: add signature in skeleton Matteo Croce 0 siblings, 2 replies; 8+ messages in thread From: Matteo Croce @ 2021-10-12 19:00 UTC (permalink / raw) To: bpf Cc: linux-kernel, Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko, Arnaldo Carvalho de Melo, Luca Boccassi, David S. Miller From: Matteo Croce <mcroce@microsoft.com> Add a field in bpf_attr which contains a signature for the eBPF instructions. The signature is validated bpf_prog_load() in a similar way as kernel modules are checked in load_module(). This only works with CO-RE programs. The signature is generated by bpftool and embedded into the light skeleton along with the instructions. The bpftool crypto code is based on sign-file, supports the same interface, and is compiled only if libcrypto is available, to avoid potential breaks. Possible improvements: - Add a knob which makes the signature check mandatory, similarly to CONFIG_MODULE_SIG_FORCE - Add a dedicate key_being_used_for type instead of using VERIFYING_MODULE_SIGNATURE, e.g. VERIFYING_BPF_SIGNATURE This depends on the kernel side co-re relocation[1]. [1] https://lore.kernel.org/bpf/20210917215721.43491-1-alexei.starovoitov@gmail.com/ Matteo Croce (2): bpf: add signature to eBPF instructions bpftool: add signature in skeleton include/uapi/linux/bpf.h | 2 + kernel/bpf/syscall.c | 33 ++++- tools/bpf/bpftool/Makefile | 14 ++- tools/bpf/bpftool/gen.c | 33 +++++ tools/bpf/bpftool/main.c | 28 +++++ tools/bpf/bpftool/main.h | 7 ++ tools/bpf/bpftool/sign.c | 217 +++++++++++++++++++++++++++++++++ tools/include/uapi/linux/bpf.h | 2 + tools/lib/bpf/skel_internal.h | 4 + 9 files changed, 336 insertions(+), 4 deletions(-) create mode 100644 tools/bpf/bpftool/sign.c -- 2.33.0 ^ permalink raw reply [flat|nested] 8+ messages in thread
* [RFC bpf-next 1/2] bpf: add signature to eBPF instructions 2021-10-12 19:00 [RFC bpf-next 0/2] bpf: sign bpf programs Matteo Croce @ 2021-10-12 19:00 ` Matteo Croce 2021-10-13 2:37 ` kernel test robot ` (4 more replies) 2021-10-12 19:00 ` [RFC bpf-next 2/2] bpftool: add signature in skeleton Matteo Croce 1 sibling, 5 replies; 8+ messages in thread From: Matteo Croce @ 2021-10-12 19:00 UTC (permalink / raw) To: bpf Cc: linux-kernel, Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko, Arnaldo Carvalho de Melo, Luca Boccassi, David S. Miller From: Matteo Croce <mcroce@microsoft.com> When loading a BPF program, pass a signature which is used to validate the instructions. The signature type is the same used to validate the kernel modules. Signed-off-by: Matteo Croce <mcroce@microsoft.com> --- include/uapi/linux/bpf.h | 2 ++ kernel/bpf/syscall.c | 33 ++++++++++++++++++++++++++++++++- 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index c2b8857b8a1c..b9d259f26e92 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -1336,6 +1336,8 @@ union bpf_attr { }; __u32 :32; /* pad */ __aligned_u64 fd_array; /* array of FDs */ + __aligned_u64 signature; /* instruction's signature */ + __u32 sig_len; /* signature size */ }; struct { /* anonymous struct used by BPF_OBJ_* commands */ diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index 3c349b244a28..5589f655033d 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -31,6 +31,8 @@ #include <linux/bpf-netns.h> #include <linux/rcupdate_trace.h> #include <linux/memcontrol.h> +#include <linux/verification.h> +#include <linux/module_signature.h> #define IS_FD_ARRAY(map) ((map)->map_type == BPF_MAP_TYPE_PERF_EVENT_ARRAY || \ (map)->map_type == BPF_MAP_TYPE_CGROUP_ARRAY || \ @@ -2156,7 +2158,7 @@ static bool is_perfmon_prog_type(enum bpf_prog_type prog_type) } /* last field in 'union bpf_attr' used by this command */ -#define BPF_PROG_LOAD_LAST_FIELD fd_array +#define BPF_PROG_LOAD_LAST_FIELD sig_len static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr) { @@ -2274,6 +2276,35 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr) bpf_prog_insn_size(prog)) != 0) goto free_prog_sec; + if (attr->sig_len) { + char *signature; + + signature = kmalloc(attr->sig_len, GFP_USER); + if (!signature) { + err = -ENOMEM; + goto free_prog_sec; + } + + if (copy_from_user(signature, (char *)attr->signature, attr->sig_len)) { + err = -EFAULT; + kfree(signature); + goto free_prog_sec; + } + + err = verify_pkcs7_signature(prog->insns, + prog->len * sizeof(struct bpf_insn), + signature, attr->sig_len, + VERIFY_USE_SECONDARY_KEYRING, + VERIFYING_MODULE_SIGNATURE, + NULL, NULL); + kfree(signature); + + if (err) { + printk("verify_pkcs7_signature(): %pe\n", (void*)(uintptr_t)err); + goto free_prog_sec; + } + } + prog->orig_prog = NULL; prog->jited = 0; -- 2.33.0 ^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [RFC bpf-next 1/2] bpf: add signature to eBPF instructions 2021-10-12 19:00 ` [RFC bpf-next 1/2] bpf: add signature to eBPF instructions Matteo Croce @ 2021-10-13 2:37 ` kernel test robot 2021-10-13 3:13 ` kernel test robot ` (3 subsequent siblings) 4 siblings, 0 replies; 8+ messages in thread From: kernel test robot @ 2021-10-13 2:37 UTC (permalink / raw) To: kbuild-all [-- Attachment #1: Type: text/plain, Size: 10337 bytes --] Hi Matteo, [FYI, it's a private test report for your RFC patch.] [auto build test WARNING on bpf-next/master] url: https://github.com/0day-ci/linux/commits/Matteo-Croce/bpf-sign-bpf-programs/20211013-030207 base: https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git master config: sparc64-randconfig-s032-20211012 (attached as .config) compiler: sparc64-linux-gcc (GCC) 11.2.0 reproduce: wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross # apt-get install sparse # sparse version: v0.6.4-dirty # https://github.com/0day-ci/linux/commit/45c21d28e868dac39e5267e2e2b6f4e35f86b661 git remote add linux-review https://github.com/0day-ci/linux git fetch --no-tags linux-review Matteo-Croce/bpf-sign-bpf-programs/20211013-030207 git checkout 45c21d28e868dac39e5267e2e2b6f4e35f86b661 # save the attached .config to linux build tree COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-11.2.0 make.cross C=1 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__' ARCH=sparc64 If you fix the issue, kindly add following tag as appropriate Reported-by: kernel test robot <lkp@intel.com> sparse warnings: (new ones prefixed by >>) >> kernel/bpf/syscall.c:2288:48: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void const [noderef] __user *from @@ got char * @@ kernel/bpf/syscall.c:2288:48: sparse: expected void const [noderef] __user *from kernel/bpf/syscall.c:2288:48: sparse: got char * kernel/bpf/syscall.c: note: in included file (through include/linux/bpf.h): include/linux/bpfptr.h:52:47: sparse: sparse: cast to non-scalar include/linux/bpfptr.h:52:47: sparse: sparse: cast from non-scalar include/linux/bpfptr.h:52:47: sparse: sparse: cast to non-scalar include/linux/bpfptr.h:52:47: sparse: sparse: cast from non-scalar include/linux/bpfptr.h:81:43: sparse: sparse: cast to non-scalar include/linux/bpfptr.h:81:43: sparse: sparse: cast from non-scalar include/linux/bpfptr.h:52:47: sparse: sparse: cast to non-scalar include/linux/bpfptr.h:52:47: sparse: sparse: cast from non-scalar include/linux/bpfptr.h:52:47: sparse: sparse: cast to non-scalar include/linux/bpfptr.h:52:47: sparse: sparse: cast from non-scalar vim +2288 kernel/bpf/syscall.c 2162 2163 static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr) 2164 { 2165 enum bpf_prog_type type = attr->prog_type; 2166 struct bpf_prog *prog, *dst_prog = NULL; 2167 struct btf *attach_btf = NULL; 2168 int err; 2169 char license[128]; 2170 bool is_gpl; 2171 2172 if (CHECK_ATTR(BPF_PROG_LOAD)) 2173 return -EINVAL; 2174 2175 if (attr->prog_flags & ~(BPF_F_STRICT_ALIGNMENT | 2176 BPF_F_ANY_ALIGNMENT | 2177 BPF_F_TEST_STATE_FREQ | 2178 BPF_F_SLEEPABLE | 2179 BPF_F_TEST_RND_HI32)) 2180 return -EINVAL; 2181 2182 if (!IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && 2183 (attr->prog_flags & BPF_F_ANY_ALIGNMENT) && 2184 !bpf_capable()) 2185 return -EPERM; 2186 2187 /* copy eBPF program license from user space */ 2188 if (strncpy_from_bpfptr(license, 2189 make_bpfptr(attr->license, uattr.is_kernel), 2190 sizeof(license) - 1) < 0) 2191 return -EFAULT; 2192 license[sizeof(license) - 1] = 0; 2193 2194 /* eBPF programs must be GPL compatible to use GPL-ed functions */ 2195 is_gpl = license_is_gpl_compatible(license); 2196 2197 if (attr->insn_cnt == 0 || 2198 attr->insn_cnt > (bpf_capable() ? BPF_COMPLEXITY_LIMIT_INSNS : BPF_MAXINSNS)) 2199 return -E2BIG; 2200 if (type != BPF_PROG_TYPE_SOCKET_FILTER && 2201 type != BPF_PROG_TYPE_CGROUP_SKB && 2202 !bpf_capable()) 2203 return -EPERM; 2204 2205 if (is_net_admin_prog_type(type) && !capable(CAP_NET_ADMIN) && !capable(CAP_SYS_ADMIN)) 2206 return -EPERM; 2207 if (is_perfmon_prog_type(type) && !perfmon_capable()) 2208 return -EPERM; 2209 2210 /* attach_prog_fd/attach_btf_obj_fd can specify fd of either bpf_prog 2211 * or btf, we need to check which one it is 2212 */ 2213 if (attr->attach_prog_fd) { 2214 dst_prog = bpf_prog_get(attr->attach_prog_fd); 2215 if (IS_ERR(dst_prog)) { 2216 dst_prog = NULL; 2217 attach_btf = btf_get_by_fd(attr->attach_btf_obj_fd); 2218 if (IS_ERR(attach_btf)) 2219 return -EINVAL; 2220 if (!btf_is_kernel(attach_btf)) { 2221 /* attaching through specifying bpf_prog's BTF 2222 * objects directly might be supported eventually 2223 */ 2224 btf_put(attach_btf); 2225 return -ENOTSUPP; 2226 } 2227 } 2228 } else if (attr->attach_btf_id) { 2229 /* fall back to vmlinux BTF, if BTF type ID is specified */ 2230 attach_btf = bpf_get_btf_vmlinux(); 2231 if (IS_ERR(attach_btf)) 2232 return PTR_ERR(attach_btf); 2233 if (!attach_btf) 2234 return -EINVAL; 2235 btf_get(attach_btf); 2236 } 2237 2238 bpf_prog_load_fixup_attach_type(attr); 2239 if (bpf_prog_load_check_attach(type, attr->expected_attach_type, 2240 attach_btf, attr->attach_btf_id, 2241 dst_prog)) { 2242 if (dst_prog) 2243 bpf_prog_put(dst_prog); 2244 if (attach_btf) 2245 btf_put(attach_btf); 2246 return -EINVAL; 2247 } 2248 2249 /* plain bpf_prog allocation */ 2250 prog = bpf_prog_alloc(bpf_prog_size(attr->insn_cnt), GFP_USER); 2251 if (!prog) { 2252 if (dst_prog) 2253 bpf_prog_put(dst_prog); 2254 if (attach_btf) 2255 btf_put(attach_btf); 2256 return -ENOMEM; 2257 } 2258 2259 prog->expected_attach_type = attr->expected_attach_type; 2260 prog->aux->attach_btf = attach_btf; 2261 prog->aux->attach_btf_id = attr->attach_btf_id; 2262 prog->aux->dst_prog = dst_prog; 2263 prog->aux->offload_requested = !!attr->prog_ifindex; 2264 prog->aux->sleepable = attr->prog_flags & BPF_F_SLEEPABLE; 2265 2266 err = security_bpf_prog_alloc(prog->aux); 2267 if (err) 2268 goto free_prog; 2269 2270 prog->aux->user = get_current_user(); 2271 prog->len = attr->insn_cnt; 2272 2273 err = -EFAULT; 2274 if (copy_from_bpfptr(prog->insns, 2275 make_bpfptr(attr->insns, uattr.is_kernel), 2276 bpf_prog_insn_size(prog)) != 0) 2277 goto free_prog_sec; 2278 2279 if (attr->sig_len) { 2280 char *signature; 2281 2282 signature = kmalloc(attr->sig_len, GFP_USER); 2283 if (!signature) { 2284 err = -ENOMEM; 2285 goto free_prog_sec; 2286 } 2287 > 2288 if (copy_from_user(signature, (char *)attr->signature, attr->sig_len)) { 2289 err = -EFAULT; 2290 kfree(signature); 2291 goto free_prog_sec; 2292 } 2293 2294 err = verify_pkcs7_signature(prog->insns, 2295 prog->len * sizeof(struct bpf_insn), 2296 signature, attr->sig_len, 2297 VERIFY_USE_SECONDARY_KEYRING, 2298 VERIFYING_MODULE_SIGNATURE, 2299 NULL, NULL); 2300 kfree(signature); 2301 2302 if (err) { 2303 printk("verify_pkcs7_signature(): %pe\n", (void*)(uintptr_t)err); 2304 goto free_prog_sec; 2305 } 2306 } 2307 2308 prog->orig_prog = NULL; 2309 prog->jited = 0; 2310 2311 atomic64_set(&prog->aux->refcnt, 1); 2312 prog->gpl_compatible = is_gpl ? 1 : 0; 2313 2314 if (bpf_prog_is_dev_bound(prog->aux)) { 2315 err = bpf_prog_offload_init(prog, attr); 2316 if (err) 2317 goto free_prog_sec; 2318 } 2319 2320 /* find program type: socket_filter vs tracing_filter */ 2321 err = find_prog_type(type, prog); 2322 if (err < 0) 2323 goto free_prog_sec; 2324 2325 prog->aux->load_time = ktime_get_boottime_ns(); 2326 err = bpf_obj_name_cpy(prog->aux->name, attr->prog_name, 2327 sizeof(attr->prog_name)); 2328 if (err < 0) 2329 goto free_prog_sec; 2330 2331 /* run eBPF verifier */ 2332 err = bpf_check(&prog, attr, uattr); 2333 if (err < 0) 2334 goto free_used_maps; 2335 2336 prog = bpf_prog_select_runtime(prog, &err); 2337 if (err < 0) 2338 goto free_used_maps; 2339 2340 err = bpf_prog_alloc_id(prog); 2341 if (err) 2342 goto free_used_maps; 2343 2344 /* Upon success of bpf_prog_alloc_id(), the BPF prog is 2345 * effectively publicly exposed. However, retrieving via 2346 * bpf_prog_get_fd_by_id() will take another reference, 2347 * therefore it cannot be gone underneath us. 2348 * 2349 * Only for the time /after/ successful bpf_prog_new_fd() 2350 * and before returning to userspace, we might just hold 2351 * one reference and any parallel close on that fd could 2352 * rip everything out. Hence, below notifications must 2353 * happen before bpf_prog_new_fd(). 2354 * 2355 * Also, any failure handling from this point onwards must 2356 * be using bpf_prog_put() given the program is exposed. 2357 */ 2358 bpf_prog_kallsyms_add(prog); 2359 perf_event_bpf_event(prog, PERF_BPF_EVENT_PROG_LOAD, 0); 2360 bpf_audit_prog(prog, BPF_AUDIT_LOAD); 2361 2362 err = bpf_prog_new_fd(prog); 2363 if (err < 0) 2364 bpf_prog_put(prog); 2365 return err; 2366 2367 free_used_maps: 2368 /* In case we have subprogs, we need to wait for a grace 2369 * period before we can tear down JIT memory since symbols 2370 * are already exposed under kallsyms. 2371 */ 2372 __bpf_prog_put_noref(prog, prog->aux->func_cnt); 2373 return err; 2374 free_prog_sec: 2375 free_uid(prog->aux->user); 2376 security_bpf_prog_free(prog->aux); 2377 free_prog: 2378 if (prog->aux->attach_btf) 2379 btf_put(prog->aux->attach_btf); 2380 bpf_prog_free(prog); 2381 return err; 2382 } 2383 --- 0-DAY CI Kernel Test Service, Intel Corporation https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org [-- Attachment #2: config.gz --] [-- Type: application/gzip, Size: 34805 bytes --] ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [RFC bpf-next 1/2] bpf: add signature to eBPF instructions 2021-10-12 19:00 ` [RFC bpf-next 1/2] bpf: add signature to eBPF instructions Matteo Croce 2021-10-13 2:37 ` kernel test robot @ 2021-10-13 3:13 ` kernel test robot 2021-10-13 3:36 ` kernel test robot ` (2 subsequent siblings) 4 siblings, 0 replies; 8+ messages in thread From: kernel test robot @ 2021-10-13 3:13 UTC (permalink / raw) To: kbuild-all [-- Attachment #1: Type: text/plain, Size: 9799 bytes --] Hi Matteo, [FYI, it's a private test report for your RFC patch.] [auto build test ERROR on bpf-next/master] url: https://github.com/0day-ci/linux/commits/Matteo-Croce/bpf-sign-bpf-programs/20211013-030207 base: https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git master config: nios2-randconfig-r034-20211013 (attached as .config) compiler: nios2-linux-gcc (GCC) 11.2.0 reproduce (this is a W=1 build): wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross # https://github.com/0day-ci/linux/commit/45c21d28e868dac39e5267e2e2b6f4e35f86b661 git remote add linux-review https://github.com/0day-ci/linux git fetch --no-tags linux-review Matteo-Croce/bpf-sign-bpf-programs/20211013-030207 git checkout 45c21d28e868dac39e5267e2e2b6f4e35f86b661 # save the attached .config to linux build tree COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-11.2.0 make.cross ARCH=nios2 If you fix the issue, kindly add following tag as appropriate Reported-by: kernel test robot <lkp@intel.com> All error/warnings (new ones prefixed by >>): kernel/bpf/syscall.c: In function 'bpf_prog_load': >> kernel/bpf/syscall.c:2288:47: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast] 2288 | if (copy_from_user(signature, (char *)attr->signature, attr->sig_len)) { | ^ >> kernel/bpf/syscall.c:2294:23: error: implicit declaration of function 'verify_pkcs7_signature' [-Werror=implicit-function-declaration] 2294 | err = verify_pkcs7_signature(prog->insns, | ^~~~~~~~~~~~~~~~~~~~~~ cc1: some warnings being treated as errors vim +/verify_pkcs7_signature +2294 kernel/bpf/syscall.c 2162 2163 static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr) 2164 { 2165 enum bpf_prog_type type = attr->prog_type; 2166 struct bpf_prog *prog, *dst_prog = NULL; 2167 struct btf *attach_btf = NULL; 2168 int err; 2169 char license[128]; 2170 bool is_gpl; 2171 2172 if (CHECK_ATTR(BPF_PROG_LOAD)) 2173 return -EINVAL; 2174 2175 if (attr->prog_flags & ~(BPF_F_STRICT_ALIGNMENT | 2176 BPF_F_ANY_ALIGNMENT | 2177 BPF_F_TEST_STATE_FREQ | 2178 BPF_F_SLEEPABLE | 2179 BPF_F_TEST_RND_HI32)) 2180 return -EINVAL; 2181 2182 if (!IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && 2183 (attr->prog_flags & BPF_F_ANY_ALIGNMENT) && 2184 !bpf_capable()) 2185 return -EPERM; 2186 2187 /* copy eBPF program license from user space */ 2188 if (strncpy_from_bpfptr(license, 2189 make_bpfptr(attr->license, uattr.is_kernel), 2190 sizeof(license) - 1) < 0) 2191 return -EFAULT; 2192 license[sizeof(license) - 1] = 0; 2193 2194 /* eBPF programs must be GPL compatible to use GPL-ed functions */ 2195 is_gpl = license_is_gpl_compatible(license); 2196 2197 if (attr->insn_cnt == 0 || 2198 attr->insn_cnt > (bpf_capable() ? BPF_COMPLEXITY_LIMIT_INSNS : BPF_MAXINSNS)) 2199 return -E2BIG; 2200 if (type != BPF_PROG_TYPE_SOCKET_FILTER && 2201 type != BPF_PROG_TYPE_CGROUP_SKB && 2202 !bpf_capable()) 2203 return -EPERM; 2204 2205 if (is_net_admin_prog_type(type) && !capable(CAP_NET_ADMIN) && !capable(CAP_SYS_ADMIN)) 2206 return -EPERM; 2207 if (is_perfmon_prog_type(type) && !perfmon_capable()) 2208 return -EPERM; 2209 2210 /* attach_prog_fd/attach_btf_obj_fd can specify fd of either bpf_prog 2211 * or btf, we need to check which one it is 2212 */ 2213 if (attr->attach_prog_fd) { 2214 dst_prog = bpf_prog_get(attr->attach_prog_fd); 2215 if (IS_ERR(dst_prog)) { 2216 dst_prog = NULL; 2217 attach_btf = btf_get_by_fd(attr->attach_btf_obj_fd); 2218 if (IS_ERR(attach_btf)) 2219 return -EINVAL; 2220 if (!btf_is_kernel(attach_btf)) { 2221 /* attaching through specifying bpf_prog's BTF 2222 * objects directly might be supported eventually 2223 */ 2224 btf_put(attach_btf); 2225 return -ENOTSUPP; 2226 } 2227 } 2228 } else if (attr->attach_btf_id) { 2229 /* fall back to vmlinux BTF, if BTF type ID is specified */ 2230 attach_btf = bpf_get_btf_vmlinux(); 2231 if (IS_ERR(attach_btf)) 2232 return PTR_ERR(attach_btf); 2233 if (!attach_btf) 2234 return -EINVAL; 2235 btf_get(attach_btf); 2236 } 2237 2238 bpf_prog_load_fixup_attach_type(attr); 2239 if (bpf_prog_load_check_attach(type, attr->expected_attach_type, 2240 attach_btf, attr->attach_btf_id, 2241 dst_prog)) { 2242 if (dst_prog) 2243 bpf_prog_put(dst_prog); 2244 if (attach_btf) 2245 btf_put(attach_btf); 2246 return -EINVAL; 2247 } 2248 2249 /* plain bpf_prog allocation */ 2250 prog = bpf_prog_alloc(bpf_prog_size(attr->insn_cnt), GFP_USER); 2251 if (!prog) { 2252 if (dst_prog) 2253 bpf_prog_put(dst_prog); 2254 if (attach_btf) 2255 btf_put(attach_btf); 2256 return -ENOMEM; 2257 } 2258 2259 prog->expected_attach_type = attr->expected_attach_type; 2260 prog->aux->attach_btf = attach_btf; 2261 prog->aux->attach_btf_id = attr->attach_btf_id; 2262 prog->aux->dst_prog = dst_prog; 2263 prog->aux->offload_requested = !!attr->prog_ifindex; 2264 prog->aux->sleepable = attr->prog_flags & BPF_F_SLEEPABLE; 2265 2266 err = security_bpf_prog_alloc(prog->aux); 2267 if (err) 2268 goto free_prog; 2269 2270 prog->aux->user = get_current_user(); 2271 prog->len = attr->insn_cnt; 2272 2273 err = -EFAULT; 2274 if (copy_from_bpfptr(prog->insns, 2275 make_bpfptr(attr->insns, uattr.is_kernel), 2276 bpf_prog_insn_size(prog)) != 0) 2277 goto free_prog_sec; 2278 2279 if (attr->sig_len) { 2280 char *signature; 2281 2282 signature = kmalloc(attr->sig_len, GFP_USER); 2283 if (!signature) { 2284 err = -ENOMEM; 2285 goto free_prog_sec; 2286 } 2287 > 2288 if (copy_from_user(signature, (char *)attr->signature, attr->sig_len)) { 2289 err = -EFAULT; 2290 kfree(signature); 2291 goto free_prog_sec; 2292 } 2293 > 2294 err = verify_pkcs7_signature(prog->insns, 2295 prog->len * sizeof(struct bpf_insn), 2296 signature, attr->sig_len, 2297 VERIFY_USE_SECONDARY_KEYRING, 2298 VERIFYING_MODULE_SIGNATURE, 2299 NULL, NULL); 2300 kfree(signature); 2301 2302 if (err) { 2303 printk("verify_pkcs7_signature(): %pe\n", (void*)(uintptr_t)err); 2304 goto free_prog_sec; 2305 } 2306 } 2307 2308 prog->orig_prog = NULL; 2309 prog->jited = 0; 2310 2311 atomic64_set(&prog->aux->refcnt, 1); 2312 prog->gpl_compatible = is_gpl ? 1 : 0; 2313 2314 if (bpf_prog_is_dev_bound(prog->aux)) { 2315 err = bpf_prog_offload_init(prog, attr); 2316 if (err) 2317 goto free_prog_sec; 2318 } 2319 2320 /* find program type: socket_filter vs tracing_filter */ 2321 err = find_prog_type(type, prog); 2322 if (err < 0) 2323 goto free_prog_sec; 2324 2325 prog->aux->load_time = ktime_get_boottime_ns(); 2326 err = bpf_obj_name_cpy(prog->aux->name, attr->prog_name, 2327 sizeof(attr->prog_name)); 2328 if (err < 0) 2329 goto free_prog_sec; 2330 2331 /* run eBPF verifier */ 2332 err = bpf_check(&prog, attr, uattr); 2333 if (err < 0) 2334 goto free_used_maps; 2335 2336 prog = bpf_prog_select_runtime(prog, &err); 2337 if (err < 0) 2338 goto free_used_maps; 2339 2340 err = bpf_prog_alloc_id(prog); 2341 if (err) 2342 goto free_used_maps; 2343 2344 /* Upon success of bpf_prog_alloc_id(), the BPF prog is 2345 * effectively publicly exposed. However, retrieving via 2346 * bpf_prog_get_fd_by_id() will take another reference, 2347 * therefore it cannot be gone underneath us. 2348 * 2349 * Only for the time /after/ successful bpf_prog_new_fd() 2350 * and before returning to userspace, we might just hold 2351 * one reference and any parallel close on that fd could 2352 * rip everything out. Hence, below notifications must 2353 * happen before bpf_prog_new_fd(). 2354 * 2355 * Also, any failure handling from this point onwards must 2356 * be using bpf_prog_put() given the program is exposed. 2357 */ 2358 bpf_prog_kallsyms_add(prog); 2359 perf_event_bpf_event(prog, PERF_BPF_EVENT_PROG_LOAD, 0); 2360 bpf_audit_prog(prog, BPF_AUDIT_LOAD); 2361 2362 err = bpf_prog_new_fd(prog); 2363 if (err < 0) 2364 bpf_prog_put(prog); 2365 return err; 2366 2367 free_used_maps: 2368 /* In case we have subprogs, we need to wait for a grace 2369 * period before we can tear down JIT memory since symbols 2370 * are already exposed under kallsyms. 2371 */ 2372 __bpf_prog_put_noref(prog, prog->aux->func_cnt); 2373 return err; 2374 free_prog_sec: 2375 free_uid(prog->aux->user); 2376 security_bpf_prog_free(prog->aux); 2377 free_prog: 2378 if (prog->aux->attach_btf) 2379 btf_put(prog->aux->attach_btf); 2380 bpf_prog_free(prog); 2381 return err; 2382 } 2383 --- 0-DAY CI Kernel Test Service, Intel Corporation https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org [-- Attachment #2: config.gz --] [-- Type: application/gzip, Size: 31072 bytes --] ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [RFC bpf-next 1/2] bpf: add signature to eBPF instructions 2021-10-12 19:00 ` [RFC bpf-next 1/2] bpf: add signature to eBPF instructions Matteo Croce 2021-10-13 2:37 ` kernel test robot 2021-10-13 3:13 ` kernel test robot @ 2021-10-13 3:36 ` kernel test robot 2021-10-13 14:35 ` kernel test robot 2021-10-24 22:35 ` kernel test robot 4 siblings, 0 replies; 8+ messages in thread From: kernel test robot @ 2021-10-13 3:36 UTC (permalink / raw) To: kbuild-all [-- Attachment #1: Type: text/plain, Size: 9287 bytes --] Hi Matteo, [FYI, it's a private test report for your RFC patch.] [auto build test ERROR on bpf-next/master] url: https://github.com/0day-ci/linux/commits/Matteo-Croce/bpf-sign-bpf-programs/20211013-030207 base: https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git master config: i386-buildonly-randconfig-r002-20211012 (attached as .config) compiler: gcc-9 (Debian 9.3.0-22) 9.3.0 reproduce (this is a W=1 build): # https://github.com/0day-ci/linux/commit/45c21d28e868dac39e5267e2e2b6f4e35f86b661 git remote add linux-review https://github.com/0day-ci/linux git fetch --no-tags linux-review Matteo-Croce/bpf-sign-bpf-programs/20211013-030207 git checkout 45c21d28e868dac39e5267e2e2b6f4e35f86b661 # save the attached .config to linux build tree make W=1 ARCH=i386 If you fix the issue, kindly add following tag as appropriate Reported-by: kernel test robot <lkp@intel.com> All errors (new ones prefixed by >>): kernel/bpf/syscall.c: In function 'bpf_prog_load': >> kernel/bpf/syscall.c:2288:33: error: cast to pointer from integer of different size [-Werror=int-to-pointer-cast] 2288 | if (copy_from_user(signature, (char *)attr->signature, attr->sig_len)) { | ^ cc1: all warnings being treated as errors vim +2288 kernel/bpf/syscall.c 2162 2163 static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr) 2164 { 2165 enum bpf_prog_type type = attr->prog_type; 2166 struct bpf_prog *prog, *dst_prog = NULL; 2167 struct btf *attach_btf = NULL; 2168 int err; 2169 char license[128]; 2170 bool is_gpl; 2171 2172 if (CHECK_ATTR(BPF_PROG_LOAD)) 2173 return -EINVAL; 2174 2175 if (attr->prog_flags & ~(BPF_F_STRICT_ALIGNMENT | 2176 BPF_F_ANY_ALIGNMENT | 2177 BPF_F_TEST_STATE_FREQ | 2178 BPF_F_SLEEPABLE | 2179 BPF_F_TEST_RND_HI32)) 2180 return -EINVAL; 2181 2182 if (!IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && 2183 (attr->prog_flags & BPF_F_ANY_ALIGNMENT) && 2184 !bpf_capable()) 2185 return -EPERM; 2186 2187 /* copy eBPF program license from user space */ 2188 if (strncpy_from_bpfptr(license, 2189 make_bpfptr(attr->license, uattr.is_kernel), 2190 sizeof(license) - 1) < 0) 2191 return -EFAULT; 2192 license[sizeof(license) - 1] = 0; 2193 2194 /* eBPF programs must be GPL compatible to use GPL-ed functions */ 2195 is_gpl = license_is_gpl_compatible(license); 2196 2197 if (attr->insn_cnt == 0 || 2198 attr->insn_cnt > (bpf_capable() ? BPF_COMPLEXITY_LIMIT_INSNS : BPF_MAXINSNS)) 2199 return -E2BIG; 2200 if (type != BPF_PROG_TYPE_SOCKET_FILTER && 2201 type != BPF_PROG_TYPE_CGROUP_SKB && 2202 !bpf_capable()) 2203 return -EPERM; 2204 2205 if (is_net_admin_prog_type(type) && !capable(CAP_NET_ADMIN) && !capable(CAP_SYS_ADMIN)) 2206 return -EPERM; 2207 if (is_perfmon_prog_type(type) && !perfmon_capable()) 2208 return -EPERM; 2209 2210 /* attach_prog_fd/attach_btf_obj_fd can specify fd of either bpf_prog 2211 * or btf, we need to check which one it is 2212 */ 2213 if (attr->attach_prog_fd) { 2214 dst_prog = bpf_prog_get(attr->attach_prog_fd); 2215 if (IS_ERR(dst_prog)) { 2216 dst_prog = NULL; 2217 attach_btf = btf_get_by_fd(attr->attach_btf_obj_fd); 2218 if (IS_ERR(attach_btf)) 2219 return -EINVAL; 2220 if (!btf_is_kernel(attach_btf)) { 2221 /* attaching through specifying bpf_prog's BTF 2222 * objects directly might be supported eventually 2223 */ 2224 btf_put(attach_btf); 2225 return -ENOTSUPP; 2226 } 2227 } 2228 } else if (attr->attach_btf_id) { 2229 /* fall back to vmlinux BTF, if BTF type ID is specified */ 2230 attach_btf = bpf_get_btf_vmlinux(); 2231 if (IS_ERR(attach_btf)) 2232 return PTR_ERR(attach_btf); 2233 if (!attach_btf) 2234 return -EINVAL; 2235 btf_get(attach_btf); 2236 } 2237 2238 bpf_prog_load_fixup_attach_type(attr); 2239 if (bpf_prog_load_check_attach(type, attr->expected_attach_type, 2240 attach_btf, attr->attach_btf_id, 2241 dst_prog)) { 2242 if (dst_prog) 2243 bpf_prog_put(dst_prog); 2244 if (attach_btf) 2245 btf_put(attach_btf); 2246 return -EINVAL; 2247 } 2248 2249 /* plain bpf_prog allocation */ 2250 prog = bpf_prog_alloc(bpf_prog_size(attr->insn_cnt), GFP_USER); 2251 if (!prog) { 2252 if (dst_prog) 2253 bpf_prog_put(dst_prog); 2254 if (attach_btf) 2255 btf_put(attach_btf); 2256 return -ENOMEM; 2257 } 2258 2259 prog->expected_attach_type = attr->expected_attach_type; 2260 prog->aux->attach_btf = attach_btf; 2261 prog->aux->attach_btf_id = attr->attach_btf_id; 2262 prog->aux->dst_prog = dst_prog; 2263 prog->aux->offload_requested = !!attr->prog_ifindex; 2264 prog->aux->sleepable = attr->prog_flags & BPF_F_SLEEPABLE; 2265 2266 err = security_bpf_prog_alloc(prog->aux); 2267 if (err) 2268 goto free_prog; 2269 2270 prog->aux->user = get_current_user(); 2271 prog->len = attr->insn_cnt; 2272 2273 err = -EFAULT; 2274 if (copy_from_bpfptr(prog->insns, 2275 make_bpfptr(attr->insns, uattr.is_kernel), 2276 bpf_prog_insn_size(prog)) != 0) 2277 goto free_prog_sec; 2278 2279 if (attr->sig_len) { 2280 char *signature; 2281 2282 signature = kmalloc(attr->sig_len, GFP_USER); 2283 if (!signature) { 2284 err = -ENOMEM; 2285 goto free_prog_sec; 2286 } 2287 > 2288 if (copy_from_user(signature, (char *)attr->signature, attr->sig_len)) { 2289 err = -EFAULT; 2290 kfree(signature); 2291 goto free_prog_sec; 2292 } 2293 2294 err = verify_pkcs7_signature(prog->insns, 2295 prog->len * sizeof(struct bpf_insn), 2296 signature, attr->sig_len, 2297 VERIFY_USE_SECONDARY_KEYRING, 2298 VERIFYING_MODULE_SIGNATURE, 2299 NULL, NULL); 2300 kfree(signature); 2301 2302 if (err) { 2303 printk("verify_pkcs7_signature(): %pe\n", (void*)(uintptr_t)err); 2304 goto free_prog_sec; 2305 } 2306 } 2307 2308 prog->orig_prog = NULL; 2309 prog->jited = 0; 2310 2311 atomic64_set(&prog->aux->refcnt, 1); 2312 prog->gpl_compatible = is_gpl ? 1 : 0; 2313 2314 if (bpf_prog_is_dev_bound(prog->aux)) { 2315 err = bpf_prog_offload_init(prog, attr); 2316 if (err) 2317 goto free_prog_sec; 2318 } 2319 2320 /* find program type: socket_filter vs tracing_filter */ 2321 err = find_prog_type(type, prog); 2322 if (err < 0) 2323 goto free_prog_sec; 2324 2325 prog->aux->load_time = ktime_get_boottime_ns(); 2326 err = bpf_obj_name_cpy(prog->aux->name, attr->prog_name, 2327 sizeof(attr->prog_name)); 2328 if (err < 0) 2329 goto free_prog_sec; 2330 2331 /* run eBPF verifier */ 2332 err = bpf_check(&prog, attr, uattr); 2333 if (err < 0) 2334 goto free_used_maps; 2335 2336 prog = bpf_prog_select_runtime(prog, &err); 2337 if (err < 0) 2338 goto free_used_maps; 2339 2340 err = bpf_prog_alloc_id(prog); 2341 if (err) 2342 goto free_used_maps; 2343 2344 /* Upon success of bpf_prog_alloc_id(), the BPF prog is 2345 * effectively publicly exposed. However, retrieving via 2346 * bpf_prog_get_fd_by_id() will take another reference, 2347 * therefore it cannot be gone underneath us. 2348 * 2349 * Only for the time /after/ successful bpf_prog_new_fd() 2350 * and before returning to userspace, we might just hold 2351 * one reference and any parallel close on that fd could 2352 * rip everything out. Hence, below notifications must 2353 * happen before bpf_prog_new_fd(). 2354 * 2355 * Also, any failure handling from this point onwards must 2356 * be using bpf_prog_put() given the program is exposed. 2357 */ 2358 bpf_prog_kallsyms_add(prog); 2359 perf_event_bpf_event(prog, PERF_BPF_EVENT_PROG_LOAD, 0); 2360 bpf_audit_prog(prog, BPF_AUDIT_LOAD); 2361 2362 err = bpf_prog_new_fd(prog); 2363 if (err < 0) 2364 bpf_prog_put(prog); 2365 return err; 2366 2367 free_used_maps: 2368 /* In case we have subprogs, we need to wait for a grace 2369 * period before we can tear down JIT memory since symbols 2370 * are already exposed under kallsyms. 2371 */ 2372 __bpf_prog_put_noref(prog, prog->aux->func_cnt); 2373 return err; 2374 free_prog_sec: 2375 free_uid(prog->aux->user); 2376 security_bpf_prog_free(prog->aux); 2377 free_prog: 2378 if (prog->aux->attach_btf) 2379 btf_put(prog->aux->attach_btf); 2380 bpf_prog_free(prog); 2381 return err; 2382 } 2383 --- 0-DAY CI Kernel Test Service, Intel Corporation https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org [-- Attachment #2: config.gz --] [-- Type: application/gzip, Size: 38303 bytes --] ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [RFC bpf-next 1/2] bpf: add signature to eBPF instructions 2021-10-12 19:00 ` [RFC bpf-next 1/2] bpf: add signature to eBPF instructions Matteo Croce ` (2 preceding siblings ...) 2021-10-13 3:36 ` kernel test robot @ 2021-10-13 14:35 ` kernel test robot 2021-10-24 22:35 ` kernel test robot 4 siblings, 0 replies; 8+ messages in thread From: kernel test robot @ 2021-10-13 14:35 UTC (permalink / raw) To: kbuild-all [-- Attachment #1: Type: text/plain, Size: 11053 bytes --] Hi Matteo, [FYI, it's a private test report for your RFC patch.] [auto build test WARNING on bpf-next/master] url: https://github.com/0day-ci/linux/commits/Matteo-Croce/bpf-sign-bpf-programs/20211013-030207 base: https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git master config: mips-randconfig-s031-20211013 (attached as .config) compiler: mipsel-linux-gcc (GCC) 11.2.0 reproduce: wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross # apt-get install sparse # sparse version: v0.6.4-dirty # https://github.com/0day-ci/linux/commit/45c21d28e868dac39e5267e2e2b6f4e35f86b661 git remote add linux-review https://github.com/0day-ci/linux git fetch --no-tags linux-review Matteo-Croce/bpf-sign-bpf-programs/20211013-030207 git checkout 45c21d28e868dac39e5267e2e2b6f4e35f86b661 # save the attached .config to linux build tree COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-11.2.0 make.cross C=1 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__' O=build_dir ARCH=mips SHELL=/bin/bash kernel/bpf/ If you fix the issue, kindly add following tag as appropriate Reported-by: kernel test robot <lkp@intel.com> sparse warnings: (new ones prefixed by >>) command-line: note: in included file: builtin:1:9: sparse: sparse: preprocessor token __ATOMIC_ACQUIRE redefined builtin:0:0: sparse: this was the original definition builtin:1:9: sparse: sparse: preprocessor token __ATOMIC_SEQ_CST redefined builtin:0:0: sparse: this was the original definition builtin:1:9: sparse: sparse: preprocessor token __ATOMIC_ACQ_REL redefined builtin:0:0: sparse: this was the original definition builtin:1:9: sparse: sparse: preprocessor token __ATOMIC_RELEASE redefined builtin:0:0: sparse: this was the original definition kernel/bpf/syscall.c:2288:48: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void const [noderef] __user *from @@ got char * @@ kernel/bpf/syscall.c:2288:48: sparse: expected void const [noderef] __user *from kernel/bpf/syscall.c:2288:48: sparse: got char * kernel/bpf/syscall.c: note: in included file (through include/linux/bpf.h): include/linux/bpfptr.h:52:47: sparse: sparse: cast to non-scalar include/linux/bpfptr.h:52:47: sparse: sparse: cast from non-scalar include/linux/bpfptr.h:52:47: sparse: sparse: cast to non-scalar include/linux/bpfptr.h:52:47: sparse: sparse: cast from non-scalar include/linux/bpfptr.h:81:43: sparse: sparse: cast to non-scalar include/linux/bpfptr.h:81:43: sparse: sparse: cast from non-scalar include/linux/bpfptr.h:52:47: sparse: sparse: cast to non-scalar include/linux/bpfptr.h:52:47: sparse: sparse: cast from non-scalar >> kernel/bpf/syscall.c:2288:55: sparse: sparse: non size-preserving integer to pointer cast include/linux/bpfptr.h:52:47: sparse: sparse: cast to non-scalar include/linux/bpfptr.h:52:47: sparse: sparse: cast from non-scalar vim +2288 kernel/bpf/syscall.c 2162 2163 static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr) 2164 { 2165 enum bpf_prog_type type = attr->prog_type; 2166 struct bpf_prog *prog, *dst_prog = NULL; 2167 struct btf *attach_btf = NULL; 2168 int err; 2169 char license[128]; 2170 bool is_gpl; 2171 2172 if (CHECK_ATTR(BPF_PROG_LOAD)) 2173 return -EINVAL; 2174 2175 if (attr->prog_flags & ~(BPF_F_STRICT_ALIGNMENT | 2176 BPF_F_ANY_ALIGNMENT | 2177 BPF_F_TEST_STATE_FREQ | 2178 BPF_F_SLEEPABLE | 2179 BPF_F_TEST_RND_HI32)) 2180 return -EINVAL; 2181 2182 if (!IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && 2183 (attr->prog_flags & BPF_F_ANY_ALIGNMENT) && 2184 !bpf_capable()) 2185 return -EPERM; 2186 2187 /* copy eBPF program license from user space */ 2188 if (strncpy_from_bpfptr(license, 2189 make_bpfptr(attr->license, uattr.is_kernel), 2190 sizeof(license) - 1) < 0) 2191 return -EFAULT; 2192 license[sizeof(license) - 1] = 0; 2193 2194 /* eBPF programs must be GPL compatible to use GPL-ed functions */ 2195 is_gpl = license_is_gpl_compatible(license); 2196 2197 if (attr->insn_cnt == 0 || 2198 attr->insn_cnt > (bpf_capable() ? BPF_COMPLEXITY_LIMIT_INSNS : BPF_MAXINSNS)) 2199 return -E2BIG; 2200 if (type != BPF_PROG_TYPE_SOCKET_FILTER && 2201 type != BPF_PROG_TYPE_CGROUP_SKB && 2202 !bpf_capable()) 2203 return -EPERM; 2204 2205 if (is_net_admin_prog_type(type) && !capable(CAP_NET_ADMIN) && !capable(CAP_SYS_ADMIN)) 2206 return -EPERM; 2207 if (is_perfmon_prog_type(type) && !perfmon_capable()) 2208 return -EPERM; 2209 2210 /* attach_prog_fd/attach_btf_obj_fd can specify fd of either bpf_prog 2211 * or btf, we need to check which one it is 2212 */ 2213 if (attr->attach_prog_fd) { 2214 dst_prog = bpf_prog_get(attr->attach_prog_fd); 2215 if (IS_ERR(dst_prog)) { 2216 dst_prog = NULL; 2217 attach_btf = btf_get_by_fd(attr->attach_btf_obj_fd); 2218 if (IS_ERR(attach_btf)) 2219 return -EINVAL; 2220 if (!btf_is_kernel(attach_btf)) { 2221 /* attaching through specifying bpf_prog's BTF 2222 * objects directly might be supported eventually 2223 */ 2224 btf_put(attach_btf); 2225 return -ENOTSUPP; 2226 } 2227 } 2228 } else if (attr->attach_btf_id) { 2229 /* fall back to vmlinux BTF, if BTF type ID is specified */ 2230 attach_btf = bpf_get_btf_vmlinux(); 2231 if (IS_ERR(attach_btf)) 2232 return PTR_ERR(attach_btf); 2233 if (!attach_btf) 2234 return -EINVAL; 2235 btf_get(attach_btf); 2236 } 2237 2238 bpf_prog_load_fixup_attach_type(attr); 2239 if (bpf_prog_load_check_attach(type, attr->expected_attach_type, 2240 attach_btf, attr->attach_btf_id, 2241 dst_prog)) { 2242 if (dst_prog) 2243 bpf_prog_put(dst_prog); 2244 if (attach_btf) 2245 btf_put(attach_btf); 2246 return -EINVAL; 2247 } 2248 2249 /* plain bpf_prog allocation */ 2250 prog = bpf_prog_alloc(bpf_prog_size(attr->insn_cnt), GFP_USER); 2251 if (!prog) { 2252 if (dst_prog) 2253 bpf_prog_put(dst_prog); 2254 if (attach_btf) 2255 btf_put(attach_btf); 2256 return -ENOMEM; 2257 } 2258 2259 prog->expected_attach_type = attr->expected_attach_type; 2260 prog->aux->attach_btf = attach_btf; 2261 prog->aux->attach_btf_id = attr->attach_btf_id; 2262 prog->aux->dst_prog = dst_prog; 2263 prog->aux->offload_requested = !!attr->prog_ifindex; 2264 prog->aux->sleepable = attr->prog_flags & BPF_F_SLEEPABLE; 2265 2266 err = security_bpf_prog_alloc(prog->aux); 2267 if (err) 2268 goto free_prog; 2269 2270 prog->aux->user = get_current_user(); 2271 prog->len = attr->insn_cnt; 2272 2273 err = -EFAULT; 2274 if (copy_from_bpfptr(prog->insns, 2275 make_bpfptr(attr->insns, uattr.is_kernel), 2276 bpf_prog_insn_size(prog)) != 0) 2277 goto free_prog_sec; 2278 2279 if (attr->sig_len) { 2280 char *signature; 2281 2282 signature = kmalloc(attr->sig_len, GFP_USER); 2283 if (!signature) { 2284 err = -ENOMEM; 2285 goto free_prog_sec; 2286 } 2287 > 2288 if (copy_from_user(signature, (char *)attr->signature, attr->sig_len)) { 2289 err = -EFAULT; 2290 kfree(signature); 2291 goto free_prog_sec; 2292 } 2293 2294 err = verify_pkcs7_signature(prog->insns, 2295 prog->len * sizeof(struct bpf_insn), 2296 signature, attr->sig_len, 2297 VERIFY_USE_SECONDARY_KEYRING, 2298 VERIFYING_MODULE_SIGNATURE, 2299 NULL, NULL); 2300 kfree(signature); 2301 2302 if (err) { 2303 printk("verify_pkcs7_signature(): %pe\n", (void*)(uintptr_t)err); 2304 goto free_prog_sec; 2305 } 2306 } 2307 2308 prog->orig_prog = NULL; 2309 prog->jited = 0; 2310 2311 atomic64_set(&prog->aux->refcnt, 1); 2312 prog->gpl_compatible = is_gpl ? 1 : 0; 2313 2314 if (bpf_prog_is_dev_bound(prog->aux)) { 2315 err = bpf_prog_offload_init(prog, attr); 2316 if (err) 2317 goto free_prog_sec; 2318 } 2319 2320 /* find program type: socket_filter vs tracing_filter */ 2321 err = find_prog_type(type, prog); 2322 if (err < 0) 2323 goto free_prog_sec; 2324 2325 prog->aux->load_time = ktime_get_boottime_ns(); 2326 err = bpf_obj_name_cpy(prog->aux->name, attr->prog_name, 2327 sizeof(attr->prog_name)); 2328 if (err < 0) 2329 goto free_prog_sec; 2330 2331 /* run eBPF verifier */ 2332 err = bpf_check(&prog, attr, uattr); 2333 if (err < 0) 2334 goto free_used_maps; 2335 2336 prog = bpf_prog_select_runtime(prog, &err); 2337 if (err < 0) 2338 goto free_used_maps; 2339 2340 err = bpf_prog_alloc_id(prog); 2341 if (err) 2342 goto free_used_maps; 2343 2344 /* Upon success of bpf_prog_alloc_id(), the BPF prog is 2345 * effectively publicly exposed. However, retrieving via 2346 * bpf_prog_get_fd_by_id() will take another reference, 2347 * therefore it cannot be gone underneath us. 2348 * 2349 * Only for the time /after/ successful bpf_prog_new_fd() 2350 * and before returning to userspace, we might just hold 2351 * one reference and any parallel close on that fd could 2352 * rip everything out. Hence, below notifications must 2353 * happen before bpf_prog_new_fd(). 2354 * 2355 * Also, any failure handling from this point onwards must 2356 * be using bpf_prog_put() given the program is exposed. 2357 */ 2358 bpf_prog_kallsyms_add(prog); 2359 perf_event_bpf_event(prog, PERF_BPF_EVENT_PROG_LOAD, 0); 2360 bpf_audit_prog(prog, BPF_AUDIT_LOAD); 2361 2362 err = bpf_prog_new_fd(prog); 2363 if (err < 0) 2364 bpf_prog_put(prog); 2365 return err; 2366 2367 free_used_maps: 2368 /* In case we have subprogs, we need to wait for a grace 2369 * period before we can tear down JIT memory since symbols 2370 * are already exposed under kallsyms. 2371 */ 2372 __bpf_prog_put_noref(prog, prog->aux->func_cnt); 2373 return err; 2374 free_prog_sec: 2375 free_uid(prog->aux->user); 2376 security_bpf_prog_free(prog->aux); 2377 free_prog: 2378 if (prog->aux->attach_btf) 2379 btf_put(prog->aux->attach_btf); 2380 bpf_prog_free(prog); 2381 return err; 2382 } 2383 --- 0-DAY CI Kernel Test Service, Intel Corporation https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org [-- Attachment #2: config.gz --] [-- Type: application/gzip, Size: 37722 bytes --] ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [RFC bpf-next 1/2] bpf: add signature to eBPF instructions 2021-10-12 19:00 ` [RFC bpf-next 1/2] bpf: add signature to eBPF instructions Matteo Croce ` (3 preceding siblings ...) 2021-10-13 14:35 ` kernel test robot @ 2021-10-24 22:35 ` kernel test robot 4 siblings, 0 replies; 8+ messages in thread From: kernel test robot @ 2021-10-24 22:35 UTC (permalink / raw) To: kbuild-all [-- Attachment #1: Type: text/plain, Size: 11053 bytes --] Hi Matteo, [FYI, it's a private test report for your RFC patch.] [auto build test WARNING on bpf-next/master] url: https://github.com/0day-ci/linux/commits/Matteo-Croce/bpf-sign-bpf-programs/20211013-030207 base: https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git master config: mips-randconfig-s031-20211013 (attached as .config) compiler: mipsel-linux-gcc (GCC) 11.2.0 reproduce: wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross chmod +x ~/bin/make.cross # apt-get install sparse # sparse version: v0.6.4-dirty # https://github.com/0day-ci/linux/commit/45c21d28e868dac39e5267e2e2b6f4e35f86b661 git remote add linux-review https://github.com/0day-ci/linux git fetch --no-tags linux-review Matteo-Croce/bpf-sign-bpf-programs/20211013-030207 git checkout 45c21d28e868dac39e5267e2e2b6f4e35f86b661 # save the attached .config to linux build tree COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-11.2.0 make.cross C=1 CF='-fdiagnostic-prefix -D__CHECK_ENDIAN__' O=build_dir ARCH=mips SHELL=/bin/bash kernel/bpf/ If you fix the issue, kindly add following tag as appropriate Reported-by: kernel test robot <lkp@intel.com> sparse warnings: (new ones prefixed by >>) command-line: note: in included file: builtin:1:9: sparse: sparse: preprocessor token __ATOMIC_ACQUIRE redefined builtin:0:0: sparse: this was the original definition builtin:1:9: sparse: sparse: preprocessor token __ATOMIC_SEQ_CST redefined builtin:0:0: sparse: this was the original definition builtin:1:9: sparse: sparse: preprocessor token __ATOMIC_ACQ_REL redefined builtin:0:0: sparse: this was the original definition builtin:1:9: sparse: sparse: preprocessor token __ATOMIC_RELEASE redefined builtin:0:0: sparse: this was the original definition kernel/bpf/syscall.c:2288:48: sparse: sparse: incorrect type in argument 2 (different address spaces) @@ expected void const [noderef] __user *from @@ got char * @@ kernel/bpf/syscall.c:2288:48: sparse: expected void const [noderef] __user *from kernel/bpf/syscall.c:2288:48: sparse: got char * kernel/bpf/syscall.c: note: in included file (through include/linux/bpf.h): include/linux/bpfptr.h:52:47: sparse: sparse: cast to non-scalar include/linux/bpfptr.h:52:47: sparse: sparse: cast from non-scalar include/linux/bpfptr.h:52:47: sparse: sparse: cast to non-scalar include/linux/bpfptr.h:52:47: sparse: sparse: cast from non-scalar include/linux/bpfptr.h:81:43: sparse: sparse: cast to non-scalar include/linux/bpfptr.h:81:43: sparse: sparse: cast from non-scalar include/linux/bpfptr.h:52:47: sparse: sparse: cast to non-scalar include/linux/bpfptr.h:52:47: sparse: sparse: cast from non-scalar >> kernel/bpf/syscall.c:2288:55: sparse: sparse: non size-preserving integer to pointer cast include/linux/bpfptr.h:52:47: sparse: sparse: cast to non-scalar include/linux/bpfptr.h:52:47: sparse: sparse: cast from non-scalar vim +2288 kernel/bpf/syscall.c 2162 2163 static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr) 2164 { 2165 enum bpf_prog_type type = attr->prog_type; 2166 struct bpf_prog *prog, *dst_prog = NULL; 2167 struct btf *attach_btf = NULL; 2168 int err; 2169 char license[128]; 2170 bool is_gpl; 2171 2172 if (CHECK_ATTR(BPF_PROG_LOAD)) 2173 return -EINVAL; 2174 2175 if (attr->prog_flags & ~(BPF_F_STRICT_ALIGNMENT | 2176 BPF_F_ANY_ALIGNMENT | 2177 BPF_F_TEST_STATE_FREQ | 2178 BPF_F_SLEEPABLE | 2179 BPF_F_TEST_RND_HI32)) 2180 return -EINVAL; 2181 2182 if (!IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && 2183 (attr->prog_flags & BPF_F_ANY_ALIGNMENT) && 2184 !bpf_capable()) 2185 return -EPERM; 2186 2187 /* copy eBPF program license from user space */ 2188 if (strncpy_from_bpfptr(license, 2189 make_bpfptr(attr->license, uattr.is_kernel), 2190 sizeof(license) - 1) < 0) 2191 return -EFAULT; 2192 license[sizeof(license) - 1] = 0; 2193 2194 /* eBPF programs must be GPL compatible to use GPL-ed functions */ 2195 is_gpl = license_is_gpl_compatible(license); 2196 2197 if (attr->insn_cnt == 0 || 2198 attr->insn_cnt > (bpf_capable() ? BPF_COMPLEXITY_LIMIT_INSNS : BPF_MAXINSNS)) 2199 return -E2BIG; 2200 if (type != BPF_PROG_TYPE_SOCKET_FILTER && 2201 type != BPF_PROG_TYPE_CGROUP_SKB && 2202 !bpf_capable()) 2203 return -EPERM; 2204 2205 if (is_net_admin_prog_type(type) && !capable(CAP_NET_ADMIN) && !capable(CAP_SYS_ADMIN)) 2206 return -EPERM; 2207 if (is_perfmon_prog_type(type) && !perfmon_capable()) 2208 return -EPERM; 2209 2210 /* attach_prog_fd/attach_btf_obj_fd can specify fd of either bpf_prog 2211 * or btf, we need to check which one it is 2212 */ 2213 if (attr->attach_prog_fd) { 2214 dst_prog = bpf_prog_get(attr->attach_prog_fd); 2215 if (IS_ERR(dst_prog)) { 2216 dst_prog = NULL; 2217 attach_btf = btf_get_by_fd(attr->attach_btf_obj_fd); 2218 if (IS_ERR(attach_btf)) 2219 return -EINVAL; 2220 if (!btf_is_kernel(attach_btf)) { 2221 /* attaching through specifying bpf_prog's BTF 2222 * objects directly might be supported eventually 2223 */ 2224 btf_put(attach_btf); 2225 return -ENOTSUPP; 2226 } 2227 } 2228 } else if (attr->attach_btf_id) { 2229 /* fall back to vmlinux BTF, if BTF type ID is specified */ 2230 attach_btf = bpf_get_btf_vmlinux(); 2231 if (IS_ERR(attach_btf)) 2232 return PTR_ERR(attach_btf); 2233 if (!attach_btf) 2234 return -EINVAL; 2235 btf_get(attach_btf); 2236 } 2237 2238 bpf_prog_load_fixup_attach_type(attr); 2239 if (bpf_prog_load_check_attach(type, attr->expected_attach_type, 2240 attach_btf, attr->attach_btf_id, 2241 dst_prog)) { 2242 if (dst_prog) 2243 bpf_prog_put(dst_prog); 2244 if (attach_btf) 2245 btf_put(attach_btf); 2246 return -EINVAL; 2247 } 2248 2249 /* plain bpf_prog allocation */ 2250 prog = bpf_prog_alloc(bpf_prog_size(attr->insn_cnt), GFP_USER); 2251 if (!prog) { 2252 if (dst_prog) 2253 bpf_prog_put(dst_prog); 2254 if (attach_btf) 2255 btf_put(attach_btf); 2256 return -ENOMEM; 2257 } 2258 2259 prog->expected_attach_type = attr->expected_attach_type; 2260 prog->aux->attach_btf = attach_btf; 2261 prog->aux->attach_btf_id = attr->attach_btf_id; 2262 prog->aux->dst_prog = dst_prog; 2263 prog->aux->offload_requested = !!attr->prog_ifindex; 2264 prog->aux->sleepable = attr->prog_flags & BPF_F_SLEEPABLE; 2265 2266 err = security_bpf_prog_alloc(prog->aux); 2267 if (err) 2268 goto free_prog; 2269 2270 prog->aux->user = get_current_user(); 2271 prog->len = attr->insn_cnt; 2272 2273 err = -EFAULT; 2274 if (copy_from_bpfptr(prog->insns, 2275 make_bpfptr(attr->insns, uattr.is_kernel), 2276 bpf_prog_insn_size(prog)) != 0) 2277 goto free_prog_sec; 2278 2279 if (attr->sig_len) { 2280 char *signature; 2281 2282 signature = kmalloc(attr->sig_len, GFP_USER); 2283 if (!signature) { 2284 err = -ENOMEM; 2285 goto free_prog_sec; 2286 } 2287 > 2288 if (copy_from_user(signature, (char *)attr->signature, attr->sig_len)) { 2289 err = -EFAULT; 2290 kfree(signature); 2291 goto free_prog_sec; 2292 } 2293 2294 err = verify_pkcs7_signature(prog->insns, 2295 prog->len * sizeof(struct bpf_insn), 2296 signature, attr->sig_len, 2297 VERIFY_USE_SECONDARY_KEYRING, 2298 VERIFYING_MODULE_SIGNATURE, 2299 NULL, NULL); 2300 kfree(signature); 2301 2302 if (err) { 2303 printk("verify_pkcs7_signature(): %pe\n", (void*)(uintptr_t)err); 2304 goto free_prog_sec; 2305 } 2306 } 2307 2308 prog->orig_prog = NULL; 2309 prog->jited = 0; 2310 2311 atomic64_set(&prog->aux->refcnt, 1); 2312 prog->gpl_compatible = is_gpl ? 1 : 0; 2313 2314 if (bpf_prog_is_dev_bound(prog->aux)) { 2315 err = bpf_prog_offload_init(prog, attr); 2316 if (err) 2317 goto free_prog_sec; 2318 } 2319 2320 /* find program type: socket_filter vs tracing_filter */ 2321 err = find_prog_type(type, prog); 2322 if (err < 0) 2323 goto free_prog_sec; 2324 2325 prog->aux->load_time = ktime_get_boottime_ns(); 2326 err = bpf_obj_name_cpy(prog->aux->name, attr->prog_name, 2327 sizeof(attr->prog_name)); 2328 if (err < 0) 2329 goto free_prog_sec; 2330 2331 /* run eBPF verifier */ 2332 err = bpf_check(&prog, attr, uattr); 2333 if (err < 0) 2334 goto free_used_maps; 2335 2336 prog = bpf_prog_select_runtime(prog, &err); 2337 if (err < 0) 2338 goto free_used_maps; 2339 2340 err = bpf_prog_alloc_id(prog); 2341 if (err) 2342 goto free_used_maps; 2343 2344 /* Upon success of bpf_prog_alloc_id(), the BPF prog is 2345 * effectively publicly exposed. However, retrieving via 2346 * bpf_prog_get_fd_by_id() will take another reference, 2347 * therefore it cannot be gone underneath us. 2348 * 2349 * Only for the time /after/ successful bpf_prog_new_fd() 2350 * and before returning to userspace, we might just hold 2351 * one reference and any parallel close on that fd could 2352 * rip everything out. Hence, below notifications must 2353 * happen before bpf_prog_new_fd(). 2354 * 2355 * Also, any failure handling from this point onwards must 2356 * be using bpf_prog_put() given the program is exposed. 2357 */ 2358 bpf_prog_kallsyms_add(prog); 2359 perf_event_bpf_event(prog, PERF_BPF_EVENT_PROG_LOAD, 0); 2360 bpf_audit_prog(prog, BPF_AUDIT_LOAD); 2361 2362 err = bpf_prog_new_fd(prog); 2363 if (err < 0) 2364 bpf_prog_put(prog); 2365 return err; 2366 2367 free_used_maps: 2368 /* In case we have subprogs, we need to wait for a grace 2369 * period before we can tear down JIT memory since symbols 2370 * are already exposed under kallsyms. 2371 */ 2372 __bpf_prog_put_noref(prog, prog->aux->func_cnt); 2373 return err; 2374 free_prog_sec: 2375 free_uid(prog->aux->user); 2376 security_bpf_prog_free(prog->aux); 2377 free_prog: 2378 if (prog->aux->attach_btf) 2379 btf_put(prog->aux->attach_btf); 2380 bpf_prog_free(prog); 2381 return err; 2382 } 2383 --- 0-DAY CI Kernel Test Service, Intel Corporation https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org [-- Attachment #2: config.gz --] [-- Type: application/gzip, Size: 37722 bytes --] ^ permalink raw reply [flat|nested] 8+ messages in thread
* [RFC bpf-next 2/2] bpftool: add signature in skeleton 2021-10-12 19:00 [RFC bpf-next 0/2] bpf: sign bpf programs Matteo Croce 2021-10-12 19:00 ` [RFC bpf-next 1/2] bpf: add signature to eBPF instructions Matteo Croce @ 2021-10-12 19:00 ` Matteo Croce 1 sibling, 0 replies; 8+ messages in thread From: Matteo Croce @ 2021-10-12 19:00 UTC (permalink / raw) To: bpf Cc: linux-kernel, Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko, Arnaldo Carvalho de Melo, Luca Boccassi, David S. Miller From: Matteo Croce <mcroce@microsoft.com> When generating the skeleton, allow to add a signature. The signature will be passed to the kernel in the newly added field. As in sign-file, allow specifing "pkcs11:..." as key file, to use the openssl engine. Still as in sign-file, read the environment variable KBUILD_SIGN_PIN. Signed-off-by: Matteo Croce <mcroce@microsoft.com> --- tools/bpf/bpftool/Makefile | 14 ++- tools/bpf/bpftool/gen.c | 33 +++++ tools/bpf/bpftool/main.c | 28 +++++ tools/bpf/bpftool/main.h | 7 ++ tools/bpf/bpftool/sign.c | 217 +++++++++++++++++++++++++++++++++ tools/include/uapi/linux/bpf.h | 2 + tools/lib/bpf/skel_internal.h | 4 + 7 files changed, 302 insertions(+), 3 deletions(-) create mode 100644 tools/bpf/bpftool/sign.c diff --git a/tools/bpf/bpftool/Makefile b/tools/bpf/bpftool/Makefile index 1fcf5b01a193..b67d6e0b9067 100644 --- a/tools/bpf/bpftool/Makefile +++ b/tools/bpf/bpftool/Makefile @@ -78,9 +78,9 @@ RM ?= rm -f FEATURE_USER = .bpftool FEATURE_TESTS = libbfd disassembler-four-args reallocarray zlib libcap \ - clang-bpf-co-re + clang-bpf-co-re libcrypto FEATURE_DISPLAY = libbfd disassembler-four-args zlib libcap \ - clang-bpf-co-re + clang-bpf-co-re libcrypto check_feat := 1 NON_CHECK_FEAT_TARGETS := clean uninstall doc doc-clean doc-install doc-uninstall @@ -113,6 +113,11 @@ CFLAGS += -DUSE_LIBCAP LIBS += -lcap endif +ifeq ($(feature-libcrypto), 1) +CFLAGS_SSL := -DUSE_SIGN +LIBS += -lssl -lcrypto +endif + include $(wildcard $(OUTPUT)*.d) all: $(OUTPUT)bpftool @@ -120,6 +125,9 @@ all: $(OUTPUT)bpftool BFD_SRCS = jit_disasm.c SRCS = $(filter-out $(BFD_SRCS),$(wildcard *.c)) +ifneq ($(feature-libcrypto), 1) +SRCS := $(filter-out sign.c,$(SRCS)) +endif ifeq ($(feature-libbfd),1) LIBS += -lbfd -ldl -lopcodes @@ -202,7 +210,7 @@ $(BOOTSTRAP_OUTPUT)%.o: %.c | $(BOOTSTRAP_OUTPUT) $(QUIET_CC)$(HOSTCC) $(CFLAGS) -c -MMD -o $@ $< $(OUTPUT)%.o: %.c - $(QUIET_CC)$(CC) $(CFLAGS) -c -MMD -o $@ $< + $(QUIET_CC)$(CC) $(CFLAGS) $(CFLAGS_SSL) -c -MMD -o $@ $< feature-detect-clean: $(call QUIET_CLEAN, feature-detect) diff --git a/tools/bpf/bpftool/gen.c b/tools/bpf/bpftool/gen.c index cc835859465b..2551fe90dc89 100644 --- a/tools/bpf/bpftool/gen.c +++ b/tools/bpf/bpftool/gen.c @@ -434,6 +434,10 @@ static int gen_trace(struct bpf_object *obj, const char *obj_name, const char *h DECLARE_LIBBPF_OPTS(gen_loader_opts, opts); struct bpf_map *map; int err = 0; +#ifdef USE_SIGN + char *signature = NULL; + int sig_len = 0; +#endif err = bpf_object__gen_loader(obj, &opts); if (err) @@ -453,6 +457,19 @@ static int gen_trace(struct bpf_object *obj, const char *obj_name, const char *h * are populated with the loader program. */ +#ifdef USE_SIGN + if (sign_bpf) { + sig_len = sign(sign_hash, sign_key, sign_cert, + opts.insns, opts.insns_sz, + (unsigned char **)&signature); + if (sig_len <= 0) { + p_err("failed to sign instructions"); + err = -EINVAL; + goto out; + } + } +#endif + /* finish generating 'struct skel' */ codegen("\ \n\ @@ -537,6 +554,18 @@ static int gen_trace(struct bpf_object *obj, const char *obj_name, const char *h ", opts.insns_sz); print_hex(opts.insns, opts.insns_sz); +#ifdef USE_SIGN + if (sign_bpf) { + codegen("\ + \n\ + \"; \n\ + opts.sig_sz = %d; \n\ + opts.signature = (void *)\"\\ \n\ + ", + sig_len); + print_hex(signature, sig_len); + } +#endif codegen("\ \n\ \"; \n\ @@ -1037,6 +1066,10 @@ static int do_help(int argc, char **argv) " %1$s %2$s help\n" "\n" " " HELP_SPEC_OPTIONS " |\n" +#ifdef USE_SIGN + " {-s|--sign} | {-H|--hash} |\n" + " {-c|--cert} | {-k|--key} |\n" +#endif " {-L|--use-loader} }\n" "", bin_name, "gen"); diff --git a/tools/bpf/bpftool/main.c b/tools/bpf/bpftool/main.c index 02eaaf065f65..4e70b89c5b22 100644 --- a/tools/bpf/bpftool/main.c +++ b/tools/bpf/bpftool/main.c @@ -30,6 +30,10 @@ bool block_mount; bool verifier_logs; bool relaxed_maps; bool use_loader; +bool sign_bpf; +const char *sign_hash; +const char *sign_cert; +const char *sign_key; struct btf *base_btf; struct pinned_obj_table prog_table; struct pinned_obj_table map_table; @@ -398,6 +402,12 @@ int main(int argc, char **argv) { "debug", no_argument, NULL, 'd' }, { "use-loader", no_argument, NULL, 'L' }, { "base-btf", required_argument, NULL, 'B' }, +#ifdef USE_SIGN + { "sign", no_argument, NULL, 's' }, + { "hash", required_argument, NULL, 'H' }, + { "cert", required_argument, NULL, 'c' }, + { "key", required_argument, NULL, 'k' }, +#endif { 0 } }; int opt, ret; @@ -414,7 +424,11 @@ int main(int argc, char **argv) hash_init(link_table.table); opterr = 0; +#ifdef USE_SIGN + while ((opt = getopt_long(argc, argv, "VhpjfLmndB:sH:c:k:", +#else while ((opt = getopt_long(argc, argv, "VhpjfLmndB:", +#endif options, NULL)) >= 0) { switch (opt) { case 'V': @@ -460,6 +474,20 @@ int main(int argc, char **argv) case 'L': use_loader = true; break; +#ifdef USE_SIGN + case 's': + sign_bpf = true; + break; + case 'H': + sign_hash = optarg; + break; + case 'c': + sign_cert = optarg; + break; + case 'k': + sign_key = optarg; + break; +#endif default: p_err("unrecognized option '%s'", argv[optind - 1]); if (json_output) diff --git a/tools/bpf/bpftool/main.h b/tools/bpf/bpftool/main.h index 90caa42aac4c..78742720447f 100644 --- a/tools/bpf/bpftool/main.h +++ b/tools/bpf/bpftool/main.h @@ -90,6 +90,10 @@ extern bool block_mount; extern bool verifier_logs; extern bool relaxed_maps; extern bool use_loader; +extern bool sign_bpf; +extern const char *sign_hash; +extern const char *sign_cert; +extern const char *sign_key; extern struct btf *base_btf; extern struct pinned_obj_table prog_table; extern struct pinned_obj_table map_table; @@ -259,4 +263,7 @@ int do_filter_dump(struct tcmsg *ifinfo, struct nlattr **tb, const char *kind, int print_all_levels(__maybe_unused enum libbpf_print_level level, const char *format, va_list args); + +int sign(const char *hash_algo, const char *key_path, const char *x509_path, + const char *indata, int indatalen, unsigned char **outdata); #endif diff --git a/tools/bpf/bpftool/sign.c b/tools/bpf/bpftool/sign.c new file mode 100644 index 000000000000..50b257a7177c --- /dev/null +++ b/tools/bpf/bpftool/sign.c @@ -0,0 +1,217 @@ +/* Sign a module file using the given key and certificate. + * + * Inspired by Linux scripts/sign-file.c + * Copyright (C) 2021 Matteo Croce <mcroce@microsoft.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the licence, or (at your option) any later version. + */ +#define _GNU_SOURCE +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> +#include <stdbool.h> +#include <string.h> +#include <err.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> + +#include <openssl/opensslv.h> +#include <openssl/bio.h> +#include <openssl/evp.h> +#include <openssl/pem.h> +#include <openssl/err.h> +#include <openssl/engine.h> +#include <openssl/cms.h> + +#include "main.h" + +static const char *key_pass; + +static int pem_pw_cb(char *buf, int len, int w, void *v) +{ + int pwlen; + + if (!key_pass) + return -1; + + pwlen = strlen(key_pass); + if (pwlen >= len) + return -1; + + strcpy(buf, key_pass); + + /* If it's wrong, don't keep trying it. */ + key_pass = NULL; + + return pwlen; +} + +static void display_openssl_errors(void) +{ + const char *file; + char buf[120]; + int e, line; + + if (!ERR_peek_error()) + return; + + while ((e = ERR_get_error_line(&file, &line))) { + ERR_error_string(e, buf); + fprintf(stderr, "- SSL %s: %s:%d\n", buf, file, line); + } +} + +static EVP_PKEY *read_private_key(const char *key_path) +{ + EVP_PKEY *private_key; + + if (!strncmp(key_path, "pkcs11:", 7)) { + ENGINE *e; + + ENGINE_load_builtin_engines(); + display_openssl_errors(); + e = ENGINE_by_id("pkcs11"); + if (!e) + return NULL; + + if (!ENGINE_init(e)) { + display_openssl_errors(); + return NULL; + } + display_openssl_errors(); + + if (key_pass) + if (!ENGINE_ctrl_cmd_string(e, "PIN", key_pass, 0)) + return NULL; + private_key = ENGINE_load_private_key(e, key_path, NULL, NULL); + } else { + BIO *b; + + b = BIO_new_file(key_path, "rb"); + if (!b) + return NULL; + private_key = PEM_read_bio_PrivateKey(b, NULL, pem_pw_cb, NULL); + BIO_free(b); + } + + return private_key; +} + +static X509 *read_x509(const char *x509_path) +{ + unsigned char buf[2]; + X509 *x509 = NULL; + BIO *b; + int n; + + b = BIO_new_file(x509_path, "rb"); + if (!b) { + display_openssl_errors(); + return NULL; + } + + /* Look at the first two bytes of the file to determine the encoding */ + n = BIO_read(b, buf, 2); + if (n != 2) { + if (BIO_should_retry(b)) + fprintf(stderr, "%s: Read wanted retry\n", x509_path); + if (n >= 0) + fprintf(stderr, "%s: Short read\n", x509_path); + display_openssl_errors(); + goto out_free; + } + + if (BIO_reset(b)) { + display_openssl_errors(); + goto out_free; + } + + if (buf[0] == 0x30 && buf[1] >= 0x81 && buf[1] <= 0x84) + /* Assume raw DER encoded X.509 */ + x509 = d2i_X509_bio(b, NULL); + else + /* Assume PEM encoded X.509 */ + x509 = PEM_read_bio_X509(b, NULL, NULL, NULL); + + if (!x509) + display_openssl_errors(); + +out_free: + BIO_free(b); + + return x509; +} + +int sign(const char *hash_algo, const char *key_path, const char *x509_path, + const char *indata, int indatalen, unsigned char **outdata) +{ + CMS_ContentInfo *cms = NULL; + const EVP_MD *digest_algo; + EVP_PKEY *private_key; + X509 *x509; + BIO *bm; + + OpenSSL_add_all_algorithms(); + ERR_load_crypto_strings(); + ERR_clear_error(); + + key_pass = getenv("KBUILD_SIGN_PIN"); + + /* Open the module file */ + bm = BIO_new_mem_buf(indata, indatalen); + if (!bm) { + display_openssl_errors(); + return -1; + } + + /* Read the private key and the X.509 cert the PKCS#7 message + * will point to. + */ + private_key = read_private_key(key_path); + if (!private_key) + goto out_free; + + x509 = read_x509(x509_path); + if (!x509) + goto out_free; + + /* Digest the module data. */ + OpenSSL_add_all_digests(); + display_openssl_errors(); + + digest_algo = EVP_get_digestbyname(hash_algo); + if (!digest_algo) { + display_openssl_errors(); + goto out_free; + } + + /* Load the signature message from the digest buffer. */ + cms = CMS_sign(NULL, NULL, NULL, NULL, CMS_NOCERTS | CMS_PARTIAL | + CMS_BINARY | CMS_DETACHED | CMS_STREAM); + if (!cms) { + display_openssl_errors(); + goto out_free; + } + + if (!CMS_add1_signer(cms, x509, private_key, digest_algo, + CMS_NOCERTS | CMS_BINARY | CMS_NOSMIMECAP | + CMS_NOATTR)) { + display_openssl_errors(); + goto out_free; + } + + if (CMS_final(cms, bm, NULL, CMS_NOCERTS | CMS_BINARY) < 0) + display_openssl_errors(); + +out_free: + BIO_free(bm); + + if (!cms) + return -1; + + return i2d_CMS_ContentInfo(cms, outdata); +} diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index c2b8857b8a1c..b9d259f26e92 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -1336,6 +1336,8 @@ union bpf_attr { }; __u32 :32; /* pad */ __aligned_u64 fd_array; /* array of FDs */ + __aligned_u64 signature; /* instruction's signature */ + __u32 sig_len; /* signature size */ }; struct { /* anonymous struct used by BPF_OBJ_* commands */ diff --git a/tools/lib/bpf/skel_internal.h b/tools/lib/bpf/skel_internal.h index 9cf66702fa8d..1ef2df16f90c 100644 --- a/tools/lib/bpf/skel_internal.h +++ b/tools/lib/bpf/skel_internal.h @@ -42,8 +42,10 @@ struct bpf_load_and_run_opts { struct bpf_loader_ctx *ctx; const void *data; const void *insns; + const void *signature; __u32 data_sz; __u32 insns_sz; + __u32 sig_sz; const char *errstr; }; @@ -84,6 +86,8 @@ static inline int bpf_load_and_run(struct bpf_load_and_run_opts *opts) attr.prog_type = BPF_PROG_TYPE_SYSCALL; attr.insns = (long) opts->insns; attr.insn_cnt = opts->insns_sz / sizeof(struct bpf_insn); + attr.signature = (long) opts->signature; + attr.sig_len = opts->sig_sz; attr.license = (long) "Dual BSD/GPL"; memcpy(attr.prog_name, "__loader.prog", sizeof("__loader.prog")); attr.fd_array = (long) &map_fd; -- 2.33.0 ^ permalink raw reply related [flat|nested] 8+ messages in thread
end of thread, other threads:[~2021-10-24 22:35 UTC | newest] Thread overview: 8+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2021-10-12 19:00 [RFC bpf-next 0/2] bpf: sign bpf programs Matteo Croce 2021-10-12 19:00 ` [RFC bpf-next 1/2] bpf: add signature to eBPF instructions Matteo Croce 2021-10-13 2:37 ` kernel test robot 2021-10-13 3:13 ` kernel test robot 2021-10-13 3:36 ` kernel test robot 2021-10-13 14:35 ` kernel test robot 2021-10-24 22:35 ` kernel test robot 2021-10-12 19:00 ` [RFC bpf-next 2/2] bpftool: add signature in skeleton Matteo Croce
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.