]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
6.12-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 2 Jul 2026 08:39:39 +0000 (10:39 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 2 Jul 2026 08:39:39 +0000 (10:39 +0200)
added patches:
apparmor-fix-use-after-free-in-rawdata-dedup-loop.patch
apparmor-mediate-the-implicit-connect-of-tcp-fast-open-sendmsg.patch
mac802154-llsec-add-skb_cow_data-before-in-place-crypto.patch
net-ip_gre-require-cap_net_admin-in-the-device-netns-for-changelink.patch
net-skmsg-preserve-sg.copy-across-sg-transforms.patch

queue-6.12/apparmor-fix-use-after-free-in-rawdata-dedup-loop.patch [new file with mode: 0644]
queue-6.12/apparmor-mediate-the-implicit-connect-of-tcp-fast-open-sendmsg.patch [new file with mode: 0644]
queue-6.12/mac802154-llsec-add-skb_cow_data-before-in-place-crypto.patch [new file with mode: 0644]
queue-6.12/net-ip_gre-require-cap_net_admin-in-the-device-netns-for-changelink.patch [new file with mode: 0644]
queue-6.12/net-skmsg-preserve-sg.copy-across-sg-transforms.patch [new file with mode: 0644]
queue-6.12/series

diff --git a/queue-6.12/apparmor-fix-use-after-free-in-rawdata-dedup-loop.patch b/queue-6.12/apparmor-fix-use-after-free-in-rawdata-dedup-loop.patch
new file mode 100644 (file)
index 0000000..0a55cb8
--- /dev/null
@@ -0,0 +1,107 @@
+From 6f060496d03e4dc560a40f73770bd08335cb7a27 Mon Sep 17 00:00:00 2001
+From: Ruslan Valiyev <linuxoid@gmail.com>
+Date: Tue, 26 May 2026 00:04:46 +0200
+Subject: apparmor: fix use-after-free in rawdata dedup loop
+
+From: Ruslan Valiyev <linuxoid@gmail.com>
+
+commit 6f060496d03e4dc560a40f73770bd08335cb7a27 upstream.
+
+aa_replace_profiles() walks ns->rawdata_list to dedup the incoming
+policy blob against entries already attached to existing profiles.
+Per the kernel-doc on struct aa_loaddata, list membership does not
+hold a reference: profiles hold pcount, and when the last pcount
+drops, do_ploaddata_rmfs() is queued on a workqueue that takes
+ns->lock and removes the entry. Between dropping the last pcount
+and the workqueue running, an entry remains on the list with
+pcount == 0.
+
+aa_get_profile_loaddata() is an unconditional kref_get() on
+pcount, so when the dedup loop hits such an entry, refcount
+hardening reports
+
+  refcount_t: addition on 0; use-after-free.
+
+inside aa_replace_profiles(), and the poisoned counter then
+trips "saturated" and "underflow" warnings on the subsequent
+uses of the same loaddata.
+
+Before commit a0b7091c4de4 ("apparmor: fix race on rawdata
+dereference") the dedup path used a get_unless_zero-style helper
+on a single counter, so the existing "if (tmp)" guard was
+meaningful. The split-refcount refactor introduced
+aa_get_profile_loaddata(), which has plain kref_get() semantics,
+and the guard quietly became a no-op.
+
+Introduce aa_get_profile_loaddata_not0(), matching the existing
+_not0 convention used by aa_get_profile_not0(), and use it for
+the rawdata_list dedup lookup so dying entries are skipped.
+
+Reproduced on x86_64 with v7.1-rc5 in QEMU+KVM running Ubuntu
+24.04 + stress-ng 0.17.06:
+
+  stress-ng --apparmor 1 --klog-check --timeout 60s
+
+Without this patch the three refcount_t warnings fire within a
+few seconds. With it the same 60 s run is clean. Coverage is a
+smoke-test only; a longer soak with CONFIG_KASAN, CONFIG_KCSAN
+and CONFIG_PROVE_LOCKING would be welcome from anyone with the
+cycles.
+
+Fixes: a0b7091c4de4 ("apparmor: fix race on rawdata dereference")
+Reported-by: Colin Ian King <colin.i.king@gmail.com>
+Closes: https://bugzilla.kernel.org/show_bug.cgi?id=221513
+Cc: stable@vger.kernel.org
+Signed-off-by: Ruslan Valiyev <linuxoid@gmail.com>
+Signed-off-by: John Johansen <john.johansen@canonical.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ security/apparmor/include/policy_unpack.h |   19 +++++++++++++++++++
+ security/apparmor/policy.c                |    8 ++++++--
+ 2 files changed, 25 insertions(+), 2 deletions(-)
+
+--- a/security/apparmor/include/policy_unpack.h
++++ b/security/apparmor/include/policy_unpack.h
+@@ -163,6 +163,25 @@ aa_get_profile_loaddata(struct aa_loadda
+       return data;
+ }
++/**
++ * aa_get_profile_loaddata_not0 - get a profile reference count if not zero
++ * @data: reference to get a count on
++ *
++ * Like aa_get_profile_loaddata(), but safe to call on an entry that may
++ * be on a list (e.g. ns->rawdata_list) where the last pcount has already
++ * dropped and the deferred cleanup has not yet run.
++ *
++ * Returns: pointer to reference, or %NULL if @data is NULL or its
++ *          profile refcount has already reached zero.
++ */
++static inline struct aa_loaddata *
++aa_get_profile_loaddata_not0(struct aa_loaddata *data)
++{
++      if (data && kref_get_unless_zero(&data->pcount))
++              return data;
++      return NULL;
++}
++
+ void __aa_loaddata_update(struct aa_loaddata *data, long revision);
+ bool aa_rawdata_eq(struct aa_loaddata *l, struct aa_loaddata *r);
+ void aa_loaddata_kref(struct kref *kref);
+--- a/security/apparmor/policy.c
++++ b/security/apparmor/policy.c
+@@ -1175,8 +1175,12 @@ ssize_t aa_replace_profiles(struct aa_ns
+                       if (aa_rawdata_eq(rawdata_ent, udata)) {
+                               struct aa_loaddata *tmp;
+-                              tmp = aa_get_profile_loaddata(rawdata_ent);
+-                              /* check we didn't fail the race */
++                              /*
++                               * Entries remain on rawdata_list with
++                               * pcount == 0 until do_ploaddata_rmfs()
++                               * runs; only take a live profile ref.
++                               */
++                              tmp = aa_get_profile_loaddata_not0(rawdata_ent);
+                               if (tmp) {
+                                       aa_put_profile_loaddata(udata);
+                                       udata = tmp;
diff --git a/queue-6.12/apparmor-mediate-the-implicit-connect-of-tcp-fast-open-sendmsg.patch b/queue-6.12/apparmor-mediate-the-implicit-connect-of-tcp-fast-open-sendmsg.patch
new file mode 100644 (file)
index 0000000..5a9ff17
--- /dev/null
@@ -0,0 +1,55 @@
+From 4d587cd8a72155089a627130bbd4716ec0856e21 Mon Sep 17 00:00:00 2001
+From: Bryam Vargas <hexlabsecurity@proton.me>
+Date: Mon, 22 Jun 2026 15:57:38 -0500
+Subject: apparmor: mediate the implicit connect of TCP fast open sendmsg
+
+From: Bryam Vargas <hexlabsecurity@proton.me>
+
+commit 4d587cd8a72155089a627130bbd4716ec0856e21 upstream.
+
+sendmsg()/sendto() with MSG_FASTOPEN is a combination of connect(2) and
+write(2): it opens the connection in the SYN. apparmor_socket_sendmsg()
+only checks AA_MAY_SEND, so a profile that grants send but denies connect
+lets a confined task open an outbound TCP/MPTCP connection that connect(2)
+would have refused, bypassing connect mediation.
+
+Mediate the implicit connect when MSG_FASTOPEN is set and a destination
+is supplied. Add it to apparmor_socket_sendmsg() (not the shared
+aa_sock_msg_perm() helper, which recvmsg also uses) and call aa_sk_perm()
+directly, mirroring the selinux and tomoyo fixes. sk_is_tcp() does not
+cover MPTCP fast open, so the SOCK_STREAM/IPPROTO_MPTCP arm is explicit.
+
+Fixes: cf60af03ca4e ("net-tcp: Fast Open client - sendmsg(MSG_FASTOPEN)")
+Cc: stable@vger.kernel.org
+Signed-off-by: Bryam Vargas <hexlabsecurity@proton.me>
+Signed-off-by: John Johansen <john.johansen@canonical.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ security/apparmor/lsm.c |   16 +++++++++++++++-
+ 1 file changed, 15 insertions(+), 1 deletion(-)
+
+--- a/security/apparmor/lsm.c
++++ b/security/apparmor/lsm.c
+@@ -1207,7 +1207,21 @@ static int aa_sock_msg_perm(const char *
+ static int apparmor_socket_sendmsg(struct socket *sock,
+                                  struct msghdr *msg, int size)
+ {
+-      return aa_sock_msg_perm(OP_SENDMSG, AA_MAY_SEND, sock, msg, size);
++      int error = aa_sock_msg_perm(OP_SENDMSG, AA_MAY_SEND, sock, msg, size);
++
++      if (error)
++              return error;
++
++      /* TCP fast open carries connect() semantics in sendmsg(); mediate
++       * the implicit connect so it cannot bypass the connect permission.
++       */
++      if ((msg->msg_flags & MSG_FASTOPEN) && msg->msg_name &&
++          (sk_is_tcp(sock->sk) ||
++           (sk_is_inet(sock->sk) && sock->sk->sk_type == SOCK_STREAM &&
++            sock->sk->sk_protocol == IPPROTO_MPTCP)))
++              error = aa_sk_perm(OP_CONNECT, AA_MAY_CONNECT, sock->sk);
++
++      return error;
+ }
+ static int apparmor_socket_recvmsg(struct socket *sock,
diff --git a/queue-6.12/mac802154-llsec-add-skb_cow_data-before-in-place-crypto.patch b/queue-6.12/mac802154-llsec-add-skb_cow_data-before-in-place-crypto.patch
new file mode 100644 (file)
index 0000000..b37ace2
--- /dev/null
@@ -0,0 +1,98 @@
+From 84a04eb5b210643bd67aab81ff805d32f62aa865 Mon Sep 17 00:00:00 2001
+From: Doruk Tan Ozturk <doruk@0sec.ai>
+Date: Tue, 26 May 2026 20:37:26 +0200
+Subject: mac802154: llsec: add skb_cow_data() before in-place crypto
+
+From: Doruk Tan Ozturk <doruk@0sec.ai>
+
+commit 84a04eb5b210643bd67aab81ff805d32f62aa865 upstream.
+
+llsec_do_encrypt_unauth(), llsec_do_encrypt_auth(),
+llsec_do_decrypt_unauth(), and llsec_do_decrypt_auth() all perform
+in-place cryptographic transformations on skb data.  They build a
+scatterlist with sg_init_one() pointing into the skb's linear data area
+and then pass the same scatterlist as both src and dst to the crypto API
+(e.g. crypto_skcipher_encrypt/decrypt, crypto_aead_encrypt/decrypt).
+
+On the RX path, __ieee802154_rx_handle_packet() clones the received skb
+before handing it to each subscriber via ieee802154_subif_frame().  The
+cloned skb shares the same underlying data buffer via reference
+counting.  When llsec_do_decrypt() subsequently modifies this shared
+buffer in place, it corrupts data that other clones -- potentially
+belonging to other sockets or subsystems -- still reference.
+
+On the TX path, similar data sharing can occur when an skb's head has
+been cloned (skb_cloned() returns true).
+
+The fix is to call skb_cow_data() before performing any in-place crypto
+operation.  skb_cow_data() ensures that the skb's data area is not
+shared: if the skb head is cloned or the data spans multiple fragments,
+it copies the data into a private buffer that can be safely modified in
+place.  This is the same pattern used by:
+
+  - ESP (net/ipv4/esp4.c, net/ipv6/esp6.c)
+  - MACsec (drivers/net/macsec.c)
+  - WireGuard (drivers/net/wireguard/receive.c)
+  - TIPC (net/tipc/crypto.c)
+
+Without this guard, in-place crypto on shared skb data leads to:
+  - Silent data corruption of other skb clones
+  - Use-after-free when the crypto API scatterwalk writes through a
+    page that has already been freed by another clone's kfree_skb()
+  - Kernel crashes under concurrent 802.15.4 traffic with security
+    enabled (KASAN/KMSAN reports slab-use-after-free)
+
+Found by 0sec (https://0sec.ai) using automated source analysis.
+
+Fixes: 4c14a2fb5d14 ("mac802154: add llsec decryption method")
+Fixes: 03556e4d0dbb ("mac802154: add llsec encryption method")
+Cc: stable@vger.kernel.org
+Reported-by: Doruk Tan Ozturk <doruk@0sec.ai>
+Closes: https://lore.kernel.org/linux-wpan/20260525161806.96158-1-doruk@0sec.ai/
+Reviewed-by: Alexander Lobakin <aleksander.lobakin@intel.com>
+Signed-off-by: Doruk Tan Ozturk <doruk@0sec.ai>
+Closes: <link to your mail on lore>
+Link: https://lore.kernel.org/20260526183726.56100-1-doruk@0sec.ai
+Signed-off-by: Stefan Schmidt <stefan@datenfreihafen.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ net/mac802154/llsec.c |   14 ++++++++++++++
+ 1 file changed, 14 insertions(+)
+
+--- a/net/mac802154/llsec.c
++++ b/net/mac802154/llsec.c
+@@ -710,6 +710,7 @@ int mac802154_llsec_encrypt(struct mac80
+ {
+       struct ieee802154_hdr hdr;
+       int rc, authlen, hlen;
++      struct sk_buff *trailer;
+       struct mac802154_llsec_key *key;
+       u32 frame_ctr;
+@@ -769,6 +770,12 @@ int mac802154_llsec_encrypt(struct mac80
+       skb->mac_len = ieee802154_hdr_push(skb, &hdr);
+       skb_reset_mac_header(skb);
++      rc = skb_cow_data(skb, 0, &trailer);
++      if (rc < 0) {
++              llsec_key_put(key);
++              return rc;
++      }
++
+       rc = llsec_do_encrypt(skb, sec, &hdr, key);
+       llsec_key_put(key);
+@@ -908,6 +915,13 @@ llsec_do_decrypt(struct sk_buff *skb, co
+                const struct ieee802154_hdr *hdr,
+                struct mac802154_llsec_key *key, __le64 dev_addr)
+ {
++      struct sk_buff *trailer;
++      int err;
++
++      err = skb_cow_data(skb, 0, &trailer);
++      if (err < 0)
++              return err;
++
+       if (hdr->sec.level == IEEE802154_SCF_SECLEVEL_ENC)
+               return llsec_do_decrypt_unauth(skb, sec, hdr, key, dev_addr);
+       else
diff --git a/queue-6.12/net-ip_gre-require-cap_net_admin-in-the-device-netns-for-changelink.patch b/queue-6.12/net-ip_gre-require-cap_net_admin-in-the-device-netns-for-changelink.patch
new file mode 100644 (file)
index 0000000..6497509
--- /dev/null
@@ -0,0 +1,95 @@
+From 8165f7ff57d9667d2bb477ef6af83ede7fed4ad7 Mon Sep 17 00:00:00 2001
+From: Maoyi Xie <maoyixie.tju@gmail.com>
+Date: Fri, 12 Jun 2026 16:59:35 +0800
+Subject: net: ip_gre: require CAP_NET_ADMIN in the device netns for changelink
+
+From: Maoyi Xie <maoyixie.tju@gmail.com>
+
+commit 8165f7ff57d9667d2bb477ef6af83ede7fed4ad7 upstream.
+
+A tunnel changelink() operates on at most two netns, dev_net(dev) and
+the tunnel link netns t->net. They differ once the device is created in
+or moved to a netns other than the one the request runs in. The rtnl
+changelink path checks CAP_NET_ADMIN only against dev_net(dev), so a
+caller privileged there but not in t->net can rewrite a tunnel that
+lives in t->net.
+
+Add rtnl_dev_link_net_capable() next to rtnl_get_net_ns_capable() in
+net/core/rtnetlink.c. It requires CAP_NET_ADMIN in the link netns and is
+skipped when the link netns is dev_net(dev), where the rtnl path already
+checked it. The other patches in this series use the same helper.
+
+Gate ipgre_changelink() and erspan_changelink() with it, at the top of
+the op before any attribute is parsed, because the parsers update live
+tunnel fields first. ipgre_netlink_parms() sets t->collect_md before
+ip_tunnel_changelink() runs.
+
+Commit 8b484efd5cb4 ("ip6: vti: Use ip6_tnl.net in
+vti6_siocdevprivate().") added the same check on the ioctl path. This
+adds it on RTM_NEWLINK.
+
+Reported-by: Xiao Liang <shaw.leon@gmail.com>
+Closes: https://lore.kernel.org/netdev/CABAhCOSzP1vaThGV35_VnsRCb=87_CPjPVsTHbq905k8A+BuUg@mail.gmail.com/
+Fixes: b57708add314 ("gre: add x-netns support")
+Cc: stable@vger.kernel.org
+Signed-off-by: Maoyi Xie <maoyixie.tju@gmail.com>
+Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com>
+Link: https://patch.msgid.link/20260612085941.3158249-2-maoyixie.tju@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/net/rtnetlink.h |    2 ++
+ net/core/rtnetlink.c    |    8 ++++++++
+ net/ipv4/ip_gre.c       |    6 ++++++
+ 3 files changed, 16 insertions(+)
+
+--- a/include/net/rtnetlink.h
++++ b/include/net/rtnetlink.h
+@@ -212,6 +212,8 @@ int rtnl_configure_link(struct net_devic
+ int rtnl_nla_parse_ifinfomsg(struct nlattr **tb, const struct nlattr *nla_peer,
+                            struct netlink_ext_ack *exterr);
+ struct net *rtnl_get_net_ns_capable(struct sock *sk, int netnsid);
++bool rtnl_dev_link_net_capable(const struct net_device *dev,
++                             const struct net *link_net);
+ #define MODULE_ALIAS_RTNL_LINK(kind) MODULE_ALIAS("rtnl-link-" kind)
+--- a/net/core/rtnetlink.c
++++ b/net/core/rtnetlink.c
+@@ -2205,6 +2205,14 @@ struct net *rtnl_get_net_ns_capable(stru
+ }
+ EXPORT_SYMBOL_GPL(rtnl_get_net_ns_capable);
++bool rtnl_dev_link_net_capable(const struct net_device *dev,
++                             const struct net *link_net)
++{
++      return net_eq(link_net, dev_net(dev)) ||
++             ns_capable(link_net->user_ns, CAP_NET_ADMIN);
++}
++EXPORT_SYMBOL_GPL(rtnl_dev_link_net_capable);
++
+ static int rtnl_valid_dump_ifinfo_req(const struct nlmsghdr *nlh,
+                                     bool strict_check, struct nlattr **tb,
+                                     struct netlink_ext_ack *extack)
+--- a/net/ipv4/ip_gre.c
++++ b/net/ipv4/ip_gre.c
+@@ -1446,6 +1446,9 @@ static int ipgre_changelink(struct net_d
+       __u32 fwmark = t->fwmark;
+       int err;
++      if (!rtnl_dev_link_net_capable(dev, t->net))
++              return -EPERM;
++
+       err = ipgre_newlink_encap_setup(dev, data);
+       if (err)
+               return err;
+@@ -1475,6 +1478,9 @@ static int erspan_changelink(struct net_
+       __u32 fwmark = t->fwmark;
+       int err;
++      if (!rtnl_dev_link_net_capable(dev, t->net))
++              return -EPERM;
++
+       err = ipgre_newlink_encap_setup(dev, data);
+       if (err)
+               return err;
diff --git a/queue-6.12/net-skmsg-preserve-sg.copy-across-sg-transforms.patch b/queue-6.12/net-skmsg-preserve-sg.copy-across-sg-transforms.patch
new file mode 100644 (file)
index 0000000..9c26783
--- /dev/null
@@ -0,0 +1,288 @@
+From 406e8a651a7b854c41fecd5117bb282b3a6c2c6b Mon Sep 17 00:00:00 2001
+From: Yiming Qian <yimingqian591@gmail.com>
+Date: Wed, 10 Jun 2026 06:21:36 +0000
+Subject: net: skmsg: preserve sg.copy across SG transforms
+
+From: Yiming Qian <yimingqian591@gmail.com>
+
+commit 406e8a651a7b854c41fecd5117bb282b3a6c2c6b upstream.
+
+The sk_msg sg.copy bitmap is part of the scatterlist entry ownership
+state. A set bit tells sk_msg_compute_data_pointers() not to expose the
+entry through writable BPF ctx->data. This protects entries backed by
+pages that are not private to the sk_msg, such as splice-backed file
+page-cache pages.
+
+Several sk_msg transform paths move, copy, split, or compact
+msg->sg.data[] entries without moving the matching sg.copy bit. This can
+make an externally backed entry arrive at a new slot with a clear copy
+bit. A later SK_MSG verdict can then expose sg_virt(sge) as writable
+ctx->data and BPF stores can modify the original page cache.
+
+Keep sg.copy synchronized with sg.data[] whenever entries are
+transferred, shifted, split, or copied into a new sk_msg. Clear the bit
+when an entry is replaced by a newly allocated private page or freed.
+This covers the BPF pull/push/pop helpers, sk_msg_shift_left/right(),
+sk_msg_xfer(), and tls_split_open_record(), including the partial tail
+entry created during TLS open-record splitting.
+
+Fixes: d3b18ad31f93 ("tls: add bpf support to sk_msg handling")
+Cc: stable@vger.kernel.org
+Reported-by: Yiming Qian <yimingqian591@gmail.com>
+Reported-by: Keenan Dong <keenanat2000@gmail.com>
+Signed-off-by: Yiming Qian <yimingqian591@gmail.com>
+Link: https://patch.msgid.link/20260610062137.49075-1-yimingqian591@gmail.com
+Signed-off-by: Jakub Kicinski <kuba@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ include/linux/skmsg.h |   15 +++++++++++----
+ net/core/filter.c     |   27 +++++++++++++++++++++++++++
+ net/core/skmsg.c      |    2 ++
+ net/tls/tls_sw.c      |    4 ++++
+ 4 files changed, 44 insertions(+), 4 deletions(-)
+
+--- a/include/linux/skmsg.h
++++ b/include/linux/skmsg.h
+@@ -4,6 +4,7 @@
+ #ifndef _LINUX_SKMSG_H
+ #define _LINUX_SKMSG_H
++#include <linux/bitops.h>
+ #include <linux/bpf.h>
+ #include <linux/filter.h>
+ #include <linux/scatterlist.h>
+@@ -199,11 +200,14 @@ static inline void sk_msg_xfer(struct sk
+                              int which, u32 size)
+ {
+       dst->sg.data[which] = src->sg.data[which];
++      __assign_bit(which, dst->sg.copy, test_bit(which, src->sg.copy));
+       dst->sg.data[which].length  = size;
+       dst->sg.size               += size;
+       src->sg.size               -= size;
+       src->sg.data[which].length -= size;
+       src->sg.data[which].offset += size;
++      if (!src->sg.data[which].length)
++              __clear_bit(which, src->sg.copy);
+ }
+ static inline void sk_msg_xfer_full(struct sk_msg *dst, struct sk_msg *src)
+@@ -273,16 +277,19 @@ static inline void sk_msg_page_add(struc
+ static inline void sk_msg_sg_copy(struct sk_msg *msg, u32 i, bool copy_state)
+ {
+       do {
+-              if (copy_state)
+-                      __set_bit(i, msg->sg.copy);
+-              else
+-                      __clear_bit(i, msg->sg.copy);
++              __assign_bit(i, msg->sg.copy, copy_state);
+               sk_msg_iter_var_next(i);
+               if (i == msg->sg.end)
+                       break;
+       } while (1);
+ }
++static inline void sk_msg_sg_copy_assign(struct sk_msg *dst, u32 dst_i,
++                                       const struct sk_msg *src, u32 src_i)
++{
++      __assign_bit(dst_i, dst->sg.copy, test_bit(src_i, src->sg.copy));
++}
++
+ static inline void sk_msg_sg_copy_set(struct sk_msg *msg, u32 start)
+ {
+       sk_msg_sg_copy(msg, start, true);
+--- a/net/core/filter.c
++++ b/net/core/filter.c
+@@ -2740,11 +2740,13 @@ BPF_CALL_4(bpf_msg_pull_data, struct sk_
+               poffset += len;
+               sge->length = 0;
+               put_page(sg_page(sge));
++              __clear_bit(i, msg->sg.copy);
+               sk_msg_iter_var_next(i);
+       } while (i != last_sge);
+       sg_set_page(&msg->sg.data[first_sge], page, copy, 0);
++      __clear_bit(first_sge, msg->sg.copy);
+       /* To repair sg ring we need to shift entries. If we only
+        * had a single entry though we can just replace it and
+@@ -2770,9 +2772,11 @@ BPF_CALL_4(bpf_msg_pull_data, struct sk_
+                       break;
+               msg->sg.data[i] = msg->sg.data[move_from];
++              sk_msg_sg_copy_assign(msg, i, msg, move_from);
+               msg->sg.data[move_from].length = 0;
+               msg->sg.data[move_from].page_link = 0;
+               msg->sg.data[move_from].offset = 0;
++              __clear_bit(move_from, msg->sg.copy);
+               sk_msg_iter_var_next(i);
+       } while (1);
+@@ -2801,6 +2805,7 @@ BPF_CALL_4(bpf_msg_push_data, struct sk_
+ {
+       struct scatterlist sge, nsge, nnsge, rsge = {0}, *psge;
+       u32 new, i = 0, l = 0, space, copy = 0, offset = 0;
++      bool sge_copy, nsge_copy, nnsge_copy, rsge_copy = false;
+       u8 *raw, *to, *from;
+       struct page *page;
+@@ -2873,6 +2878,7 @@ BPF_CALL_4(bpf_msg_push_data, struct sk_
+                       sk_msg_iter_var_prev(i);
+               psge = sk_msg_elem(msg, i);
+               rsge = sk_msg_elem_cpy(msg, i);
++              rsge_copy = test_bit(i, msg->sg.copy);
+               psge->length = start - offset;
+               rsge.length -= psge->length;
+@@ -2897,24 +2903,32 @@ BPF_CALL_4(bpf_msg_push_data, struct sk_
+       /* Shift one or two slots as needed */
+       sge = sk_msg_elem_cpy(msg, new);
++      sge_copy = test_bit(new, msg->sg.copy);
+       sg_unmark_end(&sge);
+       nsge = sk_msg_elem_cpy(msg, i);
++      nsge_copy = test_bit(i, msg->sg.copy);
+       if (rsge.length) {
+               sk_msg_iter_var_next(i);
+               nnsge = sk_msg_elem_cpy(msg, i);
++              nnsge_copy = test_bit(i, msg->sg.copy);
+               sk_msg_iter_next(msg, end);
+       }
+       while (i != msg->sg.end) {
+               msg->sg.data[i] = sge;
++              __assign_bit(i, msg->sg.copy, sge_copy);
+               sge = nsge;
++              sge_copy = nsge_copy;
+               sk_msg_iter_var_next(i);
+               if (rsge.length) {
+                       nsge = nnsge;
++                      nsge_copy = nnsge_copy;
+                       nnsge = sk_msg_elem_cpy(msg, i);
++                      nnsge_copy = test_bit(i, msg->sg.copy);
+               } else {
+                       nsge = sk_msg_elem_cpy(msg, i);
++                      nsge_copy = test_bit(i, msg->sg.copy);
+               }
+       }
+@@ -2928,6 +2942,7 @@ place_new:
+               get_page(sg_page(&rsge));
+               sk_msg_iter_var_next(new);
+               msg->sg.data[new] = rsge;
++              __assign_bit(new, msg->sg.copy, rsge_copy);
+       }
+       sk_msg_reset_curr(msg);
+@@ -2955,25 +2970,33 @@ static void sk_msg_shift_left(struct sk_
+               prev = i;
+               sk_msg_iter_var_next(i);
+               msg->sg.data[prev] = msg->sg.data[i];
++              sk_msg_sg_copy_assign(msg, prev, msg, i);
+       } while (i != msg->sg.end);
+       sk_msg_iter_prev(msg, end);
++      __clear_bit(msg->sg.end, msg->sg.copy);
+ }
+ static void sk_msg_shift_right(struct sk_msg *msg, int i)
+ {
+       struct scatterlist tmp, sge;
++      bool tmp_copy, sge_copy;
+       sk_msg_iter_next(msg, end);
+       sge = sk_msg_elem_cpy(msg, i);
++      sge_copy = test_bit(i, msg->sg.copy);
+       sk_msg_iter_var_next(i);
+       tmp = sk_msg_elem_cpy(msg, i);
++      tmp_copy = test_bit(i, msg->sg.copy);
+       while (i != msg->sg.end) {
+               msg->sg.data[i] = sge;
++              __assign_bit(i, msg->sg.copy, sge_copy);
+               sk_msg_iter_var_next(i);
+               sge = tmp;
++              sge_copy = tmp_copy;
+               tmp = sk_msg_elem_cpy(msg, i);
++              tmp_copy = test_bit(i, msg->sg.copy);
+       }
+ }
+@@ -3033,6 +3056,8 @@ BPF_CALL_4(bpf_msg_pop_data, struct sk_m
+               struct scatterlist *nsge, *sge = sk_msg_elem(msg, i);
+               int a = start - offset;
+               int b = sge->length - pop - a;
++              u32 sge_i = i;
++              bool sge_copy = test_bit(i, msg->sg.copy);
+               sk_msg_iter_var_next(i);
+@@ -3045,6 +3070,7 @@ BPF_CALL_4(bpf_msg_pop_data, struct sk_m
+                               sg_set_page(nsge,
+                                           sg_page(sge),
+                                           b, sge->offset + pop + a);
++                              __assign_bit(i, msg->sg.copy, sge_copy);
+                       } else {
+                               struct page *page, *orig;
+                               u8 *to, *from;
+@@ -3061,6 +3087,7 @@ BPF_CALL_4(bpf_msg_pop_data, struct sk_m
+                               memcpy(to, from, a);
+                               memcpy(to + a, from + a + pop, b);
+                               sg_set_page(sge, page, a + b, 0);
++                              __clear_bit(sge_i, msg->sg.copy);
+                               put_page(orig);
+                       }
+                       pop = 0;
+--- a/net/core/skmsg.c
++++ b/net/core/skmsg.c
+@@ -66,6 +66,7 @@ int sk_msg_alloc(struct sock *sk, struct
+                       sge = &msg->sg.data[msg->sg.end];
+                       sg_unmark_end(sge);
+                       sg_set_page(sge, pfrag->page, use, orig_offset);
++                      __clear_bit(msg->sg.end, msg->sg.copy);
+                       get_page(pfrag->page);
+                       sk_msg_iter_next(msg, end);
+               }
+@@ -186,6 +187,7 @@ static int sk_msg_free_elem(struct sock
+                       sk_mem_uncharge(sk, len);
+               put_page(sg_page(sge));
+       }
++      __clear_bit(i, msg->sg.copy);
+       memset(sge, 0, sizeof(*sge));
+       return len;
+ }
+--- a/net/tls/tls_sw.c
++++ b/net/tls/tls_sw.c
+@@ -623,6 +623,7 @@ static int tls_split_open_record(struct
+       struct scatterlist *sge, *osge, *nsge;
+       u32 orig_size = msg_opl->sg.size;
+       struct scatterlist tmp = { };
++      u32 tmp_i = 0;
+       struct sk_msg *msg_npl;
+       struct tls_rec *new;
+       int ret;
+@@ -644,6 +645,7 @@ static int tls_split_open_record(struct
+               if (sge->length > apply) {
+                       u32 len = sge->length - apply;
++                      tmp_i = i;
+                       get_page(sg_page(sge));
+                       sg_set_page(&tmp, sg_page(sge), len,
+                                   sge->offset + apply);
+@@ -675,6 +677,7 @@ static int tls_split_open_record(struct
+       nsge = sk_msg_elem(msg_npl, j);
+       if (tmp.length) {
+               memcpy(nsge, &tmp, sizeof(*nsge));
++              sk_msg_sg_copy_assign(msg_npl, j, msg_opl, tmp_i);
+               sk_msg_iter_var_next(j);
+               nsge = sk_msg_elem(msg_npl, j);
+       }
+@@ -682,6 +685,7 @@ static int tls_split_open_record(struct
+       osge = sk_msg_elem(msg_opl, i);
+       while (osge->length) {
+               memcpy(nsge, osge, sizeof(*nsge));
++              sk_msg_sg_copy_assign(msg_npl, j, msg_opl, i);
+               sg_unmark_end(nsge);
+               sk_msg_iter_var_next(i);
+               sk_msg_iter_var_next(j);
index a3a53049f745748bce5db7ef25fa10126177fd02..34310da391fdb9c86984b359eafb5a9e13c5c47e 100644 (file)
@@ -133,3 +133,8 @@ kvm-sev-unmap-and-unpin-the-ghcb-as-needed-on-vcpu-f.patch
 af_unix-set-gc_in_progress-to-true-in-unix_gc.patch
 mtd-spi-nor-macronix-add-post_sfdp-fixups-for-quad-i.patch
 mtd-spi-nor-macronix-add-support-for-mx66-l2-u1-g45g.patch
+mac802154-llsec-add-skb_cow_data-before-in-place-crypto.patch
+net-skmsg-preserve-sg.copy-across-sg-transforms.patch
+net-ip_gre-require-cap_net_admin-in-the-device-netns-for-changelink.patch
+apparmor-mediate-the-implicit-connect-of-tcp-fast-open-sendmsg.patch
+apparmor-fix-use-after-free-in-rawdata-dedup-loop.patch