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:
Linus Torvalds
2025-10-11 10:31:38 -07:00
10 changed files with 117 additions and 24 deletions

View File

@@ -4891,7 +4891,7 @@ union bpf_attr {
*
* **-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
* Return full path for given **struct path** object, which
* needs to be the kernel BTF *path* object. The path is

View File

@@ -775,7 +775,7 @@ static int bpf_show_options(struct seq_file *m, struct dentry *root)
return 0;
}
static void bpf_free_inode(struct inode *inode)
static void bpf_destroy_inode(struct inode *inode)
{
enum bpf_type type;
@@ -790,7 +790,7 @@ const struct super_operations bpf_super_ops = {
.statfs = simple_statfs,
.drop_inode = inode_just_drop,
.show_options = bpf_show_options,
.free_inode = bpf_free_inode,
.destroy_inode = bpf_destroy_inode,
};
enum {

View File

@@ -2281,6 +2281,7 @@ static int __bpf_redirect_neigh_v6(struct sk_buff *skb, struct net_device *dev,
if (IS_ERR(dst))
goto out_drop;
skb_dst_drop(skb);
skb_dst_set(skb, dst);
} else if (nh->nh_family != AF_INET6) {
goto out_drop;
@@ -2389,6 +2390,7 @@ static int __bpf_redirect_neigh_v4(struct sk_buff *skb, struct net_device *dev,
goto out_drop;
}
skb_dst_drop(skb);
skb_dst_set(skb, &rt->dst);
}

View File

@@ -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,
struct xdp_desc *desc)
{
u64 addr = desc->addr - pool->tx_metadata_len;
u64 len = desc->len + pool->tx_metadata_len;
u64 offset = addr & (pool->chunk_size - 1);
u64 len = desc->len;
u64 addr, offset;
if (!desc->len)
if (!len)
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;
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))
return false;
return true;
}
static inline bool xp_unaligned_validate_desc(struct xsk_buff_pool *pool,
struct xdp_desc *desc)
{
u64 addr = xp_unaligned_add_offset_to_addr(desc->addr) - pool->tx_metadata_len;
u64 len = desc->len + pool->tx_metadata_len;
u64 len = desc->len;
u64 addr, end;
if (!desc->len)
if (!len)
return false;
/* Can't overflow: @len is guaranteed to be <= ``U32_MAX`` */
len += pool->tx_metadata_len;
if (len > pool->chunk_size)
return false;
if (addr >= pool->addrs_cnt || addr + len > pool->addrs_cnt ||
xp_desc_crosses_non_contig_pg(pool, addr, len))
/* Can overflow if desc->addr is close to 0 */
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;
if (xp_unused_options_set(desc->options))
return false;
return true;
}

View File

@@ -788,6 +788,7 @@ class PrinterHelpersHeader(Printer):
'struct task_struct',
'struct cgroup',
'struct path',
'const struct path',
'struct btf_ptr',
'struct inode',
'struct socket',

View File

@@ -4891,7 +4891,7 @@ union bpf_attr {
*
* **-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
* Return full path for given **struct path** object, which
* needs to be the kernel BTF *path* object. The path is

View File

@@ -148,16 +148,20 @@ const char *libbpf_errstr(int err)
}
}
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpacked"
#pragma GCC diagnostic ignored "-Wattributes"
struct __packed_u32 { __u32 __val; } __attribute__((packed));
#pragma GCC diagnostic pop
static inline __u32 get_unaligned_be32(const void *p)
{
__be32 val;
#define get_unaligned_be32(p) be32_to_cpu((((struct __packed_u32 *)(p))->__val))
#define put_unaligned_be32(v, p) do { \
((struct __packed_u32 *)(p))->__val = cpu_to_be32(v); \
} while (0)
memcpy(&val, p, sizeof(val));
return be32_to_cpu(val);
}
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 Ch(x, y, z) (((x) & (y)) ^ (~(x) & (z)))

View File

@@ -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");
}

View File

@@ -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");

View File

@@ -70,7 +70,7 @@ __success
int BPF_PROG(path_d_path_from_file_argument, struct file *file)
{
int ret;
struct path *path;
const struct path *path;
/* The f_path member is a path which is embedded directly within a
* file. Therefore, a pointer to such embedded members are still