From patchwork Mon Oct 25 23:12:54 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hao Luo X-Patchwork-Id: 12583469 X-Patchwork-Delegate: bpf@iogearbox.net Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 823BBC433EF for ; Mon, 25 Oct 2021 23:13:05 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 6569E6108B for ; Mon, 25 Oct 2021 23:13:05 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233207AbhJYXP0 (ORCPT ); Mon, 25 Oct 2021 19:15:26 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:47516 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232664AbhJYXP0 (ORCPT ); Mon, 25 Oct 2021 19:15:26 -0400 Received: from mail-pf1-x449.google.com (mail-pf1-x449.google.com [IPv6:2607:f8b0:4864:20::449]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 845E4C061745 for ; Mon, 25 Oct 2021 16:13:03 -0700 (PDT) Received: by mail-pf1-x449.google.com with SMTP id p10-20020a056a000b4a00b0044cf01eccdbso7276122pfo.19 for ; Mon, 25 Oct 2021 16:13:03 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=eBsK+hWSeBPw9+4g3rN87k1gD0iWMBYoLR6VY9WttkE=; b=URFeoI2I9qBs65gG6z1xqucZDzTgLuX4pvLcoXkM+jWRK6K/hM+wAM4CH7sFknFMrY Ju6aJBnv8WOeFCkVxixCaXEcsMXl4Xt7PArxdOVSn+hK3Rvgn0kOYylMJF/vKrIFIrvF onH6CUySn5RAXAqV66mJOdQl0IFQ6mW6STqreXB31wDNp9rSCR1QKU4aPge2XLNEMbK2 J9UzI3jgmllH5PXYs8r8qrNM2mo5duItVGykDPC44Ol8qQq0PHuk4IeczfyeMa+z/hcT rJCuG6ogb9m5WMmgJkzBGBk+FN8EBItjJPtXog56GgMwnp2bjMOno4T3Y5R54MaSp4fK g88w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=eBsK+hWSeBPw9+4g3rN87k1gD0iWMBYoLR6VY9WttkE=; b=TNZaW83c95+OeP8/Y3yJAKeyXUeQMdd2FqG0sOdL2Hi8yAEbKjuSf0jfPYTC3yo1MB 7vS1qpJ9wDDWO9Bd0NbERN9qsnxrqj9pPneudgq2p+M4m6lI0xWWBeogtpMaT/Brts7n 1PvQah6kOo1FaKEI29ZmGjIkqm1GKxULQEEpI0TVBQUJAnKGs6W9jPsLeDVzNQvH7lv3 La9RYUBaMnW8OF9XwaFmQs7TOXUxE/OdyaNKOPaaBkS4o4qIeI/oVz37ZYCSifUCyo7A dPVa1fj6iKiwlfz/QXfRj4gQw9i9T5Ohvop5ZF4xBldZVwG4WuwIyDrJnIoEuSCcVgzD qutw== X-Gm-Message-State: AOAM530+8Bg+mLR0xa4k2MSUWBqijaJap4mDk45A042uDQknsVYbDeEY NDswijbcWCVCIoVDnNsSoDSwqmsTpOQ= X-Google-Smtp-Source: ABdhPJyShj3n4QFlCqQnU8qwErxSIEXI9qkpgfnKg/fPbY+9FW5OGsLg/vTL4h1v1rpTEcOgL6cIRvoREQA= X-Received: from haoluo.svl.corp.google.com ([2620:15c:2cd:202:b4ab:b78c:418f:ca5c]) (user=haoluo job=sendgmr) by 2002:a17:90b:60d:: with SMTP id gb13mr200414pjb.0.1635203582514; Mon, 25 Oct 2021 16:13:02 -0700 (PDT) Date: Mon, 25 Oct 2021 16:12:54 -0700 In-Reply-To: <20211025231256.4030142-1-haoluo@google.com> Message-Id: <20211025231256.4030142-2-haoluo@google.com> Mime-Version: 1.0 References: <20211025231256.4030142-1-haoluo@google.com> X-Mailer: git-send-email 2.33.0.1079.g6e70778dc9-goog Subject: [PATCH bpf-next 1/3] bpf: Prevent write to ksym memory From: Hao Luo To: Alexei Starovoitov , Andrii Nakryiko , Daniel Borkmann Cc: KP Singh , bpf@vger.kernel.org, Hao Luo Precedence: bulk List-ID: X-Mailing-List: bpf@vger.kernel.org X-Patchwork-Delegate: bpf@iogearbox.net A ksym could be used to refer a global variable in the kernel. Previously if this variable is of non-struct type, bpf verifier resolves its value type to be PTR_TO_MEM, which allows the program to write to the memory. This patch introduces PTR_TO_RDONLY_MEM, which is similar to PTR_TO_MEM, but forbids writing. This should prevent program from writing kernel memory through ksyms. Right now a PTR_TO_RDONLY_MEM can not be passed into any helper as argument. But a PTR_TO_RDONLY_MEM can be read into a PTR_TO_MEM (e.g. stack variable), which can be passed to helpers such as bpf_snprintf. The following patch will add checks to differentiate the read-write arguments and read-only arguments, and support for passing PTR_TO_RDONLY_MEM to helper's read-only arguments. Fixes: 63d9b80dcf2c ("bpf: Introducte bpf_this_cpu_ptr()") Fixes: eaa6bcb71ef6 ("bpf: Introduce bpf_per_cpu_ptr()") Fixes: 4976b718c355 ("bpf: Introduce pseudo_btf_id") Signed-off-by: Hao Luo --- Changes since v1: - Added Fixes tag. - Removed PTR_TO_RDONLY_MEM[_OR_NULL] from reg_type_may_be_refcounted. include/linux/bpf.h | 6 ++++-- include/uapi/linux/bpf.h | 4 ++-- kernel/bpf/helpers.c | 4 ++-- kernel/bpf/verifier.c | 36 ++++++++++++++++++++++++++-------- tools/include/uapi/linux/bpf.h | 4 ++-- 5 files changed, 38 insertions(+), 16 deletions(-) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 31421c74ba08..7b47e8f344cb 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -355,8 +355,8 @@ enum bpf_return_type { RET_PTR_TO_SOCK_COMMON_OR_NULL, /* returns a pointer to a sock_common or NULL */ RET_PTR_TO_ALLOC_MEM_OR_NULL, /* returns a pointer to dynamically allocated memory or NULL */ RET_PTR_TO_BTF_ID_OR_NULL, /* returns a pointer to a btf_id or NULL */ - RET_PTR_TO_MEM_OR_BTF_ID_OR_NULL, /* returns a pointer to a valid memory or a btf_id or NULL */ - RET_PTR_TO_MEM_OR_BTF_ID, /* returns a pointer to a valid memory or a btf_id */ + RET_PTR_TO_RDONLY_MEM_OR_BTF_ID_OR_NULL, /* returns a pointer to a readonly memory or a btf_id or NULL */ + RET_PTR_TO_RDONLY_MEM_OR_BTF_ID, /* returns a pointer to a readonly memory or a btf_id */ RET_PTR_TO_BTF_ID, /* returns a pointer to a btf_id */ }; @@ -459,6 +459,8 @@ enum bpf_reg_type { PTR_TO_PERCPU_BTF_ID, /* reg points to a percpu kernel variable */ PTR_TO_FUNC, /* reg points to a bpf program function */ PTR_TO_MAP_KEY, /* reg points to a map element key */ + PTR_TO_RDONLY_MEM, /* reg points to valid readonly memory region */ + PTR_TO_RDONLY_MEM_OR_NULL, /* reg points to valid readonly memory region or null */ __BPF_REG_TYPE_MAX, }; diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index c10820037883..9fb931de668a 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -1141,8 +1141,8 @@ enum bpf_link_type { * insn[0].off: 0 * insn[1].off: 0 * ldimm64 rewrite: address of the kernel variable - * verifier type: PTR_TO_BTF_ID or PTR_TO_MEM, depending on whether the var - * is struct/union. + * verifier type: PTR_TO_BTF_ID or PTR_TO_RDONLY_MEM, depending on whether + * the var is struct/union. */ #define BPF_PSEUDO_BTF_ID 3 /* insn[0].src_reg: BPF_PSEUDO_FUNC diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c index 1ffd469c217f..14531757087f 100644 --- a/kernel/bpf/helpers.c +++ b/kernel/bpf/helpers.c @@ -667,7 +667,7 @@ BPF_CALL_2(bpf_per_cpu_ptr, const void *, ptr, u32, cpu) const struct bpf_func_proto bpf_per_cpu_ptr_proto = { .func = bpf_per_cpu_ptr, .gpl_only = false, - .ret_type = RET_PTR_TO_MEM_OR_BTF_ID_OR_NULL, + .ret_type = RET_PTR_TO_RDONLY_MEM_OR_BTF_ID_OR_NULL, .arg1_type = ARG_PTR_TO_PERCPU_BTF_ID, .arg2_type = ARG_ANYTHING, }; @@ -680,7 +680,7 @@ BPF_CALL_1(bpf_this_cpu_ptr, const void *, percpu_ptr) const struct bpf_func_proto bpf_this_cpu_ptr_proto = { .func = bpf_this_cpu_ptr, .gpl_only = false, - .ret_type = RET_PTR_TO_MEM_OR_BTF_ID, + .ret_type = RET_PTR_TO_RDONLY_MEM_OR_BTF_ID, .arg1_type = ARG_PTR_TO_PERCPU_BTF_ID, }; diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index c6616e325803..ae3ff297240e 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -453,6 +453,7 @@ static bool reg_type_may_be_null(enum bpf_reg_type type) type == PTR_TO_TCP_SOCK_OR_NULL || type == PTR_TO_BTF_ID_OR_NULL || type == PTR_TO_MEM_OR_NULL || + type == PTR_TO_RDONLY_MEM_OR_NULL || type == PTR_TO_RDONLY_BUF_OR_NULL || type == PTR_TO_RDWR_BUF_OR_NULL; } @@ -571,6 +572,8 @@ static const char * const reg_type_str[] = { [PTR_TO_PERCPU_BTF_ID] = "percpu_ptr_", [PTR_TO_MEM] = "mem", [PTR_TO_MEM_OR_NULL] = "mem_or_null", + [PTR_TO_RDONLY_MEM] = "rdonly_mem", + [PTR_TO_RDONLY_MEM_OR_NULL] = "rdonly_mem_or_null", [PTR_TO_RDONLY_BUF] = "rdonly_buf", [PTR_TO_RDONLY_BUF_OR_NULL] = "rdonly_buf_or_null", [PTR_TO_RDWR_BUF] = "rdwr_buf", @@ -1183,6 +1186,9 @@ static void mark_ptr_not_null_reg(struct bpf_reg_state *reg) case PTR_TO_MEM_OR_NULL: reg->type = PTR_TO_MEM; break; + case PTR_TO_RDONLY_MEM_OR_NULL: + reg->type = PTR_TO_RDONLY_MEM; + break; case PTR_TO_RDONLY_BUF_OR_NULL: reg->type = PTR_TO_RDONLY_BUF; break; @@ -2741,6 +2747,8 @@ static bool is_spillable_regtype(enum bpf_reg_type type) case PTR_TO_PERCPU_BTF_ID: case PTR_TO_MEM: case PTR_TO_MEM_OR_NULL: + case PTR_TO_RDONLY_MEM: + case PTR_TO_RDONLY_MEM_OR_NULL: case PTR_TO_FUNC: case PTR_TO_MAP_KEY: return true; @@ -3367,6 +3375,7 @@ static int __check_mem_access(struct bpf_verifier_env *env, int regno, off, size, regno, reg->id, off, mem_size); break; case PTR_TO_MEM: + case PTR_TO_RDONLY_MEM: default: verbose(env, "invalid access to memory, mem_size=%u off=%d size=%d\n", mem_size, off, size); @@ -4377,6 +4386,16 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn reg->mem_size, false); if (!err && t == BPF_READ && value_regno >= 0) mark_reg_unknown(env, regs, value_regno); + } else if (reg->type == PTR_TO_RDONLY_MEM) { + if (t == BPF_WRITE) { + verbose(env, "R%d cannot write into %s\n", + regno, reg_type_str[reg->type]); + return -EACCES; + } + err = check_mem_region_access(env, regno, off, size, + reg->mem_size, false); + if (!err && value_regno >= 0) + mark_reg_unknown(env, regs, value_regno); } else if (reg->type == PTR_TO_CTX) { enum bpf_reg_type reg_type = SCALAR_VALUE; struct btf *btf = NULL; @@ -6532,8 +6551,8 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn mark_reg_known_zero(env, regs, BPF_REG_0); regs[BPF_REG_0].type = PTR_TO_MEM_OR_NULL; regs[BPF_REG_0].mem_size = meta.mem_size; - } else if (fn->ret_type == RET_PTR_TO_MEM_OR_BTF_ID_OR_NULL || - fn->ret_type == RET_PTR_TO_MEM_OR_BTF_ID) { + } else if (fn->ret_type == RET_PTR_TO_RDONLY_MEM_OR_BTF_ID_OR_NULL || + fn->ret_type == RET_PTR_TO_RDONLY_MEM_OR_BTF_ID) { const struct btf_type *t; mark_reg_known_zero(env, regs, BPF_REG_0); @@ -6552,12 +6571,12 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn return -EINVAL; } regs[BPF_REG_0].type = - fn->ret_type == RET_PTR_TO_MEM_OR_BTF_ID ? - PTR_TO_MEM : PTR_TO_MEM_OR_NULL; + fn->ret_type == RET_PTR_TO_RDONLY_MEM_OR_BTF_ID ? + PTR_TO_RDONLY_MEM : PTR_TO_RDONLY_MEM_OR_NULL; regs[BPF_REG_0].mem_size = tsize; } else { regs[BPF_REG_0].type = - fn->ret_type == RET_PTR_TO_MEM_OR_BTF_ID ? + fn->ret_type == RET_PTR_TO_RDONLY_MEM_OR_BTF_ID ? PTR_TO_BTF_ID : PTR_TO_BTF_ID_OR_NULL; regs[BPF_REG_0].btf = meta.ret_btf; regs[BPF_REG_0].btf_id = meta.ret_btf_id; @@ -9363,7 +9382,7 @@ static int check_ld_imm(struct bpf_verifier_env *env, struct bpf_insn *insn) dst_reg->type = aux->btf_var.reg_type; switch (dst_reg->type) { - case PTR_TO_MEM: + case PTR_TO_RDONLY_MEM: dst_reg->mem_size = aux->btf_var.mem_size; break; case PTR_TO_BTF_ID: @@ -11510,7 +11529,7 @@ static int check_pseudo_btf_id(struct bpf_verifier_env *env, err = -EINVAL; goto err_put; } - aux->btf_var.reg_type = PTR_TO_MEM; + aux->btf_var.reg_type = PTR_TO_RDONLY_MEM; aux->btf_var.mem_size = tsize; } else { aux->btf_var.reg_type = PTR_TO_BTF_ID; @@ -13332,7 +13351,8 @@ static int do_check_common(struct bpf_verifier_env *env, int subprog) mark_reg_known_zero(env, regs, i); else if (regs[i].type == SCALAR_VALUE) mark_reg_unknown(env, regs, i); - else if (regs[i].type == PTR_TO_MEM_OR_NULL) { + else if (regs[i].type == PTR_TO_MEM_OR_NULL || + regs[i].type == PTR_TO_RDONLY_MEM_OR_NULL) { const u32 mem_size = regs[i].mem_size; mark_reg_known_zero(env, regs, i); diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index c10820037883..9fb931de668a 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -1141,8 +1141,8 @@ enum bpf_link_type { * insn[0].off: 0 * insn[1].off: 0 * ldimm64 rewrite: address of the kernel variable - * verifier type: PTR_TO_BTF_ID or PTR_TO_MEM, depending on whether the var - * is struct/union. + * verifier type: PTR_TO_BTF_ID or PTR_TO_RDONLY_MEM, depending on whether + * the var is struct/union. */ #define BPF_PSEUDO_BTF_ID 3 /* insn[0].src_reg: BPF_PSEUDO_FUNC From patchwork Mon Oct 25 23:12:55 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hao Luo X-Patchwork-Id: 12583471 X-Patchwork-Delegate: bpf@iogearbox.net Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3B4DAC433F5 for ; Mon, 25 Oct 2021 23:13:07 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 1D5ED6108C for ; Mon, 25 Oct 2021 23:13:07 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233363AbhJYXP3 (ORCPT ); Mon, 25 Oct 2021 19:15:29 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:47530 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232664AbhJYXP2 (ORCPT ); Mon, 25 Oct 2021 19:15:28 -0400 Received: from mail-pf1-x44a.google.com (mail-pf1-x44a.google.com [IPv6:2607:f8b0:4864:20::44a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E9283C061745 for ; Mon, 25 Oct 2021 16:13:05 -0700 (PDT) Received: by mail-pf1-x44a.google.com with SMTP id w196-20020a627bcd000000b0047c07de537aso867024pfc.6 for ; Mon, 25 Oct 2021 16:13:05 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=IyRfP/b4ge8j+g+G8W/A3ZJlY+yOBfcu89IbY5D9Syg=; b=kNYvIKCs7yfoOT7dBLJL7n4CNGPSGuy0zZpdsAqy5vs0j4buzMz2MtzFLIJXIkqDJa IuWwp/M1Y5g1C9eD67CfSQxizFaQGqFUOZaFigxasWzTHitPIGFwlqxBLV2KQymN33uh DmE44yjmZ79MrSntPZEybdriPkp2LWo233vKMM2IklvoJFu5QUWHzCjbJbbE7m6QTnug CuuT/ub27L5dZQxmOmdL6rrn/7NU2anB/hE+l5Oc3jv7yu9LIbkIH2M8x8sXf10n9Yiw m4NBahtk8nC6NCdL34gfcQvajn18L/omy8kNRR2aYfwKLIAnk9WYZxvQmVYKjiOns6jc arvA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=IyRfP/b4ge8j+g+G8W/A3ZJlY+yOBfcu89IbY5D9Syg=; b=LQ6t8ceveyPkq+daT5tJOEdKfJ3Xh6sRq/PhxEQseYVPOU4dLReQZ2zxIXbnyVtDE+ JhyABCk2Q/xFAPFa+tQ5raSNjnDGVYfz4sLCouftfC54IMYZcJpUWP6TAynGWcXq0mqM t5JGTwBxPkHR64TFtoQoV1KbU5LuCxOr2mkKmntsd8m0mMtl+gHHs5Eu6O0aHmzWdv8V D5nt6F3FCrwS5KOOmRhAGbvLPqxhZWTf31aH52Ppy05V+h0LmdRElv6h9/XNSK3HypzM m/yC00ec48NrKjryu8CLOYn85CUSVsz6teBgSptJ73zC5xArpVV5altD30l2WaliYgLK wAig== X-Gm-Message-State: AOAM531inmgUn3VKW9LjzbEZTY26PLez3dJK0vFwFipHj6Pa8cfnfC9M rFDfpMpIVERPuzQEH2tgZnRdt9SZ3V0= X-Google-Smtp-Source: ABdhPJw6ZUyTrqJpLXcSR1z/FYmCc/5KGbkCmngzhcM+QCVWNuzH77/5tQwPWvR+qOSOfBal7YiWlV82fmI= X-Received: from haoluo.svl.corp.google.com ([2620:15c:2cd:202:b4ab:b78c:418f:ca5c]) (user=haoluo job=sendgmr) by 2002:a17:90b:60d:: with SMTP id gb13mr200420pjb.0.1635203585127; Mon, 25 Oct 2021 16:13:05 -0700 (PDT) Date: Mon, 25 Oct 2021 16:12:55 -0700 In-Reply-To: <20211025231256.4030142-1-haoluo@google.com> Message-Id: <20211025231256.4030142-3-haoluo@google.com> Mime-Version: 1.0 References: <20211025231256.4030142-1-haoluo@google.com> X-Mailer: git-send-email 2.33.0.1079.g6e70778dc9-goog Subject: [PATCH bpf-next v2 2/3] bpf: Introduce ARG_PTR_TO_WRITABLE_MEM From: Hao Luo To: Alexei Starovoitov , Andrii Nakryiko , Daniel Borkmann Cc: KP Singh , bpf@vger.kernel.org, Hao Luo Precedence: bulk List-ID: X-Mailing-List: bpf@vger.kernel.org X-Patchwork-Delegate: bpf@iogearbox.net Some helper functions may modify its arguments, for example, bpf_d_path, bpf_get_stack etc. Previously, their argument types were marked as ARG_PTR_TO_MEM, which is compatible with read-only mem types, such as PTR_TO_RDONLY_BUF. Therefore it's legitimate to modify a read-only memory by passing it into one of such helper functions. This patch introduces a new arg type ARG_PTR_TO_WRITABLE_MEM to annotate the arguments that may be modified by the helpers. For arguments that are of ARG_PTR_TO_MEM, it's ok to take any mem type, while for ARG_PTR_TO_WRITABLE_MEM, readonly mem reg types are not acceptable. In short, when a helper may modify its input parameter, use ARG_PTR_TO_WRITABLE_MEM instead of ARG_PTR_TO_MEM. So far the difference between ARG_PTR_TO_MEM and ARG_PTR_TO_WRITABLE_MEM is PTR_TO_RDONLY_BUF and PTR_TO_RDONLY_MEM. PTR_TO_RDONLY_BUF is only used in bpf_iter prog as the type of key, which hasn't been used in the affected helper functions. PTR_TO_RDONLY_MEM currently has no consumers. Signed-off-by: Hao Luo --- Changes since v1: - new patch, introduced ARG_PTR_TO_WRITABLE_MEM to differentiate read-only and read-write mem arg types. include/linux/bpf.h | 9 +++++++++ kernel/bpf/cgroup.c | 2 +- kernel/bpf/helpers.c | 2 +- kernel/bpf/verifier.c | 18 ++++++++++++++++++ kernel/trace/bpf_trace.c | 6 +++--- net/core/filter.c | 6 +++--- 6 files changed, 35 insertions(+), 8 deletions(-) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 7b47e8f344cb..586ce67d63a9 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -341,6 +341,15 @@ enum bpf_arg_type { ARG_PTR_TO_STACK_OR_NULL, /* pointer to stack or NULL */ ARG_PTR_TO_CONST_STR, /* pointer to a null terminated read-only string */ ARG_PTR_TO_TIMER, /* pointer to bpf_timer */ + ARG_PTR_TO_WRITABLE_MEM, /* pointer to valid memory. Compared to + * ARG_PTR_TO_MEM, this arg_type is not + * compatible with RDONLY memory. If the + * argument may be updated by the helper, + * use this type. + */ + ARG_PTR_TO_WRITABLE_MEM_OR_NULL, /* pointer to memory or null, similar to + * ARG_PTR_TO_WRITABLE_MEM. + */ __BPF_ARG_TYPE_MAX, }; diff --git a/kernel/bpf/cgroup.c b/kernel/bpf/cgroup.c index 03145d45e3d5..683269b7cd92 100644 --- a/kernel/bpf/cgroup.c +++ b/kernel/bpf/cgroup.c @@ -1666,7 +1666,7 @@ static const struct bpf_func_proto bpf_sysctl_get_name_proto = { .gpl_only = false, .ret_type = RET_INTEGER, .arg1_type = ARG_PTR_TO_CTX, - .arg2_type = ARG_PTR_TO_MEM, + .arg2_type = ARG_PTR_TO_WRITABLE_MEM, .arg3_type = ARG_CONST_SIZE, .arg4_type = ARG_ANYTHING, }; diff --git a/kernel/bpf/helpers.c b/kernel/bpf/helpers.c index 14531757087f..db98385ee7af 100644 --- a/kernel/bpf/helpers.c +++ b/kernel/bpf/helpers.c @@ -1008,7 +1008,7 @@ const struct bpf_func_proto bpf_snprintf_proto = { .func = bpf_snprintf, .gpl_only = true, .ret_type = RET_INTEGER, - .arg1_type = ARG_PTR_TO_MEM_OR_NULL, + .arg1_type = ARG_PTR_TO_WRITABLE_MEM_OR_NULL, .arg2_type = ARG_CONST_SIZE_OR_ZERO, .arg3_type = ARG_PTR_TO_CONST_STR, .arg4_type = ARG_PTR_TO_MEM_OR_NULL, diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index ae3ff297240e..d8817c3d990e 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -486,6 +486,7 @@ static bool arg_type_may_be_null(enum bpf_arg_type type) type == ARG_PTR_TO_CTX_OR_NULL || type == ARG_PTR_TO_SOCKET_OR_NULL || type == ARG_PTR_TO_ALLOC_MEM_OR_NULL || + type == ARG_PTR_TO_WRITABLE_MEM_OR_NULL || type == ARG_PTR_TO_STACK_OR_NULL; } @@ -4971,6 +4972,8 @@ static bool arg_type_is_mem_ptr(enum bpf_arg_type type) { return type == ARG_PTR_TO_MEM || type == ARG_PTR_TO_MEM_OR_NULL || + type == ARG_PTR_TO_WRITABLE_MEM || + type == ARG_PTR_TO_WRITABLE_MEM_OR_NULL || type == ARG_PTR_TO_UNINIT_MEM; } @@ -5075,6 +5078,19 @@ static const struct bpf_reg_types mem_types = { PTR_TO_MEM, PTR_TO_RDONLY_BUF, PTR_TO_RDWR_BUF, + PTR_TO_RDONLY_MEM, + }, +}; + +static const struct bpf_reg_types writable_mem_types = { + .types = { + PTR_TO_STACK, + PTR_TO_PACKET, + PTR_TO_PACKET_META, + PTR_TO_MAP_KEY, + PTR_TO_MAP_VALUE, + PTR_TO_MEM, + PTR_TO_RDWR_BUF, }, }; @@ -5125,6 +5141,8 @@ static const struct bpf_reg_types *compatible_reg_types[__BPF_ARG_TYPE_MAX] = { [ARG_PTR_TO_UNINIT_MEM] = &mem_types, [ARG_PTR_TO_ALLOC_MEM] = &alloc_mem_types, [ARG_PTR_TO_ALLOC_MEM_OR_NULL] = &alloc_mem_types, + [ARG_PTR_TO_WRITABLE_MEM] = &writable_mem_types, + [ARG_PTR_TO_WRITABLE_MEM_OR_NULL] = &writable_mem_types, [ARG_PTR_TO_INT] = &int_ptr_types, [ARG_PTR_TO_LONG] = &int_ptr_types, [ARG_PTR_TO_PERCPU_BTF_ID] = &percpu_btf_ptr_types, diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c index cbcd0d6fca7c..5815845222de 100644 --- a/kernel/trace/bpf_trace.c +++ b/kernel/trace/bpf_trace.c @@ -945,7 +945,7 @@ static const struct bpf_func_proto bpf_d_path_proto = { .ret_type = RET_INTEGER, .arg1_type = ARG_PTR_TO_BTF_ID, .arg1_btf_id = &bpf_d_path_btf_ids[0], - .arg2_type = ARG_PTR_TO_MEM, + .arg2_type = ARG_PTR_TO_WRITABLE_MEM, .arg3_type = ARG_CONST_SIZE_OR_ZERO, .allowed = bpf_d_path_allowed, }; @@ -1002,7 +1002,7 @@ const struct bpf_func_proto bpf_snprintf_btf_proto = { .func = bpf_snprintf_btf, .gpl_only = false, .ret_type = RET_INTEGER, - .arg1_type = ARG_PTR_TO_MEM, + .arg1_type = ARG_PTR_TO_WRITABLE_MEM, .arg2_type = ARG_CONST_SIZE, .arg3_type = ARG_PTR_TO_MEM, .arg4_type = ARG_CONST_SIZE, @@ -1433,7 +1433,7 @@ static const struct bpf_func_proto bpf_read_branch_records_proto = { .gpl_only = true, .ret_type = RET_INTEGER, .arg1_type = ARG_PTR_TO_CTX, - .arg2_type = ARG_PTR_TO_MEM_OR_NULL, + .arg2_type = ARG_PTR_TO_WRITABLE_MEM_OR_NULL, .arg3_type = ARG_CONST_SIZE_OR_ZERO, .arg4_type = ARG_ANYTHING, }; diff --git a/net/core/filter.c b/net/core/filter.c index 8e8d3b49c297..7dadabe12ceb 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -5639,7 +5639,7 @@ static const struct bpf_func_proto bpf_xdp_fib_lookup_proto = { .gpl_only = true, .ret_type = RET_INTEGER, .arg1_type = ARG_PTR_TO_CTX, - .arg2_type = ARG_PTR_TO_MEM, + .arg2_type = ARG_PTR_TO_WRITABLE_MEM, .arg3_type = ARG_CONST_SIZE, .arg4_type = ARG_ANYTHING, }; @@ -5694,7 +5694,7 @@ static const struct bpf_func_proto bpf_skb_fib_lookup_proto = { .gpl_only = true, .ret_type = RET_INTEGER, .arg1_type = ARG_PTR_TO_CTX, - .arg2_type = ARG_PTR_TO_MEM, + .arg2_type = ARG_PTR_TO_WRITABLE_MEM, .arg3_type = ARG_CONST_SIZE, .arg4_type = ARG_ANYTHING, }; @@ -6977,7 +6977,7 @@ static const struct bpf_func_proto bpf_sock_ops_load_hdr_opt_proto = { .gpl_only = false, .ret_type = RET_INTEGER, .arg1_type = ARG_PTR_TO_CTX, - .arg2_type = ARG_PTR_TO_MEM, + .arg2_type = ARG_PTR_TO_WRITABLE_MEM, .arg3_type = ARG_CONST_SIZE, .arg4_type = ARG_ANYTHING, }; From patchwork Mon Oct 25 23:12:56 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Hao Luo X-Patchwork-Id: 12583473 X-Patchwork-Delegate: bpf@iogearbox.net Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 2F2A2C433EF for ; Mon, 25 Oct 2021 23:13:09 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 12CB86108B for ; Mon, 25 Oct 2021 23:13:09 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233482AbhJYXPb (ORCPT ); Mon, 25 Oct 2021 19:15:31 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:47536 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232664AbhJYXPa (ORCPT ); Mon, 25 Oct 2021 19:15:30 -0400 Received: from mail-pg1-x54a.google.com (mail-pg1-x54a.google.com [IPv6:2607:f8b0:4864:20::54a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id CD2BBC061745 for ; Mon, 25 Oct 2021 16:13:07 -0700 (PDT) Received: by mail-pg1-x54a.google.com with SMTP id b6-20020a631b46000000b0029a054d00f3so6942261pgm.17 for ; Mon, 25 Oct 2021 16:13:07 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20210112; h=date:in-reply-to:message-id:mime-version:references:subject:from:to :cc; bh=r3ezkXqwfg4lQ3I8OPwkNyvqCHNsjE/QJmJWEIQdqaA=; b=obrw6ngjZLOY87g7X0uaSepQC+CnmU2ojBNlZ9BMSzWIzpTqXZdC8guYH5idPNjuOK Icf8ntqsncB414CHX/HQiKdPpVqr2I7NdfVlpbMeiQv+c/nr1uPCvjKok+nkiw3xJuyA cB/BpoVo239+yG1rjX5fsFaZFpNWZTAtGE1qmgqMSjalvt69vWFvBWQUuJjkH+SfkMx0 BDbGi7M/h7QlB6VpGggh/9YhFtccBPs1Nm0gq0zlPi73T8yyInUhXReF5bgQBMMmGczp SI70EUPtbUCMDJSbOYXtWMtkOP+473xvWR1lSPdngzcuwM9DMPkNj+srGxq9K/YNuUjB deJQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=r3ezkXqwfg4lQ3I8OPwkNyvqCHNsjE/QJmJWEIQdqaA=; b=e2VWbCasVBvIGQLlg3e0EGDDUMkEzzqdc72QQjYvl4DEhG8jyb0z8oghaXUZXTL2ZZ 7WTCeuffeOdU1FLrBBB5kMgU3CCGC/0fZGOdRsNxrwfCBKZAEIpLDPrRS9lQqylgRNgr yO8inAcoKUHbH9594NSw5QrQQq3kXaUHlNvinqNyfbc5s18kJnKQ37f9nuJ9/afWd6Me IOkJGUBkK+CwRd3SDz43RrgyeQNqp17fVuqlwB/IT49ag7lmV9c5FrbElp38bLgCokpw 6ae8P7pHJ+OmXh725rnvX4kNyskDsYrjAsoZTlVEnAtJjfPHoI01SFfalnYILCBOngpJ Xs4A== X-Gm-Message-State: AOAM532ajBhkWVAph7gib+gLFpliDuNn4prQBloBWLatJIxrqq2i/xlP 39zicC5XcFh2c8Ov9a5frQ86Bcf+I2M= X-Google-Smtp-Source: ABdhPJwUgcwCje+5A4YtyxI1l73zvMNJD+6C07kc5BgsrzKassry+rlAOJ2osgk6F8QKJYY2zXBgbVaJE0Q= X-Received: from haoluo.svl.corp.google.com ([2620:15c:2cd:202:b4ab:b78c:418f:ca5c]) (user=haoluo job=sendgmr) by 2002:a17:90a:d510:: with SMTP id t16mr24649541pju.55.1635203587275; Mon, 25 Oct 2021 16:13:07 -0700 (PDT) Date: Mon, 25 Oct 2021 16:12:56 -0700 In-Reply-To: <20211025231256.4030142-1-haoluo@google.com> Message-Id: <20211025231256.4030142-4-haoluo@google.com> Mime-Version: 1.0 References: <20211025231256.4030142-1-haoluo@google.com> X-Mailer: git-send-email 2.33.0.1079.g6e70778dc9-goog Subject: [PATCH bpf-next v2 3/3] bpf/selftests: Test PTR_TO_RDONLY_MEM From: Hao Luo To: Alexei Starovoitov , Andrii Nakryiko , Daniel Borkmann Cc: KP Singh , bpf@vger.kernel.org, Hao Luo Precedence: bulk List-ID: X-Mailing-List: bpf@vger.kernel.org X-Patchwork-Delegate: bpf@iogearbox.net This test verifies that a ksym of non-struct can not be directly updated. Signed-off-by: Hao Luo --- Changes since v1: - Replaced CHECK() with ASSERT_ERR_PTR() - Commented in the test for the reason of verification failure. .../selftests/bpf/prog_tests/ksyms_btf.c | 14 +++++++++ .../bpf/progs/test_ksyms_btf_write_check.c | 29 +++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 tools/testing/selftests/bpf/progs/test_ksyms_btf_write_check.c diff --git a/tools/testing/selftests/bpf/prog_tests/ksyms_btf.c b/tools/testing/selftests/bpf/prog_tests/ksyms_btf.c index cf3acfa5a91d..69455fe90ac3 100644 --- a/tools/testing/selftests/bpf/prog_tests/ksyms_btf.c +++ b/tools/testing/selftests/bpf/prog_tests/ksyms_btf.c @@ -7,6 +7,7 @@ #include "test_ksyms_btf.skel.h" #include "test_ksyms_btf_null_check.skel.h" #include "test_ksyms_weak.skel.h" +#include "test_ksyms_btf_write_check.skel.h" static int duration; @@ -109,6 +110,16 @@ static void test_weak_syms(void) test_ksyms_weak__destroy(skel); } +static void test_write_check(void) +{ + struct test_ksyms_btf_write_check *skel; + + skel = test_ksyms_btf_write_check__open_and_load(); + ASSERT_ERR_PTR(skel, "unexpected load of a prog writing to ksym memory\n"); + + test_ksyms_btf_write_check__destroy(skel); +} + void test_ksyms_btf(void) { int percpu_datasec; @@ -136,4 +147,7 @@ void test_ksyms_btf(void) if (test__start_subtest("weak_ksyms")) test_weak_syms(); + + if (test__start_subtest("write_check")) + test_write_check(); } diff --git a/tools/testing/selftests/bpf/progs/test_ksyms_btf_write_check.c b/tools/testing/selftests/bpf/progs/test_ksyms_btf_write_check.c new file mode 100644 index 000000000000..2180c41cd890 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_ksyms_btf_write_check.c @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2021 Google */ + +#include "vmlinux.h" + +#include + +extern const int bpf_prog_active __ksym; /* int type global var. */ + +SEC("raw_tp/sys_enter") +int handler(const void *ctx) +{ + int *active; + __u32 cpu; + + cpu = bpf_get_smp_processor_id(); + active = (int *)bpf_per_cpu_ptr(&bpf_prog_active, cpu); + if (active) { + /* Kernel memory obtained from bpf_{per,this}_cpu_ptr + * is read-only, should _not_ pass verification. + */ + /* WRITE_ONCE */ + *(volatile int *)active = -1; + } + + return 0; +} + +char _license[] SEC("license") = "GPL";