Received: by 2002:a05:7412:d8a:b0:e2:908c:2ebd with SMTP id b10csp618132rdg; Tue, 10 Oct 2023 23:46:56 -0700 (PDT) X-Google-Smtp-Source: AGHT+IGUrixKmipkbR/w/qt9VJTWZJ399oYctI4hYrz4OvgzV2GzxMrzjpjGSkGFO1EFhCbx3gnG X-Received: by 2002:a05:6808:1919:b0:3ae:5442:ed1b with SMTP id bf25-20020a056808191900b003ae5442ed1bmr30178000oib.43.1697006815851; Tue, 10 Oct 2023 23:46:55 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1697006815; cv=none; d=google.com; s=arc-20160816; b=MvhJrp4dbskSSYX2UuQUYSSpSelD1mGYr3n7LkvELv6nXjJXmDeG8RWQBeJvYN9SVj aDZvr2hoJJsdV1JiMh8NuvQjZ0nJoS6UyzPGvUtP7Sy5dzFuipugYNp4+gaQr2FI9Gv1 vLnPUn3qE9Fj8iFZ3OrekYD10aWkkj29FJA6tRCjWBZH+UDgs1D7aqCxB5/BMgfpP7eT enha2mDWL8W+t69mPYn5sIQ18i9A85JHag/YXcKO8zC1dsLYSo23+DjGr+IZ1sdM8shl Zl3sFFKdJHOM1Cxq2gWa45ZTUarAMX0MZpyj30zfcKKahrkaiIoSZXSYBz3QM3C3MVAa EOKg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:cc:to:subject :message-id:date:from:in-reply-to:references:mime-version :dkim-signature; bh=ZYYIViihW/2ykLsxlNp0GKeIrzDIn8ZJ1ct4n1urTnA=; fh=aNPsZ2g0LtKBD1JbEg90EbG70fTqgqOTEIX0fHGYC0k=; b=UMHN/7Ppy/GJsQOtkKHgaY98iIYwEgUfyZxGpLSsukovvw/JYno1OlinqxZ8DDudHe fs+9ABApQGCRdPY82Elx5GsIZNOgazvLyvVrn4Otil0enGRG4eEr6D9w7SVlxNurD4Ix bCxEVZAr5Oyj2xxR/w2jLunOJ5cSaTb/1RaQC/PNmIZ8efdTaRemwe1LX+8MNsl4Lv4x vh6KZB24ZPsyFq0eCBbffYdcVhvd9SVF5dSRhdO7lrJ3RMeUQncqyJzgc8DUyXdwF84Q rFgaU6J6D5lo0oflJCVf+DTwFTG9bk+D8kBhDCMT8C2VZNp7Slauo43LMO4hx2bloS8A rtIQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b=Ub0qmiYD; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::3:7 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Return-Path: Received: from snail.vger.email (snail.vger.email. [2620:137:e000::3:7]) by mx.google.com with ESMTPS id 19-20020a631753000000b0055785a37147si13060239pgx.590.2023.10.10.23.46.55 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 10 Oct 2023 23:46:55 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::3:7 as permitted sender) client-ip=2620:137:e000::3:7; Authentication-Results: mx.google.com; dkim=pass header.i=@gmail.com header.s=20230601 header.b=Ub0qmiYD; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::3:7 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from out1.vger.email (depot.vger.email [IPv6:2620:137:e000::3:0]) by snail.vger.email (Postfix) with ESMTP id C0D5981A334D; Tue, 10 Oct 2023 23:46:54 -0700 (PDT) X-Virus-Status: Clean X-Virus-Scanned: clamav-milter 0.103.10 at snail.vger.email Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1345406AbjJKGqw (ORCPT + 99 others); Wed, 11 Oct 2023 02:46:52 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59624 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1344451AbjJKGqv (ORCPT ); Wed, 11 Oct 2023 02:46:51 -0400 Received: from mail-yw1-x1134.google.com (mail-yw1-x1134.google.com [IPv6:2607:f8b0:4864:20::1134]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 6A67D9E; Tue, 10 Oct 2023 23:46:49 -0700 (PDT) Received: by mail-yw1-x1134.google.com with SMTP id 00721157ae682-5a505762c9dso79429017b3.2; Tue, 10 Oct 2023 23:46:49 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1697006808; x=1697611608; darn=vger.kernel.org; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:from:to:cc:subject:date :message-id:reply-to; bh=ZYYIViihW/2ykLsxlNp0GKeIrzDIn8ZJ1ct4n1urTnA=; b=Ub0qmiYDUARgQVAoNnZCnCu8/mWR3fkmcJYiOwjX+AceA5geHUHL+XlopnYykbbXb3 aIK7+WQHa/7OF4VXaupoo2KIcYg+cwP3fm1DxMMJf+UTgBXl5O9CSJGbCtDU8+W40beA bpEbC0ykJweFzVOBxb2qlaBR4tjexkaCT517rS+xwqPvvo9wKBXGarHb/0uM/M4ttZT1 pIesjoXeg/BrjofpnZ0nkoFJQz8FRVIjeq18b4RE+kKvRwNHwi415owgODixmTMmpx1L YY3alBKYJvX1jThLV5Cs2WsVwnUtDv9exa1D9+lRDfp6S3qy9NfXr1YPZ3vgG7Or3Z3w FaAw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1697006808; x=1697611608; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=ZYYIViihW/2ykLsxlNp0GKeIrzDIn8ZJ1ct4n1urTnA=; b=fSbA5R1lk04LSsm7ZfAY/ofVNOm8KRAwA1AX2GkTMX9bbo7dCCoFYT3sM98HCK9b5k OAlP6uV9W6OOWf7+2tXdGaD+j2cuXk+5ProHgu7WppzW4htfam4O90YMjrMiPnrFEldD 6iGfkf9wehk+wpShcJiIP5Oc+OYHAe9PeTsCxwO3W6AZDyVyXGmNE9Gkne0X4i4HG1l+ 5bxnxGg+9cSU4DK4oyGW1HelkDM4b+vWbPltRJLWo7UnQ2U5THnJ8lzUd8ZVQPRpBJrI rMwudiZAsqxw1rJu+zewHY/ErdlkS2NzQrLRxodDMTqBEdZ2O1HZzaSmVDuO/q5sUqWa fi6g== X-Gm-Message-State: AOJu0YwjpvIjGiKKDIJKdrFT7OoPCZnibo0tmyomEoaF6X4tznJt1H9B EV1TO4zNjDomOjttoXCzVVEMuw+uTPe42HsThQ== X-Received: by 2002:a25:ae85:0:b0:d9a:4362:67ac with SMTP id b5-20020a25ae85000000b00d9a436267acmr5278982ybj.15.1697006808431; Tue, 10 Oct 2023 23:46:48 -0700 (PDT) MIME-Version: 1.0 References: <20231009-jmp-into-reserved-fields-v1-1-d8006e2ac1f6@gmail.com> <6524f6f77b896_66abc2084d@john.notmuch> <92f824ec-9538-501c-e63e-8483ffe14bad@iogearbox.net> In-Reply-To: From: Hao Sun Date: Wed, 11 Oct 2023 08:46:37 +0200 Message-ID: Subject: Re: [PATCH bpf-next] Detect jumping to reserved code during check_cfg() To: Andrii Nakryiko Cc: Daniel Borkmann , John Fastabend , Alexei Starovoitov , Andrii Nakryiko , Martin KaFai Lau , Song Liu , Yonghong Song , KP Singh , Stanislav Fomichev , Hao Luo , Jiri Olsa , bpf@vger.kernel.org, linux-kernel@vger.kernel.org Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,FREEMAIL_FROM, RCVD_IN_DNSWL_BLOCKED,SPF_HELO_NONE,SPF_PASS autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-Greylist: Sender passed SPF test, not delayed by milter-greylist-4.6.4 (snail.vger.email [0.0.0.0]); Tue, 10 Oct 2023 23:46:54 -0700 (PDT) On Wed, Oct 11, 2023 at 4:42=E2=80=AFAM Andrii Nakryiko wrote: > > On Tue, Oct 10, 2023 at 1:33=E2=80=AFAM Daniel Borkmann wrote: > > > > On 10/10/23 9:02 AM, John Fastabend wrote: > > > Hao Sun wrote: > > >> Currently, we don't check if the branch-taken of a jump is reserved = code of > > >> ld_imm64. Instead, such a issue is captured in check_ld_imm(). The v= erifier > > >> gives the following log in such case: > > >> > > >> func#0 @0 > > >> 0: R1=3Dctx(off=3D0,imm=3D0) R10=3Dfp0 > > >> 0: (18) r4 =3D 0xffff888103436000 ; R4_w=3Dmap_ptr(off=3D0,ks= =3D4,vs=3D128,imm=3D0) > > >> 2: (18) r1 =3D 0x1d ; R1_w=3D29 > > >> 4: (55) if r4 !=3D 0x0 goto pc+4 ; R4_w=3Dmap_ptr(off=3D0,ks= =3D4,vs=3D128,imm=3D0) > > >> 5: (1c) w1 -=3D w1 ; R1_w=3D0 > > >> 6: (18) r5 =3D 0x32 ; R5_w=3D50 > > >> 8: (56) if w5 !=3D 0xfffffff4 goto pc-2 > > >> mark_precise: frame0: last_idx 8 first_idx 0 subseq_idx -1 > > >> mark_precise: frame0: regs=3Dr5 stack=3D before 6: (18) r5 =3D 0x32 > > >> 7: R5_w=3D50 > > >> 7: BUG_ld_00 > > >> invalid BPF_LD_IMM insn > > >> > > >> Here the verifier rejects the program because it thinks insn at 7 is= an > > >> invalid BPF_LD_IMM, but such a error log is not accurate since the i= ssue > > >> is jumping to reserved code not because the program contains invalid= insn. > > >> Therefore, make the verifier check the jump target during check_cfg(= ). For > > >> the same program, the verifier reports the following log: > > > > > > I think we at least would want a test case for this. Also how did you= create > > > this case? Is it just something you did manually and noticed a strang= e error? > > > > Curious as well. > > > > We do have test cases which try to jump into the middle of a double ins= n as can > > be seen that this patch breaks BPF CI with regards to log mismatch belo= w (which > > still needs to be adapted, too). Either way, it probably doesn't hurt t= o also add > > the above snippet as a test. > > > > Hao, as I understand, the patch here is an usability improvement (not a= fix per se) > > where we reject such cases earlier during cfg check rather than at a la= ter point > > where we validate ld_imm instruction. Or are there cases you found whic= h were not > > yet captured via current check_ld_imm()? > > > > test_verifier failure log : > > > > #458/u test1 ld_imm64 FAIL > > Unexpected verifier log! > > EXP: R1 pointer comparison > > RES: > > FAIL > > Unexpected error message! > > EXP: R1 pointer comparison > > RES: jump to reserved code from insn 0 to 2 > > verification time 22 usec > > stack depth 0 > > processed 0 insns (limit 1000000) max_states_per_insn 0 total_states= 0 peak_states 0 mark_read 0 > > > > jump to reserved code from insn 0 to 2 > > verification time 22 usec > > stack depth 0 > > processed 0 insns (limit 1000000) max_states_per_insn 0 total_states= 0 peak_states 0 mark_read 0 > > #458/p test1 ld_imm64 FAIL > > Unexpected verifier log! > > EXP: invalid BPF_LD_IMM insn > > RES: > > FAIL > > Unexpected error message! > > EXP: invalid BPF_LD_IMM insn > > RES: jump to reserved code from insn 0 to 2 > > verification time 9 usec > > stack depth 0 > > processed 0 insns (limit 1000000) max_states_per_insn 0 total_states= 0 peak_states 0 mark_read 0 > > > > jump to reserved code from insn 0 to 2 > > verification time 9 usec > > stack depth 0 > > processed 0 insns (limit 1000000) max_states_per_insn 0 total_states= 0 peak_states 0 mark_read 0 > > #459/u test2 ld_imm64 FAIL > > Unexpected verifier log! > > EXP: R1 pointer comparison > > RES: > > FAIL > > Unexpected error message! > > EXP: R1 pointer comparison > > RES: jump to reserved code from insn 0 to 2 > > verification time 11 usec > > stack depth 0 > > processed 0 insns (limit 1000000) max_states_per_insn 0 total_states= 0 peak_states 0 mark_read 0 > > > > jump to reserved code from insn 0 to 2 > > verification time 11 usec > > stack depth 0 > > processed 0 insns (limit 1000000) max_states_per_insn 0 total_states= 0 peak_states 0 mark_read 0 > > #459/p test2 ld_imm64 FAIL > > Unexpected verifier log! > > EXP: invalid BPF_LD_IMM insn > > RES: > > FAIL > > Unexpected error message! > > EXP: invalid BPF_LD_IMM insn > > RES: jump to reserved code from insn 0 to 2 > > verification time 8 usec > > stack depth 0 > > processed 0 insns (limit 1000000) max_states_per_insn 0 total_states= 0 peak_states 0 mark_read 0 > > > > jump to reserved code from insn 0 to 2 > > verification time 8 usec > > stack depth 0 > > processed 0 insns (limit 1000000) max_states_per_insn 0 total_states= 0 peak_states 0 mark_read 0 > > #460/u test3 ld_imm64 OK > > > > >> func#0 @0 > > >> jump to reserved code from insn 8 to 7 > > >> > > >> --- > > >> > > >> > > >> Signed-off-by: Hao Sun > > > > nit: This needs to be before the "---" line. > > > > >> --- > > >> kernel/bpf/verifier.c | 7 +++++++ > > >> 1 file changed, 7 insertions(+) > > >> > > >> diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c > > >> index eed7350e15f4..725ac0b464cf 100644 > > >> --- a/kernel/bpf/verifier.c > > >> +++ b/kernel/bpf/verifier.c > > >> @@ -14980,6 +14980,7 @@ static int push_insn(int t, int w, int e, st= ruct bpf_verifier_env *env, > > >> { > > >> int *insn_stack =3D env->cfg.insn_stack; > > >> int *insn_state =3D env->cfg.insn_state; > > >> + struct bpf_insn *insns =3D env->prog->insnsi; > > >> > > >> if (e =3D=3D FALLTHROUGH && insn_state[t] >=3D (DISCOVERED | FA= LLTHROUGH)) > > >> return DONE_EXPLORING; > > >> @@ -14993,6 +14994,12 @@ static int push_insn(int t, int w, int e, s= truct bpf_verifier_env *env, > > >> return -EINVAL; > > >> } > > >> > > >> + if (e =3D=3D BRANCH && insns[w].code =3D=3D 0) { > > >> + verbose_linfo(env, t, "%d", t); > > >> + verbose(env, "jump to reserved code from insn %d to %d\= n", t, w); > > >> + return -EINVAL; > > >> + } > > > > Other than that, lgtm. > > We do rely quite a lot on verifier not complaining eagerly about some > potentially invalid instructions if it's provable that some portion of > the code won't ever be reached (think using .rodata variables for > feature gating, poisoning intructions due to failed CO-RE relocation, > which libbpf does actively, except it's using a call to non-existing > helper). As such, check_cfg() is a wrong place to do such validity > checks because some of the branches might never be run and validated > in practice. > Don't really agree. Jump to the middle of ld_imm64 is just like jumping out of bounds, both break the CFG integrity immediately. For those apparently incorrect jumps, rejecting early makes everything simple; otherwise, we probably need some rewrite in the end. Also, as you mentioned, libbpf relies on non-existing helpers, not jump to the middle of ld_imm64. It seems better and easier to not leave this hole. > This seems like a pretty obscure case of fuzzer generated test with > random jumps into the middle of ldimm64 instruction. I think the tool > should be able to avoid this or handle verifier log just fine in such > situations. On the other hand, valid code generated by compilers will > never have such jumps. > > So perhaps we can improve existing "invalid BPF_LD_IMM insn" message, > but let's not teach check_cfg() more checks than necessary? > Improving that `invalid BPF_LD_IMM` log does not solve the problem, the issue here is an invalid jump. Also, there could be various causes that mak= e the verifier see an invalid BPF_LD_IMM in check_ld_imm(). > > > > >> if (e =3D=3D BRANCH) { > > >> /* mark branch target for state pruning */ > > >> mark_prune_point(env, w); > > >> > >