summaryrefslogtreecommitdiff
path: root/net/core
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-10-23 13:08:49 -1000
committerLinus Torvalds <torvalds@linux-foundation.org>2026-10-23 13:08:49 -1000
commit55fbedcec622a943cb09a969aef1ddcba87ee40a (patch)
tree99bf57398ef32396f831f31efffb5d917ce22e0c /net/core
parent90b754d40117b2889bbe847ce7bb4dcf968e7cb8 (diff)
parentb116ac6087541d3d98031e786adbe9c733cd6df3 (diff)
Merge tag 'bpf-next-7.4' of git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next
Pull bpf updates from Alexei Starovoitov: "Major changes: - Introduce scalar evolution (SCEV) analysis in the verifier. It infers how registers and stack slots change in a loop and lets the verifier check bounded loops with induction variables as ranges instead of walking every iteration. The number of processed insns drops ten fold in programs with loops (Eduard Zingerman) - Add 'callx' instruction: indirect call of a static BPF subprogram. The address is taken with ld_imm64 or loaded from read-only data. Supported by x86-64, arm64 and riscv64 JITs (Alexei Starovoitov, Pu Lehui) - Add unwind_goto and unwind_exit instructions, so that Rust panic or C++ exception can run destructors of every frame it passes through. The normal path is free of unwind code. Supported by x86-64 and arm64 JITs (Alexei Starovoitov) - Support programs compiled by rust-bpf: treat load and store through a number as arena access with BPF_F_ARENA_SCALAR, accept rust names in BTF (Alexei Starovoitov) - Raise BPF program stack size from 512 bytes to 2 KiB on x86-64 and arm64 (Kumar Kartikeya Dwivedi) - Support struct, union and __int128 up to 16 bytes passed and returned by value in BPF subprograms and kfuncs, and fix x86-64 and arm64 trampolines for such arguments (Yonghong Song) - Introduce a common way to attach struct_ops to a cgroup via bpf_link. bpf_tcp_ops is the first user and mirrors TCP sock_ops callbacks (Martin KaFai Lau, Amery Hung) - Describe inlined functions in BTF. New kinds tell where the inline sites are and how to fetch the arguments there. CONFIG_DEBUG_INFO_BTF_INLINE keeps it apart from the main BTF in .BTF.inline section or in btf_vmlinux_inline.ko (Alan Maguire) - Fix many memory safety, lifetime and locking bugs in BPF core, verifier, iterators, local storage, dynptr, devmap, cpumap and seg6local (Josef Bacik, Alexei Starovoitov) - Diff stat is dominated by selftests and by removal of lib/test_bpf.c. Its 16k lines of instruction tests were converted to BPF selftests that BPF CI runs on every architecture it covers (Daniel Borkmann) Other features and fixes: - Add KASAN checks to memory accesses of JITed programs on x86-64 (Alexis Lothoré) - Complete unification of helper, kfunc and subprog argument checks in the verifier (Amery Hung) - Add bpf_copy_from_user_mm[_str]() kfuncs (Anastasios Papagiannis) - Various features and fixes (Daniel Borkmann): - Add .bpf keyring for program signature verification, modelled after dm-verity keyring, and support ML-DSA in signing tools - Emit shorter and faster code in x86-64 JIT for patterns that LLVM generates - Fix various issues in gotox handling - Let BPF LSM set xattrs at inode creation with bpf_inode_init_xattr() (David Windsor, Daniel Borkmann) - Use sleepable page allocation in sleepable arena paths. Fix races between arena free, allocation and user page fault (Emil Tsalapatis) - Switch BPF crypto from lskcipher to AES-CBC and AES-ECB libraries (Eric Biggers) - Add bpf_proactive_reclaim() kfunc (Hui Zhu) - Render decl_tags in libbpf btf_dump and add tests for bpftool C dump (Ihor Solodrai) - Speed up tracing_multi attach on x86 (Jiri Olsa) - Various features and fixes (Kumar Kartikeya Dwivedi): - Add BPF_PROG_STREAM_OPEN command to read BPF streams through a file descriptor with poll support - Let kernel structs publish arena pointers with __arena type tag - Fix __uninit kfunc output buffers and fastcall rewrite with indirect stack accesses - Refuse CO-RE relocations for signed programs - Add enqueue_rcvq and dequeue_rcvq hooks to bpf_tcp_ops to adjust sk_rcvlowat and avoid unnecessary wakeups (Kuniyuki Iwashima) - Add bpf_ksock_sendto() kfunc and allow ksock connect and send from bpf_wq (Mahe Tardy) - Fix racy plt target update in arm64 bpf_arch_text_poke() (Matthew Wood) - Restructure BPF selftests Makefile as a layered build (Mykola Lysenko) - Speed up hash map lookups for u32 and u64 keys (Mykyta Yatsenko) - Add signed div/mod, movsx, bswap and gotol to MIPS JITs, signed div/mod to parisc JITs (Nicholas Dudar, Johan Almbladh) - Fix stack overflow in build ID parser on 32-bit (Nickolai Zeldovich) - Add stack arguments, signed arena loads and gotox to riscv64 JIT. Pu Lehui is now co-maintainer of riscv BPF JITs (Pu Lehui, Chen Pei, Feng Jiang) - Add bpf_call_rcu() and bpf_call_rcu_tasks_trace() kfuncs. Support fetching and/or/xor atomics in arena on x86-64 (Puranjay Mohan) - Fix flaky selftests, selftests with clang 23 and bpf-gcc (Qiliang Yuan, KaFai Wan, Vineet Gupta) - Fix builds broken by fatal resolve_btfids warnings, BTF generation on ARC, and define arch_cmpxchg_local() on arc, hexagon and openrisc (Sasha Levin) - Reduce memory use of hash maps by up to 50% per element (T.J. Mercier) - Mark pointer fields of sched_ext ops arguments as trusted (Tejun Heo) - Remove legacy bpf_asm, bpf_dbg and bpf_jit_disasm tools (Xia Yan) - Fix index overflow in queue and stack maps, arena range tree after allocation failure, tail call loop after freplace detach, lost signal in bpf_send_signal() (Yuan Chen) - Many more fixes and cleanups" * tag 'bpf-next-7.4' of git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next: (660 commits) selftests/bpf: Time tc_edt from its first packet with data selftests/bpf: Test unwind_exit of an exception callback selftests/bpf: Tests for 32-bit scalar evolution bounds computation bpf: Reject unwind_goto and unwind_exit in offloaded progs bpf: Support 32-bit linear scalar evolution bpf: Make unwind_exit of an exception callback exit in JITs selftests/bpf: Test forbidden bpf_ksock_sendto() LSM attach selftests/bpf: Test ksock sendto() bpf: Add bpf_ksock_sendto() kfunc selftests/bpf: Test unwinding from R0: R2 subprog selftests/bpf: Add a C++ prog with exceptions selftests/bpf: Add tests for unwind_goto and unwind_exit bpf, arm64: Support unwind_goto and unwind_exit bpf, x86: Support unwind_goto and unwind_exit bpf: Add unwind_goto and unwind_exit insns tools/bpf: Remove legacy BPF tools bpf: Annotate data races on bpf_lru_node type selftests/bpf: Add arena allocation race tests bpf: Fix arena race between page free and alloc leading to incoherency bpf: Revalidate faulted arena pages before installing user mappings ...
Diffstat (limited to 'net/core')
-rw-r--r--net/core/bpf_ksock.c121
-rw-r--r--net/core/bpf_sk_storage.c96
-rw-r--r--net/core/filter.c98
-rw-r--r--net/core/ptp_classifier.c8
-rw-r--r--net/core/sock_map.c17
5 files changed, 252 insertions, 88 deletions
diff --git a/net/core/bpf_ksock.c b/net/core/bpf_ksock.c
index e9943aeeadd3..37168f43c16c 100644
--- a/net/core/bpf_ksock.c
+++ b/net/core/bpf_ksock.c
@@ -37,13 +37,47 @@ static void ksock_release_work_fn(struct work_struct *work)
kfree(ks);
}
-static bool bpf_ksock_has_user_task_context(void)
+static int bpf_ksock_addr_to_sockaddr(const union bpf_ksock_addr *addr,
+ u32 addr_sz, struct sockaddr_storage *sa)
{
- /*
- * Task work can run from do_exit() after exit_nsproxy_namespaces()
- * cleared current->nsproxy, while current is still not a kthread.
- */
- return !(current->flags & PF_KTHREAD) && current->nsproxy;
+ if (!addr || addr_sz != sizeof(*addr))
+ return -EINVAL;
+
+ /* Kfunc memory arguments may be unaligned. */
+ memcpy(sa, addr, sizeof(*addr));
+
+ switch (sa->ss_family) {
+ case AF_INET:
+ return sizeof(struct sockaddr_in);
+ case AF_INET6:
+ return sizeof(struct sockaddr_in6);
+ default:
+ return -EAFNOSUPPORT;
+ }
+}
+
+static int ksock_sendto(struct bpf_ksock *ks, const void *data, u32 data_sz,
+ const union bpf_ksock_addr *addr, u32 addr_sz)
+{
+ struct sockaddr_storage sa;
+ struct msghdr msg = {
+ .msg_flags = MSG_DONTWAIT,
+ };
+ struct kvec iov = {
+ .iov_base = (void *)data,
+ .iov_len = data_sz,
+ };
+ int addrlen;
+
+ if (addr) {
+ addrlen = bpf_ksock_addr_to_sockaddr(addr, addr_sz, &sa);
+ if (addrlen < 0)
+ return addrlen;
+ msg.msg_name = &sa;
+ msg.msg_namelen = addrlen;
+ }
+
+ return kernel_sendmsg(ks->sock, &msg, &iov, 1, data_sz);
}
__bpf_kfunc_start_defs();
@@ -59,7 +93,7 @@ __bpf_kfunc_start_defs();
* This function may sleep (sock_create), so it can only be used
* in sleepable BPF programs (SYSCALL).
* It cannot be called from a BPF workqueue callback because that callback
- * does not retain the invoking task's namespace or security context.
+ * does not retain the invoking task's namespace.
*
* @opts: Pointer to struct bpf_ksock_create_opts with socket parameters.
* @opts__sz: Size of the opts struct.
@@ -74,11 +108,10 @@ bpf_ksock_create(const struct bpf_ksock_create_opts *opts, u32 opts__sz,
int err;
/*
- * sock_create() derives the network namespace, credentials, and cgroup
- * from current. Kernel threads, including BPF workqueue callbacks, do
- * not carry the context of the task that invoked the BPF program.
+ * sock_create() derives the network namespace from current and task
+ * work can run from do_exit() after exit_nsproxy_namespaces()
*/
- if (!bpf_ksock_has_user_task_context()) {
+ if ((current->flags & PF_KTHREAD) || !current->nsproxy) {
err = -EOPNOTSUPP;
goto err_out;
}
@@ -165,25 +198,9 @@ __bpf_kfunc int bpf_ksock_connect(struct bpf_ksock *ks,
struct sockaddr_storage sa;
int addrlen;
- if (!bpf_ksock_has_user_task_context())
- return -EOPNOTSUPP;
-
- if (!addr || addr__sz != sizeof(*addr))
- return -EINVAL;
-
- /* Kfunc memory arguments may be unaligned. */
- memcpy(&sa, addr, sizeof(*addr));
-
- switch (sa.ss_family) {
- case AF_INET:
- addrlen = sizeof(struct sockaddr_in);
- break;
- case AF_INET6:
- addrlen = sizeof(struct sockaddr_in6);
- break;
- default:
- return -EAFNOSUPPORT;
- }
+ addrlen = bpf_ksock_addr_to_sockaddr(addr, addr__sz, &sa);
+ if (addrlen < 0)
+ return addrlen;
return connect_socket(ks->sock, &sa, addrlen, 0);
}
@@ -238,21 +255,29 @@ CFI_NOSEAL(bpf_ksock_release_dtor);
__bpf_kfunc int bpf_ksock_send(struct bpf_ksock *ks, const void *data,
u32 data__sz)
{
- struct msghdr msg = {
- .msg_flags = MSG_DONTWAIT,
- };
- struct kvec iov = {
- .iov_base = (void *)data,
- .iov_len = data__sz,
- };
- int ret;
-
- if (!bpf_ksock_has_user_task_context())
- return -EOPNOTSUPP;
-
- ret = kernel_sendmsg(ks->sock, &msg, &iov, 1, data__sz);
+ return ksock_sendto(ks, data, data__sz, NULL, 0);
+}
- return ret;
+/**
+ * bpf_ksock_sendto() - Send data through a BPF kernel socket to a remote address.
+ * @ks: The BPF kernel socket context. Must be an acquired reference.
+ * @data: Pointer to the data to send.
+ * @data__sz: Size of the data to send.
+ * @addr__nullable: Pointer to an IPv4 or IPv6 socket address, or NULL to use
+ * the connected destination.
+ * @addr__sz: Size of the address union, ignored when the address is NULL.
+ *
+ * Sends data to the specified address, or to the connected destination when
+ * the address is NULL, best-effort and nonblocking. This may sleep
+ * (kernel_sendmsg), so it can only be called from sleepable BPF programs.
+ *
+ * Return: Number of bytes sent on success, negative errno on error.
+ */
+__bpf_kfunc int bpf_ksock_sendto(struct bpf_ksock *ks, const void *data, u32 data__sz,
+ const union bpf_ksock_addr *addr__nullable,
+ u32 addr__sz)
+{
+ return ksock_sendto(ks, data, data__sz, addr__nullable, addr__sz);
}
__bpf_kfunc_end_defs();
@@ -271,10 +296,16 @@ BTF_KFUNCS_START(ksock_kfunc_btf_ids)
BTF_ID_FLAGS(func, bpf_ksock_release, KF_RELEASE)
BTF_ID_FLAGS(func, bpf_ksock_acquire, KF_ACQUIRE | KF_RCU | KF_RET_NULL)
BTF_ID_FLAGS(func, bpf_ksock_send, KF_SLEEPABLE)
+BTF_ID_FLAGS(func, bpf_ksock_sendto, KF_SLEEPABLE)
BTF_KFUNCS_END(ksock_kfunc_btf_ids)
#ifdef CONFIG_BPF_LSM
-BTF_ID_LIST_SINGLE(bpf_lsm_socket_sendmsg_id, func, bpf_lsm_socket_sendmsg)
+BTF_ID_LIST(bpf_lsm_socket_sendmsg_id)
+#ifdef CONFIG_SECURITY_NETWORK
+BTF_ID(func, bpf_lsm_socket_sendmsg)
+#else
+BTF_ID_UNUSED
+#endif
#endif
static int bpf_ksock_kfunc_filter(const struct bpf_prog *prog, u32 kfunc_id)
diff --git a/net/core/bpf_sk_storage.c b/net/core/bpf_sk_storage.c
index 1d295a8769fa..1c59300af05c 100644
--- a/net/core/bpf_sk_storage.c
+++ b/net/core/bpf_sk_storage.c
@@ -164,6 +164,13 @@ int bpf_sk_storage_clone(const struct sock *sk, struct sock *newsk)
if (!sk_storage || hlist_empty(&sk_storage->list))
goto out;
+ /*
+ * The maps lead to newsk as soon as an element is linked, but
+ * sk_clone() sets sk_refcnt only later. Until then it holds whatever
+ * the slab object held before: no reference can be had yet.
+ */
+ refcount_set(&newsk->sk_refcnt, 0);
+
hlist_for_each_entry_rcu(selem, &sk_storage->list, snode) {
struct bpf_local_storage_elem *copy_selem;
struct bpf_local_storage_map *smap;
@@ -692,8 +699,37 @@ struct bpf_iter_seq_sk_storage_map_info {
struct bpf_map *map;
unsigned int bucket_id;
unsigned skip_elems;
+ struct rcu_head *dead_sks;
};
+/*
+ * sock_put() in two halves. The end of a socket may want process context:
+ * rfcomm_sock_destruct() takes a mutex. If the iterator drops the last
+ * reference, it keeps the socket until it has left the RCU read side critical
+ * section. Nobody uses sk_rcu before sk_destruct().
+ */
+static void
+bpf_sk_storage_map_seq_put_sk(struct bpf_iter_seq_sk_storage_map_info *info,
+ struct sock *sk)
+{
+ if (refcount_dec_and_test(&sk->sk_refcnt)) {
+ sk->sk_rcu.next = info->dead_sks;
+ info->dead_sks = &sk->sk_rcu;
+ }
+}
+
+static void
+bpf_sk_storage_map_seq_free_sks(struct bpf_iter_seq_sk_storage_map_info *info)
+{
+ struct sock *sk;
+
+ while (info->dead_sks) {
+ sk = container_of(info->dead_sks, struct sock, sk_rcu);
+ info->dead_sks = sk->sk_rcu.next;
+ sk_free(sk);
+ }
+}
+
static struct bpf_local_storage_elem *
bpf_sk_storage_map_seq_find_next(struct bpf_iter_seq_sk_storage_map_info *info,
struct bpf_local_storage_elem *prev_selem)
@@ -722,6 +758,7 @@ bpf_sk_storage_map_seq_find_next(struct bpf_iter_seq_sk_storage_map_info *info,
/* not found, unlock and go to the next bucket */
b = &smap->buckets[bucket_id++];
rcu_read_unlock();
+ bpf_sk_storage_map_seq_free_sks(info);
skip_elems = 0;
break;
}
@@ -789,12 +826,44 @@ DEFINE_BPF_ITER_FUNC(bpf_sk_storage_map, struct bpf_iter_meta *meta,
struct bpf_map *map, struct sock *sk,
void *value)
+/*
+ * Take a reference on the socket which owns @selem. RCU keeps the element, not
+ * its owner. As long as the element is linked under the lock of the storage,
+ * the owner has not got past bpf_sk_storage_free(), unless that has given up
+ * on the lock. Then it still waits for owner_refcnt.
+ */
+static struct sock *
+bpf_sk_storage_selem_get_sk(struct bpf_local_storage_elem *selem)
+{
+ struct bpf_local_storage *sk_storage;
+ struct sock *sk = NULL;
+ unsigned long flags;
+
+ sk_storage = rcu_dereference(selem->local_storage);
+ /* reset since ->next() looked: the socket goes away */
+ if (!sk_storage)
+ return NULL;
+
+ if (raw_res_spin_lock_irqsave(&sk_storage->lock, flags))
+ return NULL;
+
+ if (!hlist_unhashed(&selem->snode) &&
+ refcount_inc_not_zero(&sk_storage->owner_refcnt)) {
+ sk = sk_storage->owner;
+ if (!refcount_inc_not_zero(&sk->sk_refcnt))
+ sk = NULL;
+ bpf_local_storage_unpin_owner(sk_storage);
+ }
+ raw_res_spin_unlock_irqrestore(&sk_storage->lock, flags);
+
+ return sk;
+}
+
static int __bpf_sk_storage_map_seq_show(struct seq_file *seq,
struct bpf_local_storage_elem *selem)
{
struct bpf_iter_seq_sk_storage_map_info *info = seq->private;
struct bpf_iter__bpf_sk_storage_map ctx = {};
- struct bpf_local_storage *sk_storage;
struct bpf_iter_meta meta;
struct bpf_prog *prog;
int ret = 0;
@@ -805,11 +874,14 @@ static int __bpf_sk_storage_map_seq_show(struct seq_file *seq,
ctx.meta = &meta;
ctx.map = info->map;
if (selem) {
- sk_storage = rcu_dereference(selem->local_storage);
- ctx.sk = sk_storage->owner;
+ ctx.sk = bpf_sk_storage_selem_get_sk(selem);
+ if (!ctx.sk)
+ return SEQ_SKIP;
ctx.value = SDATA(selem)->data;
}
ret = bpf_iter_run_prog(prog, &ctx);
+ if (ctx.sk)
+ bpf_sk_storage_map_seq_put_sk(info, ctx.sk);
}
return ret;
@@ -827,6 +899,7 @@ static void bpf_sk_storage_map_seq_stop(struct seq_file *seq, void *v)
(void)__bpf_sk_storage_map_seq_show(seq, v);
else
rcu_read_unlock();
+ bpf_sk_storage_map_seq_free_sks(seq->private);
}
static int bpf_iter_init_sk_storage_map(void *priv_data,
@@ -846,6 +919,15 @@ static void bpf_iter_fini_sk_storage_map(void *priv_data)
bpf_map_put_with_uref(seq_info->map);
}
+static int bpf_iter_map_check_prog(const struct bpf_prog *prog,
+ const struct bpf_iter_aux_info *aux)
+{
+ if (prog->aux->max_rdwr_access > aux->map->value_size)
+ return -EACCES;
+
+ return bpf_iter_map_check_value_write(prog, aux->map);
+}
+
static int bpf_iter_attach_map(struct bpf_prog *prog,
union bpf_iter_link_info *linfo,
struct bpf_iter_aux_info *aux)
@@ -863,12 +945,11 @@ static int bpf_iter_attach_map(struct bpf_prog *prog,
if (map->map_type != BPF_MAP_TYPE_SK_STORAGE)
goto put_map;
- if (prog->aux->max_rdwr_access > map->value_size) {
- err = -EACCES;
+ aux->map = map;
+ err = bpf_iter_map_check_prog(prog, aux);
+ if (err)
goto put_map;
- }
- aux->map = map;
return 0;
put_map:
@@ -899,6 +980,7 @@ static struct bpf_iter_reg bpf_sk_storage_map_reg_info = {
.target = "bpf_sk_storage_map",
.attach_target = bpf_iter_attach_map,
.detach_target = bpf_iter_detach_map,
+ .check_prog = bpf_iter_map_check_prog,
.show_fdinfo = bpf_iter_map_show_fdinfo,
.fill_link_info = bpf_iter_map_fill_link_info,
.ctx_arg_info_size = 2,
diff --git a/net/core/filter.c b/net/core/filter.c
index 70dc621672f2..b7ac145b68b1 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -1715,6 +1715,24 @@ static inline void bpf_pull_mac_rcsum(struct sk_buff *skb)
skb_postpull_rcsum(skb, skb_mac_header(skb), skb->mac_len);
}
+/*
+ * The source of a write through a dynptr may be a slice of the same skb.
+ * Making the skb writable can move its head: follow the move.
+ */
+static int bpf_try_make_writable_from(struct sk_buff *skb, u32 write_len,
+ const void **from)
+{
+ const void *head = skb->head;
+ bool in_head = *from >= head &&
+ *from < (const void *)skb_end_pointer(skb);
+ int err;
+
+ err = bpf_try_make_writable(skb, write_len);
+ if (!err && in_head)
+ *from = skb->head + (*from - head);
+ return err;
+}
+
BPF_CALL_5(bpf_skb_store_bytes, struct sk_buff *, skb, u32, offset,
const void *, from, u32, len, u64, flags)
{
@@ -1724,14 +1742,15 @@ BPF_CALL_5(bpf_skb_store_bytes, struct sk_buff *, skb, u32, offset,
return -EINVAL;
if (unlikely(offset > INT_MAX))
return -EFAULT;
- if (unlikely(bpf_try_make_writable(skb, offset + len)))
+ if (unlikely(bpf_try_make_writable_from(skb, offset + len, &from)))
return -EFAULT;
ptr = skb->data + offset;
if (flags & BPF_F_RECOMPUTE_CSUM)
__skb_postpull_rcsum(skb, ptr, len, offset);
- memcpy(ptr, from, len);
+ /* through a dynptr the source may be an overlapping slice of the skb */
+ memmove(ptr, from, len);
if (flags & BPF_F_RECOMPUTE_CSUM)
__skb_postpush_rcsum(skb, ptr, len, offset);
@@ -3612,6 +3631,14 @@ static int bpf_skb_net_grow(struct sk_buff *skb, u32 off, u32 len_diff,
return -ENOTSUPP;
}
+ /*
+ * The MSS is lowered by len_diff. Leave the least that the stack lets a
+ * TCP GSO packet have, or gso_segs can overflow.
+ */
+ if (skb_is_gso(skb) && !(flags & BPF_F_ADJ_ROOM_FIXED_GSO) &&
+ skb_shinfo(skb)->gso_size < len_diff + TCP_MIN_GSO_SIZE)
+ return -ENOTSUPP;
+
ret = skb_cow_head(skb, meta_len + len_diff);
if (unlikely(ret < 0))
return ret;
@@ -4303,7 +4330,8 @@ BPF_CALL_4(bpf_xdp_store_bytes, struct xdp_buff *, xdp, u32, offset,
if (!ptr)
bpf_xdp_copy_buf(xdp, offset, buf, len, true);
else
- memcpy(ptr, buf, len);
+ /* through a dynptr the source may be an overlapping slice */
+ memmove(ptr, buf, len);
return 0;
}
@@ -7017,15 +7045,15 @@ static void bpf_update_srh_state(struct sk_buff *skb)
{
struct seg6_bpf_srh_state *srh_state =
this_cpu_ptr(&seg6_bpf_srh_states);
- int srhoff = 0;
- if (ipv6_find_hdr(skb, &srhoff, IPPROTO_ROUTING, NULL, NULL) < 0) {
- srh_state->srh = NULL;
- } else {
- srh_state->srh = (struct ipv6_sr_hdr *)(skb->data + srhoff);
+ /* Behind a decapsulation this is a header that nobody has looked at */
+ srh_state->srh = seg6_get_srh(skb, 0);
+ if (srh_state->srh) {
srh_state->hdrlen = srh_state->srh->hdrlen << 3;
srh_state->valid = true;
}
+ /* it may have been pulled into the head */
+ bpf_compute_data_pointers(skb);
}
BPF_CALL_4(bpf_lwt_seg6_action, struct sk_buff *, skb,
@@ -7058,9 +7086,14 @@ BPF_CALL_4(bpf_lwt_seg6_action, struct sk_buff *, skb,
if (ipv6_find_hdr(skb, &hdroff, IPPROTO_IPV6, NULL, NULL) < 0)
return -EBADMSG;
- if (!pskb_pull(skb, hdroff))
+ /* As long as nothing has been changed, the program goes on */
+ if (!pskb_may_pull(skb, hdroff + sizeof(struct ipv6hdr))) {
+ /* but the head may have moved */
+ bpf_update_srh_state(skb);
return -EBADMSG;
+ }
+ __skb_pull(skb, hdroff);
skb_postpull_rcsum(skb, skb_network_header(skb), hdroff);
skb_reset_network_header(skb);
skb_reset_transport_header(skb);
@@ -7074,8 +7107,8 @@ BPF_CALL_4(bpf_lwt_seg6_action, struct sk_buff *, skb,
return -EBADMSG;
err = bpf_push_seg6_encap(skb, BPF_LWT_ENCAP_SEG6_INLINE,
param, param_len);
- if (!err)
- bpf_update_srh_state(skb);
+ /* The header can be in place although err says otherwise */
+ bpf_update_srh_state(skb);
return err;
case SEG6_LOCAL_ACTION_END_B6_ENCAP:
@@ -7083,8 +7116,8 @@ BPF_CALL_4(bpf_lwt_seg6_action, struct sk_buff *, skb,
return -EBADMSG;
err = bpf_push_seg6_encap(skb, BPF_LWT_ENCAP_SEG6,
param, param_len);
- if (!err)
- bpf_update_srh_state(skb);
+ /* The header can be in place although err says otherwise */
+ bpf_update_srh_state(skb);
return err;
default:
@@ -7600,8 +7633,8 @@ bool bpf_tcp_sock_is_valid_access(int off, int size, enum bpf_access_type type,
return false;
switch (off) {
- case offsetof(struct bpf_tcp_sock, bytes_received):
- case offsetof(struct bpf_tcp_sock, bytes_acked):
+ case bpf_ctx_range(struct bpf_tcp_sock, bytes_received):
+ case bpf_ctx_range(struct bpf_tcp_sock, bytes_acked):
return size == sizeof(__u64);
default:
return size == sizeof(__u32);
@@ -8052,17 +8085,14 @@ static const u8 *bpf_search_tcp_opt(const u8 *op, const u8 *opend,
return ERR_PTR(-ENOMSG);
}
-BPF_CALL_4(bpf_sock_ops_load_hdr_opt, struct bpf_sock_ops_kern *, bpf_sock,
- void *, search_res, u32, len, u64, flags)
+int __bpf_sock_ops_load_hdr_opt(struct bpf_sock_ops_kern *bpf_sock,
+ void *search_res, u32 len, u64 flags)
{
bool eol, load_syn = flags & BPF_LOAD_HDR_OPT_TCP_SYN;
const u8 *op, *opend, *magic, *search = search_res;
u8 search_kind, search_len, copy_len, magic_len;
int ret;
- if (!is_locked_tcp_sock_ops(bpf_sock))
- return -EOPNOTSUPP;
-
/* 2 byte is the minimal option len except TCPOPT_NOP and
* TCPOPT_EOL which are useless for the bpf prog to learn
* and this helper disallow loading them also.
@@ -8123,6 +8153,15 @@ BPF_CALL_4(bpf_sock_ops_load_hdr_opt, struct bpf_sock_ops_kern *, bpf_sock,
return ret;
}
+BPF_CALL_4(bpf_sock_ops_load_hdr_opt, struct bpf_sock_ops_kern *, bpf_sock,
+ void *, search_res, u32, len, u64, flags)
+{
+ if (!is_locked_tcp_sock_ops(bpf_sock))
+ return -EOPNOTSUPP;
+
+ return __bpf_sock_ops_load_hdr_opt(bpf_sock, search_res, len, flags);
+}
+
static const struct bpf_func_proto bpf_sock_ops_load_hdr_opt_proto = {
.func = bpf_sock_ops_load_hdr_opt,
.gpl_only = false,
@@ -8133,17 +8172,14 @@ static const struct bpf_func_proto bpf_sock_ops_load_hdr_opt_proto = {
.arg4_type = ARG_ANYTHING,
};
-BPF_CALL_4(bpf_sock_ops_store_hdr_opt, struct bpf_sock_ops_kern *, bpf_sock,
- const void *, from, u32, len, u64, flags)
+int __bpf_sock_ops_store_hdr_opt(struct bpf_sock_ops_kern *bpf_sock,
+ const void *from, u32 len, u64 flags)
{
u8 new_kind, new_kind_len, magic_len = 0, *opend;
const u8 *op, *new_op, *magic = NULL;
struct sk_buff *skb;
bool eol;
- if (bpf_sock->op != BPF_SOCK_OPS_WRITE_HDR_OPT_CB)
- return -EPERM;
-
if (len < 2 || flags)
return -EINVAL;
@@ -8201,6 +8237,15 @@ BPF_CALL_4(bpf_sock_ops_store_hdr_opt, struct bpf_sock_ops_kern *, bpf_sock,
return 0;
}
+BPF_CALL_4(bpf_sock_ops_store_hdr_opt, struct bpf_sock_ops_kern *, bpf_sock,
+ const void *, from, u32, len, u64, flags)
+{
+ if (bpf_sock->op != BPF_SOCK_OPS_WRITE_HDR_OPT_CB)
+ return -EPERM;
+
+ return __bpf_sock_ops_store_hdr_opt(bpf_sock, from, len, flags);
+}
+
static const struct bpf_func_proto bpf_sock_ops_store_hdr_opt_proto = {
.func = bpf_sock_ops_store_hdr_opt,
.gpl_only = false,
@@ -12402,7 +12447,7 @@ int __bpf_skb_meta_store_bytes(struct sk_buff *skb, u32 offset,
{
if (unlikely(flags))
return -EINVAL;
- if (unlikely(bpf_try_make_writable(skb, 0)))
+ if (unlikely(bpf_try_make_writable_from(skb, 0, &from)))
return -EFAULT;
memmove(bpf_skb_meta_pointer(skb, offset), from, len);
@@ -12878,6 +12923,7 @@ static int __init bpf_kfunc_init(void)
ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_LWT_SEG6LOCAL, &bpf_kfunc_set_skb);
ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_NETFILTER, &bpf_kfunc_set_skb);
ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_TRACING, &bpf_kfunc_set_skb);
+ ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_STRUCT_OPS, &bpf_kfunc_set_skb);
ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_SCHED_CLS, &bpf_kfunc_set_skb_meta);
ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_SCHED_ACT, &bpf_kfunc_set_skb_meta);
ret = ret ?: register_btf_kfunc_id_set(BPF_PROG_TYPE_XDP, &bpf_kfunc_set_xdp);
diff --git a/net/core/ptp_classifier.c b/net/core/ptp_classifier.c
index 598041b0499e..939104e25c75 100644
--- a/net/core/ptp_classifier.c
+++ b/net/core/ptp_classifier.c
@@ -2,12 +2,8 @@
/* PTP classifier
*/
-/* The below program is the bpf_asm (tools/net/) representation of
- * the opcode array in the ptp_filter structure.
- *
- * For convenience, this can easily be altered and reviewed with
- * bpf_asm and bpf_dbg, e.g. `./bpf_asm -c prog` where prog is a
- * simple file containing the below program:
+/* The below program is the classic BPF assembly representation of
+ * the opcode array in the ptp_filter structure:
*
* ldh [12] ; load ethertype
*
diff --git a/net/core/sock_map.c b/net/core/sock_map.c
index 38df84284328..057e2f3c0265 100644
--- a/net/core/sock_map.c
+++ b/net/core/sock_map.c
@@ -1933,6 +1933,15 @@ out:
return ret;
}
+static int sock_map_iter_check_prog(const struct bpf_prog *prog,
+ const struct bpf_iter_aux_info *aux)
+{
+ if (prog->aux->max_rdonly_access > aux->map->key_size)
+ return -EACCES;
+
+ return 0;
+}
+
static int sock_map_iter_attach_target(struct bpf_prog *prog,
union bpf_iter_link_info *linfo,
struct bpf_iter_aux_info *aux)
@@ -1951,12 +1960,11 @@ static int sock_map_iter_attach_target(struct bpf_prog *prog,
map->map_type != BPF_MAP_TYPE_SOCKHASH)
goto put_map;
- if (prog->aux->max_rdonly_access > map->key_size) {
- err = -EACCES;
+ aux->map = map;
+ err = sock_map_iter_check_prog(prog, aux);
+ if (err)
goto put_map;
- }
- aux->map = map;
return 0;
put_map:
@@ -1973,6 +1981,7 @@ static struct bpf_iter_reg sock_map_iter_reg = {
.target = "sockmap",
.attach_target = sock_map_iter_attach_target,
.detach_target = sock_map_iter_detach_target,
+ .check_prog = sock_map_iter_check_prog,
.show_fdinfo = bpf_iter_map_show_fdinfo,
.fill_link_info = bpf_iter_map_fill_link_info,
.ctx_arg_info_size = 2,