* [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; 10+ 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] 10+ 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; 10+ 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] 10+ 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; 10+ 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] 10+ 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; 10+ 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] 10+ 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; 10+ 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] 10+ 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; 10+ 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] 10+ 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; 10+ 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] 10+ 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; 10+ 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] 10+ messages in thread
* [RFC bpf-next 1/2] bpf: add signature to eBPF instructions @ 2021-10-12 18:58 Matteo Croce 2021-10-12 19:02 ` Matteo Croce 0 siblings, 1 reply; 10+ messages in thread From: Matteo Croce @ 2021-10-12 18:58 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] 10+ messages in thread
* Re: [RFC bpf-next 1/2] bpf: add signature to eBPF instructions 2021-10-12 18:58 [RFC bpf-next 1/2] bpf: add signature to eBPF instructions Matteo Croce @ 2021-10-12 19:02 ` Matteo Croce 0 siblings, 0 replies; 10+ messages in thread From: Matteo Croce @ 2021-10-12 19:02 UTC (permalink / raw) To: bpf Cc: Linux Kernel Mailing List, Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko, Arnaldo Carvalho de Melo, Luca Boccassi, David S. Miller On Tue, Oct 12, 2021 at 8:59 PM Matteo Croce <mcroce@linux.microsoft.com> wrote: > > 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> > --- Slipped out by mistake, duplicate of: https://lore.kernel.org/bpf/20211012190028.54828-2-mcroce@linux.microsoft.com/T/#u Sorry, -- per aspera ad upstream ^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2021-10-24 22:35 UTC | newest] Thread overview: 10+ 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 -- strict thread matches above, loose matches on Subject: below -- 2021-10-12 18:58 [RFC bpf-next 1/2] bpf: add signature to eBPF instructions Matteo Croce 2021-10-12 19:02 ` 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.