From patchwork Wed Mar 10 22:02:07 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florent Revest X-Patchwork-Id: 12129583 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 X-Spam-Level: X-Spam-Status: No, score=-19.0 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER,INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS, URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 0FF89C43381 for ; Wed, 10 Mar 2021 22:03:46 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id D804A64FD8 for ; Wed, 10 Mar 2021 22:03:45 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233770AbhCJWDP (ORCPT ); Wed, 10 Mar 2021 17:03:15 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45124 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234372AbhCJWCw (ORCPT ); Wed, 10 Mar 2021 17:02:52 -0500 Received: from mail-wm1-x32b.google.com (mail-wm1-x32b.google.com [IPv6:2a00:1450:4864:20::32b]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 79729C061761 for ; Wed, 10 Mar 2021 14:02:29 -0800 (PST) Received: by mail-wm1-x32b.google.com with SMTP id y124-20020a1c32820000b029010c93864955so11990655wmy.5 for ; Wed, 10 Mar 2021 14:02:29 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=QHAXRp5cjvFe5tOwLQufuvHj4q8NvqNGvXDx3zXkaA4=; b=U6+Nq610gcxHKdFeY47vS8PPCzFV27nnVAtzLR5quvgbjkblFoy39EvLscG8l+5OW2 7kmeEhaSLd7HWtOv4Bbb8LUN1Lsr83xGKQbtgJ8Xj/vfC2bMF/33OBQwV63KKhSPsKXJ zOinN93ztMiP14oQrofxLGxVNBg6u1IZEXQxY= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=QHAXRp5cjvFe5tOwLQufuvHj4q8NvqNGvXDx3zXkaA4=; b=HYSQSgfvM82z/xsycu6P2K4waMZVczsVc5tiLPKIq2wH2Wc+hXRqe4CYklBVvK0n33 mnuYVG1U9lU7f5ihqz6RyfQX0Wgsk1srVcudjY+F6Q0htoq3nl5rcoudXQYmBBjrS0VG ghNItYK0ENYJwNxJO/gLDF82IwO97HhTOjvcbWdW01i06/jIZoj9W0EzdrVdT90QEqvJ /IAHgDYATV9JkwVHRAiM0vKPniDaNCTQypfBpoo8MUCKH0fPNytLvMjM+aYPD+NTjgm8 iclfrwGqMUjTZIhky2qluLyuSuaiPvVNw2EKZGX4au6NkXsT5yBDBfj6LqHvTuYF+X4x lTUw== X-Gm-Message-State: AOAM533IaQW6hxExxuzs6E+/UrYbW/pP0DD3dHsnOknjEHV7B7zjZQWm 7LweCKdX8jYYUDLDd5cYADyy1gJgfeRvpA== X-Google-Smtp-Source: ABdhPJzpWpebzf0c61H/lJ2zQRw60kkX/cWWJoDKfBhbV797QkHfXd98E21ocytgVprI4DCdLyjfuw== X-Received: by 2002:a1c:2857:: with SMTP id o84mr5238166wmo.181.1615413747789; Wed, 10 Mar 2021 14:02:27 -0800 (PST) Received: from revest.zrh.corp.google.com ([2a00:79e0:42:204:e08c:1e90:4e6b:365a]) by smtp.gmail.com with ESMTPSA id y16sm699234wrh.3.2021.03.10.14.02.27 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 10 Mar 2021 14:02:27 -0800 (PST) From: Florent Revest To: bpf@vger.kernel.org Cc: ast@kernel.org, daniel@iogearbox.net, andrii@kernel.org, yhs@fb.com, kpsingh@kernel.org, jackmanb@chromium.org, linux-kernel@vger.kernel.org, Florent Revest Subject: [PATCH bpf-next 1/5] bpf: Add a ARG_PTR_TO_CONST_STR argument type Date: Wed, 10 Mar 2021 23:02:07 +0100 Message-Id: <20210310220211.1454516-2-revest@chromium.org> X-Mailer: git-send-email 2.30.1.766.gb4fecdf3b7-goog In-Reply-To: <20210310220211.1454516-1-revest@chromium.org> References: <20210310220211.1454516-1-revest@chromium.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: bpf@vger.kernel.org X-Patchwork-Delegate: bpf@iogearbox.net This type provides the guarantee that an argument is going to be a const pointer to somewhere in a read-only map value. It also checks that this pointer is followed by a NULL character before the end of the map value. Signed-off-by: Florent Revest Reported-by: kernel test robot Reported-by: kernel test robot --- include/linux/bpf.h | 1 + kernel/bpf/verifier.c | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index a25730eaa148..7b5319d75b3e 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -308,6 +308,7 @@ enum bpf_arg_type { ARG_PTR_TO_PERCPU_BTF_ID, /* pointer to in-kernel percpu type */ ARG_PTR_TO_FUNC, /* pointer to a bpf program function */ ARG_PTR_TO_STACK_OR_NULL, /* pointer to stack or NULL */ + ARG_PTR_TO_CONST_STR, /* pointer to a null terminated read-only string */ __BPF_ARG_TYPE_MAX, }; diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index f9096b049cd6..c99b2b67dc8d 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -4601,6 +4601,7 @@ static const struct bpf_reg_types spin_lock_types = { .types = { PTR_TO_MAP_VALU static const struct bpf_reg_types percpu_btf_ptr_types = { .types = { PTR_TO_PERCPU_BTF_ID } }; static const struct bpf_reg_types func_ptr_types = { .types = { PTR_TO_FUNC } }; static const struct bpf_reg_types stack_ptr_types = { .types = { PTR_TO_STACK } }; +static const struct bpf_reg_types const_str_ptr_types = { .types = { PTR_TO_MAP_VALUE } }; static const struct bpf_reg_types *compatible_reg_types[__BPF_ARG_TYPE_MAX] = { [ARG_PTR_TO_MAP_KEY] = &map_key_value_types, @@ -4631,6 +4632,7 @@ static const struct bpf_reg_types *compatible_reg_types[__BPF_ARG_TYPE_MAX] = { [ARG_PTR_TO_PERCPU_BTF_ID] = &percpu_btf_ptr_types, [ARG_PTR_TO_FUNC] = &func_ptr_types, [ARG_PTR_TO_STACK_OR_NULL] = &stack_ptr_types, + [ARG_PTR_TO_CONST_STR] = &const_str_ptr_types, }; static int check_reg_type(struct bpf_verifier_env *env, u32 regno, @@ -4881,6 +4883,45 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg, if (err) return err; err = check_ptr_alignment(env, reg, 0, size, true); + } else if (arg_type == ARG_PTR_TO_CONST_STR) { + struct bpf_map *map = reg->map_ptr; + int map_off, i; + u64 map_addr; + char *map_ptr; + + if (!map || !bpf_map_is_rdonly(map)) { + verbose(env, "R%d does not point to a readonly map'\n", regno); + return -EACCES; + } + + if (!tnum_is_const(reg->var_off)) { + verbose(env, "R%d is not a constant address'\n", regno); + return -EACCES; + } + + if (!map->ops->map_direct_value_addr) { + verbose(env, "no direct value access support for this map type\n"); + return -EACCES; + } + + err = check_helper_mem_access(env, regno, + map->value_size - reg->off, + false, meta); + if (err) + return err; + + map_off = reg->off + reg->var_off.value; + err = map->ops->map_direct_value_addr(map, &map_addr, map_off); + if (err) + return err; + + map_ptr = (char *)(map_addr); + for (i = map_off; map_ptr[i] != '\0'; i++) { + if (i == map->value_size - 1) { + verbose(env, "map does not contain a NULL-terminated string\n"); + return -EACCES; + } + } } return err; From patchwork Wed Mar 10 22:02:08 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florent Revest X-Patchwork-Id: 12129587 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 X-Spam-Level: X-Spam-Status: No, score=-19.0 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER,INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS, URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id E5197C433E6 for ; Wed, 10 Mar 2021 22:03:45 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id B489C64FD2 for ; Wed, 10 Mar 2021 22:03:45 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233801AbhCJWDO (ORCPT ); Wed, 10 Mar 2021 17:03:14 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45172 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234055AbhCJWCl (ORCPT ); Wed, 10 Mar 2021 17:02:41 -0500 Received: from mail-wr1-x42b.google.com (mail-wr1-x42b.google.com [IPv6:2a00:1450:4864:20::42b]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 9787CC061765 for ; Wed, 10 Mar 2021 14:02:31 -0800 (PST) Received: by mail-wr1-x42b.google.com with SMTP id h98so24984068wrh.11 for ; Wed, 10 Mar 2021 14:02:31 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=5Es0AexKvs5+khKMtAaBpvDUkgE/LO3Ums9bZgZDut8=; b=nZr7K5aVtBYC5lYJXrp1mCaeM4f6aDVH5sjejYluMn2iKMdxVJ0ZrDV3FSHwZ9j5yp zVeJpPsfKGQHSNW15yHrDa22bWB43FBl71uC78X1dyEjoZ2vsyCrQ1dGYhkWSefj1Kpi T7teA09RrIAqsR4loABMgKrRz+sNW6ZmKsw1E= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=5Es0AexKvs5+khKMtAaBpvDUkgE/LO3Ums9bZgZDut8=; b=k64GeXxrCdCRKzNW+7D+z0RNqTlBu5LjFY2rCQBLuqmA77ofxSZC6Ye+yEAU1X3Swc h8PzqruSxWbTVmIFFzsj1O1/8JW1zQfMOOkPFS8i+Ozz87fe/pw6sC/wn1f+Bo+2MUtS RsSXnBmkUYV6hyIZVpqUk2hp4cDB/zSe0IfVg7dj9rgq5RgdYxtqGwRCe8I5ZOO4ej+h XNZd2Flg+ziFGyB/4SUfBG8jrkY+EUD8Tgywi91qBQCBEDuwk/S5UPF3uyMzJeO8o5PK 6ymkM6Wh3DiI98rIj25bngKucpILmPTuaRV6V5N9hyS4doPqXmBazyugowIxEXE745cr Q0Vw== X-Gm-Message-State: AOAM530JvtnRzKeuC2JjHyJ+x0ZpKTeFhFZEWRi/Dd1p0oknQEg3g4Cq sgrMVdkI4Z122ly++XOzhNnV/NagpLYAYQ== X-Google-Smtp-Source: ABdhPJyITXTET0D7rYQI8CuuZCzNEGrJN21HJ/hMIAjqwpxqvoAt1MLC9ITeLE9NNHZQiEDc7mVQSQ== X-Received: by 2002:adf:8562:: with SMTP id 89mr5576981wrh.101.1615413748820; Wed, 10 Mar 2021 14:02:28 -0800 (PST) Received: from revest.zrh.corp.google.com ([2a00:79e0:42:204:e08c:1e90:4e6b:365a]) by smtp.gmail.com with ESMTPSA id y16sm699234wrh.3.2021.03.10.14.02.27 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 10 Mar 2021 14:02:28 -0800 (PST) From: Florent Revest To: bpf@vger.kernel.org Cc: ast@kernel.org, daniel@iogearbox.net, andrii@kernel.org, yhs@fb.com, kpsingh@kernel.org, jackmanb@chromium.org, linux-kernel@vger.kernel.org, Florent Revest Subject: [PATCH bpf-next 2/5] bpf: Add a bpf_snprintf helper Date: Wed, 10 Mar 2021 23:02:08 +0100 Message-Id: <20210310220211.1454516-3-revest@chromium.org> X-Mailer: git-send-email 2.30.1.766.gb4fecdf3b7-goog In-Reply-To: <20210310220211.1454516-1-revest@chromium.org> References: <20210310220211.1454516-1-revest@chromium.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: bpf@vger.kernel.org X-Patchwork-Delegate: bpf@iogearbox.net The implementation takes inspiration from the existing bpf_trace_printk helper but there are a few differences: To allow for a large number of format-specifiers, parameters are provided in an array, like in bpf_seq_printf. Because the output string takes two arguments and the array of parameters also takes two arguments, the format string needs to fit in one argument. But because ARG_PTR_TO_CONST_STR guarantees to point to a NULL-terminated read-only map, we don't need a format string length arg. Because the format-string is known at verification time, we also move most of the format string validation, currently done in formatting helper calls, into the verifier logic. This makes debugging easier and also slightly improves the runtime performance. Signed-off-by: Florent Revest Reported-by: kernel test robot Reported-by: kernel test robot --- include/linux/bpf.h | 4 + include/uapi/linux/bpf.h | 28 +++++++ kernel/bpf/verifier.c | 137 +++++++++++++++++++++++++++++++++ kernel/trace/bpf_trace.c | 110 ++++++++++++++++++++++++++ tools/include/uapi/linux/bpf.h | 28 +++++++ 5 files changed, 307 insertions(+) diff --git a/include/linux/bpf.h b/include/linux/bpf.h index 7b5319d75b3e..d78175c9a887 100644 --- a/include/linux/bpf.h +++ b/include/linux/bpf.h @@ -1902,6 +1902,10 @@ extern const struct bpf_func_proto bpf_task_storage_get_proto; extern const struct bpf_func_proto bpf_task_storage_delete_proto; extern const struct bpf_func_proto bpf_for_each_map_elem_proto; +#define MAX_SNPRINTF_VARARGS 12 +#define MAX_SNPRINTF_MEMCPY 6 +#define MAX_SNPRINTF_STR_LEN 128 + const struct bpf_func_proto *bpf_tracing_func_proto( enum bpf_func_id func_id, const struct bpf_prog *prog); diff --git a/include/uapi/linux/bpf.h b/include/uapi/linux/bpf.h index 2d3036e292a9..3cbdc8ae00e7 100644 --- a/include/uapi/linux/bpf.h +++ b/include/uapi/linux/bpf.h @@ -4660,6 +4660,33 @@ union bpf_attr { * Return * The number of traversed map elements for success, **-EINVAL** for * invalid **flags**. + * + * long bpf_snprintf(char *out, u32 out_size, const char *fmt, u64 *data, u32 data_len) + * Description + * Outputs a string into the **out** buffer of size **out_size** + * based on a format string stored in a read-only map pointed by + * **fmt**. + * + * Each format specifier in **fmt** corresponds to one u64 element + * in the **data** array. For strings and pointers where pointees + * are accessed, only the pointer values are stored in the *data* + * array. The *data_len* is the size of *data* in bytes. + * + * Formats **%s** and **%p{i,I}{4,6}** require to read kernel + * memory. Reading kernel memory may fail due to either invalid + * address or valid address but requiring a major memory fault. If + * reading kernel memory fails, the string for **%s** will be an + * empty string, and the ip address for **%p{i,I}{4,6}** will be 0. + * Not returning error to bpf program is consistent with what + * **bpf_trace_printk**\ () does for now. + * + * Return + * The strictly positive length of the printed string, including + * the trailing NUL character. If the return value is greater than + * **out_size**, **out** contains a truncated string, without a + * trailing NULL character. + * + * Or **-EBUSY** if the per-CPU memory copy buffer is busy. */ #define __BPF_FUNC_MAPPER(FN) \ FN(unspec), \ @@ -4827,6 +4854,7 @@ union bpf_attr { FN(sock_from_file), \ FN(check_mtu), \ FN(for_each_map_elem), \ + FN(snprintf), \ /* */ /* integer value in 'imm' field of BPF_CALL instruction selects which helper diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index c99b2b67dc8d..3ab549df817b 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -5732,6 +5732,137 @@ static int check_reference_leak(struct bpf_verifier_env *env) return state->acquired_refs ? -EINVAL : 0; } +int check_bpf_snprintf_call(struct bpf_verifier_env *env, + struct bpf_reg_state *regs) +{ + struct bpf_reg_state *fmt_reg = ®s[BPF_REG_3]; + struct bpf_reg_state *data_len_reg = ®s[BPF_REG_5]; + struct bpf_map *fmt_map = fmt_reg->map_ptr; + int err, fmt_map_off, i, fmt_cnt = 0, memcpy_cnt = 0, num_args; + u64 fmt_addr; + char *fmt; + + /* data must be an array of u64 so data_len must be a multiple of 8 */ + if (data_len_reg->var_off.value & 7) + return -EINVAL; + num_args = data_len_reg->var_off.value / 8; + + /* fmt being ARG_PTR_TO_CONST_STR guarantees that var_off is const + * and map_direct_value_addr is set. + */ + fmt_map_off = fmt_reg->off + fmt_reg->var_off.value; + err = fmt_map->ops->map_direct_value_addr(fmt_map, &fmt_addr, + fmt_map_off); + if (err) + return err; + fmt = (char *)fmt_addr; + + /* We are also guaranteed that fmt+fmt_map_off is NULL terminated, we + * can focus on validating the format specifiers. + */ + for (i = fmt_map_off; fmt[i] != '\0'; i++) { + if ((!isprint(fmt[i]) && !isspace(fmt[i])) || + !isascii(fmt[i])) { + verbose(env, "only printable ascii for now\n"); + return -EINVAL; + } + + if (fmt[i] != '%') + continue; + + if (fmt[i + 1] == '%') { + i++; + continue; + } + + if (fmt_cnt >= MAX_SNPRINTF_VARARGS) { + verbose(env, "too many format specifiers\n"); + return -E2BIG; + } + + if (fmt_cnt >= num_args) { + verbose(env, "not enough parameters to print\n"); + return -EINVAL; + } + + /* fmt[i] != 0 && fmt[last] == 0, so we can access fmt[i + 1] */ + i++; + + /* skip optional "[0 +-][num]" width formating field */ + while (fmt[i] == '0' || fmt[i] == '+' || fmt[i] == '-' || + fmt[i] == ' ') + i++; + if (fmt[i] >= '1' && fmt[i] <= '9') { + i++; + while (fmt[i] >= '0' && fmt[i] <= '9') + i++; + } + + if (fmt[i] == 's') { + if (memcpy_cnt >= MAX_SNPRINTF_MEMCPY) { + verbose(env, "too many buffer copies\n"); + return -E2BIG; + } + + fmt_cnt++; + memcpy_cnt++; + continue; + } + + if (fmt[i] == 'p') { + if (fmt[i + 1] == 0 || fmt[i + 1] == 'K' || + fmt[i + 1] == 'x' || fmt[i + 1] == 'B' || + fmt[i + 1] == 's' || fmt[i + 1] == 'S') { + fmt_cnt++; + continue; + } + + /* only support "%pI4", "%pi4", "%pI6" and "%pi6". */ + if (fmt[i + 1] != 'i' && fmt[i + 1] != 'I') { + verbose(env, "invalid specifier %%p%c\n", + fmt[i+1]); + return -EINVAL; + } + if (fmt[i + 2] != '4' && fmt[i + 2] != '6') { + verbose(env, "invalid specifier %%p%c%c\n", + fmt[i+1], fmt[i+2]); + return -EINVAL; + } + + if (memcpy_cnt >= MAX_SNPRINTF_MEMCPY) { + verbose(env, "too many buffer copies\n"); + return -E2BIG; + } + + i += 2; + fmt_cnt++; + memcpy_cnt++; + continue; + } + + if (fmt[i] == 'l') { + i++; + if (fmt[i] == 'l') + i++; + } + + if (fmt[i] != 'i' && fmt[i] != 'd' && fmt[i] != 'u' && + fmt[i] != 'x' && fmt[i] != 'X') { + verbose(env, "invalid format specifier %%%c\n", fmt[i]); + return -EINVAL; + } + + fmt_cnt++; + } + + if (fmt_cnt != num_args) { + verbose(env, "too many parameters to print\n"); + return -EINVAL; + } + + return 0; +} + static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn, int *insn_idx_p) { @@ -5846,6 +5977,12 @@ static int check_helper_call(struct bpf_verifier_env *env, struct bpf_insn *insn return -EINVAL; } + if (func_id == BPF_FUNC_snprintf) { + err = check_bpf_snprintf_call(env, regs); + if (err < 0) + return err; + } + /* reset caller saved regs */ for (i = 0; i < CALLER_SAVED_REGS; i++) { mark_reg_not_init(env, regs, caller_saved[i]); diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c index 0d23755c2747..7b80759c10a9 100644 --- a/kernel/trace/bpf_trace.c +++ b/kernel/trace/bpf_trace.c @@ -1271,6 +1271,114 @@ const struct bpf_func_proto bpf_snprintf_btf_proto = { .arg5_type = ARG_ANYTHING, }; +struct bpf_snprintf_buf { + char buf[MAX_SNPRINTF_MEMCPY][MAX_SNPRINTF_STR_LEN]; +}; +static DEFINE_PER_CPU(struct bpf_snprintf_buf, bpf_snprintf_buf); +static DEFINE_PER_CPU(int, bpf_snprintf_buf_used); + +BPF_CALL_5(bpf_snprintf, char *, out, u32, out_size, char *, fmt, u64 *, args, + u32, args_len) +{ + int err, i, buf_used, copy_size, fmt_cnt = 0, memcpy_cnt = 0; + u64 params[MAX_SNPRINTF_VARARGS]; + struct bpf_snprintf_buf *bufs; + + buf_used = this_cpu_inc_return(bpf_snprintf_buf_used); + if (WARN_ON_ONCE(buf_used > 1)) { + err = -EBUSY; + goto out; + } + + bufs = this_cpu_ptr(&bpf_snprintf_buf); + + /* + * The verifier has already done most of the heavy-work for us in + * check_bpf_snprintf_call. We know that fmt is well formatted and that + * args_len is valid. The only task left is to convert some of the + * arguments. For the %s and %pi* specifiers, we need to read buffers + * from a kernel address during the helper call. + */ + for (i = 0; fmt[i] != '\0'; i++) { + if (fmt[i] != '%') + continue; + + if (fmt[i + 1] == '%') { + i++; + continue; + } + + /* fmt[i] != 0 && fmt[last] == 0, so we can access fmt[i + 1] */ + i++; + + /* skip optional "[0 +-][num]" width formating field */ + while (fmt[i] == '0' || fmt[i] == '+' || fmt[i] == '-' || + fmt[i] == ' ') + i++; + if (fmt[i] >= '1' && fmt[i] <= '9') { + i++; + while (fmt[i] >= '0' && fmt[i] <= '9') + i++; + } + + if (fmt[i] == 's') { + void *unsafe_ptr = (void *)(long)args[fmt_cnt]; + + err = strncpy_from_kernel_nofault(bufs->buf[memcpy_cnt], + unsafe_ptr, + MAX_SNPRINTF_STR_LEN); + if (err < 0) + bufs->buf[memcpy_cnt][0] = '\0'; + params[fmt_cnt] = (u64)(long)bufs->buf[memcpy_cnt]; + + fmt_cnt++; + memcpy_cnt++; + continue; + } + + if (fmt[i] == 'p' && (fmt[i + 1] == 'i' || fmt[i + 1] == 'I')) { + copy_size = (fmt[i + 2] == '4') ? 4 : 16; + + err = copy_from_kernel_nofault(bufs->buf[memcpy_cnt], + (void *) (long) args[fmt_cnt], + copy_size); + if (err < 0) + memset(bufs->buf[memcpy_cnt], 0, copy_size); + params[fmt_cnt] = (u64)(long)bufs->buf[memcpy_cnt]; + + i += 2; + fmt_cnt++; + memcpy_cnt++; + continue; + } + + params[fmt_cnt] = args[fmt_cnt]; + fmt_cnt++; + } + + /* Maximumly we can have MAX_SNPRINTF_VARARGS parameters, just give + * all of them to snprintf(). + */ + err = snprintf(out, out_size, fmt, params[0], params[1], params[2], + params[3], params[4], params[5], params[6], params[7], + params[8], params[9], params[10], params[11]) + 1; + +out: + this_cpu_dec(bpf_snprintf_buf_used); + return err; +} + +static const struct bpf_func_proto bpf_snprintf_proto = { + .func = bpf_snprintf, + .gpl_only = true, + .ret_type = RET_INTEGER, + .arg1_type = ARG_PTR_TO_MEM, + .arg2_type = ARG_CONST_SIZE, + .arg3_type = ARG_PTR_TO_CONST_STR, + .arg4_type = ARG_PTR_TO_MEM, + .arg5_type = ARG_CONST_SIZE_OR_ZERO, +}; + const struct bpf_func_proto * bpf_tracing_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) { @@ -1373,6 +1481,8 @@ bpf_tracing_func_proto(enum bpf_func_id func_id, const struct bpf_prog *prog) return &bpf_task_storage_delete_proto; case BPF_FUNC_for_each_map_elem: return &bpf_for_each_map_elem_proto; + case BPF_FUNC_snprintf: + return &bpf_snprintf_proto; default: return NULL; } diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index 2d3036e292a9..3cbdc8ae00e7 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -4660,6 +4660,33 @@ union bpf_attr { * Return * The number of traversed map elements for success, **-EINVAL** for * invalid **flags**. + * + * long bpf_snprintf(char *out, u32 out_size, const char *fmt, u64 *data, u32 data_len) + * Description + * Outputs a string into the **out** buffer of size **out_size** + * based on a format string stored in a read-only map pointed by + * **fmt**. + * + * Each format specifier in **fmt** corresponds to one u64 element + * in the **data** array. For strings and pointers where pointees + * are accessed, only the pointer values are stored in the *data* + * array. The *data_len* is the size of *data* in bytes. + * + * Formats **%s** and **%p{i,I}{4,6}** require to read kernel + * memory. Reading kernel memory may fail due to either invalid + * address or valid address but requiring a major memory fault. If + * reading kernel memory fails, the string for **%s** will be an + * empty string, and the ip address for **%p{i,I}{4,6}** will be 0. + * Not returning error to bpf program is consistent with what + * **bpf_trace_printk**\ () does for now. + * + * Return + * The strictly positive length of the printed string, including + * the trailing NUL character. If the return value is greater than + * **out_size**, **out** contains a truncated string, without a + * trailing NULL character. + * + * Or **-EBUSY** if the per-CPU memory copy buffer is busy. */ #define __BPF_FUNC_MAPPER(FN) \ FN(unspec), \ @@ -4827,6 +4854,7 @@ union bpf_attr { FN(sock_from_file), \ FN(check_mtu), \ FN(for_each_map_elem), \ + FN(snprintf), \ /* */ /* integer value in 'imm' field of BPF_CALL instruction selects which helper From patchwork Wed Mar 10 22:02:09 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florent Revest X-Patchwork-Id: 12129579 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 X-Spam-Level: X-Spam-Status: No, score=-19.0 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER,INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS, URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 734FBC433DB for ; Wed, 10 Mar 2021 22:03:45 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 44E3664F42 for ; Wed, 10 Mar 2021 22:03:45 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234294AbhCJWDN (ORCPT ); Wed, 10 Mar 2021 17:03:13 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45150 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234355AbhCJWCg (ORCPT ); Wed, 10 Mar 2021 17:02:36 -0500 Received: from mail-wr1-x436.google.com (mail-wr1-x436.google.com [IPv6:2a00:1450:4864:20::436]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 705C5C061764 for ; Wed, 10 Mar 2021 14:02:31 -0800 (PST) Received: by mail-wr1-x436.google.com with SMTP id l11so21661473wrp.7 for ; Wed, 10 Mar 2021 14:02:31 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=BQ2hKQWhpJ/WTdKG9UWGdly9pe3CMhv89pfXyaQmgfE=; b=YhsFvX1QktFHIWBCy6YnZtuUwh/y9Vkf5pPz9uqPdkC55xYf3v7ff2d67tv52x/bo2 XFJR2svsqaTSYeQUOk+dnEj44wtY9uUjNHSXL7BK55ZFHhuB/HEToOG5uM9gc0VxPY4G y45qELB7GtbglYR6i+U8wM9UYYHCticWOwKBU= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=BQ2hKQWhpJ/WTdKG9UWGdly9pe3CMhv89pfXyaQmgfE=; b=roWLacGt6Ig/umSE8UebJFIjWVYS8tBlD26q82Zk9fvahdRwYV6rpcPz4L7JyMOmTX Ky9VtJd1O4imSeId/Pfimi67qPrfxt7lon0rwX9dj6tMsOy4f6NZT2GW3UAbd79Gzo3b YvDIb7CTGA3PYyPmmvoU33NN68LdPKbUxgvHIjRS3rf0PgCke6jKveWUElM+hHeg6img yLQgWj90CDoClW7l/UFoH4gVzwlP0blnZA7/mrkWPWJscvPJjjZ73/MjoTud5pvOu90J IAMX4witFSc2FRBY9TwyFX9ylm7NBt8ooAhdJcaB4+XAt7rAfUMO4qJ0m6eK8hISda7/ 9yJg== X-Gm-Message-State: AOAM530gvVf29Vh4LpgeXbsWxr3kzG7a7nZEvhtU1sxDTV0Qf367cIPU /2Z+Hb0jt8NWebIEDSFKJjhxvs1Hm8HyGQ== X-Google-Smtp-Source: ABdhPJyR3we1bikA48yPH7LSQyZ6ykyowWWr2CR5qm+5WfsA0mofpIB4dthmSTwirh+/fG0c0Geoeg== X-Received: by 2002:a5d:4b06:: with SMTP id v6mr5676166wrq.41.1615413749649; Wed, 10 Mar 2021 14:02:29 -0800 (PST) Received: from revest.zrh.corp.google.com ([2a00:79e0:42:204:e08c:1e90:4e6b:365a]) by smtp.gmail.com with ESMTPSA id y16sm699234wrh.3.2021.03.10.14.02.28 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 10 Mar 2021 14:02:29 -0800 (PST) From: Florent Revest To: bpf@vger.kernel.org Cc: ast@kernel.org, daniel@iogearbox.net, andrii@kernel.org, yhs@fb.com, kpsingh@kernel.org, jackmanb@chromium.org, linux-kernel@vger.kernel.org, Florent Revest Subject: [PATCH bpf-next 3/5] libbpf: Initialize the bpf_seq_printf parameters array field by field Date: Wed, 10 Mar 2021 23:02:09 +0100 Message-Id: <20210310220211.1454516-4-revest@chromium.org> X-Mailer: git-send-email 2.30.1.766.gb4fecdf3b7-goog In-Reply-To: <20210310220211.1454516-1-revest@chromium.org> References: <20210310220211.1454516-1-revest@chromium.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: bpf@vger.kernel.org X-Patchwork-Delegate: bpf@iogearbox.net When initializing the __param array with a one liner, if all args are const, the initial array value will be placed in the rodata section but because libbpf does not support relocation in the rodata section, any pointer in this array will stay NULL. This is a workaround, ideally the rodata relocation should be supported by libbpf but this would require a disproportionate amount of work given the actual usecases. (it is very unlikely that one uses a const array of relocated addresses) Signed-off-by: Florent Revest --- tools/lib/bpf/bpf_tracing.h | 30 +++++++++++++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/tools/lib/bpf/bpf_tracing.h b/tools/lib/bpf/bpf_tracing.h index f9ef37707888..f6a2deb3cd5b 100644 --- a/tools/lib/bpf/bpf_tracing.h +++ b/tools/lib/bpf/bpf_tracing.h @@ -413,6 +413,34 @@ typeof(name(0)) name(struct pt_regs *ctx) \ } \ static __always_inline typeof(name(0)) ____##name(struct pt_regs *ctx, ##args) +#define ___bpf_build_param0(narg, x) +#define ___bpf_build_param1(narg, x) ___param[narg - 1] = x +#define ___bpf_build_param2(narg, x, args...) ___param[narg - 2] = x; \ + ___bpf_build_param1(narg, args) +#define ___bpf_build_param3(narg, x, args...) ___param[narg - 3] = x; \ + ___bpf_build_param2(narg, args) +#define ___bpf_build_param4(narg, x, args...) ___param[narg - 4] = x; \ + ___bpf_build_param3(narg, args) +#define ___bpf_build_param5(narg, x, args...) ___param[narg - 5] = x; \ + ___bpf_build_param4(narg, args) +#define ___bpf_build_param6(narg, x, args...) ___param[narg - 6] = x; \ + ___bpf_build_param5(narg, args) +#define ___bpf_build_param7(narg, x, args...) ___param[narg - 7] = x; \ + ___bpf_build_param6(narg, args) +#define ___bpf_build_param8(narg, x, args...) ___param[narg - 8] = x; \ + ___bpf_build_param7(narg, args) +#define ___bpf_build_param9(narg, x, args...) ___param[narg - 9] = x; \ + ___bpf_build_param8(narg, args) +#define ___bpf_build_param10(narg, x, args...) ___param[narg - 10] = x; \ + ___bpf_build_param9(narg, args) +#define ___bpf_build_param11(narg, x, args...) ___param[narg - 11] = x; \ + ___bpf_build_param10(narg, args) +#define ___bpf_build_param12(narg, x, args...) ___param[narg - 12] = x; \ + ___bpf_build_param11(narg, args) +#define ___bpf_build_param(args...) \ + unsigned long long ___param[___bpf_narg(args)]; \ + ___bpf_apply(___bpf_build_param, ___bpf_narg(args))(___bpf_narg(args), args) + /* * BPF_SEQ_PRINTF to wrap bpf_seq_printf to-be-printed values * in a structure. @@ -422,7 +450,7 @@ static __always_inline typeof(name(0)) ____##name(struct pt_regs *ctx, ##args) _Pragma("GCC diagnostic push") \ _Pragma("GCC diagnostic ignored \"-Wint-conversion\"") \ static const char ___fmt[] = fmt; \ - unsigned long long ___param[] = { args }; \ + ___bpf_build_param(args); \ _Pragma("GCC diagnostic pop") \ int ___ret = bpf_seq_printf(seq, ___fmt, sizeof(___fmt), \ ___param, sizeof(___param)); \ From patchwork Wed Mar 10 22:02:10 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florent Revest X-Patchwork-Id: 12129581 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 X-Spam-Level: X-Spam-Status: No, score=-19.0 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER,INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS, URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id D135AC433E0 for ; Wed, 10 Mar 2021 22:03:45 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id 9ED7364F42 for ; Wed, 10 Mar 2021 22:03:45 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232536AbhCJWDO (ORCPT ); Wed, 10 Mar 2021 17:03:14 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45178 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234202AbhCJWCm (ORCPT ); Wed, 10 Mar 2021 17:02:42 -0500 Received: from mail-wr1-x42b.google.com (mail-wr1-x42b.google.com [IPv6:2a00:1450:4864:20::42b]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 21F0EC0613D8 for ; Wed, 10 Mar 2021 14:02:32 -0800 (PST) Received: by mail-wr1-x42b.google.com with SMTP id a18so25009188wrc.13 for ; Wed, 10 Mar 2021 14:02:32 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=JPXJZO7MToUvf4q+MCl8l3dLahahtNLVnU5sI9beblw=; b=NLYx5TphKj9sRLeVfLuFQrvYg3epOz+xFbTZFuwZs3r433Qw/RdxeKFjteTUEAMBi1 aGej6L8jUSdppH+eygN6vpyU8vEPzh33SzaLT7vCE3WFMspGhJuSe2OOSArZ/mU7EE+a isXrj4JZn0M2b/3EtXQ4QGwTRySKfNw9y7smg= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=JPXJZO7MToUvf4q+MCl8l3dLahahtNLVnU5sI9beblw=; b=q4ZFq/t1pE5RKAr0l0oh1YaNy4++ltg0fLKMOjg/r+5r67NNg5pcbLXQeffnlakNOP LUt2O0lujmS2olQCQvkc6TKXyvNqE9AexOxwl26+AHpc6CLcQx0gBSRtdH1E72lrUtCk 03YIc71dSFXNRWr1hBBjDt+6y5o7E9XK6fPGwoAEIWM4tCh5KMJDBG4eaXEvGec7iqbo 1ORykpAZE5FXq+AaS9jVoiSoGEi1fMM3IjRTMCRJEQm5CYVzTV1MulwN/FkK0RXYQAy1 etW99W3EoIbLqyvEFvWhLJviaqAXHAUeyH8TBLqOZ6XoXb1sc1QoNT9gXuCqsy+Re2h7 +sKw== X-Gm-Message-State: AOAM5336YxY5Qd/jwz6wmS9ack9C4+XraZZgsPOepos/IjLTE9ixIOzQ SPzqqZJ5OBE3Ch8XRBxDgp4uNI0BAV9W2g== X-Google-Smtp-Source: ABdhPJwuPfFDGCTxE9brofNXk2DcargQP8ONxDJUt9MQUP7V0CwVDtkM1/xVW0D8lV+5TBiZFDdZpg== X-Received: by 2002:adf:a2c2:: with SMTP id t2mr5516389wra.47.1615413750578; Wed, 10 Mar 2021 14:02:30 -0800 (PST) Received: from revest.zrh.corp.google.com ([2a00:79e0:42:204:e08c:1e90:4e6b:365a]) by smtp.gmail.com with ESMTPSA id y16sm699234wrh.3.2021.03.10.14.02.29 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 10 Mar 2021 14:02:30 -0800 (PST) From: Florent Revest To: bpf@vger.kernel.org Cc: ast@kernel.org, daniel@iogearbox.net, andrii@kernel.org, yhs@fb.com, kpsingh@kernel.org, jackmanb@chromium.org, linux-kernel@vger.kernel.org, Florent Revest Subject: [PATCH bpf-next 4/5] libbpf: Introduce a BPF_SNPRINTF helper macro Date: Wed, 10 Mar 2021 23:02:10 +0100 Message-Id: <20210310220211.1454516-5-revest@chromium.org> X-Mailer: git-send-email 2.30.1.766.gb4fecdf3b7-goog In-Reply-To: <20210310220211.1454516-1-revest@chromium.org> References: <20210310220211.1454516-1-revest@chromium.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: bpf@vger.kernel.org X-Patchwork-Delegate: bpf@iogearbox.net Similarly to BPF_SEQ_PRINTF, this macro turns variadic arguments into an array of u64, making it more natural to call the bpf_snprintf helper. Signed-off-by: Florent Revest --- tools/lib/bpf/bpf_tracing.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tools/lib/bpf/bpf_tracing.h b/tools/lib/bpf/bpf_tracing.h index f6a2deb3cd5b..89e82da9b8a0 100644 --- a/tools/lib/bpf/bpf_tracing.h +++ b/tools/lib/bpf/bpf_tracing.h @@ -457,4 +457,19 @@ static __always_inline typeof(name(0)) ____##name(struct pt_regs *ctx, ##args) ___ret; \ }) +/* + * BPF_SNPRINTF wraps the bpf_snprintf helper with variadic arguments instead of + * an array of u64. + */ +#define BPF_SNPRINTF(out, out_size, fmt, args...) \ + ({ \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wint-conversion\"") \ + ___bpf_build_param(args); \ + _Pragma("GCC diagnostic pop") \ + int ___ret = bpf_snprintf(out, out_size, fmt, \ + ___param, sizeof(___param)); \ + ___ret; \ + }) + #endif From patchwork Wed Mar 10 22:02:11 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Florent Revest X-Patchwork-Id: 12129585 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 X-Spam-Level: X-Spam-Status: No, score=-19.0 required=3.0 tests=BAYES_00,DKIMWL_WL_HIGH, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER,INCLUDES_PATCH,MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS, URIBL_BLOCKED,USER_AGENT_GIT autolearn=ham autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 240CDC4332D for ; Wed, 10 Mar 2021 22:03:46 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by mail.kernel.org (Postfix) with ESMTP id E828A64FD4 for ; Wed, 10 Mar 2021 22:03:45 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234212AbhCJWDP (ORCPT ); Wed, 10 Mar 2021 17:03:15 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:45148 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234271AbhCJWCr (ORCPT ); Wed, 10 Mar 2021 17:02:47 -0500 Received: from mail-wr1-x42d.google.com (mail-wr1-x42d.google.com [IPv6:2a00:1450:4864:20::42d]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id DD9F2C0613DA for ; Wed, 10 Mar 2021 14:02:32 -0800 (PST) Received: by mail-wr1-x42d.google.com with SMTP id l11so21661533wrp.7 for ; Wed, 10 Mar 2021 14:02:32 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=chromium.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=kvULu6wQqvVvCSIiS2jIB0soaoJgdRgxlx9E1MVIok4=; b=kG+dofg6FiOzD4Z7qcCs1lAynZh6scqcZVq1/t9JhKvXAUtP2itqsrkWoCVzq2ZCKK 4qb2mmx1Fc6cmP25PLk1GBcGwELkPwTSWcVQeoXtbVEQcuRIez9BF61z1ohpeDocFJK9 NQMFEiS07rRtFx96nvFwXDnXe8n64k5UzQej0= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=kvULu6wQqvVvCSIiS2jIB0soaoJgdRgxlx9E1MVIok4=; b=S/zHX1/QewXnUsm55UQiU21ZND77SOvRCcMMpelB1fbmDII5iwZw29ftM3bQALpXpz rYgYnvQ2KmdUVjNjldLO0qwj7I1JC0ZjGmvStHCVhWGHG+MICy98P+qf2K+dsvLteEDh XK26DKmjb2dA2+fz9/j5MNtw1gOzklqY796khtOvqL1d2ILkfH/3+Rl7YedXLKfyJ3XG ya1W3JAymCcbKm758I1aMi/+VVpsRyPUcC0+pehFGPrkf3rqDAb4Ir36bYS7grxuM4cX Ix7O/KgLqddd5ASp4V1+rTdTqpYSh39mAYQu7uYWW9JhEgpaj3525D2fcxtZQFeK8ChO /14Q== X-Gm-Message-State: AOAM5307yghzuNhOBGC2Y0nqhYTv8G/cWkNY7mRf2WVBfnCErMTYujgv RyweMjfW+tqacluj5hbQn3VN0INRUlSMLQ== X-Google-Smtp-Source: ABdhPJyeu1V5+w5viGBt4njm65B0BKluUNYql60eGXK3hOj1b/IsJgt4+NSAuEW9eY7K/wKFa7hNog== X-Received: by 2002:adf:e441:: with SMTP id t1mr5507996wrm.21.1615413751375; Wed, 10 Mar 2021 14:02:31 -0800 (PST) Received: from revest.zrh.corp.google.com ([2a00:79e0:42:204:e08c:1e90:4e6b:365a]) by smtp.gmail.com with ESMTPSA id y16sm699234wrh.3.2021.03.10.14.02.30 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 10 Mar 2021 14:02:31 -0800 (PST) From: Florent Revest To: bpf@vger.kernel.org Cc: ast@kernel.org, daniel@iogearbox.net, andrii@kernel.org, yhs@fb.com, kpsingh@kernel.org, jackmanb@chromium.org, linux-kernel@vger.kernel.org, Florent Revest Subject: [PATCH bpf-next 5/5] selftests/bpf: Add a series of tests for bpf_snprintf Date: Wed, 10 Mar 2021 23:02:11 +0100 Message-Id: <20210310220211.1454516-6-revest@chromium.org> X-Mailer: git-send-email 2.30.1.766.gb4fecdf3b7-goog In-Reply-To: <20210310220211.1454516-1-revest@chromium.org> References: <20210310220211.1454516-1-revest@chromium.org> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: bpf@vger.kernel.org X-Patchwork-Delegate: bpf@iogearbox.net This exercices most of the format specifiers when things go well. Signed-off-by: Florent Revest --- .../selftests/bpf/prog_tests/snprintf.c | 71 +++++++++++++++++++ .../selftests/bpf/progs/test_snprintf.c | 71 +++++++++++++++++++ 2 files changed, 142 insertions(+) create mode 100644 tools/testing/selftests/bpf/prog_tests/snprintf.c create mode 100644 tools/testing/selftests/bpf/progs/test_snprintf.c diff --git a/tools/testing/selftests/bpf/prog_tests/snprintf.c b/tools/testing/selftests/bpf/prog_tests/snprintf.c new file mode 100644 index 000000000000..23af1dbd1eeb --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/snprintf.c @@ -0,0 +1,71 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2021 Google LLC. */ + +#include +#include "test_snprintf.skel.h" + +static int duration; + +#define EXP_NUM_OUT "-8 9 96 -424242 1337 DABBAD00" +#define EXP_NUM_RET sizeof(EXP_NUM_OUT) + +#define EXP_IP_OUT "127.000.000.001 0000:0000:0000:0000:0000:0000:0000:0001" +#define EXP_IP_RET sizeof(EXP_IP_OUT) + +/* The third specifier, %pB, depends on compiler inlining so don't check it */ +#define EXP_SYM_OUT "schedule schedule+0x0/" +#define MIN_SYM_RET sizeof(EXP_SYM_OUT) + +/* The third specifier, %p, is a hashed pointer which changes on every reboot */ +#define EXP_ADDR_OUT "0000000000000000 ffff00000add4e55 " +#define EXP_ADDR_RET sizeof(EXP_ADDR_OUT "unknownhashedptr") + +#define EXP_STR_OUT "str1 longstr" +#define EXP_STR_RET sizeof(EXP_STR_OUT) + +#define EXP_OVER_OUT {'%', 'o', 'v', 'e', 'r'} +#define EXP_OVER_RET 10 + +void test_snprintf(void) +{ + char exp_addr_out[] = EXP_ADDR_OUT; + char exp_over_out[] = EXP_OVER_OUT; + char exp_sym_out[] = EXP_SYM_OUT; + struct test_snprintf *skel; + int err; + + skel = test_snprintf__open_and_load(); + if (CHECK(!skel, "skel_open", "failed to open and load skeleton\n")) + return; + + err = test_snprintf__attach(skel); + if (CHECK(err, "skel_attach", "skeleton attach failed: %d\n", err)) + goto cleanup; + + /* trigger tracepoint */ + usleep(1); + + ASSERT_STREQ(skel->bss->num_out, EXP_NUM_OUT, "num_out"); + ASSERT_EQ(skel->bss->num_ret, EXP_NUM_RET, "num_ret"); + + ASSERT_STREQ(skel->bss->ip_out, EXP_IP_OUT, "ip_out"); + ASSERT_EQ(skel->bss->ip_ret, EXP_IP_RET, "ip_ret"); + + ASSERT_OK(memcmp(skel->bss->sym_out, exp_sym_out, + sizeof(exp_sym_out) - 1), "sym_out"); + ASSERT_LT(MIN_SYM_RET, skel->bss->sym_ret, "sym_ret"); + + ASSERT_OK(memcmp(skel->bss->addr_out, exp_addr_out, + sizeof(exp_addr_out) - 1), "addr_out"); + ASSERT_EQ(skel->bss->addr_ret, EXP_ADDR_RET, "addr_ret"); + + ASSERT_STREQ(skel->bss->str_out, EXP_STR_OUT, "str_out"); + ASSERT_EQ(skel->bss->str_ret, EXP_STR_RET, "str_ret"); + + ASSERT_OK(memcmp(skel->bss->over_out, exp_over_out, + sizeof(exp_over_out)), "over_out"); + ASSERT_EQ(skel->bss->over_ret, EXP_OVER_RET, "over_ret"); + +cleanup: + test_snprintf__destroy(skel); +} diff --git a/tools/testing/selftests/bpf/progs/test_snprintf.c b/tools/testing/selftests/bpf/progs/test_snprintf.c new file mode 100644 index 000000000000..6c8aa4988e69 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/test_snprintf.c @@ -0,0 +1,71 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright (c) 2021 Google LLC. */ + +#include +#include +#include +#include + +#define OUT_LEN 64 + +/* Integer types */ +static const char num_fmt[] = "%d %u %x %li %llu %lX"; +#define NUMBERS -8, 9, 150, -424242, 1337, 0xDABBAD00 + +char num_out[OUT_LEN] = {}; +long num_ret = 0; + +/* IP addresses */ +static const char ip_fmt[] = "%pi4 %pI6"; +static const __u8 dummy_ipv4[] = {127, 0, 0, 1}; /* 127.0.0.1 */ +static const __u32 dummy_ipv6[] = {0, 0, 0, bpf_htonl(1)}; /* ::1/128 */ +#define IPS &dummy_ipv4, &dummy_ipv6 + +char ip_out[OUT_LEN] = {}; +long ip_ret = 0; + +/* Symbol lookup formatting */ +static const char sym_fmt[] = "%ps %pS %pB"; +extern const void schedule __ksym; +#define SYMBOLS &schedule, &schedule, &schedule + +char sym_out[OUT_LEN] = {}; +long sym_ret = 0; + +/* Kernel pointers */ +static const char addr_fmt[] = "%pK %px %p"; +#define ADDRESSES 0, 0xFFFF00000ADD4E55, 0xFFFF00000ADD4E55 + +char addr_out[OUT_LEN] = {}; +long addr_ret = 0; + +/* Strings embedding */ +static const char str_fmt[] = "%s %+05s"; +static const char str1[] = "str1"; +static const char longstr[] = "longstr"; +#define STRINGS str1, longstr + +char str_out[OUT_LEN] = {}; +long str_ret = 0; + +/* Overflow */ +static const char over_fmt[] = "%%overflow"; + +#define OVER_OUT_LEN 6 +char over_out[OVER_OUT_LEN] = {}; +long over_ret = 0; + +SEC("raw_tp/sys_enter") +int handler(const void *ctx) +{ + num_ret = BPF_SNPRINTF(num_out, OUT_LEN, num_fmt, NUMBERS); + ip_ret = BPF_SNPRINTF(ip_out, OUT_LEN, ip_fmt, IPS); + sym_ret = BPF_SNPRINTF(sym_out, OUT_LEN, sym_fmt, SYMBOLS); + addr_ret = BPF_SNPRINTF(addr_out, OUT_LEN, addr_fmt, ADDRESSES); + str_ret = BPF_SNPRINTF(str_out, OUT_LEN, str_fmt, STRINGS); + over_ret = BPF_SNPRINTF(over_out, OVER_OUT_LEN, over_fmt); + + return 0; +} + +char _license[] SEC("license") = "GPL";