Received: by 2002:a05:6a10:206:0:0:0:0 with SMTP id 6csp2622022pxj; Mon, 31 May 2021 06:46:49 -0700 (PDT) X-Google-Smtp-Source: ABdhPJyDUPsJfH3M1/btjZa+GPvyFEmFr1A+Fm+6WD5bOqCPBUV9FV37/UIwLpfTcQz8Wb0n9/qX X-Received: by 2002:a17:906:9258:: with SMTP id c24mr23065645ejx.101.1622468809632; Mon, 31 May 2021 06:46:49 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1622468809; cv=none; d=google.com; s=arc-20160816; b=mhhtyYHovEjHuh3NA7mQkcUVSe2mYlea26MpwNAAYCS2fpxdmMWfgmbiBMhQkm45A9 Sk6/t3NR4f1unb5ZKsdw+s+jjRAQDI0KQYrpaCNpQLRUrAxivS2pBXqqHpqdDpyuOjy9 etgohvgxECypnNs6oAqDxJUAG1JEt304ftlLPLL+Xf6WiFy9ef77bQDL3+BTs/eIjXFP p7s8J2nmXG1K5yEYqKbYaUj0QvaqWIvjROXtaC8hWg7MrF1kTAkvjkUJW6DVsVue20u0 nZddsBJNXCmkUkPSR1tX7tPyCtAWlLcAPsiUVcXCVwuh+g1gkfXcJi6gumez9ORrlpFN skoA== 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=MduJU0IH5Cz463z7BSNjmgsT5nonH1rdiUSVyQfV53s=; b=k4Q26ti3QK5kH392wNERWq9ULOdtAtryYzUU+tnA7FRq2pVYsSFaPbcdK4nzafqXFu VAYn+jhb+eizX3DmnVqHh1Vyy4qetDF4gsvv0q/tFBzJDXST/dJ8Uyqsr412jautSf1h jSv5mlO6achB9ezg4L2JmhIq13CZKPhK/1jUgjd21lJxTR7NE2lFOOm7/f8a9JrtoQpY +2gVm8JNDxgVK+Je0oAPr7RgAh6rKl/xhCU3+yD/2H0trwM+NpX1bKgicMOUX0ZiRvh0 x711saZ0d26BuKjYTZeubkL8e1xJJ/OE0XYnfYWczzsNvVs2dmSVJOFu7w04j39XwZIO BD9A== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linuxfoundation.org header.s=korg header.b="Z7wua/MH"; 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 n6si12279560edd.104.2021.05.31.06.46.26; Mon, 31 May 2021 06:46:49 -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="Z7wua/MH"; 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 S230510AbhEaNpg (ORCPT + 99 others); Mon, 31 May 2021 09:45:36 -0400 Received: from mail.kernel.org ([198.145.29.99]:39104 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232301AbhEaNbX (ORCPT ); Mon, 31 May 2021 09:31:23 -0400 Received: by mail.kernel.org (Postfix) with ESMTPSA id ADBDC61430; Mon, 31 May 2021 13:23:30 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=linuxfoundation.org; s=korg; t=1622467411; bh=aCkS3kVEBfSTHqZJ9K6/scoX19fi29Jt/I52jQVF82I=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=Z7wua/MHryDgguSq7ZYoPTaKXT4BimlYNH2pXG7srtxS1RVFBpVAqozw11dQAIwGe XZkuYKTJeD5BQ0PEDxDycUY+nvCtCHOL7bIKfKlC+/98CSji/ERg4vzSddaloEwSiK P709I7B68ky5MXeu8DuAbdG10wb6338JX8ekUJRU= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org, stable@vger.kernel.org Cc: Greg Kroah-Hartman , Piotr Krysiuk , Daniel Borkmann , John Fastabend , Alexei Starovoitov , Ovidiu Panait Subject: [PATCH 4.19 055/116] bpf: Fix leakage of uninitialized bpf stack under speculation Date: Mon, 31 May 2021 15:13:51 +0200 Message-Id: <20210531130642.040393050@linuxfoundation.org> X-Mailer: git-send-email 2.31.1 In-Reply-To: <20210531130640.131924542@linuxfoundation.org> References: <20210531130640.131924542@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 801c6058d14a82179a7ee17a4b532cac6fad067f upstream. The current implemented mechanisms to mitigate data disclosure under speculation mainly address stack and map value oob access from the speculative domain. However, Piotr discovered that uninitialized BPF stack is not protected yet, and thus old data from the kernel stack, potentially including addresses of kernel structures, could still be extracted from that 512 bytes large window. The BPF stack is special compared to map values since it's not zero initialized for every program invocation, whereas map values /are/ zero initialized upon their initial allocation and thus cannot leak any prior data in either domain. In the non-speculative domain, the verifier ensures that every stack slot read must have a prior stack slot write by the BPF program to avoid such data leaking issue. However, this is not enough: for example, when the pointer arithmetic operation moves the stack pointer from the last valid stack offset to the first valid offset, the sanitation logic allows for any intermediate offsets during speculative execution, which could then be used to extract any restricted stack content via side-channel. Given for unprivileged stack pointer arithmetic the use of unknown but bounded scalars is generally forbidden, we can simply turn the register-based arithmetic operation into an immediate-based arithmetic operation without the need for masking. This also gives the benefit of reducing the needed instructions for the operation. Given after the work in 7fedb63a8307 ("bpf: Tighten speculative pointer arithmetic mask"), the aux->alu_limit already holds the final immediate value for the offset register with the known scalar. Thus, a simple mov of the immediate to AX register with using AX as the source for the original instruction is sufficient and possible now in this case. Reported-by: Piotr Krysiuk Signed-off-by: Daniel Borkmann Tested-by: Piotr Krysiuk Reviewed-by: Piotr Krysiuk Reviewed-by: John Fastabend Acked-by: Alexei Starovoitov Signed-off-by: Greg Kroah-Hartman Signed-off-by: Ovidiu Panait Signed-off-by: Greg Kroah-Hartman --- include/linux/bpf_verifier.h | 5 +++-- kernel/bpf/verifier.c | 27 +++++++++++++++++---------- 2 files changed, 20 insertions(+), 12 deletions(-) --- a/include/linux/bpf_verifier.h +++ b/include/linux/bpf_verifier.h @@ -144,10 +144,11 @@ struct bpf_verifier_state_list { }; /* Possible states for alu_state member. */ -#define BPF_ALU_SANITIZE_SRC 1U -#define BPF_ALU_SANITIZE_DST 2U +#define BPF_ALU_SANITIZE_SRC (1U << 0) +#define BPF_ALU_SANITIZE_DST (1U << 1) #define BPF_ALU_NEG_VALUE (1U << 2) #define BPF_ALU_NON_POINTER (1U << 3) +#define BPF_ALU_IMMEDIATE (1U << 4) #define BPF_ALU_SANITIZE (BPF_ALU_SANITIZE_SRC | \ BPF_ALU_SANITIZE_DST) --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -2825,6 +2825,7 @@ static int sanitize_ptr_alu(struct bpf_v { struct bpf_insn_aux_data *aux = commit_window ? cur_aux(env) : tmp_aux; struct bpf_verifier_state *vstate = env->cur_state; + bool off_is_imm = tnum_is_const(off_reg->var_off); bool off_is_neg = off_reg->smin_value < 0; bool ptr_is_dst_reg = ptr_reg == dst_reg; u8 opcode = BPF_OP(insn->code); @@ -2855,6 +2856,7 @@ static int sanitize_ptr_alu(struct bpf_v alu_limit = abs(tmp_aux->alu_limit - alu_limit); } else { alu_state = off_is_neg ? BPF_ALU_NEG_VALUE : 0; + alu_state |= off_is_imm ? BPF_ALU_IMMEDIATE : 0; alu_state |= ptr_is_dst_reg ? BPF_ALU_SANITIZE_SRC : BPF_ALU_SANITIZE_DST; } @@ -6172,7 +6174,7 @@ static int fixup_bpf_calls(struct bpf_ve const u8 code_sub = BPF_ALU64 | BPF_SUB | BPF_X; struct bpf_insn insn_buf[16]; struct bpf_insn *patch = &insn_buf[0]; - bool issrc, isneg; + bool issrc, isneg, isimm; u32 off_reg; aux = &env->insn_aux_data[i + delta]; @@ -6183,16 +6185,21 @@ static int fixup_bpf_calls(struct bpf_ve isneg = aux->alu_state & BPF_ALU_NEG_VALUE; issrc = (aux->alu_state & BPF_ALU_SANITIZE) == BPF_ALU_SANITIZE_SRC; + isimm = aux->alu_state & BPF_ALU_IMMEDIATE; off_reg = issrc ? insn->src_reg : insn->dst_reg; - if (isneg) - *patch++ = BPF_ALU64_IMM(BPF_MUL, off_reg, -1); - *patch++ = BPF_MOV32_IMM(BPF_REG_AX, aux->alu_limit); - *patch++ = BPF_ALU64_REG(BPF_SUB, BPF_REG_AX, off_reg); - *patch++ = BPF_ALU64_REG(BPF_OR, BPF_REG_AX, off_reg); - *patch++ = BPF_ALU64_IMM(BPF_NEG, BPF_REG_AX, 0); - *patch++ = BPF_ALU64_IMM(BPF_ARSH, BPF_REG_AX, 63); - *patch++ = BPF_ALU64_REG(BPF_AND, BPF_REG_AX, off_reg); + if (isimm) { + *patch++ = BPF_MOV32_IMM(BPF_REG_AX, aux->alu_limit); + } else { + if (isneg) + *patch++ = BPF_ALU64_IMM(BPF_MUL, off_reg, -1); + *patch++ = BPF_MOV32_IMM(BPF_REG_AX, aux->alu_limit); + *patch++ = BPF_ALU64_REG(BPF_SUB, BPF_REG_AX, off_reg); + *patch++ = BPF_ALU64_REG(BPF_OR, BPF_REG_AX, off_reg); + *patch++ = BPF_ALU64_IMM(BPF_NEG, BPF_REG_AX, 0); + *patch++ = BPF_ALU64_IMM(BPF_ARSH, BPF_REG_AX, 63); + *patch++ = BPF_ALU64_REG(BPF_AND, BPF_REG_AX, off_reg); + } if (!issrc) *patch++ = BPF_MOV64_REG(insn->dst_reg, insn->src_reg); insn->src_reg = BPF_REG_AX; @@ -6200,7 +6207,7 @@ static int fixup_bpf_calls(struct bpf_ve insn->code = insn->code == code_add ? code_sub : code_add; *patch++ = *insn; - if (issrc && isneg) + if (issrc && isneg && !isimm) *patch++ = BPF_ALU64_IMM(BPF_MUL, off_reg, -1); cnt = patch - insn_buf;