Message ID | 20211203191844.69709-2-mcroce@linux.microsoft.com (mailing list archive) |
---|---|
State | Changes Requested |
Delegated to: | BPF |
Headers | show |
Series | bpf: add signature | expand |
Hi Matteo, Thank you for the patch! Perhaps something to improve: [auto build test WARNING on bpf-next/master] url: https://github.com/0day-ci/linux/commits/Matteo-Croce/bpf-add-signature/20211204-032018 base: https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next.git master config: nds32-allyesconfig (https://download.01.org/0day-ci/archive/20211204/202112040507.siNkODlN-lkp@intel.com/config) compiler: nds32le-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/fdfe32b9e64c6a208965002215d467ec383b6f57 git remote add linux-review https://github.com/0day-ci/linux git fetch --no-tags linux-review Matteo-Croce/bpf-add-signature/20211204-032018 git checkout fdfe32b9e64c6a208965002215d467ec383b6f57 # save the config file to linux build tree mkdir build_dir COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-11.2.0 make.cross O=build_dir ARCH=nds32 SHELL=/bin/bash kernel/bpf/ If you fix the issue, kindly add following tag as appropriate Reported-by: kernel test robot <lkp@intel.com> All warnings (new ones prefixed by >>): kernel/bpf/syscall.c: In function 'bpf_prog_load': >> kernel/bpf/syscall.c:2324:47: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast] 2324 | if (copy_from_user(signature, (char *)attr->signature, attr->sig_len)) { | ^ vim +2324 kernel/bpf/syscall.c 2192 2193 static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr) 2194 { 2195 enum bpf_prog_type type = attr->prog_type; 2196 struct bpf_prog *prog, *dst_prog = NULL; 2197 struct btf *attach_btf = NULL; 2198 int err; 2199 char license[128]; 2200 bool is_gpl; 2201 2202 if (CHECK_ATTR(BPF_PROG_LOAD)) 2203 return -EINVAL; 2204 2205 if (attr->prog_flags & ~(BPF_F_STRICT_ALIGNMENT | 2206 BPF_F_ANY_ALIGNMENT | 2207 BPF_F_TEST_STATE_FREQ | 2208 BPF_F_SLEEPABLE | 2209 BPF_F_TEST_RND_HI32)) 2210 return -EINVAL; 2211 2212 if (!IS_ENABLED(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && 2213 (attr->prog_flags & BPF_F_ANY_ALIGNMENT) && 2214 !bpf_capable()) 2215 return -EPERM; 2216 2217 /* copy eBPF program license from user space */ 2218 if (strncpy_from_bpfptr(license, 2219 make_bpfptr(attr->license, uattr.is_kernel), 2220 sizeof(license) - 1) < 0) 2221 return -EFAULT; 2222 license[sizeof(license) - 1] = 0; 2223 2224 /* eBPF programs must be GPL compatible to use GPL-ed functions */ 2225 is_gpl = license_is_gpl_compatible(license); 2226 2227 if (attr->insn_cnt == 0 || 2228 attr->insn_cnt > (bpf_capable() ? BPF_COMPLEXITY_LIMIT_INSNS : BPF_MAXINSNS)) 2229 return -E2BIG; 2230 if (type != BPF_PROG_TYPE_SOCKET_FILTER && 2231 type != BPF_PROG_TYPE_CGROUP_SKB && 2232 !bpf_capable()) 2233 return -EPERM; 2234 2235 if (is_net_admin_prog_type(type) && !capable(CAP_NET_ADMIN) && !capable(CAP_SYS_ADMIN)) 2236 return -EPERM; 2237 if (is_perfmon_prog_type(type) && !perfmon_capable()) 2238 return -EPERM; 2239 2240 /* attach_prog_fd/attach_btf_obj_fd can specify fd of either bpf_prog 2241 * or btf, we need to check which one it is 2242 */ 2243 if (attr->attach_prog_fd) { 2244 dst_prog = bpf_prog_get(attr->attach_prog_fd); 2245 if (IS_ERR(dst_prog)) { 2246 dst_prog = NULL; 2247 attach_btf = btf_get_by_fd(attr->attach_btf_obj_fd); 2248 if (IS_ERR(attach_btf)) 2249 return -EINVAL; 2250 if (!btf_is_kernel(attach_btf)) { 2251 /* attaching through specifying bpf_prog's BTF 2252 * objects directly might be supported eventually 2253 */ 2254 btf_put(attach_btf); 2255 return -ENOTSUPP; 2256 } 2257 } 2258 } else if (attr->attach_btf_id) { 2259 /* fall back to vmlinux BTF, if BTF type ID is specified */ 2260 attach_btf = bpf_get_btf_vmlinux(); 2261 if (IS_ERR(attach_btf)) 2262 return PTR_ERR(attach_btf); 2263 if (!attach_btf) 2264 return -EINVAL; 2265 btf_get(attach_btf); 2266 } 2267 2268 bpf_prog_load_fixup_attach_type(attr); 2269 if (bpf_prog_load_check_attach(type, attr->expected_attach_type, 2270 attach_btf, attr->attach_btf_id, 2271 dst_prog)) { 2272 if (dst_prog) 2273 bpf_prog_put(dst_prog); 2274 if (attach_btf) 2275 btf_put(attach_btf); 2276 return -EINVAL; 2277 } 2278 2279 /* plain bpf_prog allocation */ 2280 prog = bpf_prog_alloc(bpf_prog_size(attr->insn_cnt), GFP_USER); 2281 if (!prog) { 2282 if (dst_prog) 2283 bpf_prog_put(dst_prog); 2284 if (attach_btf) 2285 btf_put(attach_btf); 2286 return -ENOMEM; 2287 } 2288 2289 prog->expected_attach_type = attr->expected_attach_type; 2290 prog->aux->attach_btf = attach_btf; 2291 prog->aux->attach_btf_id = attr->attach_btf_id; 2292 prog->aux->dst_prog = dst_prog; 2293 prog->aux->offload_requested = !!attr->prog_ifindex; 2294 prog->aux->sleepable = attr->prog_flags & BPF_F_SLEEPABLE; 2295 2296 err = security_bpf_prog_alloc(prog->aux); 2297 if (err) 2298 goto free_prog; 2299 2300 prog->aux->user = get_current_user(); 2301 prog->len = attr->insn_cnt; 2302 2303 err = -EFAULT; 2304 if (copy_from_bpfptr(prog->insns, 2305 make_bpfptr(attr->insns, uattr.is_kernel), 2306 bpf_prog_insn_size(prog)) != 0) 2307 goto free_prog_sec; 2308 2309 err = bpf_obj_name_cpy(prog->aux->name, attr->prog_name, 2310 sizeof(attr->prog_name)); 2311 if (err < 0) 2312 goto free_prog_sec; 2313 2314 #ifdef CONFIG_BPF_SIG 2315 if (attr->sig_len) { 2316 char *signature; 2317 2318 signature = kmalloc(attr->sig_len, GFP_USER); 2319 if (!signature) { 2320 err = -ENOMEM; 2321 goto free_prog_sec; 2322 } 2323 > 2324 if (copy_from_user(signature, (char *)attr->signature, attr->sig_len)) { 2325 err = -EFAULT; 2326 kfree(signature); 2327 goto free_prog_sec; 2328 } 2329 2330 err = verify_pkcs7_signature(prog->insns, 2331 prog->len * sizeof(struct bpf_insn), 2332 signature, attr->sig_len, 2333 VERIFY_USE_SECONDARY_KEYRING, 2334 VERIFYING_BPF_SIGNATURE, 2335 NULL, NULL); 2336 kfree(signature); 2337 2338 if (err) { 2339 pr_warn("Invalid BPF signature for '%s': %pe\n", 2340 prog->aux->name, ERR_PTR(err)); 2341 goto free_prog_sec; 2342 } 2343 } 2344 #endif 2345 2346 prog->orig_prog = NULL; 2347 prog->jited = 0; 2348 2349 atomic64_set(&prog->aux->refcnt, 1); 2350 prog->gpl_compatible = is_gpl ? 1 : 0; 2351 2352 if (bpf_prog_is_dev_bound(prog->aux)) { 2353 err = bpf_prog_offload_init(prog, attr); 2354 if (err) 2355 goto free_prog_sec; 2356 } 2357 2358 /* find program type: socket_filter vs tracing_filter */ 2359 err = find_prog_type(type, prog); 2360 if (err < 0) 2361 goto free_prog_sec; 2362 2363 prog->aux->load_time = ktime_get_boottime_ns(); 2364 2365 /* run eBPF verifier */ 2366 err = bpf_check(&prog, attr, uattr); 2367 if (err < 0) 2368 goto free_used_maps; 2369 2370 prog = bpf_prog_select_runtime(prog, &err); 2371 if (err < 0) 2372 goto free_used_maps; 2373 2374 err = bpf_prog_alloc_id(prog); 2375 if (err) 2376 goto free_used_maps; 2377 2378 /* Upon success of bpf_prog_alloc_id(), the BPF prog is 2379 * effectively publicly exposed. However, retrieving via 2380 * bpf_prog_get_fd_by_id() will take another reference, 2381 * therefore it cannot be gone underneath us. 2382 * 2383 * Only for the time /after/ successful bpf_prog_new_fd() 2384 * and before returning to userspace, we might just hold 2385 * one reference and any parallel close on that fd could 2386 * rip everything out. Hence, below notifications must 2387 * happen before bpf_prog_new_fd(). 2388 * 2389 * Also, any failure handling from this point onwards must 2390 * be using bpf_prog_put() given the program is exposed. 2391 */ 2392 bpf_prog_kallsyms_add(prog); 2393 perf_event_bpf_event(prog, PERF_BPF_EVENT_PROG_LOAD, 0); 2394 bpf_audit_prog(prog, BPF_AUDIT_LOAD); 2395 2396 err = bpf_prog_new_fd(prog); 2397 if (err < 0) 2398 bpf_prog_put(prog); 2399 return err; 2400 2401 free_used_maps: 2402 /* In case we have subprogs, we need to wait for a grace 2403 * period before we can tear down JIT memory since symbols 2404 * are already exposed under kallsyms. 2405 */ 2406 __bpf_prog_put_noref(prog, prog->aux->func_cnt); 2407 return err; 2408 free_prog_sec: 2409 free_uid(prog->aux->user); 2410 security_bpf_prog_free(prog->aux); 2411 free_prog: 2412 if (prog->aux->attach_btf) 2413 btf_put(prog->aux->attach_btf); 2414 bpf_prog_free(prog); 2415 return err; 2416 } 2417 --- 0-DAY CI Kernel Test Service, Intel Corporation https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
diff --git a/crypto/asymmetric_keys/asymmetric_type.c b/crypto/asymmetric_keys/asymmetric_type.c index ad8af3d70ac0..e4f2fee19c5f 100644 --- a/crypto/asymmetric_keys/asymmetric_type.c +++ b/crypto/asymmetric_keys/asymmetric_type.c @@ -26,6 +26,7 @@ const char *const key_being_used_for[NR__KEY_BEING_USED_FOR] = { [VERIFYING_KEY_SIGNATURE] = "key sig", [VERIFYING_KEY_SELF_SIGNATURE] = "key self sig", [VERIFYING_UNSPECIFIED_SIGNATURE] = "unspec sig", + [VERIFYING_BPF_SIGNATURE] = "bpf sig", }; EXPORT_SYMBOL_GPL(key_being_used_for); diff --git a/crypto/asymmetric_keys/pkcs7_verify.c b/crypto/asymmetric_keys/pkcs7_verify.c index 0b4d07aa8811..ab645f23c021 100644 --- a/crypto/asymmetric_keys/pkcs7_verify.c +++ b/crypto/asymmetric_keys/pkcs7_verify.c @@ -411,12 +411,15 @@ int pkcs7_verify(struct pkcs7_message *pkcs7, switch (usage) { case VERIFYING_MODULE_SIGNATURE: + case VERIFYING_BPF_SIGNATURE: if (pkcs7->data_type != OID_data) { - pr_warn("Invalid module sig (not pkcs7-data)\n"); + pr_warn("Invalid %s (not pkcs7-data)\n", + key_being_used_for[usage]); return -EKEYREJECTED; } if (pkcs7->have_authattrs) { - pr_warn("Invalid module sig (has authattrs)\n"); + pr_warn("Invalid %s (has authattrs)\n", + key_being_used_for[usage]); return -EKEYREJECTED; } break; diff --git a/include/linux/verification.h b/include/linux/verification.h index a655923335ae..71482644eea0 100644 --- a/include/linux/verification.h +++ b/include/linux/verification.h @@ -27,6 +27,7 @@ enum key_being_used_for { VERIFYING_KEY_SIGNATURE, VERIFYING_KEY_SELF_SIGNATURE, VERIFYING_UNSPECIFIED_SIGNATURE, + VERIFYING_BPF_SIGNATURE, NR__KEY_BEING_USED_FOR }; extern const char *const key_being_used_for[NR__KEY_BEING_USED_FOR]; diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index c26871263f1f..bbb4435c7586 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -1346,6 +1346,8 @@ union bpf_attr { __aligned_u64 fd_array; /* array of FDs */ __aligned_u64 core_relos; __u32 core_relo_rec_size; /* sizeof(struct bpf_core_relo) */ + __aligned_u64 signature; /* instruction's signature */ + __u32 sig_len; /* signature size */ }; struct { /* anonymous struct used by BPF_OBJ_* commands */ diff --git a/kernel/bpf/Kconfig b/kernel/bpf/Kconfig index d24d518ddd63..735979bb8672 100644 --- a/kernel/bpf/Kconfig +++ b/kernel/bpf/Kconfig @@ -79,6 +79,14 @@ config BPF_UNPRIV_DEFAULT_OFF If you are unsure how to answer this question, answer Y. +config BPF_SIG + bool "BPF signature verification" + select SYSTEM_DATA_VERIFICATION + depends on BPF_SYSCALL + help + Check BPF programs for valid signatures upon load: the signature + is passed via the bpf() syscall together with the instructions. + source "kernel/bpf/preload/Kconfig" config BPF_LSM diff --git a/kernel/bpf/syscall.c b/kernel/bpf/syscall.c index b3ada4085f85..5aaa74a72b46 100644 --- a/kernel/bpf/syscall.c +++ b/kernel/bpf/syscall.c @@ -32,6 +32,10 @@ #include <linux/rcupdate_trace.h> #include <linux/memcontrol.h> +#ifdef CONFIG_BPF_SIG +#include <linux/verification.h> +#endif + #define IS_FD_ARRAY(map) ((map)->map_type == BPF_MAP_TYPE_PERF_EVENT_ARRAY || \ (map)->map_type == BPF_MAP_TYPE_CGROUP_ARRAY || \ (map)->map_type == BPF_MAP_TYPE_ARRAY_OF_MAPS) @@ -2184,7 +2188,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 core_relo_rec_size +#define BPF_PROG_LOAD_LAST_FIELD sig_len static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr) { @@ -2302,6 +2306,43 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr) bpf_prog_insn_size(prog)) != 0) goto free_prog_sec; + err = bpf_obj_name_cpy(prog->aux->name, attr->prog_name, + sizeof(attr->prog_name)); + if (err < 0) + goto free_prog_sec; + +#ifdef CONFIG_BPF_SIG + 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_BPF_SIGNATURE, + NULL, NULL); + kfree(signature); + + if (err) { + pr_warn("Invalid BPF signature for '%s': %pe\n", + prog->aux->name, ERR_PTR(err)); + goto free_prog_sec; + } + } +#endif + prog->orig_prog = NULL; prog->jited = 0; @@ -2320,10 +2361,6 @@ static int bpf_prog_load(union bpf_attr *attr, bpfptr_t uattr) goto free_prog_sec; prog->aux->load_time = ktime_get_boottime_ns(); - err = bpf_obj_name_cpy(prog->aux->name, attr->prog_name, - sizeof(attr->prog_name)); - if (err < 0) - goto free_prog_sec; /* run eBPF verifier */ err = bpf_check(&prog, attr, uattr);