Commit 13e3c779 authored by Jakub Kicinski's avatar Jakub Kicinski

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.netSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 68bb1010 f506439e
...@@ -34,13 +34,12 @@ bpf_sk_storage_get() ...@@ -34,13 +34,12 @@ bpf_sk_storage_get()
void *bpf_sk_storage_get(struct bpf_map *map, void *sk, void *value, u64 flags) 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()`` Socket-local storage for ``map`` can be retrieved from socket ``sk`` using the
helper. The helper gets the storage from ``sk`` that is associated with ``map``. ``bpf_sk_storage_get()`` helper. If the ``BPF_LOCAL_STORAGE_GET_F_CREATE``
If the ``BPF_LOCAL_STORAGE_GET_F_CREATE`` flag is used then flag is used then ``bpf_sk_storage_get()`` will create the storage for ``sk``
``bpf_sk_storage_get()`` will create the storage for ``sk`` if it does not if it does not already exist. ``value`` can be used together with
already exist. ``value`` can be used together with ``BPF_LOCAL_STORAGE_GET_F_CREATE`` to initialize the storage value, otherwise
``BPF_LOCAL_STORAGE_GET_F_CREATE`` to initialize the storage value, otherwise it it will be zero initialized. Returns a pointer to the storage on success, or
will be zero initialized. Returns a pointer to the storage on success, or
``NULL`` in case of failure. ``NULL`` in case of failure.
.. note:: .. note::
...@@ -54,9 +53,9 @@ bpf_sk_storage_delete() ...@@ -54,9 +53,9 @@ bpf_sk_storage_delete()
long bpf_sk_storage_delete(struct bpf_map *map, void *sk) long bpf_sk_storage_delete(struct bpf_map *map, void *sk)
Socket-local storage can be deleted using the ``bpf_sk_storage_delete()`` Socket-local storage for ``map`` can be deleted from socket ``sk`` using the
helper. The helper deletes the storage from ``sk`` that is identified by ``bpf_sk_storage_delete()`` helper. Returns ``0`` on success, or negative
``map``. Returns ``0`` on success, or negative error in case of failure. error in case of failure.
User space User space
---------- ----------
...@@ -68,16 +67,20 @@ bpf_map_update_elem() ...@@ -68,16 +67,20 @@ bpf_map_update_elem()
int bpf_map_update_elem(int map_fd, const void *key, const void *value, __u64 flags) 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 Socket-local storage for map ``map_fd`` can be added or updated locally to a
``map_fd`` can be added or updated using the ``bpf_map_update_elem()`` libbpf socket using the ``bpf_map_update_elem()`` libbpf function. The socket is
function. ``key`` must be a pointer to a valid ``fd`` in the user space identified by a `socket` ``fd`` stored in the pointer ``key``. The pointer
program. The ``flags`` parameter can be used to control the update behaviour: ``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. The ``flags`` parameter can be used to control the update behaviour:
- ``BPF_NOEXIST`` will create storage for ``fd`` only if it did not already
exist, otherwise the call will fail with ``-EEXIST``. - ``BPF_ANY`` will create storage for `socket` ``fd`` or update existing storage.
- ``BPF_EXIST`` will update existing storage for ``fd`` if it already exists, - ``BPF_NOEXIST`` will create storage for `socket` ``fd`` only if it did not
otherwise the call will fail with ``-ENOENT``. 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. Returns ``0`` on success, or negative error in case of failure.
...@@ -88,10 +91,10 @@ bpf_map_lookup_elem() ...@@ -88,10 +91,10 @@ bpf_map_lookup_elem()
int bpf_map_lookup_elem(int map_fd, const void *key, void *value) int bpf_map_lookup_elem(int map_fd, const void *key, void *value)
Socket-local storage for the socket identified by ``key`` belonging to Socket-local storage for map ``map_fd`` can be retrieved from a socket using
``map_fd`` can be retrieved using the ``bpf_map_lookup_elem()`` libbpf the ``bpf_map_lookup_elem()`` libbpf function. The storage is retrieved from
function. ``key`` must be a pointer to a valid ``fd`` in the user space the socket identified by a `socket` ``fd`` stored in the pointer
program. Returns ``0`` on success, or negative error in case of failure. ``key``. Returns ``0`` on success, or negative error in case of failure.
bpf_map_delete_elem() bpf_map_delete_elem()
~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~
...@@ -100,9 +103,10 @@ bpf_map_delete_elem() ...@@ -100,9 +103,10 @@ bpf_map_delete_elem()
int bpf_map_delete_elem(int map_fd, const void *key) int bpf_map_delete_elem(int map_fd, const void *key)
Socket-local storage for the socket identified by ``key`` belonging to Socket-local storage for map ``map_fd`` can be deleted from a socket using the
``map_fd`` can be deleted using the ``bpf_map_delete_elem()`` libbpf ``bpf_map_delete_elem()`` libbpf function. The storage is deleted from the
function. Returns ``0`` on success, or negative error in case of failure. socket identified by a `socket` ``fd`` stored in the pointer ``key``. Returns
``0`` on success, or negative error in case of failure.
Examples Examples
======== ========
......
...@@ -2092,6 +2092,7 @@ static unsigned int __bpf_prog_ret0_warn(const void *ctx, ...@@ -2092,6 +2092,7 @@ static unsigned int __bpf_prog_ret0_warn(const void *ctx,
bool bpf_prog_map_compatible(struct bpf_map *map, bool bpf_prog_map_compatible(struct bpf_map *map,
const struct bpf_prog *fp) const struct bpf_prog *fp)
{ {
enum bpf_prog_type prog_type = resolve_prog_type(fp);
bool ret; bool ret;
if (fp->kprobe_override) if (fp->kprobe_override)
...@@ -2102,12 +2103,12 @@ bool bpf_prog_map_compatible(struct bpf_map *map, ...@@ -2102,12 +2103,12 @@ bool bpf_prog_map_compatible(struct bpf_map *map,
/* There's no owner yet where we could check for /* There's no owner yet where we could check for
* compatibility. * compatibility.
*/ */
map->owner.type = fp->type; map->owner.type = prog_type;
map->owner.jited = fp->jited; map->owner.jited = fp->jited;
map->owner.xdp_has_frags = fp->aux->xdp_has_frags; map->owner.xdp_has_frags = fp->aux->xdp_has_frags;
ret = true; ret = true;
} else { } else {
ret = map->owner.type == fp->type && ret = map->owner.type == prog_type &&
map->owner.jited == fp->jited && map->owner.jited == fp->jited &&
map->owner.xdp_has_frags == fp->aux->xdp_has_frags; 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) ...@@ -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); __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) if (new)
d->image_off = noff; d->image_off = noff;
} }
......
...@@ -3518,9 +3518,9 @@ static int bpf_prog_attach(const union bpf_attr *attr) ...@@ -3518,9 +3518,9 @@ static int bpf_prog_attach(const union bpf_attr *attr)
case BPF_PROG_TYPE_LSM: case BPF_PROG_TYPE_LSM:
if (ptype == BPF_PROG_TYPE_LSM && if (ptype == BPF_PROG_TYPE_LSM &&
prog->expected_attach_type != BPF_LSM_CGROUP) prog->expected_attach_type != BPF_LSM_CGROUP)
return -EINVAL; ret = -EINVAL;
else
ret = cgroup_bpf_prog_attach(attr, ptype, prog); ret = cgroup_bpf_prog_attach(attr, ptype, prog);
break; break;
default: default:
ret = -EINVAL; ret = -EINVAL;
......
...@@ -16,6 +16,7 @@ CONFIG_CRYPTO_USER_API_HASH=y ...@@ -16,6 +16,7 @@ CONFIG_CRYPTO_USER_API_HASH=y
CONFIG_DYNAMIC_FTRACE=y CONFIG_DYNAMIC_FTRACE=y
CONFIG_FPROBE=y CONFIG_FPROBE=y
CONFIG_FTRACE_SYSCALLS=y CONFIG_FTRACE_SYSCALLS=y
CONFIG_FUNCTION_ERROR_INJECTION=y
CONFIG_FUNCTION_TRACER=y CONFIG_FUNCTION_TRACER=y
CONFIG_GENEVE=y CONFIG_GENEVE=y
CONFIG_IKCONFIG=y CONFIG_IKCONFIG=y
......
...@@ -4,6 +4,8 @@ ...@@ -4,6 +4,8 @@
#include <network_helpers.h> #include <network_helpers.h>
#include <bpf/btf.h> #include <bpf/btf.h>
#include "bind4_prog.skel.h" #include "bind4_prog.skel.h"
#include "freplace_progmap.skel.h"
#include "xdp_dummy.skel.h"
typedef int (*test_cb)(struct bpf_object *obj); typedef int (*test_cb)(struct bpf_object *obj);
...@@ -500,6 +502,50 @@ static void test_fentry_to_cgroup_bpf(void) ...@@ -500,6 +502,50 @@ static void test_fentry_to_cgroup_bpf(void)
bind4_prog__destroy(skel); 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 */ /* NOTE: affect other tests, must run in serial mode */
void serial_test_fexit_bpf2bpf(void) void serial_test_fexit_bpf2bpf(void)
{ {
...@@ -525,4 +571,6 @@ void serial_test_fexit_bpf2bpf(void) ...@@ -525,4 +571,6 @@ void serial_test_fexit_bpf2bpf(void)
test_func_replace_global_func(); test_func_replace_global_func();
if (test__start_subtest("fentry_to_cgroup_bpf")) if (test__start_subtest("fentry_to_cgroup_bpf"))
test_fentry_to_cgroup_bpf(); test_fentry_to_cgroup_bpf();
if (test__start_subtest("func_replace_progmap"))
test_func_replace_progmap();
} }
// 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 @@ int nested_rcu_region(void *ctx) ...@@ -288,13 +288,13 @@ int nested_rcu_region(void *ctx)
SEC("?fentry.s/" SYS_PREFIX "sys_getpgid") SEC("?fentry.s/" SYS_PREFIX "sys_getpgid")
int task_untrusted_non_rcuptr(void *ctx) 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(); task = bpf_get_current_task_btf();
bpf_rcu_read_lock(); bpf_rcu_read_lock();
/* the pointer last_wakee marked as untrusted */ /* the pointer group_leader marked as untrusted */
last_wakee = task->real_parent->last_wakee; group_leader = task->real_parent->group_leader;
(void)bpf_task_storage_get(&map_a, last_wakee, 0, 0); (void)bpf_task_storage_get(&map_a, group_leader, 0, 0);
bpf_rcu_read_unlock(); bpf_rcu_read_unlock();
return 0; return 0;
} }
......
...@@ -73,7 +73,7 @@ int BPF_PROG(task_kfunc_acquire_trusted_walked, struct task_struct *task, u64 cl ...@@ -73,7 +73,7 @@ int BPF_PROG(task_kfunc_acquire_trusted_walked, struct task_struct *task, u64 cl
struct task_struct *acquired; struct task_struct *acquired;
/* Can't invoke bpf_task_acquire() on a trusted pointer obtained from walking a struct. */ /* 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); bpf_task_release(acquired);
return 0; return 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment