Received: by 2002:a05:6a10:1d13:0:0:0:0 with SMTP id pp19csp999516pxb; Wed, 1 Sep 2021 14:56:52 -0700 (PDT) X-Google-Smtp-Source: ABdhPJyV0BJuHfM9Ri77k+sdqrRBf+aEoucrIDuD4dB+ADufCDKRr2tZqnZD010TZRYB5iCoPO9t X-Received: by 2002:a17:906:7302:: with SMTP id di2mr1689032ejc.409.1630533412663; Wed, 01 Sep 2021 14:56:52 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1630533412; cv=none; d=google.com; s=arc-20160816; b=EMmFpNQt4/tDOqgLhUM6dFE46h0CSl8mnvL+CzyT9CMCCuIDO/Irhs/M2Q08LOL4fn tfFDDYBTbZcPIWnv7RsCNGiyNIo1SIIqMnsWiiTDcTlT9zOu0v/t03HYSHS1tPnxVMwf dANSptkzW8XIeM9ANmmx+bb9CFjeRPSDTwgLPy+rxQ/TY/Eg0Ux03B1DY5m5wLwu5xIM vHRVM2Qx8wVvKLj0tecbpwQAF3kAQj1yG/DiRvXdUpLFfG5UpIhy4ZAsDla5/TmrlxXn KOH18bo0AoD8VSv1BGWIT01Q3UWt2Z0qeOc+Z6C2PU7YrpHItwLAZMMxTjIHNR6GHYrQ qWQQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :user-agent:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=UFUYkopiWn9tHxjODstm0ZdsgsqdZno1F5mnW2PqqWE=; b=S5D9irfx6s2RCueVgbrmkiDpkAYfixLZpEVgUDiN0PqVQCKJq3jNDZstEB5Ii0xoe3 rLy/3nRco0hzgcTdehv2TyAPIqUJjSir8PrLYA6ei73mfp+d3t8dJj3PzOfbBXa9UBgz hCD5NyUcqxDk7+BXwyNRLiB+Jh2f93LuufhkNJMeQhcLrZgbU3Oqo7H6mtN81/izqkQe +htu+FcjtjfcrTsWwY/ZfCTRSb12zqLQhSGB3TfmwNJrT4HLtyly7Y43/6hU3D+zFfpw VyN6sXi1qd1EHsHAkNcTtCKvuRChXUu5qpvP7UmyWUTXTlyhcywKxGBtLu5iTT5anPv+ jXiA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b=T3V+lYVg; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linuxfoundation.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id d24si10348edr.143.2021.09.01.14.56.30; Wed, 01 Sep 2021 14:56:52 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b=T3V+lYVg; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linuxfoundation.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S244658AbhIAMbh (ORCPT + 99 others); Wed, 1 Sep 2021 08:31:37 -0400 Received: from mail.kernel.org ([198.145.29.99]:33218 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S244656AbhIAMbE (ORCPT ); Wed, 1 Sep 2021 08:31:04 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id A8174610CB; Wed, 1 Sep 2021 12:30:07 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=linuxfoundation.org; s=korg; t=1630499408; bh=hMp2bFsVxSew0+NXqV8vr4RxOQiDSbYc8cCqhqj/lWA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=T3V+lYVgB9yrLQPG8OoBLJb5jrbnuGmClPE3Lm3S76TfuZEOS6RUPfNK070UZiciZ Jy7fI7pQ1I32+9uI7qufrIzne4f6zj+wdwmxSea86XGsfTWeA35usOFBof5EBtMz7r pMcSs1+opUWQws/+2zylqNm8+GnrWyY9TQUuLaYk= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org, stable@vger.kernel.org Cc: Greg Kroah-Hartman , Daniel Borkmann , John Fastabend , Salvatore Bonaccorso , Thadeu Lima de Souza Cascardo Subject: [PATCH 4.19 04/33] bpf: Fix truncation handling for mod32 dst reg wrt zero Date: Wed, 1 Sep 2021 14:27:53 +0200 Message-Id: <20210901122250.916048129@linuxfoundation.org> X-Mailer: git-send-email 2.33.0 In-Reply-To: <20210901122250.752620302@linuxfoundation.org> References: <20210901122250.752620302@linuxfoundation.org> User-Agent: quilt/0.66 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Daniel Borkmann Commit 9b00f1b78809309163dda2d044d9e94a3c0248a3 upstream. Recently noticed that when mod32 with a known src reg of 0 is performed, then the dst register is 32-bit truncated in verifier: 0: R1=ctx(id=0,off=0,imm=0) R10=fp0 0: (b7) r0 = 0 1: R0_w=inv0 R1=ctx(id=0,off=0,imm=0) R10=fp0 1: (b7) r1 = -1 2: R0_w=inv0 R1_w=inv-1 R10=fp0 2: (b4) w2 = -1 3: R0_w=inv0 R1_w=inv-1 R2_w=inv4294967295 R10=fp0 3: (9c) w1 %= w0 4: R0_w=inv0 R1_w=inv(id=0,umax_value=4294967295,var_off=(0x0; 0xffffffff)) R2_w=inv4294967295 R10=fp0 4: (b7) r0 = 1 5: R0_w=inv1 R1_w=inv(id=0,umax_value=4294967295,var_off=(0x0; 0xffffffff)) R2_w=inv4294967295 R10=fp0 5: (1d) if r1 == r2 goto pc+1 R0_w=inv1 R1_w=inv(id=0,umax_value=4294967295,var_off=(0x0; 0xffffffff)) R2_w=inv4294967295 R10=fp0 6: R0_w=inv1 R1_w=inv(id=0,umax_value=4294967295,var_off=(0x0; 0xffffffff)) R2_w=inv4294967295 R10=fp0 6: (b7) r0 = 2 7: R0_w=inv2 R1_w=inv(id=0,umax_value=4294967295,var_off=(0x0; 0xffffffff)) R2_w=inv4294967295 R10=fp0 7: (95) exit 7: R0=inv1 R1=inv(id=0,umin_value=4294967295,umax_value=4294967295,var_off=(0x0; 0xffffffff)) R2=inv4294967295 R10=fp0 7: (95) exit However, as a runtime result, we get 2 instead of 1, meaning the dst register does not contain (u32)-1 in this case. The reason is fairly straight forward given the 0 test leaves the dst register as-is: # ./bpftool p d x i 23 0: (b7) r0 = 0 1: (b7) r1 = -1 2: (b4) w2 = -1 3: (16) if w0 == 0x0 goto pc+1 4: (9c) w1 %= w0 5: (b7) r0 = 1 6: (1d) if r1 == r2 goto pc+1 7: (b7) r0 = 2 8: (95) exit This was originally not an issue given the dst register was marked as completely unknown (aka 64 bit unknown). However, after 468f6eafa6c4 ("bpf: fix 32-bit ALU op verification") the verifier casts the register output to 32 bit, and hence it becomes 32 bit unknown. Note that for the case where the src register is unknown, the dst register is marked 64 bit unknown. After the fix, the register is truncated by the runtime and the test passes: # ./bpftool p d x i 23 0: (b7) r0 = 0 1: (b7) r1 = -1 2: (b4) w2 = -1 3: (16) if w0 == 0x0 goto pc+2 4: (9c) w1 %= w0 5: (05) goto pc+1 6: (bc) w1 = w1 7: (b7) r0 = 1 8: (1d) if r1 == r2 goto pc+1 9: (b7) r0 = 2 10: (95) exit Semantics also match with {R,W}x mod{64,32} 0 -> {R,W}x. Invalid div has always been {R,W}x div{64,32} 0 -> 0. Rewrites are as follows: mod32: mod64: (16) if w0 == 0x0 goto pc+2 (15) if r0 == 0x0 goto pc+1 (9c) w1 %= w0 (9f) r1 %= r0 (05) goto pc+1 (bc) w1 = w1 Fixes: 468f6eafa6c4 ("bpf: fix 32-bit ALU op verification") Signed-off-by: Daniel Borkmann Reviewed-by: John Fastabend [Salvatore Bonaccorso: This is an earlier version based on work by Daniel and John which does not rely on availability of the BPF_JMP32 instruction class. This means it is not even strictly a backport of the upstream commit mentioned but based on Daniel's and John's work to address the issue and was finalized by Thadeu Lima de Souza Cascardo.] Tested-by: Salvatore Bonaccorso Signed-off-by: Thadeu Lima de Souza Cascardo Signed-off-by: Greg Kroah-Hartman --- kernel/bpf/verifier.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -6178,7 +6178,7 @@ static int fixup_bpf_calls(struct bpf_ve bool is64 = BPF_CLASS(insn->code) == BPF_ALU64; struct bpf_insn mask_and_div[] = { BPF_MOV_REG(BPF_CLASS(insn->code), BPF_REG_AX, insn->src_reg), - /* Rx div 0 -> 0 */ + /* [R,W]x div 0 -> 0 */ BPF_JMP_IMM(BPF_JEQ, BPF_REG_AX, 0, 2), BPF_RAW_REG(*insn, insn->dst_reg, BPF_REG_AX), BPF_JMP_IMM(BPF_JA, 0, 0, 1), @@ -6186,9 +6186,10 @@ static int fixup_bpf_calls(struct bpf_ve }; struct bpf_insn mask_and_mod[] = { BPF_MOV_REG(BPF_CLASS(insn->code), BPF_REG_AX, insn->src_reg), - /* Rx mod 0 -> Rx */ - BPF_JMP_IMM(BPF_JEQ, BPF_REG_AX, 0, 1), + BPF_JMP_IMM(BPF_JEQ, BPF_REG_AX, 0, 1 + (is64 ? 0 : 1)), BPF_RAW_REG(*insn, insn->dst_reg, BPF_REG_AX), + BPF_JMP_IMM(BPF_JA, 0, 0, 1), + BPF_MOV32_REG(insn->dst_reg, insn->dst_reg), }; struct bpf_insn *patchlet; @@ -6198,7 +6199,7 @@ static int fixup_bpf_calls(struct bpf_ve cnt = ARRAY_SIZE(mask_and_div); } else { patchlet = mask_and_mod; - cnt = ARRAY_SIZE(mask_and_mod); + cnt = ARRAY_SIZE(mask_and_mod) - (is64 ? 2 : 0); } new_prog = bpf_patch_insn_data(env, i + delta, patchlet, cnt);