mirror of https://github.com/torvalds/linux.git
bpf-fixes
-----BEGIN PGP SIGNATURE-----
iQIzBAABCAAdFiEE+soXsSLHKoYyzcli6rmadz2vbToFAmjpp+sACgkQ6rmadz2v
bTo+9Q//bUzEc2C64NbG0DTCcxnkDEadzBLIB0BAwnAkuRjR8HJiPGoCdBJhUqzM
/hNfIHTtDdyspU2qZbM+r4nVJ6zRAwIHrT2d/knERxXtRQozaWvUlRhVmf5tdWYm
DkbThS9sAfAOs21YjV7OWPrf7bC7T9syQTAfN0CE8cujZY7OnqCyzNwfb8iIusyo
+Ctm0/qUDVtd6SjdPAQjzp82fHIIwnMFZtWJiZml5LklL1Mx5cuVrT/sWgr5KATW
vZ9rUfgaiJkAsSX0sSlLnAI76+kJRB+IkmK1TRdWFlwW6dTsa/7MkDeXXPN1dEDi
o5ZqhcvaY0eAMbU4iX72Juf6gVFF6AgVwsrHmM79ICjg5umCLN/90QqYPc0ChRxl
EYuSWVQ6/cgV3W6l+KU53cwmRjjdSzyJQFei03COZ0iKF6xic0cynS3BKMQL6HkU
3BfTj19h+dxt7qywRaJFsrWK4t/uBX6N75XlVa9od/sk91tR/ibtJ6hcyuJGATr5
nkfMkyN155upAffUnkhv37TXtMXyX8/kd7BddCet31JJXyJuJZ0vYuOcur6awGyN
aB0T1ueG15sTfGf0zpxVNWhVqswHI/1Suk8EXwbDeHRcsmtrp8XWYawf5StIMwW0
Uy8GjS5KVl5bcrfDbcvj79jajpVjwnvFR1Sir9C4aROm5OpH3Hs=
=77JH
-----END PGP SIGNATURE-----
Merge tag 'bpf-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf
Pull bpf fixes from Alexei Starovoitov:
- Finish constification of 1st parameter of bpf_d_path() (Rong Tao)
- Harden userspace-supplied xdp_desc validation (Alexander Lobakin)
- Fix metadata_dst leak in __bpf_redirect_neigh_v{4,6}() (Daniel
Borkmann)
- Fix undefined behavior in {get,put}_unaligned_be32() (Eric Biggers)
- Use correct context to unpin bpf hash map with special types (KaFai
Wan)
* tag 'bpf-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf:
selftests/bpf: Add test for unpinning htab with internal timer struct
bpf: Avoid RCU context warning when unpinning htab with internal structs
xsk: Harden userspace-supplied xdp_desc validation
bpf: Fix metadata_dst leak __bpf_redirect_neigh_v{4,6}
libbpf: Fix undefined behavior in {get,put}_unaligned_be32()
bpf: Finish constification of 1st parameter of bpf_d_path()
This commit is contained in:
commit
fbde105f13
|
|
@ -4891,7 +4891,7 @@ union bpf_attr {
|
||||||
*
|
*
|
||||||
* **-ENOENT** if the bpf_local_storage cannot be found.
|
* **-ENOENT** if the bpf_local_storage cannot be found.
|
||||||
*
|
*
|
||||||
* long bpf_d_path(struct path *path, char *buf, u32 sz)
|
* long bpf_d_path(const struct path *path, char *buf, u32 sz)
|
||||||
* Description
|
* Description
|
||||||
* Return full path for given **struct path** object, which
|
* Return full path for given **struct path** object, which
|
||||||
* needs to be the kernel BTF *path* object. The path is
|
* needs to be the kernel BTF *path* object. The path is
|
||||||
|
|
|
||||||
|
|
@ -775,7 +775,7 @@ static int bpf_show_options(struct seq_file *m, struct dentry *root)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void bpf_free_inode(struct inode *inode)
|
static void bpf_destroy_inode(struct inode *inode)
|
||||||
{
|
{
|
||||||
enum bpf_type type;
|
enum bpf_type type;
|
||||||
|
|
||||||
|
|
@ -790,7 +790,7 @@ const struct super_operations bpf_super_ops = {
|
||||||
.statfs = simple_statfs,
|
.statfs = simple_statfs,
|
||||||
.drop_inode = inode_just_drop,
|
.drop_inode = inode_just_drop,
|
||||||
.show_options = bpf_show_options,
|
.show_options = bpf_show_options,
|
||||||
.free_inode = bpf_free_inode,
|
.destroy_inode = bpf_destroy_inode,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
|
|
||||||
|
|
@ -2281,6 +2281,7 @@ static int __bpf_redirect_neigh_v6(struct sk_buff *skb, struct net_device *dev,
|
||||||
if (IS_ERR(dst))
|
if (IS_ERR(dst))
|
||||||
goto out_drop;
|
goto out_drop;
|
||||||
|
|
||||||
|
skb_dst_drop(skb);
|
||||||
skb_dst_set(skb, dst);
|
skb_dst_set(skb, dst);
|
||||||
} else if (nh->nh_family != AF_INET6) {
|
} else if (nh->nh_family != AF_INET6) {
|
||||||
goto out_drop;
|
goto out_drop;
|
||||||
|
|
@ -2389,6 +2390,7 @@ static int __bpf_redirect_neigh_v4(struct sk_buff *skb, struct net_device *dev,
|
||||||
goto out_drop;
|
goto out_drop;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
skb_dst_drop(skb);
|
||||||
skb_dst_set(skb, &rt->dst);
|
skb_dst_set(skb, &rt->dst);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -143,14 +143,24 @@ static inline bool xp_unused_options_set(u32 options)
|
||||||
static inline bool xp_aligned_validate_desc(struct xsk_buff_pool *pool,
|
static inline bool xp_aligned_validate_desc(struct xsk_buff_pool *pool,
|
||||||
struct xdp_desc *desc)
|
struct xdp_desc *desc)
|
||||||
{
|
{
|
||||||
u64 addr = desc->addr - pool->tx_metadata_len;
|
u64 len = desc->len;
|
||||||
u64 len = desc->len + pool->tx_metadata_len;
|
u64 addr, offset;
|
||||||
u64 offset = addr & (pool->chunk_size - 1);
|
|
||||||
|
|
||||||
if (!desc->len)
|
if (!len)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (offset + len > pool->chunk_size)
|
/* Can overflow if desc->addr < pool->tx_metadata_len */
|
||||||
|
if (check_sub_overflow(desc->addr, pool->tx_metadata_len, &addr))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
offset = addr & (pool->chunk_size - 1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Can't overflow: @offset is guaranteed to be < ``U32_MAX``
|
||||||
|
* (pool->chunk_size is ``u32``), @len is guaranteed
|
||||||
|
* to be <= ``U32_MAX``.
|
||||||
|
*/
|
||||||
|
if (offset + len + pool->tx_metadata_len > pool->chunk_size)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (addr >= pool->addrs_cnt)
|
if (addr >= pool->addrs_cnt)
|
||||||
|
|
@ -158,27 +168,42 @@ static inline bool xp_aligned_validate_desc(struct xsk_buff_pool *pool,
|
||||||
|
|
||||||
if (xp_unused_options_set(desc->options))
|
if (xp_unused_options_set(desc->options))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool xp_unaligned_validate_desc(struct xsk_buff_pool *pool,
|
static inline bool xp_unaligned_validate_desc(struct xsk_buff_pool *pool,
|
||||||
struct xdp_desc *desc)
|
struct xdp_desc *desc)
|
||||||
{
|
{
|
||||||
u64 addr = xp_unaligned_add_offset_to_addr(desc->addr) - pool->tx_metadata_len;
|
u64 len = desc->len;
|
||||||
u64 len = desc->len + pool->tx_metadata_len;
|
u64 addr, end;
|
||||||
|
|
||||||
if (!desc->len)
|
if (!len)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
/* Can't overflow: @len is guaranteed to be <= ``U32_MAX`` */
|
||||||
|
len += pool->tx_metadata_len;
|
||||||
if (len > pool->chunk_size)
|
if (len > pool->chunk_size)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (addr >= pool->addrs_cnt || addr + len > pool->addrs_cnt ||
|
/* Can overflow if desc->addr is close to 0 */
|
||||||
xp_desc_crosses_non_contig_pg(pool, addr, len))
|
if (check_sub_overflow(xp_unaligned_add_offset_to_addr(desc->addr),
|
||||||
|
pool->tx_metadata_len, &addr))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (addr >= pool->addrs_cnt)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* Can overflow if pool->addrs_cnt is high enough */
|
||||||
|
if (check_add_overflow(addr, len, &end) || end > pool->addrs_cnt)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (xp_desc_crosses_non_contig_pg(pool, addr, len))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (xp_unused_options_set(desc->options))
|
if (xp_unused_options_set(desc->options))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -788,6 +788,7 @@ class PrinterHelpersHeader(Printer):
|
||||||
'struct task_struct',
|
'struct task_struct',
|
||||||
'struct cgroup',
|
'struct cgroup',
|
||||||
'struct path',
|
'struct path',
|
||||||
|
'const struct path',
|
||||||
'struct btf_ptr',
|
'struct btf_ptr',
|
||||||
'struct inode',
|
'struct inode',
|
||||||
'struct socket',
|
'struct socket',
|
||||||
|
|
|
||||||
|
|
@ -4891,7 +4891,7 @@ union bpf_attr {
|
||||||
*
|
*
|
||||||
* **-ENOENT** if the bpf_local_storage cannot be found.
|
* **-ENOENT** if the bpf_local_storage cannot be found.
|
||||||
*
|
*
|
||||||
* long bpf_d_path(struct path *path, char *buf, u32 sz)
|
* long bpf_d_path(const struct path *path, char *buf, u32 sz)
|
||||||
* Description
|
* Description
|
||||||
* Return full path for given **struct path** object, which
|
* Return full path for given **struct path** object, which
|
||||||
* needs to be the kernel BTF *path* object. The path is
|
* needs to be the kernel BTF *path* object. The path is
|
||||||
|
|
|
||||||
|
|
@ -148,16 +148,20 @@ const char *libbpf_errstr(int err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma GCC diagnostic push
|
static inline __u32 get_unaligned_be32(const void *p)
|
||||||
#pragma GCC diagnostic ignored "-Wpacked"
|
{
|
||||||
#pragma GCC diagnostic ignored "-Wattributes"
|
__be32 val;
|
||||||
struct __packed_u32 { __u32 __val; } __attribute__((packed));
|
|
||||||
#pragma GCC diagnostic pop
|
|
||||||
|
|
||||||
#define get_unaligned_be32(p) be32_to_cpu((((struct __packed_u32 *)(p))->__val))
|
memcpy(&val, p, sizeof(val));
|
||||||
#define put_unaligned_be32(v, p) do { \
|
return be32_to_cpu(val);
|
||||||
((struct __packed_u32 *)(p))->__val = cpu_to_be32(v); \
|
}
|
||||||
} while (0)
|
|
||||||
|
static inline void put_unaligned_be32(__u32 val, void *p)
|
||||||
|
{
|
||||||
|
__be32 be_val = cpu_to_be32(val);
|
||||||
|
|
||||||
|
memcpy(p, &be_val, sizeof(be_val));
|
||||||
|
}
|
||||||
|
|
||||||
#define SHA256_BLOCK_LENGTH 64
|
#define SHA256_BLOCK_LENGTH 64
|
||||||
#define Ch(x, y, z) (((x) & (y)) ^ (~(x) & (z)))
|
#define Ch(x, y, z) (((x) & (y)) ^ (~(x) & (z)))
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
|
||||||
|
#include <test_progs.h>
|
||||||
|
#include "test_pinning_htab.skel.h"
|
||||||
|
|
||||||
|
static void unpin_map(const char *map_name, const char *pin_path)
|
||||||
|
{
|
||||||
|
struct test_pinning_htab *skel;
|
||||||
|
struct bpf_map *map;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
skel = test_pinning_htab__open_and_load();
|
||||||
|
if (!ASSERT_OK_PTR(skel, "skel open_and_load"))
|
||||||
|
return;
|
||||||
|
|
||||||
|
map = bpf_object__find_map_by_name(skel->obj, map_name);
|
||||||
|
if (!ASSERT_OK_PTR(map, "bpf_object__find_map_by_name"))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
err = bpf_map__pin(map, pin_path);
|
||||||
|
if (!ASSERT_OK(err, "bpf_map__pin"))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
err = bpf_map__unpin(map, pin_path);
|
||||||
|
ASSERT_OK(err, "bpf_map__unpin");
|
||||||
|
out:
|
||||||
|
test_pinning_htab__destroy(skel);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_pinning_htab(void)
|
||||||
|
{
|
||||||
|
if (test__start_subtest("timer_prealloc"))
|
||||||
|
unpin_map("timer_prealloc", "/sys/fs/bpf/timer_prealloc");
|
||||||
|
if (test__start_subtest("timer_no_prealloc"))
|
||||||
|
unpin_map("timer_no_prealloc", "/sys/fs/bpf/timer_no_prealloc");
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
|
||||||
|
#include "vmlinux.h"
|
||||||
|
#include <bpf/bpf_helpers.h>
|
||||||
|
|
||||||
|
char _license[] SEC("license") = "GPL";
|
||||||
|
|
||||||
|
struct timer_val {
|
||||||
|
struct bpf_timer timer;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct {
|
||||||
|
__uint(type, BPF_MAP_TYPE_HASH);
|
||||||
|
__type(key, __u32);
|
||||||
|
__type(value, struct timer_val);
|
||||||
|
__uint(max_entries, 1);
|
||||||
|
} timer_prealloc SEC(".maps");
|
||||||
|
|
||||||
|
struct {
|
||||||
|
__uint(type, BPF_MAP_TYPE_HASH);
|
||||||
|
__type(key, __u32);
|
||||||
|
__type(value, struct timer_val);
|
||||||
|
__uint(max_entries, 1);
|
||||||
|
__uint(map_flags, BPF_F_NO_PREALLOC);
|
||||||
|
} timer_no_prealloc SEC(".maps");
|
||||||
|
|
@ -70,7 +70,7 @@ __success
|
||||||
int BPF_PROG(path_d_path_from_file_argument, struct file *file)
|
int BPF_PROG(path_d_path_from_file_argument, struct file *file)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
struct path *path;
|
const struct path *path;
|
||||||
|
|
||||||
/* The f_path member is a path which is embedded directly within a
|
/* The f_path member is a path which is embedded directly within a
|
||||||
* file. Therefore, a pointer to such embedded members are still
|
* file. Therefore, a pointer to such embedded members are still
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue