Merge: bpf: stable backports for 9.7 (phase 2)
MR: https://gitlab.com/redhat/centos-stream/src/kernel/centos-stream-9/-/merge_requests/7177 Depends: !7037 JIRA: https://issues.redhat.com/browse/RHEL-84579 JIRA: https://issues.redhat.com/browse/RHEL-101009 JIRA: https://issues.redhat.com/browse/RHEL-87910 CVE: CVE-2025-21867 CVE: CVE-2025-21997 Backporting fixes for serious issues from upstream. Signed-off-by: Felix Maurer <fmaurer@redhat.com> Approved-by: Murphy Zhou <xzhou@redhat.com> Approved-by: Guillaume Nault <gnault@redhat.com> Approved-by: Toke Høiland-Jørgensen <toke@redhat.com> Approved-by: CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> Merged-by: Jarod Wilson <jarod@redhat.com>
This commit is contained in:
commit
7c87268c54
|
@ -2813,6 +2813,11 @@ static inline bool sk_is_udp(const struct sock *sk)
|
||||||
sk->sk_protocol == IPPROTO_UDP;
|
sk->sk_protocol == IPPROTO_UDP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool sk_is_stream_unix(const struct sock *sk)
|
||||||
|
{
|
||||||
|
return sk->sk_family == AF_UNIX && sk->sk_type == SOCK_STREAM;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* sk_eat_skb - Release a skb if it is no longer needed
|
* sk_eat_skb - Release a skb if it is no longer needed
|
||||||
* @sk: socket to eat this skb from
|
* @sk: socket to eat this skb from
|
||||||
|
|
|
@ -3344,7 +3344,9 @@ int bpf_uprobe_multi_link_attach(const union bpf_attr *attr, struct bpf_prog *pr
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pid) {
|
if (pid) {
|
||||||
|
rcu_read_lock();
|
||||||
task = get_pid_task(find_vpid(pid), PIDTYPE_TGID);
|
task = get_pid_task(find_vpid(pid), PIDTYPE_TGID);
|
||||||
|
rcu_read_unlock();
|
||||||
if (!task) {
|
if (!task) {
|
||||||
err = -ESRCH;
|
err = -ESRCH;
|
||||||
goto error_path_put;
|
goto error_path_put;
|
||||||
|
|
|
@ -647,12 +647,9 @@ static void *bpf_test_init(const union bpf_attr *kattr, u32 user_size,
|
||||||
void __user *data_in = u64_to_user_ptr(kattr->test.data_in);
|
void __user *data_in = u64_to_user_ptr(kattr->test.data_in);
|
||||||
void *data;
|
void *data;
|
||||||
|
|
||||||
if (size < ETH_HLEN || size > PAGE_SIZE - headroom - tailroom)
|
if (user_size < ETH_HLEN || user_size > PAGE_SIZE - headroom - tailroom)
|
||||||
return ERR_PTR(-EINVAL);
|
return ERR_PTR(-EINVAL);
|
||||||
|
|
||||||
if (user_size > size)
|
|
||||||
return ERR_PTR(-EMSGSIZE);
|
|
||||||
|
|
||||||
size = SKB_DATA_ALIGN(size);
|
size = SKB_DATA_ALIGN(size);
|
||||||
data = kzalloc(size + headroom + tailroom, GFP_USER);
|
data = kzalloc(size + headroom + tailroom, GFP_USER);
|
||||||
if (!data)
|
if (!data)
|
||||||
|
|
|
@ -3197,6 +3197,13 @@ static const struct bpf_func_proto bpf_skb_vlan_pop_proto = {
|
||||||
.arg1_type = ARG_PTR_TO_CTX,
|
.arg1_type = ARG_PTR_TO_CTX,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void bpf_skb_change_protocol(struct sk_buff *skb, u16 proto)
|
||||||
|
{
|
||||||
|
skb->protocol = htons(proto);
|
||||||
|
if (skb_valid_dst(skb))
|
||||||
|
skb_dst_drop(skb);
|
||||||
|
}
|
||||||
|
|
||||||
static int bpf_skb_generic_push(struct sk_buff *skb, u32 off, u32 len)
|
static int bpf_skb_generic_push(struct sk_buff *skb, u32 off, u32 len)
|
||||||
{
|
{
|
||||||
/* Caller already did skb_cow() with len as headroom,
|
/* Caller already did skb_cow() with len as headroom,
|
||||||
|
@ -3293,7 +3300,7 @@ static int bpf_skb_proto_4_to_6(struct sk_buff *skb)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
skb->protocol = htons(ETH_P_IPV6);
|
bpf_skb_change_protocol(skb, ETH_P_IPV6);
|
||||||
skb_clear_hash(skb);
|
skb_clear_hash(skb);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -3323,7 +3330,7 @@ static int bpf_skb_proto_6_to_4(struct sk_buff *skb)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
skb->protocol = htons(ETH_P_IP);
|
bpf_skb_change_protocol(skb, ETH_P_IP);
|
||||||
skb_clear_hash(skb);
|
skb_clear_hash(skb);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -3514,10 +3521,10 @@ static int bpf_skb_net_grow(struct sk_buff *skb, u32 off, u32 len_diff,
|
||||||
/* Match skb->protocol to new outer l3 protocol */
|
/* Match skb->protocol to new outer l3 protocol */
|
||||||
if (skb->protocol == htons(ETH_P_IP) &&
|
if (skb->protocol == htons(ETH_P_IP) &&
|
||||||
flags & BPF_F_ADJ_ROOM_ENCAP_L3_IPV6)
|
flags & BPF_F_ADJ_ROOM_ENCAP_L3_IPV6)
|
||||||
skb->protocol = htons(ETH_P_IPV6);
|
bpf_skb_change_protocol(skb, ETH_P_IPV6);
|
||||||
else if (skb->protocol == htons(ETH_P_IPV6) &&
|
else if (skb->protocol == htons(ETH_P_IPV6) &&
|
||||||
flags & BPF_F_ADJ_ROOM_ENCAP_L3_IPV4)
|
flags & BPF_F_ADJ_ROOM_ENCAP_L3_IPV4)
|
||||||
skb->protocol = htons(ETH_P_IP);
|
bpf_skb_change_protocol(skb, ETH_P_IP);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (skb_is_gso(skb)) {
|
if (skb_is_gso(skb)) {
|
||||||
|
@ -3570,10 +3577,10 @@ static int bpf_skb_net_shrink(struct sk_buff *skb, u32 off, u32 len_diff,
|
||||||
/* Match skb->protocol to new outer l3 protocol */
|
/* Match skb->protocol to new outer l3 protocol */
|
||||||
if (skb->protocol == htons(ETH_P_IP) &&
|
if (skb->protocol == htons(ETH_P_IP) &&
|
||||||
flags & BPF_F_ADJ_ROOM_DECAP_L3_IPV6)
|
flags & BPF_F_ADJ_ROOM_DECAP_L3_IPV6)
|
||||||
skb->protocol = htons(ETH_P_IPV6);
|
bpf_skb_change_protocol(skb, ETH_P_IPV6);
|
||||||
else if (skb->protocol == htons(ETH_P_IPV6) &&
|
else if (skb->protocol == htons(ETH_P_IPV6) &&
|
||||||
flags & BPF_F_ADJ_ROOM_DECAP_L3_IPV4)
|
flags & BPF_F_ADJ_ROOM_DECAP_L3_IPV4)
|
||||||
skb->protocol = htons(ETH_P_IP);
|
bpf_skb_change_protocol(skb, ETH_P_IP);
|
||||||
|
|
||||||
if (skb_is_gso(skb)) {
|
if (skb_is_gso(skb)) {
|
||||||
struct skb_shared_info *shinfo = skb_shinfo(skb);
|
struct skb_shared_info *shinfo = skb_shinfo(skb);
|
||||||
|
|
|
@ -647,6 +647,13 @@ static void sk_psock_backlog(struct work_struct *work)
|
||||||
u32 len, off;
|
u32 len, off;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
/* Increment the psock refcnt to synchronize with close(fd) path in
|
||||||
|
* sock_map_close(), ensuring we wait for backlog thread completion
|
||||||
|
* before sk_socket freed. If refcnt increment fails, it indicates
|
||||||
|
* sock_map_close() completed with sk_socket potentially already freed.
|
||||||
|
*/
|
||||||
|
if (!sk_psock_get(psock->sk))
|
||||||
|
return;
|
||||||
mutex_lock(&psock->work_mutex);
|
mutex_lock(&psock->work_mutex);
|
||||||
if (unlikely(state->skb)) {
|
if (unlikely(state->skb)) {
|
||||||
spin_lock_bh(&psock->ingress_lock);
|
spin_lock_bh(&psock->ingress_lock);
|
||||||
|
@ -697,6 +704,7 @@ start:
|
||||||
}
|
}
|
||||||
end:
|
end:
|
||||||
mutex_unlock(&psock->work_mutex);
|
mutex_unlock(&psock->work_mutex);
|
||||||
|
sk_psock_put(psock->sk, psock);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct sk_psock *sk_psock_init(struct sock *sk, int node)
|
struct sk_psock *sk_psock_init(struct sock *sk, int node)
|
||||||
|
|
|
@ -538,6 +538,8 @@ static bool sock_map_sk_state_allowed(const struct sock *sk)
|
||||||
{
|
{
|
||||||
if (sk_is_tcp(sk))
|
if (sk_is_tcp(sk))
|
||||||
return (1 << sk->sk_state) & (TCPF_ESTABLISHED | TCPF_LISTEN);
|
return (1 << sk->sk_state) & (TCPF_ESTABLISHED | TCPF_LISTEN);
|
||||||
|
if (sk_is_stream_unix(sk))
|
||||||
|
return (1 << sk->sk_state) & TCPF_ESTABLISHED;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -162,15 +162,30 @@ int unix_stream_bpf_update_proto(struct sock *sk, struct sk_psock *psock, bool r
|
||||||
{
|
{
|
||||||
struct sock *sk_pair;
|
struct sock *sk_pair;
|
||||||
|
|
||||||
|
/* Restore does not decrement the sk_pair reference yet because we must
|
||||||
|
* keep the a reference to the socket until after an RCU grace period
|
||||||
|
* and any pending sends have completed.
|
||||||
|
*/
|
||||||
if (restore) {
|
if (restore) {
|
||||||
sk->sk_write_space = psock->saved_write_space;
|
sk->sk_write_space = psock->saved_write_space;
|
||||||
sock_replace_proto(sk, psock->sk_proto);
|
sock_replace_proto(sk, psock->sk_proto);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
sk_pair = unix_peer(sk);
|
/* psock_update_sk_prot can be called multiple times if psock is
|
||||||
sock_hold(sk_pair);
|
* added to multiple maps and/or slots in the same map. There is
|
||||||
psock->sk_pair = sk_pair;
|
* also an edge case where replacing a psock with itself can trigger
|
||||||
|
* an extra psock_update_sk_prot during the insert process. So it
|
||||||
|
* must be safe to do multiple calls. Here we need to ensure we don't
|
||||||
|
* increment the refcnt through sock_hold many times. There will only
|
||||||
|
* be a single matching destroy operation.
|
||||||
|
*/
|
||||||
|
if (!psock->sk_pair) {
|
||||||
|
sk_pair = unix_peer(sk);
|
||||||
|
sock_hold(sk_pair);
|
||||||
|
psock->sk_pair = sk_pair;
|
||||||
|
}
|
||||||
|
|
||||||
unix_stream_bpf_check_needs_rebuild(psock->sk_proto);
|
unix_stream_bpf_check_needs_rebuild(psock->sk_proto);
|
||||||
sock_replace_proto(sk, &unix_stream_bpf_prot);
|
sock_replace_proto(sk, &unix_stream_bpf_prot);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -106,7 +106,7 @@ struct xsk_buff_pool *xp_create_and_assign_umem(struct xdp_sock *xs,
|
||||||
if (pool->unaligned)
|
if (pool->unaligned)
|
||||||
pool->free_heads[i] = xskb;
|
pool->free_heads[i] = xskb;
|
||||||
else
|
else
|
||||||
xp_init_xskb_addr(xskb, pool, i * pool->chunk_size);
|
xp_init_xskb_addr(xskb, pool, (u64)i * pool->chunk_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
return pool;
|
return pool;
|
||||||
|
|
|
@ -111,6 +111,9 @@ static int xsk_diag_fill(struct sock *sk, struct sk_buff *nlskb,
|
||||||
sock_diag_save_cookie(sk, msg->xdiag_cookie);
|
sock_diag_save_cookie(sk, msg->xdiag_cookie);
|
||||||
|
|
||||||
mutex_lock(&xs->mutex);
|
mutex_lock(&xs->mutex);
|
||||||
|
if (READ_ONCE(xs->state) == XSK_UNBOUND)
|
||||||
|
goto out_nlmsg_trim;
|
||||||
|
|
||||||
if ((req->xdiag_show & XDP_SHOW_INFO) && xsk_diag_put_info(xs, nlskb))
|
if ((req->xdiag_show & XDP_SHOW_INFO) && xsk_diag_put_info(xs, nlskb))
|
||||||
goto out_nlmsg_trim;
|
goto out_nlmsg_trim;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue