mirror of
https://github.com/torvalds/linux.git
synced 2024-11-23 12:42:02 +00:00
bpf-for-netdev
-----BEGIN PGP SIGNATURE----- iHUEABYIAB0WIQTFp0I1jqZrAX+hPRXbK58LschIgwUCY5yc9AAKCRDbK58LschI g3n4AP4heagqBHPH+WcC0N/Vc4K2dmPmil4ZTuZ/Xt+EMrX0MQEAygWsa272V2C9 vx51DOu5/D+DPC20/1+mRpEnC4JIqAA= =utn+ -----END PGP SIGNATURE----- Merge tag 'for-netdev' of https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf Daniel Borkmann says: ==================== pull-request: bpf 2022-12-16 We've added 7 non-merge commits during the last 2 day(s) which contain a total of 9 files changed, 119 insertions(+), 36 deletions(-). 1) Fix for recent syzkaller XDP dispatcher update splat, from Jiri Olsa. 2) Fix BPF program refcount leak in LSM attachment failure path, from Milan Landaverde. 3) Fix BPF program type in map compatibility check for fext, from Toke Høiland-Jørgensen. 4) Fix a BPF selftest compilation error under !CONFIG_SMP config, from Yonghong Song. 5) Fix CI to enable CONFIG_FUNCTION_ERROR_INJECTION after it got changed to a prompt, from Song Liu. 6) Various BPF documentation fixes for socket local storage, from Donald Hunter. * tag 'for-netdev' of https://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf: selftests/bpf: Add a test for using a cpumap from an freplace-to-XDP program bpf: Resolve fext program type when checking map compatibility bpf: Synchronize dispatcher update with bpf_dispatcher_xdp_func bpf: prevent leak of lsm program after failed attach selftests/bpf: Select CONFIG_FUNCTION_ERROR_INJECTION selftests/bpf: Fix a selftest compilation error with CONFIG_SMP=n docs/bpf: Reword docs for BPF_MAP_TYPE_SK_STORAGE ==================== Link: https://lore.kernel.org/r/20221216174540.16598-1-daniel@iogearbox.net Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
13e3c7793e
@ -34,13 +34,12 @@ bpf_sk_storage_get()
|
||||
|
||||
void *bpf_sk_storage_get(struct bpf_map *map, void *sk, void *value, u64 flags)
|
||||
|
||||
Socket-local storage can be retrieved using the ``bpf_sk_storage_get()``
|
||||
helper. The helper gets the storage from ``sk`` that is associated with ``map``.
|
||||
If the ``BPF_LOCAL_STORAGE_GET_F_CREATE`` flag is used then
|
||||
``bpf_sk_storage_get()`` will create the storage for ``sk`` if it does not
|
||||
already exist. ``value`` can be used together with
|
||||
``BPF_LOCAL_STORAGE_GET_F_CREATE`` to initialize the storage value, otherwise it
|
||||
will be zero initialized. Returns a pointer to the storage on success, or
|
||||
Socket-local storage for ``map`` can be retrieved from socket ``sk`` using the
|
||||
``bpf_sk_storage_get()`` helper. If the ``BPF_LOCAL_STORAGE_GET_F_CREATE``
|
||||
flag is used then ``bpf_sk_storage_get()`` will create the storage for ``sk``
|
||||
if it does not already exist. ``value`` can be used together with
|
||||
``BPF_LOCAL_STORAGE_GET_F_CREATE`` to initialize the storage value, otherwise
|
||||
it will be zero initialized. Returns a pointer to the storage on success, or
|
||||
``NULL`` in case of failure.
|
||||
|
||||
.. note::
|
||||
@ -54,9 +53,9 @@ bpf_sk_storage_delete()
|
||||
|
||||
long bpf_sk_storage_delete(struct bpf_map *map, void *sk)
|
||||
|
||||
Socket-local storage can be deleted using the ``bpf_sk_storage_delete()``
|
||||
helper. The helper deletes the storage from ``sk`` that is identified by
|
||||
``map``. Returns ``0`` on success, or negative error in case of failure.
|
||||
Socket-local storage for ``map`` can be deleted from socket ``sk`` using the
|
||||
``bpf_sk_storage_delete()`` helper. Returns ``0`` on success, or negative
|
||||
error in case of failure.
|
||||
|
||||
User space
|
||||
----------
|
||||
@ -68,16 +67,20 @@ bpf_map_update_elem()
|
||||
|
||||
int bpf_map_update_elem(int map_fd, const void *key, const void *value, __u64 flags)
|
||||
|
||||
Socket-local storage for the socket identified by ``key`` belonging to
|
||||
``map_fd`` can be added or updated using the ``bpf_map_update_elem()`` libbpf
|
||||
function. ``key`` must be a pointer to a valid ``fd`` in the user space
|
||||
program. The ``flags`` parameter can be used to control the update behaviour:
|
||||
Socket-local storage for map ``map_fd`` can be added or updated locally to a
|
||||
socket using the ``bpf_map_update_elem()`` libbpf function. The socket is
|
||||
identified by a `socket` ``fd`` stored in the pointer ``key``. The pointer
|
||||
``value`` has the data to be added or updated to the socket ``fd``. The type
|
||||
and size of ``value`` should be the same as the value type of the map
|
||||
definition.
|
||||
|
||||
- ``BPF_ANY`` will create storage for ``fd`` or update existing storage.
|
||||
- ``BPF_NOEXIST`` will create storage for ``fd`` only if it did not already
|
||||
exist, otherwise the call will fail with ``-EEXIST``.
|
||||
- ``BPF_EXIST`` will update existing storage for ``fd`` if it already exists,
|
||||
otherwise the call will fail with ``-ENOENT``.
|
||||
The ``flags`` parameter can be used to control the update behaviour:
|
||||
|
||||
- ``BPF_ANY`` will create storage for `socket` ``fd`` or update existing storage.
|
||||
- ``BPF_NOEXIST`` will create storage for `socket` ``fd`` only if it did not
|
||||
already exist, otherwise the call will fail with ``-EEXIST``.
|
||||
- ``BPF_EXIST`` will update existing storage for `socket` ``fd`` if it already
|
||||
exists, otherwise the call will fail with ``-ENOENT``.
|
||||
|
||||
Returns ``0`` on success, or negative error in case of failure.
|
||||
|
||||
@ -88,10 +91,10 @@ bpf_map_lookup_elem()
|
||||
|
||||
int bpf_map_lookup_elem(int map_fd, const void *key, void *value)
|
||||
|
||||
Socket-local storage for the socket identified by ``key`` belonging to
|
||||
``map_fd`` can be retrieved using the ``bpf_map_lookup_elem()`` libbpf
|
||||
function. ``key`` must be a pointer to a valid ``fd`` in the user space
|
||||
program. Returns ``0`` on success, or negative error in case of failure.
|
||||
Socket-local storage for map ``map_fd`` can be retrieved from a socket using
|
||||
the ``bpf_map_lookup_elem()`` libbpf function. The storage is retrieved from
|
||||
the socket identified by a `socket` ``fd`` stored in the pointer
|
||||
``key``. Returns ``0`` on success, or negative error in case of failure.
|
||||
|
||||
bpf_map_delete_elem()
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
@ -100,9 +103,10 @@ bpf_map_delete_elem()
|
||||
|
||||
int bpf_map_delete_elem(int map_fd, const void *key)
|
||||
|
||||
Socket-local storage for the socket identified by ``key`` belonging to
|
||||
``map_fd`` can be deleted using the ``bpf_map_delete_elem()`` libbpf
|
||||
function. Returns ``0`` on success, or negative error in case of failure.
|
||||
Socket-local storage for map ``map_fd`` can be deleted from a socket using the
|
||||
``bpf_map_delete_elem()`` libbpf function. The storage is deleted from the
|
||||
socket identified by a `socket` ``fd`` stored in the pointer ``key``. Returns
|
||||
``0`` on success, or negative error in case of failure.
|
||||
|
||||
Examples
|
||||
========
|
||||
|
@ -2092,6 +2092,7 @@ static unsigned int __bpf_prog_ret0_warn(const void *ctx,
|
||||
bool bpf_prog_map_compatible(struct bpf_map *map,
|
||||
const struct bpf_prog *fp)
|
||||
{
|
||||
enum bpf_prog_type prog_type = resolve_prog_type(fp);
|
||||
bool ret;
|
||||
|
||||
if (fp->kprobe_override)
|
||||
@ -2102,12 +2103,12 @@ bool bpf_prog_map_compatible(struct bpf_map *map,
|
||||
/* There's no owner yet where we could check for
|
||||
* compatibility.
|
||||
*/
|
||||
map->owner.type = fp->type;
|
||||
map->owner.type = prog_type;
|
||||
map->owner.jited = fp->jited;
|
||||
map->owner.xdp_has_frags = fp->aux->xdp_has_frags;
|
||||
ret = true;
|
||||
} else {
|
||||
ret = map->owner.type == fp->type &&
|
||||
ret = map->owner.type == prog_type &&
|
||||
map->owner.jited == fp->jited &&
|
||||
map->owner.xdp_has_frags == fp->aux->xdp_has_frags;
|
||||
}
|
||||
|
@ -125,6 +125,11 @@ static void bpf_dispatcher_update(struct bpf_dispatcher *d, int prev_num_progs)
|
||||
|
||||
__BPF_DISPATCHER_UPDATE(d, new ?: (void *)&bpf_dispatcher_nop_func);
|
||||
|
||||
/* Make sure all the callers executing the previous/old half of the
|
||||
* image leave it, so following update call can modify it safely.
|
||||
*/
|
||||
synchronize_rcu();
|
||||
|
||||
if (new)
|
||||
d->image_off = noff;
|
||||
}
|
||||
|
@ -3518,9 +3518,9 @@ static int bpf_prog_attach(const union bpf_attr *attr)
|
||||
case BPF_PROG_TYPE_LSM:
|
||||
if (ptype == BPF_PROG_TYPE_LSM &&
|
||||
prog->expected_attach_type != BPF_LSM_CGROUP)
|
||||
return -EINVAL;
|
||||
|
||||
ret = cgroup_bpf_prog_attach(attr, ptype, prog);
|
||||
ret = -EINVAL;
|
||||
else
|
||||
ret = cgroup_bpf_prog_attach(attr, ptype, prog);
|
||||
break;
|
||||
default:
|
||||
ret = -EINVAL;
|
||||
|
@ -16,6 +16,7 @@ CONFIG_CRYPTO_USER_API_HASH=y
|
||||
CONFIG_DYNAMIC_FTRACE=y
|
||||
CONFIG_FPROBE=y
|
||||
CONFIG_FTRACE_SYSCALLS=y
|
||||
CONFIG_FUNCTION_ERROR_INJECTION=y
|
||||
CONFIG_FUNCTION_TRACER=y
|
||||
CONFIG_GENEVE=y
|
||||
CONFIG_IKCONFIG=y
|
||||
|
@ -4,6 +4,8 @@
|
||||
#include <network_helpers.h>
|
||||
#include <bpf/btf.h>
|
||||
#include "bind4_prog.skel.h"
|
||||
#include "freplace_progmap.skel.h"
|
||||
#include "xdp_dummy.skel.h"
|
||||
|
||||
typedef int (*test_cb)(struct bpf_object *obj);
|
||||
|
||||
@ -500,6 +502,50 @@ cleanup:
|
||||
bind4_prog__destroy(skel);
|
||||
}
|
||||
|
||||
static void test_func_replace_progmap(void)
|
||||
{
|
||||
struct bpf_cpumap_val value = { .qsize = 1 };
|
||||
struct freplace_progmap *skel = NULL;
|
||||
struct xdp_dummy *tgt_skel = NULL;
|
||||
__u32 key = 0;
|
||||
int err;
|
||||
|
||||
skel = freplace_progmap__open();
|
||||
if (!ASSERT_OK_PTR(skel, "prog_open"))
|
||||
return;
|
||||
|
||||
tgt_skel = xdp_dummy__open_and_load();
|
||||
if (!ASSERT_OK_PTR(tgt_skel, "tgt_prog_load"))
|
||||
goto out;
|
||||
|
||||
err = bpf_program__set_attach_target(skel->progs.xdp_cpumap_prog,
|
||||
bpf_program__fd(tgt_skel->progs.xdp_dummy_prog),
|
||||
"xdp_dummy_prog");
|
||||
if (!ASSERT_OK(err, "set_attach_target"))
|
||||
goto out;
|
||||
|
||||
err = freplace_progmap__load(skel);
|
||||
if (!ASSERT_OK(err, "obj_load"))
|
||||
goto out;
|
||||
|
||||
/* Prior to fixing the kernel, loading the PROG_TYPE_EXT 'redirect'
|
||||
* program above will cause the map owner type of 'cpumap' to be set to
|
||||
* PROG_TYPE_EXT. This in turn will cause the bpf_map_update_elem()
|
||||
* below to fail, because the program we are inserting into the map is
|
||||
* of PROG_TYPE_XDP. After fixing the kernel, the initial ownership will
|
||||
* be correctly resolved to the *target* of the PROG_TYPE_EXT program
|
||||
* (i.e., PROG_TYPE_XDP) and the map update will succeed.
|
||||
*/
|
||||
value.bpf_prog.fd = bpf_program__fd(skel->progs.xdp_drop_prog);
|
||||
err = bpf_map_update_elem(bpf_map__fd(skel->maps.cpu_map),
|
||||
&key, &value, 0);
|
||||
ASSERT_OK(err, "map_update");
|
||||
|
||||
out:
|
||||
xdp_dummy__destroy(tgt_skel);
|
||||
freplace_progmap__destroy(skel);
|
||||
}
|
||||
|
||||
/* NOTE: affect other tests, must run in serial mode */
|
||||
void serial_test_fexit_bpf2bpf(void)
|
||||
{
|
||||
@ -525,4 +571,6 @@ void serial_test_fexit_bpf2bpf(void)
|
||||
test_func_replace_global_func();
|
||||
if (test__start_subtest("fentry_to_cgroup_bpf"))
|
||||
test_fentry_to_cgroup_bpf();
|
||||
if (test__start_subtest("func_replace_progmap"))
|
||||
test_func_replace_progmap();
|
||||
}
|
||||
|
24
tools/testing/selftests/bpf/progs/freplace_progmap.c
Normal file
24
tools/testing/selftests/bpf/progs/freplace_progmap.c
Normal file
@ -0,0 +1,24 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
#include <linux/bpf.h>
|
||||
#include <bpf/bpf_helpers.h>
|
||||
|
||||
struct {
|
||||
__uint(type, BPF_MAP_TYPE_CPUMAP);
|
||||
__type(key, __u32);
|
||||
__type(value, struct bpf_cpumap_val);
|
||||
__uint(max_entries, 1);
|
||||
} cpu_map SEC(".maps");
|
||||
|
||||
SEC("xdp/cpumap")
|
||||
int xdp_drop_prog(struct xdp_md *ctx)
|
||||
{
|
||||
return XDP_DROP;
|
||||
}
|
||||
|
||||
SEC("freplace")
|
||||
int xdp_cpumap_prog(struct xdp_md *ctx)
|
||||
{
|
||||
return bpf_redirect_map(&cpu_map, 0, XDP_PASS);
|
||||
}
|
||||
|
||||
char _license[] SEC("license") = "GPL";
|
@ -288,13 +288,13 @@ out:
|
||||
SEC("?fentry.s/" SYS_PREFIX "sys_getpgid")
|
||||
int task_untrusted_non_rcuptr(void *ctx)
|
||||
{
|
||||
struct task_struct *task, *last_wakee;
|
||||
struct task_struct *task, *group_leader;
|
||||
|
||||
task = bpf_get_current_task_btf();
|
||||
bpf_rcu_read_lock();
|
||||
/* the pointer last_wakee marked as untrusted */
|
||||
last_wakee = task->real_parent->last_wakee;
|
||||
(void)bpf_task_storage_get(&map_a, last_wakee, 0, 0);
|
||||
/* the pointer group_leader marked as untrusted */
|
||||
group_leader = task->real_parent->group_leader;
|
||||
(void)bpf_task_storage_get(&map_a, group_leader, 0, 0);
|
||||
bpf_rcu_read_unlock();
|
||||
return 0;
|
||||
}
|
||||
|
@ -73,7 +73,7 @@ int BPF_PROG(task_kfunc_acquire_trusted_walked, struct task_struct *task, u64 cl
|
||||
struct task_struct *acquired;
|
||||
|
||||
/* Can't invoke bpf_task_acquire() on a trusted pointer obtained from walking a struct. */
|
||||
acquired = bpf_task_acquire(task->last_wakee);
|
||||
acquired = bpf_task_acquire(task->group_leader);
|
||||
bpf_task_release(acquired);
|
||||
|
||||
return 0;
|
||||
|
Loading…
Reference in New Issue
Block a user