Received: by 2002:a25:1985:0:0:0:0:0 with SMTP id 127csp643623ybz; Wed, 22 Apr 2020 05:22:14 -0700 (PDT) X-Google-Smtp-Source: APiQypKr9nqUDEM0uA3+/ziOHJLSg/1XEYZgaZpRTsNsAJOQku3rXvoW0EQEjDitVZhF0YPe0Ygl X-Received: by 2002:a17:906:5287:: with SMTP id c7mr13294924ejm.141.1587558134523; Wed, 22 Apr 2020 05:22:14 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1587558134; cv=none; d=google.com; s=arc-20160816; b=zs3ii2kvHFDnXHjmvOES6pTUKhzLrbBpsy6zfzYiAksWOF4THiotED5NHqrkayd3Za t/HxbDqkIFPY9YtD4vK05+ZizsApV/B2Ql0EUgnn/Qo5TmVF8ki/9+Qqw0H6zSyKXAXs eefdXd1ZWANEa/XxcbhzL0UkYSzLtCPdUtHOJN20yd5tMmNYR3sDxK5JsOjpNBp+psuP jE1x2k1+8QTzTc6d/IMidS/kHF13Lmy33ci5HBx7E/JFSUni+UtoIllfQnXuMuaUkczU 5ZEgALWkf6VtjpvT2+dqA3ftLRTPjgDUxkYUCW0RIUqYfcZrdUEnuyl8fse7OrrzLZ7h O9yg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :user-agent:references:in-reply-to:message-id:date:subject:cc:to :from:dkim-signature; bh=lEJhs+pLXKtB6s4IaY/MBhBCKl8LV1N7+p8c1iAQmnc=; b=qzF3Ub7KyYuaQMdCrY+CeCiabH+izBusYS/Wss9VxKwuKman+PtgjXvGuEr43KRzsx kYz+z4tLK+0f4XDeFs/6iORAGNnxIjBcbFB4g5N6HE2BulaQE5uNMSfgsQAeAARuqvjE lDAbrHk9vLIKYpEqxoUdsJabxfOZssZ31a+Ot9JoIQA2QMzcOq62Z1/tqGux+AgJVj3o o3KINpluCIc83t1Ul9MO36cphgpmcyCI4/gA/qJb5qyXvu7yOYBHCaaP0GxbT33yKWiH 1v3ynwJgTRaEVa/SuNcDhoHP81OtU88yAk/ySDI4I5Xora2TziVXxXsvAsX83Ldff72m 9qRQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=N+IOWXHD; 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 Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id dn21si4138930ejc.379.2020.04.22.05.21.50; Wed, 22 Apr 2020 05:22:14 -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=@kernel.org header.s=default header.b=N+IOWXHD; 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 Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730979AbgDVK2S (ORCPT + 99 others); Wed, 22 Apr 2020 06:28:18 -0400 Received: from mail.kernel.org ([198.145.29.99]:37072 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730947AbgDVK1w (ORCPT ); Wed, 22 Apr 2020 06:27:52 -0400 Received: from localhost (83-86-89-107.cable.dynamic.v4.ziggo.nl [83.86.89.107]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id DF3202075A; Wed, 22 Apr 2020 10:27:50 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1587551271; bh=5zaxWXYHdii+8HKF+w3wF4Uacydj1oC+B6fkTZqNBls=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=N+IOWXHDjUpa1mYy4aqT9BVhkd0ZC0DNObN/zpMQzm4oeBuQVQtueb2gfYdeQNQAX /LmhYz/GIpTgZRmNpCqTyxRbjlkHmOfBfhkJ1huWjZGhEHpd9B1YkQ+q6QNve9FLwu 5Lq015K5ogakO0DGhsnIlMAjKaeSGWRFogo+raeY= From: Greg Kroah-Hartman To: linux-kernel@vger.kernel.org Cc: Greg Kroah-Hartman , stable@vger.kernel.org, Lorenzo Fontana , Leonardo Di Donato , John Fastabend , Daniel Borkmann , Alexei Starovoitov Subject: [PATCH 5.6 163/166] bpf: fix buggy r0 retval refinement for tracing helpers Date: Wed, 22 Apr 2020 11:58:10 +0200 Message-Id: <20200422095105.857178731@linuxfoundation.org> X-Mailer: git-send-email 2.26.2 In-Reply-To: <20200422095047.669225321@linuxfoundation.org> References: <20200422095047.669225321@linuxfoundation.org> User-Agent: quilt/0.66 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Daniel Borkmann Date: Tue, 21 Apr 2020 15:01:49 +0200 [ no upstream commit ] See the glory details in 100605035e15 ("bpf: Verifier, do_refine_retval_range may clamp umin to 0 incorrectly") for why 849fa50662fb ("bpf/verifier: refine retval R0 state for bpf_get_stack helper") is buggy. The whole series however is not suitable for stable since it adds significant amount [0] of verifier complexity in order to add 32bit subreg tracking. Something simpler is needed. Unfortunately, reverting 849fa50662fb ("bpf/verifier: refine retval R0 state for bpf_get_stack helper") or just cherry-picking 100605035e15 ("bpf: Verifier, do_refine_retval_range may clamp umin to 0 incorrectly") is not an option since it will break existing tracing programs badly (at least those that are using bpf_get_stack() and bpf_probe_read_str() helpers). Not fixing it in stable is also not an option since on 4.19 kernels an error will cause a soft-lockup due to hitting dead-code sanitized branch since we don't hard-wire such branches in old kernels yet. But even then for 5.x 849fa50662fb ("bpf/verifier: refine retval R0 state for bpf_get_stack helper") would cause wrong bounds on the verifier simluation when an error is hit. In one of the earlier iterations of mentioned patch series for upstream there was the concern that just using smax_value in do_refine_retval_range() would nuke bounds by subsequent <<32 >>32 shifts before the comparison against 0 [1] which eventually led to the 32bit subreg tracking in the first place. While I initially went for implementing the idea [1] to pattern match the two shift operations, it turned out to be more complex than actually needed, meaning, we could simply treat do_refine_retval_range() similarly to how we branch off verification for conditionals or under speculation, that is, pushing a new reg state to the stack for later verification. This means, instead of verifying the current path with the ret_reg in [S32MIN, msize_max_value] interval where later bounds would get nuked, we split this into two: i) for the success case where ret_reg can be in [0, msize_max_value], and ii) for the error case with ret_reg known to be in interval [S32MIN, -1]. Latter will preserve the bounds during these shift patterns and can match reg < 0 test. test_progs also succeed with this approach. [0] https://lore.kernel.org/bpf/158507130343.15666.8018068546764556975.stgit@john-Precision-5820-Tower/ [1] https://lore.kernel.org/bpf/158015334199.28573.4940395881683556537.stgit@john-XPS-13-9370/T/#m2e0ad1d5949131014748b6daa48a3495e7f0456d Fixes: 849fa50662fb ("bpf/verifier: refine retval R0 state for bpf_get_stack helper") Reported-by: Lorenzo Fontana Reported-by: Leonardo Di Donato Reported-by: John Fastabend Signed-off-by: Daniel Borkmann Acked-by: Alexei Starovoitov Acked-by: John Fastabend Tested-by: John Fastabend Signed-off-by: Greg Kroah-Hartman --- kernel/bpf/verifier.c | 45 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 34 insertions(+), 11 deletions(-) --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -227,8 +227,7 @@ struct bpf_call_arg_meta { bool pkt_access; int regno; int access_size; - s64 msize_smax_value; - u64 msize_umax_value; + u64 msize_max_value; int ref_obj_id; int func_id; u32 btf_id; @@ -3568,8 +3567,7 @@ static int check_func_arg(struct bpf_ver /* remember the mem_size which may be used later * to refine return values. */ - meta->msize_smax_value = reg->smax_value; - meta->msize_umax_value = reg->umax_value; + meta->msize_max_value = reg->umax_value; /* The register is SCALAR_VALUE; the access check * happens using its boundaries. @@ -4095,21 +4093,44 @@ static int prepare_func_exit(struct bpf_ return 0; } -static void do_refine_retval_range(struct bpf_reg_state *regs, int ret_type, - int func_id, - struct bpf_call_arg_meta *meta) +static int do_refine_retval_range(struct bpf_verifier_env *env, + struct bpf_reg_state *regs, int ret_type, + int func_id, struct bpf_call_arg_meta *meta) { struct bpf_reg_state *ret_reg = ®s[BPF_REG_0]; + struct bpf_reg_state tmp_reg = *ret_reg; + bool ret; if (ret_type != RET_INTEGER || (func_id != BPF_FUNC_get_stack && func_id != BPF_FUNC_probe_read_str)) - return; + return 0; + + /* Error case where ret is in interval [S32MIN, -1]. */ + ret_reg->smin_value = S32_MIN; + ret_reg->smax_value = -1; - ret_reg->smax_value = meta->msize_smax_value; - ret_reg->umax_value = meta->msize_umax_value; __reg_deduce_bounds(ret_reg); __reg_bound_offset(ret_reg); + __update_reg_bounds(ret_reg); + + ret = push_stack(env, env->insn_idx + 1, env->insn_idx, false); + if (!ret) + return -EFAULT; + + *ret_reg = tmp_reg; + + /* Success case where ret is in range [0, msize_max_value]. */ + ret_reg->smin_value = 0; + ret_reg->smax_value = meta->msize_max_value; + ret_reg->umin_value = ret_reg->smin_value; + ret_reg->umax_value = ret_reg->smax_value; + + __reg_deduce_bounds(ret_reg); + __reg_bound_offset(ret_reg); + __update_reg_bounds(ret_reg); + + return 0; } static int @@ -4377,7 +4398,9 @@ static int check_helper_call(struct bpf_ regs[BPF_REG_0].ref_obj_id = id; } - do_refine_retval_range(regs, fn->ret_type, func_id, &meta); + err = do_refine_retval_range(env, regs, fn->ret_type, func_id, &meta); + if (err) + return err; err = check_map_func_compatibility(env, meta.map_ptr, func_id); if (err)