2018-10-18 13:16:25 +00:00
|
|
|
// SPDX-License-Identifier: GPL-2.0
|
|
|
|
/*
|
|
|
|
* queue_stack_maps.c: BPF queue and stack maps
|
|
|
|
*
|
|
|
|
* Copyright (c) 2018 Politecnico di Torino
|
|
|
|
*/
|
|
|
|
#include <linux/bpf.h>
|
|
|
|
#include <linux/list.h>
|
|
|
|
#include <linux/slab.h>
|
2022-04-25 13:32:47 +00:00
|
|
|
#include <linux/btf_ids.h>
|
2018-10-18 13:16:25 +00:00
|
|
|
#include "percpu_freelist.h"
|
|
|
|
|
|
|
|
#define QUEUE_STACK_CREATE_FLAG_MASK \
|
bpf: add program side {rd, wr}only support for maps
This work adds two new map creation flags BPF_F_RDONLY_PROG
and BPF_F_WRONLY_PROG in order to allow for read-only or
write-only BPF maps from a BPF program side.
Today we have BPF_F_RDONLY and BPF_F_WRONLY, but this only
applies to system call side, meaning the BPF program has full
read/write access to the map as usual while bpf(2) calls with
map fd can either only read or write into the map depending
on the flags. BPF_F_RDONLY_PROG and BPF_F_WRONLY_PROG allows
for the exact opposite such that verifier is going to reject
program loads if write into a read-only map or a read into a
write-only map is detected. For read-only map case also some
helpers are forbidden for programs that would alter the map
state such as map deletion, update, etc. As opposed to the two
BPF_F_RDONLY / BPF_F_WRONLY flags, BPF_F_RDONLY_PROG as well
as BPF_F_WRONLY_PROG really do correspond to the map lifetime.
We've enabled this generic map extension to various non-special
maps holding normal user data: array, hash, lru, lpm, local
storage, queue and stack. Further generic map types could be
followed up in future depending on use-case. Main use case
here is to forbid writes into .rodata map values from verifier
side.
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Martin KaFai Lau <kafai@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2019-04-09 21:20:05 +00:00
|
|
|
(BPF_F_NUMA_NODE | BPF_F_ACCESS_MASK)
|
2018-10-18 13:16:25 +00:00
|
|
|
|
|
|
|
struct bpf_queue_stack {
|
|
|
|
struct bpf_map map;
|
|
|
|
raw_spinlock_t lock;
|
|
|
|
u32 head, tail;
|
|
|
|
u32 size; /* max_entries + 1 */
|
|
|
|
|
bpf, libbpf: Replace zero-length array with flexible-array
The current codebase makes use of the zero-length array language
extension to the C90 standard, but the preferred mechanism to declare
variable-length types such as these ones is a flexible array member[1][2],
introduced in C99:
struct foo {
int stuff;
struct boo array[];
};
By making use of the mechanism above, we will get a compiler warning
in case the flexible array does not occur last in the structure, which
will help us prevent some kind of undefined behavior bugs from being
inadvertently introduced[3] to the codebase from now on.
Also, notice that, dynamic memory allocations won't be affected by
this change:
"Flexible array members have incomplete type, and so the sizeof operator
may not be applied. As a quirk of the original implementation of
zero-length arrays, sizeof evaluates to zero."[1]
sizeof(flexible-array-member) triggers a warning because flexible array
members have incomplete type[1]. There are some instances of code in
which the sizeof operator is being incorrectly/erroneously applied to
zero-length arrays and the result is zero. Such instances may be hiding
some bugs. So, this work (flexible-array member conversions) will also
help to get completely rid of those sorts of issues.
This issue was found with the help of Coccinelle.
[1] https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html
[2] https://github.com/KSPP/linux/issues/21
[3] commit 76497732932f ("cxgb3/l2t: Fix undefined behaviour")
Signed-off-by: Gustavo A. R. Silva <gustavoars@kernel.org>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Yonghong Song <yhs@fb.com>
Link: https://lore.kernel.org/bpf/20200507185057.GA13981@embeddedor
2020-05-07 18:50:57 +00:00
|
|
|
char elements[] __aligned(8);
|
2018-10-18 13:16:25 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static struct bpf_queue_stack *bpf_queue_stack(struct bpf_map *map)
|
|
|
|
{
|
|
|
|
return container_of(map, struct bpf_queue_stack, map);
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool queue_stack_map_is_empty(struct bpf_queue_stack *qs)
|
|
|
|
{
|
|
|
|
return qs->head == qs->tail;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool queue_stack_map_is_full(struct bpf_queue_stack *qs)
|
|
|
|
{
|
|
|
|
u32 head = qs->head + 1;
|
|
|
|
|
|
|
|
if (unlikely(head >= qs->size))
|
|
|
|
head = 0;
|
|
|
|
|
|
|
|
return head == qs->tail;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Called from syscall */
|
|
|
|
static int queue_stack_map_alloc_check(union bpf_attr *attr)
|
|
|
|
{
|
|
|
|
/* check sanity of attributes */
|
|
|
|
if (attr->max_entries == 0 || attr->key_size != 0 ||
|
2018-11-22 18:49:56 +00:00
|
|
|
attr->value_size == 0 ||
|
bpf: add program side {rd, wr}only support for maps
This work adds two new map creation flags BPF_F_RDONLY_PROG
and BPF_F_WRONLY_PROG in order to allow for read-only or
write-only BPF maps from a BPF program side.
Today we have BPF_F_RDONLY and BPF_F_WRONLY, but this only
applies to system call side, meaning the BPF program has full
read/write access to the map as usual while bpf(2) calls with
map fd can either only read or write into the map depending
on the flags. BPF_F_RDONLY_PROG and BPF_F_WRONLY_PROG allows
for the exact opposite such that verifier is going to reject
program loads if write into a read-only map or a read into a
write-only map is detected. For read-only map case also some
helpers are forbidden for programs that would alter the map
state such as map deletion, update, etc. As opposed to the two
BPF_F_RDONLY / BPF_F_WRONLY flags, BPF_F_RDONLY_PROG as well
as BPF_F_WRONLY_PROG really do correspond to the map lifetime.
We've enabled this generic map extension to various non-special
maps holding normal user data: array, hash, lru, lpm, local
storage, queue and stack. Further generic map types could be
followed up in future depending on use-case. Main use case
here is to forbid writes into .rodata map values from verifier
side.
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Martin KaFai Lau <kafai@fb.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2019-04-09 21:20:05 +00:00
|
|
|
attr->map_flags & ~QUEUE_STACK_CREATE_FLAG_MASK ||
|
|
|
|
!bpf_map_flags_access_ok(attr->map_flags))
|
2018-10-18 13:16:25 +00:00
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
if (attr->value_size > KMALLOC_MAX_SIZE)
|
|
|
|
/* if value_size is bigger, the user space won't be able to
|
|
|
|
* access the elements.
|
|
|
|
*/
|
|
|
|
return -E2BIG;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct bpf_map *queue_stack_map_alloc(union bpf_attr *attr)
|
|
|
|
{
|
2020-12-01 21:58:51 +00:00
|
|
|
int numa_node = bpf_map_attr_numa_node(attr);
|
2018-10-18 13:16:25 +00:00
|
|
|
struct bpf_queue_stack *qs;
|
2020-12-01 21:58:51 +00:00
|
|
|
u64 size, queue_size;
|
2018-10-18 13:16:25 +00:00
|
|
|
|
2018-11-22 18:49:56 +00:00
|
|
|
size = (u64) attr->max_entries + 1;
|
2020-12-01 21:58:51 +00:00
|
|
|
queue_size = sizeof(*qs) + size * attr->value_size;
|
2018-10-18 13:16:25 +00:00
|
|
|
|
|
|
|
qs = bpf_map_area_alloc(queue_size, numa_node);
|
2020-12-01 21:58:51 +00:00
|
|
|
if (!qs)
|
2018-10-18 13:16:25 +00:00
|
|
|
return ERR_PTR(-ENOMEM);
|
|
|
|
|
|
|
|
bpf_map_init_from_attr(&qs->map, attr);
|
|
|
|
|
|
|
|
qs->size = size;
|
|
|
|
|
|
|
|
raw_spin_lock_init(&qs->lock);
|
|
|
|
|
|
|
|
return &qs->map;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Called when map->refcnt goes to zero, either from workqueue or from syscall */
|
|
|
|
static void queue_stack_map_free(struct bpf_map *map)
|
|
|
|
{
|
|
|
|
struct bpf_queue_stack *qs = bpf_queue_stack(map);
|
|
|
|
|
|
|
|
bpf_map_area_free(qs);
|
|
|
|
}
|
|
|
|
|
bpf: return long from bpf_map_ops funcs
This patch changes the return types of bpf_map_ops functions to long, where
previously int was returned. Using long allows for bpf programs to maintain
the sign bit in the absence of sign extension during situations where
inlined bpf helper funcs make calls to the bpf_map_ops funcs and a negative
error is returned.
The definitions of the helper funcs are generated from comments in the bpf
uapi header at `include/uapi/linux/bpf.h`. The return type of these
helpers was previously changed from int to long in commit bdb7b79b4ce8. For
any case where one of the map helpers call the bpf_map_ops funcs that are
still returning 32-bit int, a compiler might not include sign extension
instructions to properly convert the 32-bit negative value a 64-bit
negative value.
For example:
bpf assembly excerpt of an inlined helper calling a kernel function and
checking for a specific error:
; err = bpf_map_update_elem(&mymap, &key, &val, BPF_NOEXIST);
...
46: call 0xffffffffe103291c ; htab_map_update_elem
; if (err && err != -EEXIST) {
4b: cmp $0xffffffffffffffef,%rax ; cmp -EEXIST,%rax
kernel function assembly excerpt of return value from
`htab_map_update_elem` returning 32-bit int:
movl $0xffffffef, %r9d
...
movl %r9d, %eax
...results in the comparison:
cmp $0xffffffffffffffef, $0x00000000ffffffef
Fixes: bdb7b79b4ce8 ("bpf: Switch most helper return values from 32-bit int to 64-bit long")
Tested-by: Eduard Zingerman <eddyz87@gmail.com>
Signed-off-by: JP Kobryn <inwardvessel@gmail.com>
Link: https://lore.kernel.org/r/20230322194754.185781-3-inwardvessel@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2023-03-22 19:47:54 +00:00
|
|
|
static long __queue_map_get(struct bpf_map *map, void *value, bool delete)
|
2018-10-18 13:16:25 +00:00
|
|
|
{
|
|
|
|
struct bpf_queue_stack *qs = bpf_queue_stack(map);
|
|
|
|
unsigned long flags;
|
|
|
|
int err = 0;
|
|
|
|
void *ptr;
|
|
|
|
|
2023-09-11 13:28:14 +00:00
|
|
|
if (in_nmi()) {
|
|
|
|
if (!raw_spin_trylock_irqsave(&qs->lock, flags))
|
|
|
|
return -EBUSY;
|
|
|
|
} else {
|
|
|
|
raw_spin_lock_irqsave(&qs->lock, flags);
|
|
|
|
}
|
2018-10-18 13:16:25 +00:00
|
|
|
|
|
|
|
if (queue_stack_map_is_empty(qs)) {
|
2018-10-24 20:05:48 +00:00
|
|
|
memset(value, 0, qs->map.value_size);
|
2018-10-18 13:16:25 +00:00
|
|
|
err = -ENOENT;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
ptr = &qs->elements[qs->tail * qs->map.value_size];
|
|
|
|
memcpy(value, ptr, qs->map.value_size);
|
|
|
|
|
|
|
|
if (delete) {
|
|
|
|
if (unlikely(++qs->tail >= qs->size))
|
|
|
|
qs->tail = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
|
|
|
raw_spin_unlock_irqrestore(&qs->lock, flags);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
bpf: return long from bpf_map_ops funcs
This patch changes the return types of bpf_map_ops functions to long, where
previously int was returned. Using long allows for bpf programs to maintain
the sign bit in the absence of sign extension during situations where
inlined bpf helper funcs make calls to the bpf_map_ops funcs and a negative
error is returned.
The definitions of the helper funcs are generated from comments in the bpf
uapi header at `include/uapi/linux/bpf.h`. The return type of these
helpers was previously changed from int to long in commit bdb7b79b4ce8. For
any case where one of the map helpers call the bpf_map_ops funcs that are
still returning 32-bit int, a compiler might not include sign extension
instructions to properly convert the 32-bit negative value a 64-bit
negative value.
For example:
bpf assembly excerpt of an inlined helper calling a kernel function and
checking for a specific error:
; err = bpf_map_update_elem(&mymap, &key, &val, BPF_NOEXIST);
...
46: call 0xffffffffe103291c ; htab_map_update_elem
; if (err && err != -EEXIST) {
4b: cmp $0xffffffffffffffef,%rax ; cmp -EEXIST,%rax
kernel function assembly excerpt of return value from
`htab_map_update_elem` returning 32-bit int:
movl $0xffffffef, %r9d
...
movl %r9d, %eax
...results in the comparison:
cmp $0xffffffffffffffef, $0x00000000ffffffef
Fixes: bdb7b79b4ce8 ("bpf: Switch most helper return values from 32-bit int to 64-bit long")
Tested-by: Eduard Zingerman <eddyz87@gmail.com>
Signed-off-by: JP Kobryn <inwardvessel@gmail.com>
Link: https://lore.kernel.org/r/20230322194754.185781-3-inwardvessel@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2023-03-22 19:47:54 +00:00
|
|
|
static long __stack_map_get(struct bpf_map *map, void *value, bool delete)
|
2018-10-18 13:16:25 +00:00
|
|
|
{
|
|
|
|
struct bpf_queue_stack *qs = bpf_queue_stack(map);
|
|
|
|
unsigned long flags;
|
|
|
|
int err = 0;
|
|
|
|
void *ptr;
|
|
|
|
u32 index;
|
|
|
|
|
2023-09-11 13:28:14 +00:00
|
|
|
if (in_nmi()) {
|
|
|
|
if (!raw_spin_trylock_irqsave(&qs->lock, flags))
|
|
|
|
return -EBUSY;
|
|
|
|
} else {
|
|
|
|
raw_spin_lock_irqsave(&qs->lock, flags);
|
|
|
|
}
|
2018-10-18 13:16:25 +00:00
|
|
|
|
|
|
|
if (queue_stack_map_is_empty(qs)) {
|
2018-10-24 20:05:48 +00:00
|
|
|
memset(value, 0, qs->map.value_size);
|
2018-10-18 13:16:25 +00:00
|
|
|
err = -ENOENT;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
index = qs->head - 1;
|
|
|
|
if (unlikely(index >= qs->size))
|
|
|
|
index = qs->size - 1;
|
|
|
|
|
|
|
|
ptr = &qs->elements[index * qs->map.value_size];
|
|
|
|
memcpy(value, ptr, qs->map.value_size);
|
|
|
|
|
|
|
|
if (delete)
|
|
|
|
qs->head = index;
|
|
|
|
|
|
|
|
out:
|
|
|
|
raw_spin_unlock_irqrestore(&qs->lock, flags);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Called from syscall or from eBPF program */
|
bpf: return long from bpf_map_ops funcs
This patch changes the return types of bpf_map_ops functions to long, where
previously int was returned. Using long allows for bpf programs to maintain
the sign bit in the absence of sign extension during situations where
inlined bpf helper funcs make calls to the bpf_map_ops funcs and a negative
error is returned.
The definitions of the helper funcs are generated from comments in the bpf
uapi header at `include/uapi/linux/bpf.h`. The return type of these
helpers was previously changed from int to long in commit bdb7b79b4ce8. For
any case where one of the map helpers call the bpf_map_ops funcs that are
still returning 32-bit int, a compiler might not include sign extension
instructions to properly convert the 32-bit negative value a 64-bit
negative value.
For example:
bpf assembly excerpt of an inlined helper calling a kernel function and
checking for a specific error:
; err = bpf_map_update_elem(&mymap, &key, &val, BPF_NOEXIST);
...
46: call 0xffffffffe103291c ; htab_map_update_elem
; if (err && err != -EEXIST) {
4b: cmp $0xffffffffffffffef,%rax ; cmp -EEXIST,%rax
kernel function assembly excerpt of return value from
`htab_map_update_elem` returning 32-bit int:
movl $0xffffffef, %r9d
...
movl %r9d, %eax
...results in the comparison:
cmp $0xffffffffffffffef, $0x00000000ffffffef
Fixes: bdb7b79b4ce8 ("bpf: Switch most helper return values from 32-bit int to 64-bit long")
Tested-by: Eduard Zingerman <eddyz87@gmail.com>
Signed-off-by: JP Kobryn <inwardvessel@gmail.com>
Link: https://lore.kernel.org/r/20230322194754.185781-3-inwardvessel@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2023-03-22 19:47:54 +00:00
|
|
|
static long queue_map_peek_elem(struct bpf_map *map, void *value)
|
2018-10-18 13:16:25 +00:00
|
|
|
{
|
|
|
|
return __queue_map_get(map, value, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Called from syscall or from eBPF program */
|
bpf: return long from bpf_map_ops funcs
This patch changes the return types of bpf_map_ops functions to long, where
previously int was returned. Using long allows for bpf programs to maintain
the sign bit in the absence of sign extension during situations where
inlined bpf helper funcs make calls to the bpf_map_ops funcs and a negative
error is returned.
The definitions of the helper funcs are generated from comments in the bpf
uapi header at `include/uapi/linux/bpf.h`. The return type of these
helpers was previously changed from int to long in commit bdb7b79b4ce8. For
any case where one of the map helpers call the bpf_map_ops funcs that are
still returning 32-bit int, a compiler might not include sign extension
instructions to properly convert the 32-bit negative value a 64-bit
negative value.
For example:
bpf assembly excerpt of an inlined helper calling a kernel function and
checking for a specific error:
; err = bpf_map_update_elem(&mymap, &key, &val, BPF_NOEXIST);
...
46: call 0xffffffffe103291c ; htab_map_update_elem
; if (err && err != -EEXIST) {
4b: cmp $0xffffffffffffffef,%rax ; cmp -EEXIST,%rax
kernel function assembly excerpt of return value from
`htab_map_update_elem` returning 32-bit int:
movl $0xffffffef, %r9d
...
movl %r9d, %eax
...results in the comparison:
cmp $0xffffffffffffffef, $0x00000000ffffffef
Fixes: bdb7b79b4ce8 ("bpf: Switch most helper return values from 32-bit int to 64-bit long")
Tested-by: Eduard Zingerman <eddyz87@gmail.com>
Signed-off-by: JP Kobryn <inwardvessel@gmail.com>
Link: https://lore.kernel.org/r/20230322194754.185781-3-inwardvessel@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2023-03-22 19:47:54 +00:00
|
|
|
static long stack_map_peek_elem(struct bpf_map *map, void *value)
|
2018-10-18 13:16:25 +00:00
|
|
|
{
|
|
|
|
return __stack_map_get(map, value, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Called from syscall or from eBPF program */
|
bpf: return long from bpf_map_ops funcs
This patch changes the return types of bpf_map_ops functions to long, where
previously int was returned. Using long allows for bpf programs to maintain
the sign bit in the absence of sign extension during situations where
inlined bpf helper funcs make calls to the bpf_map_ops funcs and a negative
error is returned.
The definitions of the helper funcs are generated from comments in the bpf
uapi header at `include/uapi/linux/bpf.h`. The return type of these
helpers was previously changed from int to long in commit bdb7b79b4ce8. For
any case where one of the map helpers call the bpf_map_ops funcs that are
still returning 32-bit int, a compiler might not include sign extension
instructions to properly convert the 32-bit negative value a 64-bit
negative value.
For example:
bpf assembly excerpt of an inlined helper calling a kernel function and
checking for a specific error:
; err = bpf_map_update_elem(&mymap, &key, &val, BPF_NOEXIST);
...
46: call 0xffffffffe103291c ; htab_map_update_elem
; if (err && err != -EEXIST) {
4b: cmp $0xffffffffffffffef,%rax ; cmp -EEXIST,%rax
kernel function assembly excerpt of return value from
`htab_map_update_elem` returning 32-bit int:
movl $0xffffffef, %r9d
...
movl %r9d, %eax
...results in the comparison:
cmp $0xffffffffffffffef, $0x00000000ffffffef
Fixes: bdb7b79b4ce8 ("bpf: Switch most helper return values from 32-bit int to 64-bit long")
Tested-by: Eduard Zingerman <eddyz87@gmail.com>
Signed-off-by: JP Kobryn <inwardvessel@gmail.com>
Link: https://lore.kernel.org/r/20230322194754.185781-3-inwardvessel@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2023-03-22 19:47:54 +00:00
|
|
|
static long queue_map_pop_elem(struct bpf_map *map, void *value)
|
2018-10-18 13:16:25 +00:00
|
|
|
{
|
|
|
|
return __queue_map_get(map, value, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Called from syscall or from eBPF program */
|
bpf: return long from bpf_map_ops funcs
This patch changes the return types of bpf_map_ops functions to long, where
previously int was returned. Using long allows for bpf programs to maintain
the sign bit in the absence of sign extension during situations where
inlined bpf helper funcs make calls to the bpf_map_ops funcs and a negative
error is returned.
The definitions of the helper funcs are generated from comments in the bpf
uapi header at `include/uapi/linux/bpf.h`. The return type of these
helpers was previously changed from int to long in commit bdb7b79b4ce8. For
any case where one of the map helpers call the bpf_map_ops funcs that are
still returning 32-bit int, a compiler might not include sign extension
instructions to properly convert the 32-bit negative value a 64-bit
negative value.
For example:
bpf assembly excerpt of an inlined helper calling a kernel function and
checking for a specific error:
; err = bpf_map_update_elem(&mymap, &key, &val, BPF_NOEXIST);
...
46: call 0xffffffffe103291c ; htab_map_update_elem
; if (err && err != -EEXIST) {
4b: cmp $0xffffffffffffffef,%rax ; cmp -EEXIST,%rax
kernel function assembly excerpt of return value from
`htab_map_update_elem` returning 32-bit int:
movl $0xffffffef, %r9d
...
movl %r9d, %eax
...results in the comparison:
cmp $0xffffffffffffffef, $0x00000000ffffffef
Fixes: bdb7b79b4ce8 ("bpf: Switch most helper return values from 32-bit int to 64-bit long")
Tested-by: Eduard Zingerman <eddyz87@gmail.com>
Signed-off-by: JP Kobryn <inwardvessel@gmail.com>
Link: https://lore.kernel.org/r/20230322194754.185781-3-inwardvessel@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2023-03-22 19:47:54 +00:00
|
|
|
static long stack_map_pop_elem(struct bpf_map *map, void *value)
|
2018-10-18 13:16:25 +00:00
|
|
|
{
|
|
|
|
return __stack_map_get(map, value, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Called from syscall or from eBPF program */
|
bpf: return long from bpf_map_ops funcs
This patch changes the return types of bpf_map_ops functions to long, where
previously int was returned. Using long allows for bpf programs to maintain
the sign bit in the absence of sign extension during situations where
inlined bpf helper funcs make calls to the bpf_map_ops funcs and a negative
error is returned.
The definitions of the helper funcs are generated from comments in the bpf
uapi header at `include/uapi/linux/bpf.h`. The return type of these
helpers was previously changed from int to long in commit bdb7b79b4ce8. For
any case where one of the map helpers call the bpf_map_ops funcs that are
still returning 32-bit int, a compiler might not include sign extension
instructions to properly convert the 32-bit negative value a 64-bit
negative value.
For example:
bpf assembly excerpt of an inlined helper calling a kernel function and
checking for a specific error:
; err = bpf_map_update_elem(&mymap, &key, &val, BPF_NOEXIST);
...
46: call 0xffffffffe103291c ; htab_map_update_elem
; if (err && err != -EEXIST) {
4b: cmp $0xffffffffffffffef,%rax ; cmp -EEXIST,%rax
kernel function assembly excerpt of return value from
`htab_map_update_elem` returning 32-bit int:
movl $0xffffffef, %r9d
...
movl %r9d, %eax
...results in the comparison:
cmp $0xffffffffffffffef, $0x00000000ffffffef
Fixes: bdb7b79b4ce8 ("bpf: Switch most helper return values from 32-bit int to 64-bit long")
Tested-by: Eduard Zingerman <eddyz87@gmail.com>
Signed-off-by: JP Kobryn <inwardvessel@gmail.com>
Link: https://lore.kernel.org/r/20230322194754.185781-3-inwardvessel@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2023-03-22 19:47:54 +00:00
|
|
|
static long queue_stack_map_push_elem(struct bpf_map *map, void *value,
|
|
|
|
u64 flags)
|
2018-10-18 13:16:25 +00:00
|
|
|
{
|
|
|
|
struct bpf_queue_stack *qs = bpf_queue_stack(map);
|
|
|
|
unsigned long irq_flags;
|
|
|
|
int err = 0;
|
|
|
|
void *dst;
|
|
|
|
|
|
|
|
/* BPF_EXIST is used to force making room for a new element in case the
|
|
|
|
* map is full
|
|
|
|
*/
|
|
|
|
bool replace = (flags & BPF_EXIST);
|
|
|
|
|
|
|
|
/* Check supported flags for queue and stack maps */
|
|
|
|
if (flags & BPF_NOEXIST || flags > BPF_EXIST)
|
|
|
|
return -EINVAL;
|
|
|
|
|
2023-09-11 13:28:14 +00:00
|
|
|
if (in_nmi()) {
|
|
|
|
if (!raw_spin_trylock_irqsave(&qs->lock, irq_flags))
|
|
|
|
return -EBUSY;
|
|
|
|
} else {
|
|
|
|
raw_spin_lock_irqsave(&qs->lock, irq_flags);
|
|
|
|
}
|
2018-10-18 13:16:25 +00:00
|
|
|
|
|
|
|
if (queue_stack_map_is_full(qs)) {
|
|
|
|
if (!replace) {
|
|
|
|
err = -E2BIG;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
/* advance tail pointer to overwrite oldest element */
|
|
|
|
if (unlikely(++qs->tail >= qs->size))
|
|
|
|
qs->tail = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
dst = &qs->elements[qs->head * qs->map.value_size];
|
|
|
|
memcpy(dst, value, qs->map.value_size);
|
|
|
|
|
|
|
|
if (unlikely(++qs->head >= qs->size))
|
|
|
|
qs->head = 0;
|
|
|
|
|
|
|
|
out:
|
|
|
|
raw_spin_unlock_irqrestore(&qs->lock, irq_flags);
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Called from syscall or from eBPF program */
|
|
|
|
static void *queue_stack_map_lookup_elem(struct bpf_map *map, void *key)
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Called from syscall or from eBPF program */
|
bpf: return long from bpf_map_ops funcs
This patch changes the return types of bpf_map_ops functions to long, where
previously int was returned. Using long allows for bpf programs to maintain
the sign bit in the absence of sign extension during situations where
inlined bpf helper funcs make calls to the bpf_map_ops funcs and a negative
error is returned.
The definitions of the helper funcs are generated from comments in the bpf
uapi header at `include/uapi/linux/bpf.h`. The return type of these
helpers was previously changed from int to long in commit bdb7b79b4ce8. For
any case where one of the map helpers call the bpf_map_ops funcs that are
still returning 32-bit int, a compiler might not include sign extension
instructions to properly convert the 32-bit negative value a 64-bit
negative value.
For example:
bpf assembly excerpt of an inlined helper calling a kernel function and
checking for a specific error:
; err = bpf_map_update_elem(&mymap, &key, &val, BPF_NOEXIST);
...
46: call 0xffffffffe103291c ; htab_map_update_elem
; if (err && err != -EEXIST) {
4b: cmp $0xffffffffffffffef,%rax ; cmp -EEXIST,%rax
kernel function assembly excerpt of return value from
`htab_map_update_elem` returning 32-bit int:
movl $0xffffffef, %r9d
...
movl %r9d, %eax
...results in the comparison:
cmp $0xffffffffffffffef, $0x00000000ffffffef
Fixes: bdb7b79b4ce8 ("bpf: Switch most helper return values from 32-bit int to 64-bit long")
Tested-by: Eduard Zingerman <eddyz87@gmail.com>
Signed-off-by: JP Kobryn <inwardvessel@gmail.com>
Link: https://lore.kernel.org/r/20230322194754.185781-3-inwardvessel@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2023-03-22 19:47:54 +00:00
|
|
|
static long queue_stack_map_update_elem(struct bpf_map *map, void *key,
|
|
|
|
void *value, u64 flags)
|
2018-10-18 13:16:25 +00:00
|
|
|
{
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Called from syscall or from eBPF program */
|
bpf: return long from bpf_map_ops funcs
This patch changes the return types of bpf_map_ops functions to long, where
previously int was returned. Using long allows for bpf programs to maintain
the sign bit in the absence of sign extension during situations where
inlined bpf helper funcs make calls to the bpf_map_ops funcs and a negative
error is returned.
The definitions of the helper funcs are generated from comments in the bpf
uapi header at `include/uapi/linux/bpf.h`. The return type of these
helpers was previously changed from int to long in commit bdb7b79b4ce8. For
any case where one of the map helpers call the bpf_map_ops funcs that are
still returning 32-bit int, a compiler might not include sign extension
instructions to properly convert the 32-bit negative value a 64-bit
negative value.
For example:
bpf assembly excerpt of an inlined helper calling a kernel function and
checking for a specific error:
; err = bpf_map_update_elem(&mymap, &key, &val, BPF_NOEXIST);
...
46: call 0xffffffffe103291c ; htab_map_update_elem
; if (err && err != -EEXIST) {
4b: cmp $0xffffffffffffffef,%rax ; cmp -EEXIST,%rax
kernel function assembly excerpt of return value from
`htab_map_update_elem` returning 32-bit int:
movl $0xffffffef, %r9d
...
movl %r9d, %eax
...results in the comparison:
cmp $0xffffffffffffffef, $0x00000000ffffffef
Fixes: bdb7b79b4ce8 ("bpf: Switch most helper return values from 32-bit int to 64-bit long")
Tested-by: Eduard Zingerman <eddyz87@gmail.com>
Signed-off-by: JP Kobryn <inwardvessel@gmail.com>
Link: https://lore.kernel.org/r/20230322194754.185781-3-inwardvessel@gmail.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
2023-03-22 19:47:54 +00:00
|
|
|
static long queue_stack_map_delete_elem(struct bpf_map *map, void *key)
|
2018-10-18 13:16:25 +00:00
|
|
|
{
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Called from syscall */
|
|
|
|
static int queue_stack_map_get_next_key(struct bpf_map *map, void *key,
|
|
|
|
void *next_key)
|
|
|
|
{
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2023-03-05 12:46:08 +00:00
|
|
|
static u64 queue_stack_map_mem_usage(const struct bpf_map *map)
|
|
|
|
{
|
|
|
|
u64 usage = sizeof(struct bpf_queue_stack);
|
|
|
|
|
|
|
|
usage += ((u64)map->max_entries + 1) * map->value_size;
|
|
|
|
return usage;
|
|
|
|
}
|
|
|
|
|
2022-04-25 13:32:47 +00:00
|
|
|
BTF_ID_LIST_SINGLE(queue_map_btf_ids, struct, bpf_queue_stack)
|
2018-10-18 13:16:25 +00:00
|
|
|
const struct bpf_map_ops queue_map_ops = {
|
2020-08-28 01:18:06 +00:00
|
|
|
.map_meta_equal = bpf_map_meta_equal,
|
2018-10-18 13:16:25 +00:00
|
|
|
.map_alloc_check = queue_stack_map_alloc_check,
|
|
|
|
.map_alloc = queue_stack_map_alloc,
|
|
|
|
.map_free = queue_stack_map_free,
|
|
|
|
.map_lookup_elem = queue_stack_map_lookup_elem,
|
|
|
|
.map_update_elem = queue_stack_map_update_elem,
|
|
|
|
.map_delete_elem = queue_stack_map_delete_elem,
|
|
|
|
.map_push_elem = queue_stack_map_push_elem,
|
|
|
|
.map_pop_elem = queue_map_pop_elem,
|
|
|
|
.map_peek_elem = queue_map_peek_elem,
|
|
|
|
.map_get_next_key = queue_stack_map_get_next_key,
|
2023-03-05 12:46:08 +00:00
|
|
|
.map_mem_usage = queue_stack_map_mem_usage,
|
2022-04-25 13:32:47 +00:00
|
|
|
.map_btf_id = &queue_map_btf_ids[0],
|
2018-10-18 13:16:25 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
const struct bpf_map_ops stack_map_ops = {
|
2020-08-28 01:18:06 +00:00
|
|
|
.map_meta_equal = bpf_map_meta_equal,
|
2018-10-18 13:16:25 +00:00
|
|
|
.map_alloc_check = queue_stack_map_alloc_check,
|
|
|
|
.map_alloc = queue_stack_map_alloc,
|
|
|
|
.map_free = queue_stack_map_free,
|
|
|
|
.map_lookup_elem = queue_stack_map_lookup_elem,
|
|
|
|
.map_update_elem = queue_stack_map_update_elem,
|
|
|
|
.map_delete_elem = queue_stack_map_delete_elem,
|
|
|
|
.map_push_elem = queue_stack_map_push_elem,
|
|
|
|
.map_pop_elem = stack_map_pop_elem,
|
|
|
|
.map_peek_elem = stack_map_peek_elem,
|
|
|
|
.map_get_next_key = queue_stack_map_get_next_key,
|
2023-03-05 12:46:08 +00:00
|
|
|
.map_mem_usage = queue_stack_map_mem_usage,
|
2022-04-25 13:32:47 +00:00
|
|
|
.map_btf_id = &queue_map_btf_ids[0],
|
2018-10-18 13:16:25 +00:00
|
|
|
};
|