6.12.91-rc1 review
Subsystems (7)
Greg Kroah-Hartman
maintainerPATCH 469/666 netfilter: conntrack: remove sprintf usage
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Florian Westphal <[email protected]>
[ Upstream commit 6e7066bdb481a87fe88c4fa563e348c03b2d373d ]
Replace it with scnprintf, the buffer sizes are expected to be large enough to hold the result, no need for snprintf+overflow check.
Increase buffer size in mangle_content_len() while at it.
BUG: KASAN: stack-out-of-bounds in vsnprintf+0xea5/0x1270 Write of size 1 at addr [..] vsnprintf+0xea5/0x1270 sprintf+0xb1/0xe0 mangle_content_len+0x1ac/0x280 nf_nat_sdp_session+0x1cc/0x240 process_sdp+0x8f8/0xb80 process_invite_request+0x108/0x2b0 process_sip_msg+0x5da/0xf50 sip_help_tcp+0x45e/0x780 nf_confirm+0x34d/0x990 [..]
--- net/netfilter/nf_nat_amanda.c | 2 +- net/netfilter/nf_nat_sip.c | 33 ++++++++++++++++++--------------- 2 files changed, 19 insertions(+), 16 deletions(-)
net/netfilter/nf_nat_amanda.c +1 -1
@@ -50,7 +50,7 @@ static unsigned int help(struct sk_buff *skb,return NF_DROP ; } -sprintf (buffer,"%u" , port); +snprintf (buffer,sizeof (buffer),"%u" , port);if (!nf_nat_mangle_udp_packet (skb, exp->master, ctinfo, protoff, matchoff, matchlen, buffer,strlen (buffer))) {
net/netfilter/nf_nat_sip.c +18 -15
@@ -68,25 +68,27 @@ static unsigned int mangle_packet(struct sk_buff *skb, unsigned int protoff, }static int sip_sprintf_addr (const struct nf_conn *ct,char *buffer, +size_t size,const union nf_inet_addr *addr,bool delim) {if (nf_ct_l3num (ct) ==NFPROTO_IPV4 ) -return sprintf (buffer,"%pI4" , &addr->ip); +return scnprintf (buffer, size,"%pI4" , &addr->ip);else {if (delim) -return sprintf (buffer,"[%pI6c]" , &addr->ip6); +return scnprintf (buffer, size,"[%pI6c]" , &addr->ip6);else -return sprintf (buffer,"%pI6c" , &addr->ip6); +return scnprintf (buffer, size,"%pI6c" , &addr->ip6); } }static int sip_sprintf_addr_port (const struct nf_conn *ct,char *buffer, +size_t size,const union nf_inet_addr *addr,u16 port) {if (nf_ct_l3num (ct) ==NFPROTO_IPV4 ) -return sprintf (buffer,"%pI4:%u" , &addr->ip, port); +return scnprintf (buffer, size,"%pI4:%u" , &addr->ip, port);else -return sprintf (buffer,"[%pI6c]:%u" , &addr->ip6, port); +return scnprintf (buffer, size,"[%pI6c]:%u" , &addr->ip6, port); } static int map_addr(struct sk_buff *skb, unsigned int protoff,
@@ -119,7 +121,7 @@ static int map_addr(struct sk_buff *skb, unsigned int protoff,if (nf_inet_addr_cmp (&newaddr, addr) && newport == port)return 1 ; - buflen =sip_sprintf_addr_port (ct, buffer, &newaddr,ntohs (newport)); + buflen =sip_sprintf_addr_port (ct, buffer,sizeof (buffer), &newaddr,ntohs (newport));return mangle_packet (skb, protoff, dataoff, dptr, datalen, matchoff, matchlen, buffer, buflen); }
@@ -212,7 +214,7 @@ static unsigned int nf_nat_sip(struct sk_buff *skb, unsigned int protoff, &addr, true) > 0 && nf_inet_addr_cmp(&addr, &ct->tuplehash[dir].tuple.src.u3) && !nf_inet_addr_cmp(&addr, &ct->tuplehash[!dir].tuple.dst.u3)) { - buflen = sip_sprintf_addr(ct, buffer, + buflen = sip_sprintf_addr(ct, buffer, sizeof(buffer), &ct->tuplehash[!dir].tuple.dst.u3, true); if (!mangle_packet(skb, protoff, dataoff, dptr, datalen,
@@ -229,7 +231,7 @@ static unsigned int nf_nat_sip(struct sk_buff *skb, unsigned int protoff, &addr, false) > 0 && nf_inet_addr_cmp(&addr, &ct->tuplehash[dir].tuple.dst.u3) && !nf_inet_addr_cmp(&addr, &ct->tuplehash[!dir].tuple.src.u3)) { - buflen = sip_sprintf_addr(ct, buffer, + buflen = sip_sprintf_addr(ct, buffer, sizeof(buffer), &ct->tuplehash[!dir].tuple.src.u3, false); if (!mangle_packet(skb, protoff, dataoff, dptr, datalen,
@@ -247,7 +249,7 @@ static unsigned int nf_nat_sip(struct sk_buff *skb, unsigned int protoff, htons(n) == ct->tuplehash[dir].tuple.dst.u.udp.port && htons(n) != ct->tuplehash[!dir].tuple.src.u.udp.port) {__be16 p = ct->tuplehash[!dir].tuple.src.u.udp.port; - buflen =sprintf (buffer,"%u" ,ntohs (p)); + buflen =scnprintf (buffer,sizeof (buffer),"%u" ,ntohs (p));if (!mangle_packet (skb, protoff, dataoff, dptr, datalen, poff, plen, buffer, buflen)) {nf_ct_helper_log (skb, ct,"cannot mangle rport" );
@@ -418,7 +420,8 @@ static unsigned int nf_nat_sip_expect(struct sk_buff *skb, unsigned int protoff,if (!nf_inet_addr_cmp (&exp->tuple.dst.u3, &exp->saved_addr) || exp->tuple.dst.u.udp.port != exp->saved_proto.udp.port) { - buflen =sip_sprintf_addr_port (ct, buffer, &newaddr, port); + buflen =sip_sprintf_addr_port (ct, buffer,sizeof (buffer), + &newaddr, port);if (!mangle_packet (skb, protoff, dataoff, dptr, datalen, matchoff, matchlen, buffer, buflen)) {nf_ct_helper_log (skb, ct,"cannot mangle packet" );
@@ -438,8 +441,8 @@ static int mangle_content_len(struct sk_buff *skb, unsigned int protoff, {enum ip_conntrack_info ctinfo;struct nf_conn *ct =nf_ct_get (skb, &ctinfo); +char buffer[sizeof ("4294967295" )];unsigned int matchoff, matchlen; -char buffer[sizeof ("65536" )];int buflen, c_len;/* Get actual SDP length */
@@ -454,7 +457,7 @@ static int mangle_content_len(struct sk_buff *skb, unsigned int protoff, &matchoff, &matchlen) <= 0)return 0 ; - buflen =sprintf (buffer,"%u" , c_len); + buflen =scnprintf (buffer,sizeof (buffer),"%u" , c_len);return mangle_packet (skb, protoff, dataoff, dptr, datalen, matchoff, matchlen, buffer, buflen); }
@@ -491,7 +494,7 @@ static unsigned int nf_nat_sdp_addr(struct sk_buff *skb, unsigned int protoff,char buffer[INET6_ADDRSTRLEN ];unsigned int buflen; - buflen =sip_sprintf_addr (ct, buffer, addr, false); + buflen =sip_sprintf_addr (ct, buffer,sizeof (buffer), addr, false);if (mangle_sdp_packet (skb, protoff, dataoff, dptr, datalen, sdpoff, type, term, buffer, buflen))return 0 ;
@@ -509,7 +512,7 @@ static unsigned int nf_nat_sdp_port(struct sk_buff *skb, unsigned int protoff,char buffer[sizeof ("nnnnn" )];unsigned int buflen; - buflen =sprintf (buffer,"%u" , port); + buflen =scnprintf (buffer,sizeof (buffer),"%u" , port);if (!mangle_packet (skb, protoff, dataoff, dptr, datalen, matchoff, matchlen, buffer, buflen))return 0 ;
@@ -529,7 +532,7 @@ static unsigned int nf_nat_sdp_session(struct sk_buff *skb, unsigned int protoffunsigned int buflen;/* Mangle session description owner and contact addresses */ - buflen =sip_sprintf_addr (ct, buffer, addr, false); + buflen =sip_sprintf_addr (ct, buffer,sizeof (buffer), addr, false);if (mangle_sdp_packet (skb, protoff, dataoff, dptr, datalen, sdpoff,SDP_HDR_OWNER ,SDP_HDR_MEDIA , buffer, buflen))return 0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 470/666 netfilter: xtables: restrict several matches to inet family
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pablo Neira Ayuso <[email protected]>
[ Upstream commit b6fe26f86a1649f84e057f3f15605b08eda15497 ]
This is a partial revert of:
commit ab4f21e6fb1c ("netfilter: xtables: use NFPROTO_UNSPEC in more extensions")
to allow ipv4 and ipv6 only.
- xt_mac
- xt_owner
- xt_physdev
These extensions are not used by ebtables in userspace.
Moreover, xt_realm is only for ipv4, since dst->tclassid is ipv4 specific.
--- net/netfilter/xt_mac.c | 34 +++++++++++++++++++++++----------- net/netfilter/xt_owner.c | 37 +++++++++++++++++++++++++------------ net/netfilter/xt_physdev.c | 29 +++++++++++++++++++---------- net/netfilter/xt_realm.c | 2 +- 4 files changed, 68 insertions(+), 34 deletions(-)
net/netfilter/xt_mac.c +23 -11
@@ -38,25 +38,37 @@ static bool mac_mt(const struct sk_buff *skb, struct xt_action_param *par)return ret; } -static struct xt_match mac_mt_reg__read_mostly = { - .name ="mac" , - .revision =0 , - .family =NFPROTO_UNSPEC , - .match = mac_mt, - .matchsize =sizeof (struct xt_mac_info ), - .hooks = (1 <<NF_INET_PRE_ROUTING ) | (1 <<NF_INET_LOCAL_IN ) | - (1 <<NF_INET_FORWARD ), - .me =THIS_MODULE , +static struct xt_match mac_mt_reg[]__read_mostly = { + { + .name ="mac" , + .family =NFPROTO_IPV4 , + .match = mac_mt, + .matchsize =sizeof (struct xt_mac_info ), + .hooks = (1 <<NF_INET_PRE_ROUTING ) | + (1 <<NF_INET_LOCAL_IN ) | + (1 <<NF_INET_FORWARD ), + .me =THIS_MODULE , + }, + { + .name ="mac" , + .family =NFPROTO_IPV6 , + .match = mac_mt, + .matchsize =sizeof (struct xt_mac_info ), + .hooks = (1 <<NF_INET_PRE_ROUTING ) | + (1 <<NF_INET_LOCAL_IN ) | + (1 <<NF_INET_FORWARD ), + .me =THIS_MODULE , + }, };static int __init mac_mt_init (void ) { -return xt_register_match (&mac_mt_reg); +return xt_register_matches (mac_mt_reg,ARRAY_SIZE (mac_mt_reg)); } static void __exit mac_mt_exit(void) { -xt_unregister_match (&mac_mt_reg); +xt_unregister_matches (mac_mt_reg,ARRAY_SIZE (mac_mt_reg)); }module_init (mac_mt_init);
net/netfilter/xt_owner.c +25 -12
@@ -127,26 +127,39 @@ owner_mt(const struct sk_buff *skb, struct xt_action_param *par)return true; } -static struct xt_match owner_mt_reg__read_mostly = { - .name ="owner" , - .revision =1 , - .family =NFPROTO_UNSPEC , - .checkentry = owner_check, - .match = owner_mt, - .matchsize =sizeof (struct xt_owner_match_info ), - .hooks = (1 <<NF_INET_LOCAL_OUT ) | - (1 <<NF_INET_POST_ROUTING ), - .me =THIS_MODULE , +static struct xt_match owner_mt_reg[]__read_mostly = { + { + .name ="owner" , + .revision =1 , + .family =NFPROTO_IPV4 , + .checkentry = owner_check, + .match = owner_mt, + .matchsize =sizeof (struct xt_owner_match_info ), + .hooks = (1 <<NF_INET_LOCAL_OUT ) | + (1 <<NF_INET_POST_ROUTING ), + .me =THIS_MODULE , + }, + { + .name ="owner" , + .revision =1 , + .family =NFPROTO_IPV6 , + .checkentry = owner_check, + .match = owner_mt, + .matchsize =sizeof (struct xt_owner_match_info ), + .hooks = (1 <<NF_INET_LOCAL_OUT ) | + (1 <<NF_INET_POST_ROUTING ), + .me =THIS_MODULE , + } };static int __init owner_mt_init (void ) { -return xt_register_match (&owner_mt_reg); +return xt_register_matches (owner_mt_reg,ARRAY_SIZE (owner_mt_reg)); } static void __exit owner_mt_exit(void) { -xt_unregister_match (&owner_mt_reg); +xt_unregister_matches (owner_mt_reg,ARRAY_SIZE (owner_mt_reg)); }module_init (owner_mt_init);
net/netfilter/xt_physdev.c +19 -10
@@ -115,24 +115,33 @@ static int physdev_mt_check(const struct xt_mtchk_param *par)return 0 ; } -static struct xt_match physdev_mt_reg__read_mostly = { - .name ="physdev" , - .revision =0 , - .family =NFPROTO_UNSPEC , - .checkentry = physdev_mt_check, - .match = physdev_mt, - .matchsize =sizeof (struct xt_physdev_info ), - .me =THIS_MODULE , +static struct xt_match physdev_mt_reg[]__read_mostly = { + { + .name ="physdev" , + .family =NFPROTO_IPV4 , + .checkentry = physdev_mt_check, + .match = physdev_mt, + .matchsize =sizeof (struct xt_physdev_info ), + .me =THIS_MODULE , + }, + { + .name ="physdev" , + .family =NFPROTO_IPV6 , + .checkentry = physdev_mt_check, + .match = physdev_mt, + .matchsize =sizeof (struct xt_physdev_info ), + .me =THIS_MODULE , + }, };static int __init physdev_mt_init (void ) { -return xt_register_match (&physdev_mt_reg); +return xt_register_matches (physdev_mt_reg,ARRAY_SIZE (physdev_mt_reg)); } static void __exit physdev_mt_exit(void) { -xt_unregister_match (&physdev_mt_reg); +xt_unregister_matches (physdev_mt_reg,ARRAY_SIZE (physdev_mt_reg)); }module_init (physdev_mt_init);
net/netfilter/xt_realm.c +1 -1
@@ -33,7 +33,7 @@ static struct xt_match realm_mt_reg __read_mostly = { .matchsize = sizeof(struct xt_realm_info), .hooks = (1 <<NF_INET_POST_ROUTING ) | (1 <<NF_INET_FORWARD ) | (1 << NF_INET_LOCAL_OUT) | (1 << NF_INET_LOCAL_IN), - .family = NFPROTO_UNSPEC, + .family = NFPROTO_IPV4, .me =THIS_MODULE };
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 471/666 ipvs: fix MTU check for GSO packets in tunnel mode
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yingnan Zhang <[email protected]>
[ Upstream commit 67bf42cae41d847fd6e5749eb68278ca5d748b25 ]
Currently, IPVS skips MTU checks for GSO packets by excluding them with the !skb_is_gso(skb) condition. This creates problems when IPVS tunnel mode encapsulates GSO packets with IPIP headers.
The issue manifests in two ways:
1. MTU violation after encapsulation:
When a GSO packet passes through IPVS tunnel mode, the original MTU check is bypassed. After adding the IPIP tunnel header, the packet size may exceed the outgoing interface MTU, leading to unexpected fragmentation at the IP layer.
2. Fragmentation with problematic IP IDs:
When net.ipv4.vs.pmtu_disc=1 and a GSO packet with multiple segments is fragmented after encapsulation, each segment gets a sequentially incremented IP ID (0, 1, 2, ...). This happens because:
a) The GSO packet bypasses MTU check and gets encapsulated
b) At __ip_finish_output, the oversized GSO packet is split into separate SKBs (one per segment), with IP IDs incrementing
c) Each SKB is then fragmented again based on the actual MTU
This sequential IP ID allocation differs from the expected behavior and can cause issues with fragment reassembly and packet tracking.
Fix this by properly validating GSO packets using skb_gso_validate_network_len(). This function correctly validates whether the GSO segments will fit within the MTU after segmentation. If validation fails, send an ICMP Fragmentation Needed message to enable proper PMTU discovery.
--- net/netfilter/ipvs/ip_vs_xmit.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-)
net/netfilter/ipvs/ip_vs_xmit.c +15 -4
@@ -103,6 +103,18 @@ __ip_vs_dst_check(struct ip_vs_dest *dest)return dest_dst; } +/* Based on ip_exceeds_mtu(). */ +static bool ip_vs_exceeds_mtu (const struct sk_buff *skb,unsigned int mtu) +{ +if (skb->len <= mtu) +return false; + +if (skb_is_gso (skb) &&skb_gso_validate_network_len (skb, mtu)) +return false; + +return true; +} +static inline bool __mtu_check_toobig_v6 (const struct sk_buff *skb,u32 mtu) {
@@ -112,10 +124,9 @@ __mtu_check_toobig_v6(const struct sk_buff *skb, u32 mtu)*/ if (IP6CB (skb)->frag_max_size > mtu)return true;/* largest fragment violate MTU */ - } -else if (skb->len > mtu && !skb_is_gso (skb)) { + }else if (ip_vs_exceeds_mtu (skb, mtu))return true;/* Packet size violate MTU size */ - } +return false; }
@@ -233,7 +244,7 @@ static inline bool ensure_mtu_is_adequate(struct netns_ipvs *ipvs, int skb_af,return true;if (unlikely (ip_hdr (skb)->frag_off &htons (IP_DF ) && - skb->len > mtu && !skb_is_gso (skb) && +ip_vs_exceeds_mtu (skb, mtu) && !ip_vs_iph_icmp (ipvsh))) {icmp_send (skb,ICMP_DEST_UNREACH ,ICMP_FRAG_NEEDED ,htonl (mtu));
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 472/666 netfilter: nfnetlink_osf: fix out-of-bounds read on option matching
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fernando Fernandez Mancera <[email protected]>
[ Upstream commit f5ca450087c3baf3651055e7a6de92600f827af3 ]
In nf_osf_match(), the nf_osf_hdr_ctx structure is initialized once and passed by reference to nf_osf_match_one() for each fingerprint checked. During TCP option parsing, nf_osf_match_one() advances the shared ctx->optp pointer.
If a fingerprint perfectly matches, the function returns early without restoring ctx->optp to its initial state. If the user has configured NF_OSF_LOGLEVEL_ALL, the loop continues to the next fingerprint. However, because ctx->optp was not restored, the next call to nf_osf_match_one() starts parsing from the end of the options buffer. This causes subsequent matches to read garbage data and fail immediately, making it impossible to log more than one match or logging incorrect matches.
Instead of using a shared ctx->optp pointer, pass the context as a constant pointer and use a local pointer (optp) for TCP option traversal. This makes nf_osf_match_one() strictly stateless from the caller's perspective, ensuring every fingerprint check starts at the correct option offset.
--- net/netfilter/nfnetlink_osf.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-)
net/netfilter/nfnetlink_osf.c +8 -11
@@ -64,9 +64,9 @@ struct nf_osf_hdr_ctx {static bool nf_osf_match_one (const struct sk_buff *skb,const struct nf_osf_user_finger *f,int ttl_check, -struct nf_osf_hdr_ctx *ctx) +const struct nf_osf_hdr_ctx *ctx) { -const __u8 *optpinit = ctx->optp; +const __u8 *optp = ctx->optp;unsigned int check_WSS =0 ;int fmatch =FMATCH_WRONG ;int foptsize, optnum;
@@ -95,17 +95,17 @@ static bool nf_osf_match_one(const struct sk_buff *skb, check_WSS = f->wss.wc;for (optnum =0 ; optnum < f->opt_num; ++optnum) { -if (f->opt[optnum].kind == *ctx->optp) { +if (f->opt[optnum].kind == *optp) {__u32 len = f->opt[optnum].length; -const __u8 *optend = ctx->optp + len; +const __u8 *optend = optp + len; fmatch =FMATCH_OK ; -switch (*ctx->optp) { +switch (*optp) {case OSFOPT_MSS : - mss = ctx->optp[3 ]; + mss = optp[3 ]; mss <<=8 ; - mss |= ctx->optp[2 ]; + mss |= optp[2 ]; mss =ntohs ((__force __be16 )mss);break ;
@@ -113,7 +113,7 @@ static bool nf_osf_match_one(const struct sk_buff *skb,break ; } - ctx->optp = optend; + optp = optend; }else fmatch =FMATCH_OPT_WRONG ;
@@ -156,9 +156,6 @@ static bool nf_osf_match_one(const struct sk_buff *skb, } } -if (fmatch !=FMATCH_OK ) - ctx->optp = optpinit; -return fmatch ==FMATCH_OK ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 473/666 netfilter: nfnetlink_osf: fix potential NULL dereference in ttl check
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fernando Fernandez Mancera <[email protected]>
[ Upstream commit 711987ba281fd806322a7cd244e98e2a81903114 ]
The nf_osf_ttl() function accessed skb->dev to perform a local interface address lookup without verifying that the device pointer was valid.
Additionally, the implementation utilized an in_dev_for_each_ifa_rcu loop to match the packet source address against local interface addresses. It assumed that packets from the same subnet should not see a decrement on the initial TTL. A packet might appear it is from the same subnet but it actually isn't especially in modern environments with containers and virtual switching.
Remove the device dereference and interface loop. Replace the logic with a switch statement that evaluates the TTL according to the ttl_check.
--- net/netfilter/nfnetlink_osf.c | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-)
net/netfilter/nfnetlink_osf.c +7 -15
@@ -31,26 +31,18 @@ EXPORT_SYMBOL_GPL(nf_osf_fingers);static inline int nf_osf_ttl (const struct sk_buff *skb,int ttl_check,unsigned char f_ttl) { -struct in_device *in_dev =__in_dev_get_rcu (skb->dev);const struct iphdr *ip =ip_hdr (skb); -const struct in_ifaddr *ifa; -int ret =0 ; -if (ttl_check ==NF_OSF_TTL_TRUE ) +switch (ttl_check) { +case NF_OSF_TTL_TRUE :return ip->ttl == f_ttl; -if (ttl_check ==NF_OSF_TTL_NOCHECK ) -return 1 ; -else if (ip->ttl <= f_ttl) +break ; +case NF_OSF_TTL_NOCHECK :return 1 ; - -in_dev_for_each_ifa_rcu (ifa, in_dev) { -if (inet_ifa_match (ip->saddr, ifa)) { - ret = (ip->ttl == f_ttl); -break ; - } +case NF_OSF_TTL_LESS : +default : +return ip->ttl <= f_ttl; } - -return ret; }struct nf_osf_hdr_ctx {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 474/666 slip: reject VJ receive packets on instances with no rstate array
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Weiming Shi <[email protected]>
[ Upstream commit e76607442d5b73e1ba6768f501ef815bb58c2c0e ]
slhc_init() accepts rslots == 0 as a valid configuration, with the documented meaning of 'no receive compression'. In that case the allocation loop in slhc_init() is skipped, so comp->rstate stays NULL and comp->rslot_limit stays 0 (from the kzalloc of struct slcompress).
The receive helpers do not defend against that configuration. slhc_uncompress() dereferences comp->rstate[x] when the VJ header carries an explicit connection ID, and slhc_remember() later assigns cs = &comp->rstate[...] after only comparing the packet's slot number to comp->rslot_limit. Because rslot_limit is 0, slot 0 passes the range check, and the code dereferences a NULL rstate.
The configuration is reachable in-tree through PPP. PPPIOCSMAXCID stores its argument in a signed int, and (val >> 16) uses arithmetic shift. Passing 0xffff0000 therefore sign-extends to -1, so val2 + 1 is 0 and ppp_generic.c ends up calling slhc_init(0, 1). Because /dev/ppp open is gated by ns_capable(CAP_NET_ADMIN), the whole path is reachable from an unprivileged user namespace. Once the malformed VJ state is installed, any inbound VJ-compressed or VJ-uncompressed frame that selects slot 0 crashes the kernel in softirq context:
Oops: general protection fault, probably for non-canonical
address 0xdffffc0000000000: 0000 [#1] SMP KASAN NOPTI
KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007]
RIP: 0010:slhc_uncompress (drivers/net/slip/slhc.c:519)
Call Trace:
<TASK>
ppp_receive_nonmp_frame (drivers/net/ppp/ppp_generic.c:2466)
ppp_input (drivers/net/ppp/ppp_generic.c:2359)
ppp_async_process (drivers/net/ppp/ppp_async.c:492)
tasklet_action_common (kernel/softirq.c:926)
handle_softirqs (kernel/softirq.c:623)
run_ksoftirqd (kernel/softirq.c:1055)
smpboot_thread_fn (kernel/smpboot.c:160)
kthread (kernel/kthread.c:436)
ret_from_fork (arch/x86/kernel/process.c:164)
</TASK>Reject the receive side on such instances instead of touching rstate. slhc_uncompress() falls through to its existing 'bad' label, which bumps sls_i_error and enters the toss state. slhc_remember() mirrors that with an explicit sls_i_error increment followed by slhc_toss(); the sls_i_runt counter is not used here because a missing rstate is an internal configuration state, not a runt packet.
The transmit path is unaffected: the only in-tree caller that picks rslots from userspace (ppp_generic.c) still supplies tslots >= 1, and slip.c always calls slhc_init(16, 16), so comp->tstate remains valid and slhc_compress() continues to work.
--- drivers/net/slip/slhc.c | 6 ++++++ 1 file changed, 6 insertions(+)
drivers/net/slip/slhc.c +6 -0
@@ -506,6 +506,8 @@ slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) comp->sls_i_error++;return 0 ; } +if (!comp->rstate) + goto bad; changes = *cp++;if (changes &NEW_C ){/* Make sure the state index is in range, then grab the state.
@@ -649,6 +651,10 @@ slhc_remember(struct slcompress *comp, unsigned char *icp, int isize)struct cstate *cs;unsigned int ihl; +if (!comp->rstate) { + comp->sls_i_error++; +return slhc_toss (comp); + }/* The packet is shorter than a legal IP header. * Also make sure isize is positive. */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 475/666 slip: bound decode() reads against the compressed packet length
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Weiming Shi <[email protected]>
[ Upstream commit 4c1367a2d7aad643a6f87c6931b13cc1a25e8ca7 ]
slhc_uncompress() parses a VJ-compressed TCP header by advancing a pointer through the packet via decode() and pull16(). Neither helper bounds-checks against isize, and decode() masks its return with & 0xffff so it can never return the -1 that callers test for -- those error paths are dead code.
A short compressed frame whose change byte requests optional fields lets decode() read past the end of the packet. The over-read bytes are folded into the cached cstate and reflected into subsequent reconstructed packets.
Make decode() and pull16() take the packet end pointer and return -1 when exhausted. Add a bounds check before the TCP-checksum read. The existing == -1 tests now do what they were always meant to.
--- drivers/net/slip/slhc.c | 43 ++++++++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 18 deletions(-)
drivers/net/slip/slhc.c +25 -18
@@ -80,9 +80,9 @@#include <linux/unaligned.h> static unsigned char *encode (unsigned char *cp,unsigned short n); -static long decode (unsigned char **cpp); +static long decode (unsigned char **cpp,const unsigned char *end);static unsigned char *put16 (unsigned char *cp,unsigned short x); -static unsigned short pull16 (unsigned char **cpp); +static long pull16 (unsigned char **cpp,const unsigned char *end);/* Allocate compression data structure * slots must be in range 0 to 255 (zero meaning no compression)
@@ -190,30 +190,34 @@ encode(unsigned char *cp, unsigned short n)return cp; } -/* Pull a 16-bit integer in host order from buffer in network byte order */ -static unsigned short -pull16 (unsigned char **cpp) +/* Pull a 16-bit integer in host order from buffer in network byte order. +* Returns -1 if the buffer is exhausted, otherwise the 16-bit value. +*/ +static long +pull16 (unsigned char **cpp,const unsigned char *end) { -short rval; +long rval; +if (*cpp +2 > end) +return -1 ; rval = *(*cpp)++; rval <<=8 ; rval |= *(*cpp)++;return rval; } -/* Decode a number */ +/* Decode a number. Returns -1 if the buffer is exhausted. */ static long -decode (unsigned char **cpp) +decode (unsigned char **cpp,const unsigned char *end) {int x; +if (*cpp >= end) +return -1 ; x = *(*cpp)++; -if (x ==0 ){ -return pull16 (cpp) &0xffff ;/* pull16 returns -1 on error */ - }else { -return x &0xff ;/* -1 if PULLCHAR returned error */ - } +if (x ==0 ) +return pull16 (cpp, end); +return x &0xff ; }/*
@@ -499,6 +503,7 @@ slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize)struct cstate *cs;int len, hdrlen;unsigned char *cp = icp; +const unsigned char *end = icp + isize;/* We've got a compressed packet; read the change byte */ comp->sls_i_compressed++;
@@ -536,6 +541,8 @@ slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) thp = &cs->cs_tcp; ip = &cs->cs_ip; +if (cp +2 > end) + goto bad; thp->check = *(__sum16 *)cp; cp +=2 ;
@@ -566,26 +573,26 @@ slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize)default :if (changes &NEW_U ){ thp->urg =1 ; -if ((x =decode (&cp)) ==-1 ) { +if ((x =decode (&cp, end)) ==-1 ) { goto bad; } thp->urg_ptr =htons (x); }else thp->urg =0 ;if (changes &NEW_W ){ -if ((x =decode (&cp)) ==-1 ) { +if ((x =decode (&cp, end)) ==-1 ) { goto bad; } thp->window =htons (ntohs (thp->window) + x); }if (changes &NEW_A ){ -if ((x =decode (&cp)) ==-1 ) { +if ((x =decode (&cp, end)) ==-1 ) { goto bad; } thp->ack_seq =htonl (ntohl (thp->ack_seq) + x); }if (changes &NEW_S ){ -if ((x =decode (&cp)) ==-1 ) { +if ((x =decode (&cp, end)) ==-1 ) { goto bad; } thp->seq =htonl (ntohl (thp->seq) + x);
@@ -593,7 +600,7 @@ slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize)break ; }if (changes &NEW_I ){ -if ((x =decode (&cp)) ==-1 ) { +if ((x =decode (&cp, end)) ==-1 ) { goto bad; } ip->id =htons (ntohs (ip->id) + x);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 476/666 arm64: dts: meson-gxl-p230: fix ethernet PHY interrupt number
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jun Yan <[email protected]>
[ Upstream commit 174a0ef3b33434f475c87e66f37980e39b73805a ]
Correct the interrupt number assigned to the Realtek PHY in the p230
following the same logic as commit 3106507e1004 ("ARM64: dts: meson-gxm:
fix q200 interrupt number"),as reported in [PATCH 0/2] Ethernet PHY interrupt improvements [1].
[1] https://lore.kernel.org/all/[email protected]/
--- arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts +2 -1
@@ -84,7 +84,8 @@ external_phy: ethernet-phy@0 { reset-gpios = <&gpio GPIOZ_14 GPIO_ACTIVE_LOW>; interrupt-parent = <&gpio_intc>; - interrupts = <29 IRQ_TYPE_LEVEL_LOW>; + /* MAC_INTR on GPIOZ_15 */ + interrupts = <25 IRQ_TYPE_LEVEL_LOW>; eee-broken-1000t; }; };
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 477/666 pwm: atmel-tcb: Cache clock rates and mark chip as atomic
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sangyun Kim <[email protected]>
[ Upstream commit 68637b68afcc3cb4d56aca14a3a1d1b47b879369 ]
atmel_tcb_pwm_apply() holds tcbpwmc->lock as a spinlock via guard(spinlock)() and then calls atmel_tcb_pwm_config(), which calls clk_get_rate() twice. clk_get_rate() acquires clk_prepare_lock (a mutex), so this is a sleep-in-atomic-context violation.
On CONFIG_DEBUG_ATOMIC_SLEEP kernels every pwm_apply_state() that enables or reconfigures the PWM triggers a "BUG: sleeping function called from invalid context" warning.
Acquire exclusive control over the clock rates with clk_rate_exclusive_get() at probe time and cache the rates in struct atmel_tcb_pwm_chip, then read the cached rates from atmel_tcb_pwm_config(). This keeps the spinlock-based mutual exclusion introduced in commit 37f7707077f5 ("pwm: atmel-tcb: Fix race condition and convert to guards") and removes the sleeping calls from the atomic section.
With no sleeping calls left in .apply() and the regmap-mmio bus already running with fast_io=true, also mark the chip as atomic so consumers can use pwm_apply_atomic() from atomic context.
--- drivers/pwm/pwm-atmel-tcb.c | 38 +++++++++++++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 4 deletions(-)
drivers/pwm/pwm-atmel-tcb.c +34 -4
@@ -50,6 +50,8 @@ struct atmel_tcb_pwm_chip {spinlock_t lock;u8 channel;u8 width; +unsigned long rate; +unsigned long slow_rate;struct regmap *regmap;struct clk *clk;struct clk *gclk;
@@ -266,7 +268,7 @@ static int atmel_tcb_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,int slowclk =0 ;unsigned period;unsigned duty; -unsigned rate =clk_get_rate (tcbpwmc->clk); +unsigned long rate = tcbpwmc->rate;unsigned long long min;unsigned long long max;
@@ -294,7 +296,7 @@ static int atmel_tcb_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,*/ if (i ==ARRAY_SIZE (atmel_tcb_divisors)) { i = slowclk; - rate =clk_get_rate (tcbpwmc->slow_clk); + rate = tcbpwmc->slow_rate; min =div_u64 (NSEC_PER_SEC , rate); max = min << tcbpwmc->width;
@@ -431,24 +433,49 @@ static int atmel_tcb_pwm_probe(struct platform_device *pdev) } chip->ops = &atmel_tcb_pwm_ops; + chip->atomic = true; tcbpwmc->channel = channel; tcbpwmc->width = config->counter_width; - err =clk_prepare_enable (tcbpwmc->slow_clk); + err =clk_prepare_enable (tcbpwmc->clk);if (err) goto err_gclk; + err =clk_prepare_enable (tcbpwmc->slow_clk); +if (err) + goto err_disable_clk;; + + err =clk_rate_exclusive_get (tcbpwmc->clk); +if (err) + goto err_disable_slow_clk; + + err =clk_rate_exclusive_get (tcbpwmc->slow_clk); +if (err) + goto err_clk_unlock; + + tcbpwmc->rate =clk_get_rate (tcbpwmc->clk); + tcbpwmc->slow_rate =clk_get_rate (tcbpwmc->slow_clk); +spin_lock_init (&tcbpwmc->lock); err =pwmchip_add (chip);if (err <0 ) - goto err_disable_clk; + goto err_slow_clk_unlock;platform_set_drvdata (pdev, chip);return 0 ; +err_slow_clk_unlock: +clk_rate_exclusive_put (tcbpwmc->slow_clk); + +err_clk_unlock: +clk_rate_exclusive_put (tcbpwmc->clk); + err_disable_clk: +clk_disable_unprepare (tcbpwmc->clk); + +err_disable_slow_clk:clk_disable_unprepare (tcbpwmc->slow_clk); err_gclk:
@@ -470,6 +497,9 @@ static void atmel_tcb_pwm_remove(struct platform_device *pdev)pwmchip_remove (chip); +clk_rate_exclusive_put (tcbpwmc->slow_clk); +clk_rate_exclusive_put (tcbpwmc->clk); +clk_disable_unprepare (tcbpwmc->clk);clk_disable_unprepare (tcbpwmc->slow_clk);clk_put (tcbpwmc->gclk);clk_put (tcbpwmc->clk);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 478/666 ksmbd: destroy tree_conn_ida in ksmbd_session_destroy()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: DaeMyung Kang <[email protected]>
[ Upstream commit c049ee14eb4343b69b6f7755563f961f5e153423 ]
When per-session tree_conn_ida was converted from a dynamically allocated ksmbd_ida to an embedded struct ida, ksmbd_ida_free() was removed from ksmbd_session_destroy() but no matching ida_destroy() was added. The session is therefore freed with the IDA's backing xarray still intact.
The kernel IDA API expects ida_init() and ida_destroy() to be paired over an object's lifetime, so add the missing cleanup before the enclosing session is freed.
Also move ida_init() to right after the session is allocated so that it is always paired with the destroy call even on the early error paths of __session_create() (ksmbd_init_file_table() or __init_smb2_session() failures), both of which jump to the error label and invoke ksmbd_session_destroy() on a partially initialised session.
No leak has been observed in testing; this is a pairing fix to match the IDA lifetime rules, not a response to a reproduced regression.
--- fs/smb/server/mgmt/user_session.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
fs/smb/server/mgmt/user_session.c +3 -2
@@ -171,6 +171,7 @@ void ksmbd_session_destroy(struct ksmbd_session *sess)free_channel_list (sess);kfree (sess->Preauth_HashValue);ksmbd_release_id (&session_ida, sess->id); +ida_destroy (&sess->tree_conn_ida);kfree (sess); }
@@ -445,6 +446,8 @@ static struct ksmbd_session *__session_create(int protocol)if (!sess)return NULL ; +ida_init (&sess->tree_conn_ida); +if (ksmbd_init_file_table (&sess->file_table)) goto error;
@@ -464,8 +467,6 @@ static struct ksmbd_session *__session_create(int protocol)if (ret) goto error; -ida_init (&sess->tree_conn_ida); -down_write (&sessions_table_lock);hash_add (sessions_table, &sess->hlist, sess->id);up_write (&sessions_table_lock);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 479/666 ksmbd: destroy async_ida in ksmbd_conn_free()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: DaeMyung Kang <[email protected]>
[ Upstream commit b32c8db48212a34998c36d0bbc05b29d5c407ef5 ]
When per-connection async_ida was converted from a dynamically allocated ksmbd_ida to an embedded struct ida, ksmbd_ida_free() was removed from the connection teardown path but no matching ida_destroy() was added. The connection is therefore freed with the IDA's backing xarray still intact.
The kernel IDA API expects ida_init() and ida_destroy() to be paired over an object's lifetime, so add the missing cleanup before the connection is freed.
No leak has been observed in testing; this is a pairing fix to match the IDA lifetime rules, not a response to a reproduced regression.
--- fs/smb/server/connection.c | 9 +++++++++ 1 file changed, 9 insertions(+)
fs/smb/server/connection.c +9 -0
@@ -41,6 +41,15 @@ void ksmbd_conn_free(struct ksmbd_conn *conn)kfree (conn->preauth_info);kfree (conn->mechToken);if (atomic_dec_and_test (&conn->refcnt)) { +/* +* async_ida is embedded in struct ksmbd_conn, so pair +* ida_destroy() with the final kfree() rather than with +* the unconditional field teardown above. This keeps +* the IDA valid for the entire lifetime of the struct, +* even while other refcount holders (oplock / vfs +* durable handles) still reference the connection. +*/ +ida_destroy (&conn->async_ida); conn->transport->ops->free_transport (conn->transport);kfree (conn); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 480/666 ksmbd: fix durable fd leak on ClientGUID mismatch in durable v2 open
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: DaeMyung Kang <[email protected]>
[ Upstream commit 804054d19886ac6628883d82410f6ee42a818664 ]
ksmbd_lookup_fd_cguid() returns a ksmbd_file with its refcount incremented via ksmbd_fp_get(). parse_durable_handle_context() in the DURABLE_REQ_V2 case properly releases this reference on every path inside the ClientGUID-match branch, either by calling ksmbd_put_durable_fd() or by transferring ownership to dh_info->fp for a successful reconnect. However, when an entry exists in the global file table with the same CreateGuid but a different ClientGUID, the code simply falls through to the new-open path without dropping the reference obtained from ksmbd_lookup_fd_cguid().
Per MS-SMB2 section 3.3.5.9.10 ("Handling the SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2 Create Context"), the server MUST locate an Open whose Open.CreateGuid matches the request's CreateGuid AND whose Open.ClientGuid matches the ClientGuid of the connection that received the request. If no such Open is found, the server MUST continue with the normal open execution phase. A CreateGuid hit with a ClientGUID mismatch is therefore the "Open not found" case: proceeding with a new open is correct, but the reference obtained purely as a side effect of the lookup must not be leaked.
Repeated requests that hit this mismatch pin global_ft entries, prevent __ksmbd_close_fd() from ever running for the corresponding files, and defeat the durable scavenger, leading to long-lived resource leaks.
Release the reference in the mismatch path and clear dh_info->fp so subsequent logic does not mistake a non-matching lookup result for a reconnect target.
--- fs/smb/server/smb2pdu.c | 2 ++ 1 file changed, 2 insertions(+)
fs/smb/server/smb2pdu.c +2 -0
@@ -2849,6 +2849,8 @@ static int parse_durable_handle_context(struct ksmbd_work *work, dh_info->reconnected = true; goto out; } +ksmbd_put_durable_fd (dh_info->fp); + dh_info->fp =NULL ; } if ((lc && (lc->req_state & SMB2_LEASE_HANDLE_CACHING_LE)) ||
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 481/666 ksmbd: scope conn->binding slowpath to bound sessions only
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hyunwoo Kim <[email protected]>
[ Upstream commit b0da97c034b6107d14e537e212d4ce8b22109a58 ]
When the binding SESSION_SETUP sets conn->binding = true, the flag stays set after the call so that the global session lookup in ksmbd_session_lookup_all() can find the session, which was not added to conn->sessions. Because the flag is connection-wide, the global lookup path will also resolve any other session by id if asked.
Tighten the global lookup so that the returned session must have this connection registered in its channel xarray (sess->ksmbd_chann_list). The channel entry is installed by the existing binding_session path in ntlm_authenticate()/krb5_authenticate() when a SESSION_SETUP completes successfully, so this condition is a strict equivalent of "this connection has been accepted as a channel of this session". Connections that have not bound to a given session cannot reach it via the global table.
The existing conn->binding gate for entering the slowpath is preserved so that non-binding connections keep the fast-path-only behavior, and the session->state check is unchanged.
--- fs/smb/server/mgmt/user_session.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
fs/smb/server/mgmt/user_session.c +6 -1
@@ -328,8 +328,13 @@ struct ksmbd_session *ksmbd_session_lookup_all(struct ksmbd_conn *conn,struct ksmbd_session *sess; sess =ksmbd_session_lookup (conn, id); -if (!sess && conn->binding) +if (!sess && conn->binding) { sess =ksmbd_session_lookup_slowpath (id); +if (sess && !xa_load (&sess->ksmbd_chann_list, (long )conn)) { +ksmbd_user_session_put (sess); + sess =NULL ; + } + }if (sess && sess->state !=SMB2_SESSION_VALID ) {ksmbd_user_session_put (sess); sess =NULL ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 482/666 net/rds: zero per-item info buffer before handing it to visitors
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Bommarito <[email protected]>
[ Upstream commit c88eb7e8d8397a8c1db59c425332c5a30b2a1682 ]
rds_for_each_conn_info() and rds_walk_conn_path_info() both hand a caller-allocated on-stack u64 buffer to a per-connection visitor and then copy the full item_len bytes back to user space via rds_info_copy() regardless of how much of the buffer the visitor actually wrote.
rds_ib_conn_info_visitor() and rds6_ib_conn_info_visitor() only write a subset of their output struct when the underlying rds_connection is not in state RDS_CONN_UP (src/dst addr, tos, sl and the two GIDs via explicit memsets). Several u32 fields (max_send_wr, max_recv_wr, max_send_sge, rdma_mr_max, rdma_mr_size, cache_allocs) and the 2-byte alignment hole between sl and cache_allocs remain as whatever stack contents preceded the visitor call and are then memcpy_to_user()'d out to user space.
struct rds_info_rdma_connection and struct rds6_info_rdma_connection are the only rds_info_* structs in include/uapi/linux/rds.h that are not marked __attribute__((packed)), so they have a real alignment hole. The other info visitors (rds_conn_info_visitor, rds6_conn_info_visitor, rds_tcp_tc_info, ...) write all fields of their packed output struct today and are not known to be vulnerable, but a future visitor that adds a conditional write-path would have the same bug.
Reproduction on a kernel built without CONFIG_INIT_STACK_ALL_ZERO=y:
a local unprivileged user opens AF_RDS, sets SO_RDS_TRANSPORT=IB, binds to a local address on an RDMA-capable netdev (rxe soft-RoCE on any netdev is sufficient), sendto()'s any peer on the same subnet (fails cleanly but installs an rds_connection in the global hash in RDS_CONN_CONNECTING), then calls getsockopt(SOL_RDS, RDS_INFO_IB_CONNECTIONS). The returned 68-byte item contains 26 bytes of stack garbage including kernel text/data pointers:
0..7 0a 63 00 01 0a 63 00 02 src=10.99.0.1 dst=10.99.0.2
8..39 00 ... gids (memset-zeroed)
40..47 e0 92 a3 81 ff ff ff ff kernel pointer (max_send_wr)
48..55 7f 37 b5 81 ff ff ff ff kernel pointer (rdma_mr_max)
56..59 01 00 08 00 rdma_mr_size (garbage)
60..61 00 00 tos, sl
62..63 00 00 alignment padding
64..67 18 00 00 00 cache_allocs (garbage)Fix by zeroing the per-item buffer in both rds_for_each_conn_info() and rds_walk_conn_path_info() before invoking the visitor. This covers the IPv4/IPv6 IB visitors and hardens all current and future visitors against the same class of bug.
No functional change for visitors that fully populate their output.
Changes in v2:
- retarget at the net tree (subject prefix "[PATCH net v2]", net/rds: prefix in the title)
- pick up Reviewed-by tags from Sharath Srinivasan and Allison Henderson
--- net/rds/connection.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+)
net/rds/connection.c +14 -0
@@ -673,6 +673,13 @@ void rds_for_each_conn_info(struct socket *sock, unsigned int len, i++, head++) {hlist_for_each_entry_rcu (conn, head, c_hash_node) { +/* Zero the per-item buffer before handing it to the +* visitor so any field the visitor does not write - +* including implicit alignment padding - cannot leak +* stack contents to user space via rds_info_copy(). +*/ +memset (buffer,0 , item_len); +/* XXX no c_lock usage.. */ if (!visitor (conn, buffer))continue ;
@@ -722,6 +729,13 @@ static void rds_walk_conn_path_info(struct socket *sock, unsigned int len,*/ cp = conn->c_path; +/* Zero the per-item buffer for the same reason as +* rds_for_each_conn_info(): any byte the visitor +* does not write (including alignment padding) must +* not leak stack contents via rds_info_copy(). +*/ +memset (buffer,0 , item_len); +/* XXX no cp_lock usage.. */ if (!visitor (cp, buffer))continue ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 483/666 ice: fix timestamp interrupt configuration for E825C
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Grzegorz Nitka <[email protected]>
[ Upstream commit c0a575a801a2040eb1e0db54b488f8c548c8458a ]
The E825C ice_phy_cfg_intr_eth56g() function is responsible for programming the PHY interrupt for a given port. This function writes to the PHY_REG_TS_INT_CONFIG register of the port. The register is responsible for configuring whether the port interrupt logic is enabled, as well as programming the threshold of waiting timestamps that will trigger an interrupt from this port.
This threshold value must not be programmed to zero while the interrupt is enabled. Doing so puts the port in a misconfigured state where the PHY timestamp interrupt for the quad of connected ports will become stuck.
This occurs, because a threshold of zero results in the timestamp interrupt status for the port becoming stuck high. The four ports in the connected quad have their timestamp status indicators muxed together. A new interrupt cannot be generated until the timestamp status indicators return low for all four ports.
Normally, the timestamp status for a port will clear once there are fewer timestamps in that ports timestamp memory bank than the threshold. A threshold of zero makes this impossible, so the timestamp status for the port does not clear.
The ice driver never intentionally programs the threshold to zero, indeed the driver always programs it to a value of 1, intending to get an interrupt immediately as soon as even a single packet is waiting for a timestamp.
However, there is a subtle flaw in the programming logic in the ice_phy_cfg_intr_eth56g() function. Due to the way that the hardware handles enabling the PHY interrupt. If the threshold value is modified at the same time as the interrupt is enabled, the HW PHY state machine might enable the interrupt before the new threshold value is actually updated. This leaves a potential race condition caused by the hardware logic where a PHY timestamp interrupt might be triggered before the non-zero threshold is written, resulting in the PHY timestamp logic becoming stuck.
Once the PHY timestamp status is stuck high, it will remain stuck even after attempting to reprogram the PHY block by changing its threshold or disabling the interrupt. Even a typical PF or CORE reset will not reset the particular block of the PHY that becomes stuck. Even a warm power cycle is not guaranteed to cause the PHY block to reset, and a cold power cycle is required.
Prevent this by always writing the PHY_REG_TS_INT_CONFIG in two stages. First write the threshold value with the interrupt disabled, and only write the enable bit after the threshold has been programmed. When disabling the interrupt, leave the threshold unchanged. Additionally, re-read the register after writing it to guarantee that the write to the PHY has been flushed upon exit of the function.
While we're modifying this function implementation, explicitly reject programming a threshold of 0 when enabling the interrupt. No caller does this today, but the consequences of doing so are significant. An explicit rejection in the code makes this clear.
--- drivers/net/ethernet/intel/ice/ice_ptp_hw.c | 36 ++++++++++++++++++--- 1 file changed, 32 insertions(+), 4 deletions(-)
drivers/net/ethernet/intel/ice/ice_ptp_hw.c +32 -4
@@ -2340,6 +2340,8 @@ static int ice_phy_cfg_mac_eth56g(struct ice_hw *hw, u8 port)* @ena: enable or disable interrupt * @threshold: interrupt threshold * +* The threshold cannot be 0 while the interrupt is enabled. +* * Configure TX timestamp interrupt for the specified port * * Return:
@@ -2351,19 +2353,45 @@ int ice_phy_cfg_intr_eth56g(struct ice_hw *hw, u8 port, bool ena, u8 threshold)int err;u32 val; +if (ena && !threshold) +return -EINVAL ; + err =ice_read_ptp_reg_eth56g (hw, port,PHY_REG_TS_INT_CONFIG , &val);if (err)return err; + val &= ~PHY_TS_INT_CONFIG_ENA_M ;if (ena) { - val |=PHY_TS_INT_CONFIG_ENA_M ; val &= ~PHY_TS_INT_CONFIG_THRESHOLD_M ; val |=FIELD_PREP (PHY_TS_INT_CONFIG_THRESHOLD_M , threshold); - }else { - val &= ~PHY_TS_INT_CONFIG_ENA_M ; + err =ice_write_ptp_reg_eth56g (hw, port,PHY_REG_TS_INT_CONFIG , + val); +if (err) { +ice_debug (hw,ICE_DBG_PTP , +"Failed to update 'threshold' PHY_REG_TS_INT_CONFIG port=%u ena=%u threshold=%u\n" , + port, !!ena, threshold); +return err; + } + val |=PHY_TS_INT_CONFIG_ENA_M ; } -return ice_write_ptp_reg_eth56g (hw, port,PHY_REG_TS_INT_CONFIG , val); + err =ice_write_ptp_reg_eth56g (hw, port,PHY_REG_TS_INT_CONFIG , val); +if (err) { +ice_debug (hw,ICE_DBG_PTP , +"Failed to update 'ena' PHY_REG_TS_INT_CONFIG port=%u ena=%u threshold=%u\n" , + port, !!ena, threshold); +return err; + } + + err =ice_read_ptp_reg_eth56g (hw, port,PHY_REG_TS_INT_CONFIG , &val); +if (err) { +ice_debug (hw,ICE_DBG_PTP , +"Failed to read PHY_REG_TS_INT_CONFIG port=%u ena=%u threshold=%u\n" , + port, !!ena, threshold); +return err; + } + +return 0 ; }/**
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 484/666 ice: fix ice_ptp_read_tx_hwtstamp_status_eth56g
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jacob Keller <[email protected]>
[ Upstream commit 1f75dbc53f68f0fb2acd99f92315e426a3d0b446 ]
The ice_ptp_read_tx_hwtstamp_status_eth56g function calls ice_read_phy_eth56g with a PHY index. However the function actually expects a port index. This causes the function to read the wrong PHY_PTP_INT_STATUS registers, and effectively makes the status wrong for the second set of ports from 4 to 7.
The ice_read_phy_eth56g function uses the provided port index to determine which PHY device to read. We could refactor the entire chain to take a PHY index, but this would impact many code sites. Instead, multiply the PHY index by the number of ports, so that we read from the first port of each PHY.
--- drivers/net/ethernet/intel/ice/ice_ptp_hw.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
drivers/net/ethernet/intel/ice/ice_ptp_hw.c +8 -2
@@ -2682,13 +2682,19 @@ int ice_ptp_read_tx_hwtstamp_status_eth56g(struct ice_hw *hw, u32 *ts_status) *ts_status =0 ;for (phy =0 ; phy < params->num_phys; phy++) { +u8 port;int err; - err =ice_read_phy_eth56g (hw, phy,PHY_PTP_INT_STATUS , &status); +/* ice_read_phy_eth56g expects a port index, so use the first +* port of the PHY +*/ + port = phy * hw->ptp.ports_per_phy; + + err =ice_read_phy_eth56g (hw, port,PHY_PTP_INT_STATUS , &status);if (err)return err; - *ts_status |= (status & mask) << (phy * hw->ptp.ports_per_phy); + *ts_status |= (status & mask) << port; }ice_debug (hw,ICE_DBG_PTP ,"PHY interrupt err: %x\n" , *ts_status);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 485/666 net_sched: sch_hhf: annotate data-races in hhf_dump_stats()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit a6edf2cd4156b71e07258876b7626692e158f7e8 ]
hhf_dump_stats() only runs with RTNL held, reading fields that can be changed in qdisc fast path.
Add READ_ONCE()/WRITE_ONCE() annotations.
--- net/sched/sch_hhf.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-)
net/sched/sch_hhf.c +10 -9
@@ -198,7 +198,8 @@ static struct hh_flow_state *seek_list(const u32 hash,return NULL ;list_del (&flow->flowchain);kfree (flow); - q->hh_flows_current_cnt--; +WRITE_ONCE (q->hh_flows_current_cnt, + q->hh_flows_current_cnt -1 ); }else if (flow->hash_id == hash) {return flow; }
@@ -226,7 +227,7 @@ static struct hh_flow_state *alloc_new_hh(struct list_head *head, }if (q->hh_flows_current_cnt >= q->hh_flows_limit) { - q->hh_flows_overlimit++; +WRITE_ONCE (q->hh_flows_overlimit, q->hh_flows_overlimit +1 );return NULL ; }/* Create new entry. */
@@ -234,7 +235,7 @@ static struct hh_flow_state *alloc_new_hh(struct list_head *head,if (!flow)return NULL ; - q->hh_flows_current_cnt++; +WRITE_ONCE (q->hh_flows_current_cnt, q->hh_flows_current_cnt +1 );INIT_LIST_HEAD (&flow->flowchain);list_add_tail (&flow->flowchain, head);
@@ -309,7 +310,7 @@ static enum wdrr_bucket_idx hhf_classify(struct sk_buff *skb, struct Qdisc *sch)return WDRR_BUCKET_FOR_NON_HH ; flow->hash_id = hash; flow->hit_timestamp = now; - q->hh_flows_total_cnt++; +WRITE_ONCE (q->hh_flows_total_cnt, q->hh_flows_total_cnt +1 );/* By returning without updating counters in q->hhf_arrays, * we implicitly implement "shielding" (see Optimization O1).
@@ -403,7 +404,7 @@ static int hhf_enqueue(struct sk_buff *skb, struct Qdisc *sch,return NET_XMIT_SUCCESS ; prev_backlog = sch->qstats.backlog; - q->drop_overlimit++; +WRITE_ONCE (q->drop_overlimit, q->drop_overlimit +1 );/* Return Congestion Notification only if we dropped a packet from this * bucket. */
@@ -685,10 +686,10 @@ static int hhf_dump_stats(struct Qdisc *sch, struct gnet_dump *d) {struct hhf_sched_data *q =qdisc_priv (sch);struct tc_hhf_xstats st = { - .drop_overlimit = q->drop_overlimit, - .hh_overlimit = q->hh_flows_overlimit, - .hh_tot_count = q->hh_flows_total_cnt, - .hh_cur_count = q->hh_flows_current_cnt, + .drop_overlimit =READ_ONCE (q->drop_overlimit), + .hh_overlimit =READ_ONCE (q->hh_flows_overlimit), + .hh_tot_count =READ_ONCE (q->hh_flows_total_cnt), + .hh_cur_count =READ_ONCE (q->hh_flows_current_cnt), };return gnet_stats_copy_app (d, &st,sizeof (st));
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 486/666 net/sched: sch_pie: annotate data-races in pie_dump_stats()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit 5154561d9b119f781249f8e845fecf059b38b483 ]
pie_dump_stats() only runs with RTNL held, reading fields that can be changed in qdisc fast path.
Add READ_ONCE()/WRITE_ONCE() annotations.
Alternative would be to acquire the qdisc spinlock, but our long-term goal is to make qdisc dump operations lockless as much as we can.
tc_pie_xstats fields don't need to be latched atomically, otherwise this bug would have been caught earlier.
--- include/net/pie.h | 2 +- net/sched/sch_pie.c | 38 +++++++++++++++++++------------------- 2 files changed, 20 insertions(+), 20 deletions(-)
include/net/pie.h +1 -1
@@ -104,7 +104,7 @@ static inline void pie_vars_init(struct pie_vars *vars) vars->dq_tstamp =DTIME_INVALID ; vars->accu_prob =0 ; vars->dq_count =DQCOUNT_INVALID ; - vars->avg_dq_rate =0 ; +WRITE_ONCE (vars->avg_dq_rate,0 ); }static inline struct pie_skb_cb *get_pie_cb (const struct sk_buff *skb)
net/sched/sch_pie.c +19 -19
@@ -89,7 +89,7 @@ static int pie_qdisc_enqueue(struct sk_buff *skb, struct Qdisc *sch,bool enqueue = false;if (unlikely (qdisc_qlen (sch) >= sch->limit)) { - q->stats.overlimit++; +WRITE_ONCE (q->stats.overlimit, q->stats.overlimit +1 ); goto out; }
@@ -101,7 +101,7 @@ static int pie_qdisc_enqueue(struct sk_buff *skb, struct Qdisc *sch,/* If packet is ecn capable, mark it if drop probability * is lower than 10%, else drop it. */ - q->stats.ecn_mark++; +WRITE_ONCE (q->stats.ecn_mark, q->stats.ecn_mark +1 ); enqueue = true; }
@@ -111,15 +111,15 @@ static int pie_qdisc_enqueue(struct sk_buff *skb, struct Qdisc *sch,if (!q->params.dq_rate_estimator)pie_set_enqueue_time (skb); - q->stats.packets_in++; +WRITE_ONCE (q->stats.packets_in, q->stats.packets_in +1 );if (qdisc_qlen (sch) > q->stats.maxq) - q->stats.maxq =qdisc_qlen (sch); +WRITE_ONCE (q->stats.maxq,qdisc_qlen (sch));return qdisc_enqueue_tail (skb, sch); } out: - q->stats.dropped++; +WRITE_ONCE (q->stats.dropped, q->stats.dropped +1 ); q->vars.accu_prob =0 ;return qdisc_drop (skb, sch, to_free); }
@@ -262,11 +262,11 @@ void pie_process_dequeue(struct sk_buff *skb, struct pie_params *params, count = count / dtime;if (vars->avg_dq_rate ==0 ) - vars->avg_dq_rate = count; +WRITE_ONCE (vars->avg_dq_rate, count);else - vars->avg_dq_rate = +WRITE_ONCE (vars->avg_dq_rate, (vars->avg_dq_rate - - (vars->avg_dq_rate >>3 )) + (count >>3 ); + (vars->avg_dq_rate >>3 )) + (count >>3 ));/* If the queue has receded below the threshold, we hold * on to the last drain rate calculated, else we reset
@@ -376,7 +376,7 @@ void pie_calculate_probability(struct pie_params *params, struct pie_vars *vars,if (delta >0 ) {/* prevent overflow */ if (vars->prob < oldprob) { - vars->prob =MAX_PROB ; +WRITE_ONCE (vars->prob,MAX_PROB );/* Prevent normalization error. If probability is at * maximum value already, we normalize it here, and * skip the check to do a non-linear drop in the next
@@ -387,7 +387,7 @@ void pie_calculate_probability(struct pie_params *params, struct pie_vars *vars, }else {/* prevent underflow */ if (vars->prob > oldprob) - vars->prob =0 ; +WRITE_ONCE (vars->prob,0 ); }/* Non-linear drop in probability: Reduce drop probability quickly if
@@ -398,7 +398,7 @@ void pie_calculate_probability(struct pie_params *params, struct pie_vars *vars,/* Reduce drop probability to 98.4% */ vars->prob -= vars->prob /64 ; - vars->qdelay = qdelay; +WRITE_ONCE (vars->qdelay, qdelay); vars->backlog_old = backlog;/* We restart the measurement cycle if the following conditions are met
@@ -497,21 +497,21 @@ static int pie_dump_stats(struct Qdisc *sch, struct gnet_dump *d)struct pie_sched_data *q =qdisc_priv (sch);struct tc_pie_xstats st = { .prob = q->vars.prob <<BITS_PER_BYTE , - .delay = ((u32 )PSCHED_TICKS2NS (q->vars.qdelay)) / + .delay = ((u32 )PSCHED_TICKS2NS (READ_ONCE (q->vars.qdelay))) /NSEC_PER_USEC , - .packets_in = q->stats.packets_in, - .overlimit = q->stats.overlimit, - .maxq = q->stats.maxq, - .dropped = q->stats.dropped, - .ecn_mark = q->stats.ecn_mark, + .packets_in =READ_ONCE (q->stats.packets_in), + .overlimit =READ_ONCE (q->stats.overlimit), + .maxq =READ_ONCE (q->stats.maxq), + .dropped =READ_ONCE (q->stats.dropped), + .ecn_mark =READ_ONCE (q->stats.ecn_mark), };/* avg_dq_rate is only valid if dq_rate_estimator is enabled */ st.dq_rate_estimating = q->params.dq_rate_estimator;/* unscale and return dq_rate in bytes per sec */ -if (q->params.dq_rate_estimator) - st.avg_dq_rate = q->vars.avg_dq_rate * +if (st.dq_rate_estimating) + st.avg_dq_rate =READ_ONCE (q->vars.avg_dq_rate) * (PSCHED_TICKS_PER_SEC ) >>PIE_SCALE ;return gnet_stats_copy_app (d, &st,sizeof (st));
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 487/666 net/sched: sch_fq_codel: remove data-races from fq_codel_dump_stats()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit bbfaa73ea6871db03dc05d7f05f00557a8981f25 ]
fq_codel_dump_stats() acquires the qdisc spinlock a bit too late.
Move this acquisition before we fill st.qdisc_stats with live data.
--- net/sched/sch_fq_codel.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
net/sched/sch_fq_codel.c +2 -1
@@ -581,6 +581,8 @@ static int fq_codel_dump_stats(struct Qdisc *sch, struct gnet_dump *d) };struct list_head *pos; +sch_tree_lock (sch); + st.qdisc_stats.maxpacket = q->cstats.maxpacket; st.qdisc_stats.drop_overlimit = q->drop_overlimit; st.qdisc_stats.ecn_mark = q->cstats.ecn_mark;
@@ -589,7 +591,6 @@ static int fq_codel_dump_stats(struct Qdisc *sch, struct gnet_dump *d) st.qdisc_stats.memory_usage = q->memory_usage; st.qdisc_stats.drop_overmemory = q->drop_overmemory; -sch_tree_lock (sch);list_for_each (pos, &q->new_flows) st.qdisc_stats.new_flows_len++;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 488/666 net/sched: sch_red: annotate data-races in red_dump_stats()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit a8f5192809caf636d05ba47c144f282cfd0e3839 ]
red_dump_stats() only runs with RTNL held, reading fields that can be changed in qdisc fast path.
Add READ_ONCE()/WRITE_ONCE() annotations.
Alternative would be to acquire the qdisc spinlock, but our long-term goal is to make qdisc dump operations lockless as much as we can.
tc_red_xstats fields don't need to be latched atomically, otherwise this bug would have been caught earlier.
--- net/sched/sch_red.c | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-)
net/sched/sch_red.c +21 -10
@@ -89,17 +89,20 @@ static int red_enqueue(struct sk_buff *skb, struct Qdisc *sch,case RED_PROB_MARK :qdisc_qstats_overlimit (sch);if (!red_use_ecn (q)) { - q->stats.prob_drop++; +WRITE_ONCE (q->stats.prob_drop, + q->stats.prob_drop +1 ); goto congestion_drop; }if (INET_ECN_set_ce (skb)) { - q->stats.prob_mark++; +WRITE_ONCE (q->stats.prob_mark, + q->stats.prob_mark +1 ); skb =tcf_qevent_handle (&q->qe_mark, sch, skb, to_free, &ret);if (!skb)return NET_XMIT_CN | ret; }else if (!red_use_nodrop (q)) { - q->stats.prob_drop++; +WRITE_ONCE (q->stats.prob_drop, + q->stats.prob_drop +1 ); goto congestion_drop; }
@@ -109,17 +112,20 @@ static int red_enqueue(struct sk_buff *skb, struct Qdisc *sch,case RED_HARD_MARK :qdisc_qstats_overlimit (sch);if (red_use_harddrop (q) || !red_use_ecn (q)) { - q->stats.forced_drop++; +WRITE_ONCE (q->stats.forced_drop, + q->stats.forced_drop +1 ); goto congestion_drop; }if (INET_ECN_set_ce (skb)) { - q->stats.forced_mark++; +WRITE_ONCE (q->stats.forced_mark, + q->stats.forced_mark +1 ); skb =tcf_qevent_handle (&q->qe_mark, sch, skb, to_free, &ret);if (!skb)return NET_XMIT_CN | ret; }else if (!red_use_nodrop (q)) { - q->stats.forced_drop++; +WRITE_ONCE (q->stats.forced_drop, + q->stats.forced_drop +1 ); goto congestion_drop; }
@@ -133,7 +139,8 @@ static int red_enqueue(struct sk_buff *skb, struct Qdisc *sch, sch->qstats.backlog += len; sch->q.qlen++; }else if (net_xmit_drop_count (ret)) { - q->stats.pdrop++; +WRITE_ONCE (q->stats.pdrop, + q->stats.pdrop +1 );qdisc_qstats_drop (sch); }return ret;
@@ -461,9 +468,13 @@ static int red_dump_stats(struct Qdisc *sch, struct gnet_dump *d) dev->netdev_ops->ndo_setup_tc (dev,TC_SETUP_QDISC_RED , &hw_stats_request); } - st.early = q->stats.prob_drop + q->stats.forced_drop; - st.pdrop = q->stats.pdrop; - st.marked = q->stats.prob_mark + q->stats.forced_mark; + st.early =READ_ONCE (q->stats.prob_drop) + +READ_ONCE (q->stats.forced_drop); + + st.pdrop =READ_ONCE (q->stats.pdrop); + + st.marked =READ_ONCE (q->stats.prob_mark) + +READ_ONCE (q->stats.forced_mark);return gnet_stats_copy_app (d, &st,sizeof (st)); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 489/666 net/sched: sch_sfb: annotate data-races in sfb_dump_stats()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit 1ada03fdef82d3d7d2edb9dcd3acc91917675e48 ]
sfb_dump_stats() only runs with RTNL held, reading fields that can be changed in qdisc fast path.
Add READ_ONCE()/WRITE_ONCE() annotations.
Alternative would be to acquire the qdisc spinlock, but our long-term goal is to make qdisc dump operations lockless as much as we can.
tc_sfb_xstats fields don't need to be latched atomically, otherwise this bug would have been caught earlier.
--- net/sched/sch_sfb.c | 54 +++++++++++++++++++++++++++------------------ 1 file changed, 32 insertions(+), 22 deletions(-)
net/sched/sch_sfb.c +32 -22
@@ -130,7 +130,7 @@ static void increment_one_qlen(u32 sfbhash, u32 slot, struct sfb_sched_data *q) sfbhash >>=SFB_BUCKET_SHIFT ;if (b[hash].qlen <0xFFFF ) - b[hash].qlen++; +WRITE_ONCE (b[hash].qlen, b[hash].qlen +1 ); b +=SFB_NUMBUCKETS ;/* next level */ } }
@@ -159,7 +159,7 @@ static void decrement_one_qlen(u32 sfbhash, u32 slot, sfbhash >>=SFB_BUCKET_SHIFT ;if (b[hash].qlen >0 ) - b[hash].qlen--; +WRITE_ONCE (b[hash].qlen, b[hash].qlen -1 ); b +=SFB_NUMBUCKETS ;/* next level */ } }
@@ -179,12 +179,12 @@ static void decrement_qlen(const struct sk_buff *skb, struct sfb_sched_data *q)static void decrement_prob (struct sfb_bucket *b,struct sfb_sched_data *q) { - b->p_mark =prob_minus (b->p_mark, q->decrement); +WRITE_ONCE (b->p_mark,prob_minus (b->p_mark, q->decrement)); }static void increment_prob (struct sfb_bucket *b,struct sfb_sched_data *q) { - b->p_mark =prob_plus (b->p_mark, q->increment); +WRITE_ONCE (b->p_mark,prob_plus (b->p_mark, q->increment)); }static void sfb_zero_all_buckets (struct sfb_sched_data *q)
@@ -202,11 +202,14 @@ static u32 sfb_compute_qlen(u32 *prob_r, u32 *avgpm_r, const struct sfb_sched_daconst struct sfb_bucket *b = &q->bins[q->slot].bins[0 ][0 ];for (i =0 ; i <SFB_LEVELS *SFB_NUMBUCKETS ; i++) { -if (qlen < b->qlen) - qlen = b->qlen; - totalpm += b->p_mark; -if (prob < b->p_mark) - prob = b->p_mark; +u32 b_qlen =READ_ONCE (b->qlen); +u32 b_mark =READ_ONCE (b->p_mark); + +if (qlen < b_qlen) + qlen = b_qlen; + totalpm += b_mark; +if (prob < b_mark) + prob = b_mark; b++; } *prob_r = prob;
@@ -294,7 +297,8 @@ static int sfb_enqueue(struct sk_buff *skb, struct Qdisc *sch,if (unlikely (sch->q.qlen >= q->limit)) {qdisc_qstats_overlimit (sch); - q->stats.queuedrop++; +WRITE_ONCE (q->stats.queuedrop, + q->stats.queuedrop +1 ); goto drop; }
@@ -347,7 +351,8 @@ static int sfb_enqueue(struct sk_buff *skb, struct Qdisc *sch,if (unlikely (minqlen >= q->max)) {qdisc_qstats_overlimit (sch); - q->stats.bucketdrop++; +WRITE_ONCE (q->stats.bucketdrop, + q->stats.bucketdrop +1 ); goto drop; }
@@ -373,7 +378,8 @@ static int sfb_enqueue(struct sk_buff *skb, struct Qdisc *sch, }if (sfb_rate_limit (skb, q)) {qdisc_qstats_overlimit (sch); - q->stats.penaltydrop++; +WRITE_ONCE (q->stats.penaltydrop, + q->stats.penaltydrop +1 ); goto drop; } goto enqueue;
@@ -388,14 +394,17 @@ static int sfb_enqueue(struct sk_buff *skb, struct Qdisc *sch,* In either case, we want to start dropping packets. */ if (r < (p_min -SFB_MAX_PROB /2 ) *2 ) { - q->stats.earlydrop++; +WRITE_ONCE (q->stats.earlydrop, + q->stats.earlydrop +1 ); goto drop; } }if (INET_ECN_set_ce (skb)) { - q->stats.marked++; +WRITE_ONCE (q->stats.marked, + q->stats.marked +1 ); }else { - q->stats.earlydrop++; +WRITE_ONCE (q->stats.earlydrop, + q->stats.earlydrop +1 ); goto drop; } }
@@ -408,7 +417,8 @@ static int sfb_enqueue(struct sk_buff *skb, struct Qdisc *sch, sch->q.qlen++;increment_qlen (&cb, q); }else if (net_xmit_drop_count (ret)) { - q->stats.childdrop++; +WRITE_ONCE (q->stats.childdrop, + q->stats.childdrop +1 );qdisc_qstats_drop (sch); }return ret;
@@ -597,12 +607,12 @@ static int sfb_dump_stats(struct Qdisc *sch, struct gnet_dump *d) {struct sfb_sched_data *q =qdisc_priv (sch);struct tc_sfb_xstats st = { - .earlydrop = q->stats.earlydrop, - .penaltydrop = q->stats.penaltydrop, - .bucketdrop = q->stats.bucketdrop, - .queuedrop = q->stats.queuedrop, - .childdrop = q->stats.childdrop, - .marked = q->stats.marked, + .earlydrop =READ_ONCE (q->stats.earlydrop), + .penaltydrop =READ_ONCE (q->stats.penaltydrop), + .bucketdrop =READ_ONCE (q->stats.bucketdrop), + .queuedrop =READ_ONCE (q->stats.queuedrop), + .childdrop =READ_ONCE (q->stats.childdrop), + .marked =READ_ONCE (q->stats.marked), }; st.maxqlen =sfb_compute_qlen (&st.maxprob, &st.avgprob, q);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 490/666 net: dsa: realtek: rtl8365mb: fix mode mask calculation
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mieczyslaw Nalewaj <[email protected]>
[ Upstream commit 0c078021d3861966614d5e594ee03587f0c9e74d ]
The RTL8365MB_DIGITAL_INTERFACE_SELECT_MODE_MASK macro was shifting the 4-bit mask (0xF) by only (_extint % 2) bits instead of (_extint % 2) * 4. This caused the mask to overlap with the adjacent nibble when configuring odd-numbered external interfaces, selecting the wrong bits entirely.
Align the shift calculation with the existing ...MODE_OFFSET macro.
--- drivers/net/dsa/realtek/rtl8365mb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/dsa/realtek/rtl8365mb.c +1 -1
@@ -216,7 +216,7 @@ (_extint) == 2 ? RTL8365MB_DIGITAL_INTERFACE_SELECT_REG1 : \ 0x0)#define RTL8365MB_DIGITAL_INTERFACE_SELECT_MODE_MASK (_extint) \ - (0xF << (((_extint) % 2))) + (0xF << (((_extint) % 2) * 4))#define RTL8365MB_DIGITAL_INTERFACE_SELECT_MODE_OFFSET (_extint) \ (((_extint) % 2) * 4)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 491/666 net: airoha: Move ndesc initialization at end of airoha_qdma_init_rx_queue()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lorenzo Bianconi <[email protected]>
[ Upstream commit 379050947a1828826ad7ea50c95245a56929b35a ]
If queue entry or DMA descriptor list allocation fails in airoha_qdma_init_rx_queue routine, airoha_qdma_cleanup() will trigger a NULL pointer dereference running netif_napi_del() for RX queue NAPIs since netif_napi_add() has never been executed to this particular RX NAPI. The issue is due to the early ndesc initialization in airoha_qdma_init_rx_queue() since airoha_qdma_cleanup() relies on ndesc value to check if the queue is properly initialized. Fix the issue moving ndesc initialization at end of airoha_qdma_init_tx routine. Move page_pool allocation after descriptor list allocation in order to avoid memory leaks if desc allocation fails.
--- drivers/net/ethernet/mediatek/airoha_eth.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-)
drivers/net/ethernet/mediatek/airoha_eth.c +7 -7
@@ -1574,14 +1574,18 @@ static int airoha_qdma_init_rx_queue(struct airoha_queue *q,dma_addr_t dma_addr; q->buf_size =PAGE_SIZE /2 ; - q->ndesc = ndesc; q->qdma = qdma; - q->entry =devm_kzalloc (eth->dev, q->ndesc *sizeof (*q->entry), + q->entry =devm_kzalloc (eth->dev, ndesc *sizeof (*q->entry),GFP_KERNEL );if (!q->entry)return -ENOMEM ; + q->desc =dmam_alloc_coherent (eth->dev, ndesc *sizeof (*q->desc), + &dma_addr,GFP_KERNEL ); +if (!q->desc) +return -ENOMEM ; + q->page_pool =page_pool_create (&pp_params);if (IS_ERR (q->page_pool)) {int err =PTR_ERR (q->page_pool);
@@ -1590,11 +1594,7 @@ static int airoha_qdma_init_rx_queue(struct airoha_queue *q,return err; } - q->desc =dmam_alloc_coherent (eth->dev, q->ndesc *sizeof (*q->desc), - &dma_addr,GFP_KERNEL ); -if (!q->desc) -return -ENOMEM ; - + q->ndesc = ndesc;netif_napi_add (eth->napi_dev, &q->napi, airoha_qdma_rx_napi_poll);airoha_qdma_wr (qdma,REG_RX_RING_BASE (qid), dma_addr);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 492/666 virtio_net: Split struct virtio_net_rss_config
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Akihiko Odaki <[email protected]>
[ Upstream commit 976c2696b71da376d42e63ca3802eb2aafc164eb ]
struct virtio_net_rss_config was less useful in actual code because of a flexible array placed in the middle. Add new structures that split it into two to avoid having a flexible array in the middle.
Stable-dep-of: 3bc06da858ef ("virtio_net: sync rss_trailer.max_tx_vq on queue_pairs change via VQ_PAIRS_SET")
--- include/uapi/linux/virtio_net.h | 13 +++++++++++++ 1 file changed, 13 insertions(+)
include/uapi/linux/virtio_net.h +13 -0
@@ -327,6 +327,19 @@ struct virtio_net_rss_config {__u8 hash_key_data[/* hash_key_length */ ]; }; +struct virtio_net_rss_config_hdr { +__le32 hash_types; +__le16 indirection_table_mask; +__le16 unclassified_queue; +__le16 indirection_table[/* 1 + indirection_table_mask */ ]; +}; + +struct virtio_net_rss_config_trailer { +__le16 max_tx_vq; +__u8 hash_key_length; +__u8 hash_key_data[/* hash_key_length */ ]; +}; +#define VIRTIO_NET_CTRL_MQ_RSS_CONFIG 1/*
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 493/666 virtio_net: Fix endian with virtio_net_ctrl_rss
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Akihiko Odaki <[email protected]>
[ Upstream commit 97841341e302eac13d54eb5e968570b5626196a7 ]
Mark the fields of struct virtio_net_ctrl_rss as little endian as they are in struct virtio_net_rss_config, which it follows.
Stable-dep-of: 3bc06da858ef ("virtio_net: sync rss_trailer.max_tx_vq on queue_pairs change via VQ_PAIRS_SET")
--- drivers/net/virtio_net.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-)
drivers/net/virtio_net.c +15 -15
@@ -373,15 +373,15 @@ struct receive_queue {*/ #define VIRTIO_NET_RSS_MAX_KEY_SIZE 40struct virtio_net_ctrl_rss { -u32 hash_types; -u16 indirection_table_mask; -u16 unclassified_queue; -u16 hash_cfg_reserved;/* for HASH_CONFIG (see virtio_net_hash_config for details) */ -u16 max_tx_vq; +__le32 hash_types; +__le16 indirection_table_mask; +__le16 unclassified_queue; +__le16 hash_cfg_reserved;/* for HASH_CONFIG (see virtio_net_hash_config for details) */ +__le16 max_tx_vq;u8 hash_key_length;u8 key[VIRTIO_NET_RSS_MAX_KEY_SIZE ]; -u16 *indirection_table; +__le16 *indirection_table; };/* Control VQ buffers: protected by the rtnl lock */
@@ -3477,9 +3477,9 @@ static void virtnet_rss_update_by_qpairs(struct virtnet_info *vi, u16 queue_pairfor (; i < vi->rss_indir_table_size; ++i) { indir_val =ethtool_rxfh_indir_default (i, queue_pairs); - vi->rss.indirection_table[i] = indir_val; + vi->rss.indirection_table[i] =cpu_to_le16 (indir_val); } - vi->rss.max_tx_vq = queue_pairs; + vi->rss.max_tx_vq =cpu_to_le16 (queue_pairs); }static int virtnet_set_queues (struct virtnet_info *vi,u16 queue_pairs)
@@ -3998,10 +3998,10 @@ static bool virtnet_commit_rss_command(struct virtnet_info *vi)static void virtnet_init_default_rss (struct virtnet_info *vi) { - vi->rss.hash_types = vi->rss_hash_types_supported; + vi->rss.hash_types =cpu_to_le32 (vi->rss_hash_types_supported); vi->rss_hash_types_saved = vi->rss_hash_types_supported; vi->rss.indirection_table_mask = vi->rss_indir_table_size - ? vi->rss_indir_table_size -1 :0 ; + ?cpu_to_le16 (vi->rss_indir_table_size -1 ) :0 ; vi->rss.unclassified_queue =0 ;virtnet_rss_update_by_qpairs (vi, vi->curr_queue_pairs);
@@ -4119,7 +4119,7 @@ static bool virtnet_set_hashflow(struct virtnet_info *vi, struct ethtool_rxnfc *if (new_hashtypes != vi->rss_hash_types_saved) { vi->rss_hash_types_saved = new_hashtypes; - vi->rss.hash_types = vi->rss_hash_types_saved; + vi->rss.hash_types =cpu_to_le32 (vi->rss_hash_types_saved);if (vi->dev->features &NETIF_F_RXHASH )return virtnet_commit_rss_command (vi); }
@@ -5291,7 +5291,7 @@ static int virtnet_get_rxfh(struct net_device *dev,if (rxfh->indir) {for (i =0 ; i < vi->rss_indir_table_size; ++i) - rxfh->indir[i] = vi->rss.indirection_table[i]; + rxfh->indir[i] =le16_to_cpu (vi->rss.indirection_table[i]); }if (rxfh->key)
@@ -5319,7 +5319,7 @@ static int virtnet_set_rxfh(struct net_device *dev,return -EOPNOTSUPP ;for (i =0 ; i < vi->rss_indir_table_size; ++i) - vi->rss.indirection_table[i] = rxfh->indir[i]; + vi->rss.indirection_table[i] =cpu_to_le16 (rxfh->indir[i]); update = true; }
@@ -5945,9 +5945,9 @@ static int virtnet_set_features(struct net_device *dev,if ((dev->features ^ features) &NETIF_F_RXHASH ) {if (features &NETIF_F_RXHASH ) - vi->rss.hash_types = vi->rss_hash_types_saved; + vi->rss.hash_types =cpu_to_le32 (vi->rss_hash_types_saved);else - vi->rss.hash_types =VIRTIO_NET_HASH_REPORT_NONE ; + vi->rss.hash_types =cpu_to_le32 (VIRTIO_NET_HASH_REPORT_NONE );if (!virtnet_commit_rss_command (vi))return -EINVAL ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 494/666 virtio_net: Use new RSS config structs
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Akihiko Odaki <[email protected]>
[ Upstream commit ed3100e90d0d120a045a551b85eb43cf2527e885 ]
The new RSS configuration structures allow easily constructing data for VIRTIO_NET_CTRL_MQ_RSS_CONFIG as they strictly follow the order of data for the command.
Stable-dep-of: 3bc06da858ef ("virtio_net: sync rss_trailer.max_tx_vq on queue_pairs change via VQ_PAIRS_SET")
--- drivers/net/virtio_net.c | 117 ++++++++++++++------------------------- 1 file changed, 43 insertions(+), 74 deletions(-)
drivers/net/virtio_net.c +43 -74
@@ -365,24 +365,7 @@ struct receive_queue {bool do_dma; }; -/* This structure can contain rss message with maximum settings for indirection table and keysize -* Note, that default structure that describes RSS configuration virtio_net_rss_config -* contains same info but can't handle table values. -* In any case, structure would be passed to virtio hw through sg_buf split by parts -* because table sizes may be differ according to the device configuration. -*/ #define VIRTIO_NET_RSS_MAX_KEY_SIZE 40 -struct virtio_net_ctrl_rss { -__le32 hash_types; -__le16 indirection_table_mask; -__le16 unclassified_queue; -__le16 hash_cfg_reserved;/* for HASH_CONFIG (see virtio_net_hash_config for details) */ -__le16 max_tx_vq; -u8 hash_key_length; -u8 key[VIRTIO_NET_RSS_MAX_KEY_SIZE ]; - -__le16 *indirection_table; -};/* Control VQ buffers: protected by the rtnl lock */ struct control_buf {
@@ -426,7 +409,9 @@ struct virtnet_info {u16 rss_indir_table_size;u32 rss_hash_types_supported;u32 rss_hash_types_saved; -struct virtio_net_ctrl_rss rss; +struct virtio_net_rss_config_hdr *rss_hdr; +struct virtio_net_rss_config_trailer rss_trailer; +u8 rss_hash_key_data[VIRTIO_NET_RSS_MAX_KEY_SIZE ];/* Has control virtqueue */ bool has_cvq;
@@ -520,23 +505,16 @@ static struct sk_buff *virtnet_skb_append_frag(struct sk_buff *head_skb, struct page *page, void *buf, int len, int truesize); -static int rss_indirection_table_alloc (struct virtio_net_ctrl_rss *rss,u16 indir_table_size) +static size_t virtnet_rss_hdr_size (const struct virtnet_info *vi) { -if (!indir_table_size) { - rss->indirection_table =NULL ; -return 0 ; - } +u16 indir_table_size = vi->has_rss ? vi->rss_indir_table_size :1 ; - rss->indirection_table =kmalloc_array (indir_table_size,sizeof (u16),GFP_KERNEL ); -if (!rss->indirection_table) -return -ENOMEM ; - -return 0 ; +return struct_size (vi->rss_hdr, indirection_table, indir_table_size); } -static void rss_indirection_table_free (struct virtio_net_ctrl_rss *rss) +static size_t virtnet_rss_trailer_size (const struct virtnet_info *vi) { -kfree (rss->indirection_table); +return struct_size (&vi->rss_trailer, hash_key_data, vi->rss_key_size); }static bool is_xdp_frame (void *ptr)
@@ -3477,15 +3455,16 @@ static void virtnet_rss_update_by_qpairs(struct virtnet_info *vi, u16 queue_pairfor (; i < vi->rss_indir_table_size; ++i) { indir_val =ethtool_rxfh_indir_default (i, queue_pairs); - vi->rss.indirection_table[i] =cpu_to_le16 (indir_val); + vi->rss_hdr->indirection_table[i] =cpu_to_le16 (indir_val); } - vi->rss.max_tx_vq =cpu_to_le16 (queue_pairs); + vi->rss_trailer.max_tx_vq =cpu_to_le16 (queue_pairs); }static int virtnet_set_queues (struct virtnet_info *vi,u16 queue_pairs) { struct virtio_net_ctrl_mq *mq __free(kfree) = NULL; -struct virtio_net_ctrl_rss old_rss; +struct virtio_net_rss_config_hdr *old_rss_hdr; +struct virtio_net_rss_config_trailer old_rss_trailer;struct net_device *dev = vi->dev;struct scatterlist sg;
@@ -3500,24 +3479,28 @@ static int virtnet_set_queues(struct virtnet_info *vi, u16 queue_pairs)* update (VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET below) and return directly. */ if (vi->has_rss && !netif_is_rxfh_configured (dev)) { -memcpy (&old_rss, &vi->rss,sizeof (old_rss)); -if (rss_indirection_table_alloc (&vi->rss, vi->rss_indir_table_size)) { - vi->rss.indirection_table = old_rss.indirection_table; + old_rss_hdr = vi->rss_hdr; + old_rss_trailer = vi->rss_trailer; + vi->rss_hdr =kzalloc (virtnet_rss_hdr_size (vi),GFP_KERNEL ); +if (!vi->rss_hdr) { + vi->rss_hdr = old_rss_hdr;return -ENOMEM ; } + *vi->rss_hdr = *old_rss_hdr;virtnet_rss_update_by_qpairs (vi, queue_pairs);if (!virtnet_commit_rss_command (vi)) {/* restore ctrl_rss if commit_rss_command failed */ -rss_indirection_table_free (&vi->rss); -memcpy (&vi->rss, &old_rss,sizeof (old_rss)); +kfree (vi->rss_hdr); + vi->rss_hdr = old_rss_hdr; + vi->rss_trailer = old_rss_trailer;dev_warn (&dev->dev,"Fail to set num of queue pairs to %d, because committing RSS failed\n" , queue_pairs);return -EINVAL ; } -rss_indirection_table_free (&old_rss); +kfree (old_rss_hdr); goto succ; }
@@ -3960,28 +3943,12 @@ static int virtnet_set_ringparam(struct net_device *dev, static bool virtnet_commit_rss_command(struct virtnet_info *vi) { struct net_device *dev = vi->dev; - struct scatterlist sgs[4]; - unsigned int sg_buf_size; + struct scatterlist sgs[2]; /* prepare sgs */ - sg_init_table(sgs, 4); - - sg_buf_size = offsetof(struct virtio_net_ctrl_rss, hash_cfg_reserved); - sg_set_buf(&sgs[0], &vi->rss, sg_buf_size); - - if (vi->has_rss) { - sg_buf_size = sizeof(uint16_t) * vi->rss_indir_table_size; - sg_set_buf(&sgs[1], vi->rss.indirection_table, sg_buf_size); - } else { - sg_set_buf(&sgs[1], &vi->rss.hash_cfg_reserved, sizeof(uint16_t)); - } - - sg_buf_size = offsetof(struct virtio_net_ctrl_rss, key) - - offsetof(struct virtio_net_ctrl_rss, max_tx_vq); - sg_set_buf(&sgs[2], &vi->rss.max_tx_vq, sg_buf_size); - - sg_buf_size = vi->rss_key_size; - sg_set_buf(&sgs[3], vi->rss.key, sg_buf_size); + sg_init_table(sgs, 2); + sg_set_buf(&sgs[0], vi->rss_hdr, virtnet_rss_hdr_size(vi)); + sg_set_buf(&sgs[1], &vi->rss_trailer, virtnet_rss_trailer_size(vi)); if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_MQ, vi->has_rss ? VIRTIO_NET_CTRL_MQ_RSS_CONFIG
@@ -3998,17 +3965,17 @@ static bool virtnet_commit_rss_command(struct virtnet_info *vi)static void virtnet_init_default_rss (struct virtnet_info *vi) { - vi->rss.hash_types =cpu_to_le32 (vi->rss_hash_types_supported); + vi->rss_hdr->hash_types =cpu_to_le32 (vi->rss_hash_types_supported); vi->rss_hash_types_saved = vi->rss_hash_types_supported; - vi->rss.indirection_table_mask = vi->rss_indir_table_size + vi->rss_hdr->indirection_table_mask = vi->rss_indir_table_size ?cpu_to_le16 (vi->rss_indir_table_size -1 ) :0 ; - vi->rss.unclassified_queue =0 ; + vi->rss_hdr->unclassified_queue =0 ;virtnet_rss_update_by_qpairs (vi, vi->curr_queue_pairs); - vi->rss.hash_key_length = vi->rss_key_size; + vi->rss_trailer.hash_key_length = vi->rss_key_size; -netdev_rss_key_fill (vi->rss.key, vi->rss_key_size); +netdev_rss_key_fill (vi->rss_hash_key_data, vi->rss_key_size); }static void virtnet_get_hashflow (const struct virtnet_info *vi,struct ethtool_rxnfc *info)
@@ -4119,7 +4086,7 @@ static bool virtnet_set_hashflow(struct virtnet_info *vi, struct ethtool_rxnfc *if (new_hashtypes != vi->rss_hash_types_saved) { vi->rss_hash_types_saved = new_hashtypes; - vi->rss.hash_types =cpu_to_le32 (vi->rss_hash_types_saved); + vi->rss_hdr->hash_types =cpu_to_le32 (vi->rss_hash_types_saved);if (vi->dev->features &NETIF_F_RXHASH )return virtnet_commit_rss_command (vi); }
@@ -5291,11 +5258,11 @@ static int virtnet_get_rxfh(struct net_device *dev,if (rxfh->indir) {for (i =0 ; i < vi->rss_indir_table_size; ++i) - rxfh->indir[i] =le16_to_cpu (vi->rss.indirection_table[i]); + rxfh->indir[i] =le16_to_cpu (vi->rss_hdr->indirection_table[i]); }if (rxfh->key) -memcpy (rxfh->key, vi->rss.key, vi->rss_key_size); +memcpy (rxfh->key, vi->rss_hash_key_data, vi->rss_key_size); rxfh->hfunc =ETH_RSS_HASH_TOP ;
@@ -5319,7 +5286,7 @@ static int virtnet_set_rxfh(struct net_device *dev,return -EOPNOTSUPP ;for (i =0 ; i < vi->rss_indir_table_size; ++i) - vi->rss.indirection_table[i] =cpu_to_le16 (rxfh->indir[i]); + vi->rss_hdr->indirection_table[i] =cpu_to_le16 (rxfh->indir[i]); update = true; }
@@ -5331,7 +5298,7 @@ static int virtnet_set_rxfh(struct net_device *dev,if (!vi->has_rss && !vi->has_rss_hash_report)return -EOPNOTSUPP ; -memcpy (vi->rss.key, rxfh->key, vi->rss_key_size); +memcpy (vi->rss_hash_key_data, rxfh->key, vi->rss_key_size); update = true; }
@@ -5945,9 +5912,9 @@ static int virtnet_set_features(struct net_device *dev,if ((dev->features ^ features) &NETIF_F_RXHASH ) {if (features &NETIF_F_RXHASH ) - vi->rss.hash_types =cpu_to_le32 (vi->rss_hash_types_saved); + vi->rss_hdr->hash_types =cpu_to_le32 (vi->rss_hash_types_saved);else - vi->rss.hash_types =cpu_to_le32 (VIRTIO_NET_HASH_REPORT_NONE ); + vi->rss_hdr->hash_types =cpu_to_le32 (VIRTIO_NET_HASH_REPORT_NONE );if (!virtnet_commit_rss_command (vi))return -EINVAL ;
@@ -6619,9 +6586,11 @@ static int virtnet_probe(struct virtio_device *vdev)virtio_cread16 (vdev, offsetof(struct virtio_net_config , rss_max_indirection_table_length)); } - err =rss_indirection_table_alloc (&vi->rss, vi->rss_indir_table_size); -if (err) + vi->rss_hdr =kzalloc (virtnet_rss_hdr_size (vi),GFP_KERNEL ); +if (!vi->rss_hdr) { + err = -ENOMEM ; goto free; + }if (vi->has_rss || vi->has_rss_hash_report) { vi->rss_key_size =
@@ -6900,7 +6869,7 @@ static void virtnet_remove(struct virtio_device *vdev)remove_vq_common (vi); -rss_indirection_table_free (&vi->rss); +kfree (vi->rss_hdr);free_netdev (vi->dev); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 495/666 virtio_net: sync rss_trailer.max_tx_vq on queue_pairs change via VQ_PAIRS_SET
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Brett Creeley <[email protected]>
[ Upstream commit 3bc06da858ef17cfe94b49efc0d9713727012835 ]
When netif_is_rxfh_configured() is true (i.e., the user has explicitly configured the RSS indirection table), virtnet_set_queues() skips the RSS update path and falls through to the VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET command to change the number of queue pairs. However, it does not update vi->rss_trailer.max_tx_vq to reflect the new queue_pairs value.
This causes a mismatch between vi->curr_queue_pairs and vi->rss_trailer.max_tx_vq. Any subsequent RSS reconfiguration (e.g., via ethtool -X) calls virtnet_commit_rss_command(), which sends the stale max_tx_vq to the device, silently reverting the queue count.
Reproduction:
1. User configured RSS
ethtool -X eth0 equal 8
2. VQ_PAIRS_SET path; max_tx_vq stays 16
ethtool -L eth0 combined 12
3. RSS commit uses max_tx_vq=16 instead of 12
ethtool -X eth0 equal 4
Fix this by updating vi->rss_trailer.max_tx_vq after a successful VQ_PAIRS_SET command when RSS is enabled, keeping it in sync with curr_queue_pairs.
--- drivers/net/virtio_net.c | 6 ++++++ 1 file changed, 6 insertions(+)
drivers/net/virtio_net.c +6 -0
@@ -3517,6 +3517,12 @@ static int virtnet_set_queues(struct virtnet_info *vi, u16 queue_pairs) queue_pairs);return -EINVAL ; } + +/* Keep max_tx_vq in sync so that a later RSS command does not +* revert queue_pairs to a stale value. +*/ +if (vi->has_rss) + vi->rss_trailer.max_tx_vq =cpu_to_le16 (queue_pairs); succ: vi->curr_queue_pairs = queue_pairs;/* virtnet_open() will refill when device is going to up. */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 496/666 nfp: fix swapped arguments in nfp_encode_basic_qdr() calls
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alexey Kodanev <[email protected]>
[ Upstream commit 4078c5611d7585548b249377ebd60c272e410490 ]
There is a mismatch between the passed arguments and the actual nfp_encode_basic_qdr() function parameter names:
static int nfp_encode_basic_qdr(u64 addr, int dest_island, int cpp_tgt,
int mode, bool addr40, int isld1, int isld0)
{
...But "dest_island" and "cpp_tgt" are swapped at every call-site. For example:
return nfp_encode_basic_qdr(*addr, cpp_tgt, dest_island,
mode, addr40, isld1, isld0);
As a result, nfp_encode_basic_qdr() receives "dest_island" as CPP target type, which is always NFP_CPP_TARGET_QDR(2) for these calls, and "cpp_tgt" as the destination island ID, which can accidentally match or be outside the valid NFP_CPP_TARGET_* types (e.g. '-1' for any destination).
Since code already worked for years, also add extra pr_warn() to error paths in nfp_encode_basic_qdr() to help identify any potential address verification failures.
Detected using the static analysis tool - Svace.
--- .../ethernet/netronome/nfp/nfpcore/nfp_target.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-)
drivers/net/ethernet/netronome/nfp/nfpcore/nfp_target.c +11 -6
@@ -435,12 +435,17 @@ static int nfp_encode_basic_qdr(u64 addr, int dest_island, int cpp_tgt,/* Full Island ID and channel bits overlap? */ ret =nfp_decode_basic (addr, &v, cpp_tgt, mode, addr40, isld1, isld0); -if (ret) +if (ret) { +pr_warn ("%s: decode dest_island failed: %d\n" , __func__, ret);return ret; + }/* The current address won't go where expected? */ -if (dest_island !=-1 && dest_island != v) +if (dest_island !=-1 && dest_island != v) { +pr_warn ("%s: dest_island mismatch: current (%d) != decoded (%d)\n" , + __func__, dest_island, v);return -EINVAL ; + }/* If dest_island was -1, we don't care where it goes. */ return 0 ;
@@ -493,7 +498,7 @@ static int nfp_encode_basic(u64 *addr, int dest_island, int cpp_tgt,* the address but we can verify if the existing * contents will point to a valid island. */ -return nfp_encode_basic_qdr (*addr, cpp_tgt, dest_island, +return nfp_encode_basic_qdr (*addr, dest_island, cpp_tgt, mode, addr40, isld1, isld0); iid_lsb = addr40 ?34 :26 ;
@@ -504,7 +509,7 @@ static int nfp_encode_basic(u64 *addr, int dest_island, int cpp_tgt,return 0 ;case 1 :if (cpp_tgt ==NFP_CPP_TARGET_QDR && !addr40) -return nfp_encode_basic_qdr (*addr, cpp_tgt, dest_island, +return nfp_encode_basic_qdr (*addr, dest_island, cpp_tgt, mode, addr40, isld1, isld0); idx_lsb = addr40 ?39 :31 ;
@@ -530,7 +535,7 @@ static int nfp_encode_basic(u64 *addr, int dest_island, int cpp_tgt,* be set before hand and with them select an island. * So we need to confirm that it's at least plausible. */ -return nfp_encode_basic_qdr (*addr, cpp_tgt, dest_island, +return nfp_encode_basic_qdr (*addr, dest_island, cpp_tgt, mode, addr40, isld1, isld0);/* Make sure we compare against isldN values
@@ -551,7 +556,7 @@ static int nfp_encode_basic(u64 *addr, int dest_island, int cpp_tgt,* iid<1> = addr<30> = channel<0> * channel<1> = addr<31> = Index */ -return nfp_encode_basic_qdr (*addr, cpp_tgt, dest_island, +return nfp_encode_basic_qdr (*addr, dest_island, cpp_tgt, mode, addr40, isld1, isld0); isld[0 ] &= ~3 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 497/666 tipc: fix double-free in tipc_buf_append()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lee Jones <[email protected]>
[ Upstream commit d293ca716e7d5dffdaecaf6b9b2f857a33dc3d3a ]
tipc_msg_validate() can potentially reallocate the skb it is validating, freeing the old one. In tipc_buf_append(), it was being called with a pointer to a local variable which was a copy of the caller's skb pointer.
If the skb was reallocated and validation subsequently failed, the error handling path would free the original skb pointer, which had already been freed, leading to double-free.
Fix this by checking if head now points to a newly allocated reassembled skb. If it does, reassign *headbuf for later freeing operations.
--- net/tipc/msg.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-)
net/tipc/msg.c +13 -1
@@ -177,8 +177,20 @@ int tipc_buf_append(struct sk_buff **headbuf, struct sk_buff **buf)if (fragid ==LAST_FRAGMENT ) {TIPC_SKB_CB (head)->validated =0 ; -if (unlikely (!tipc_msg_validate (&head))) + +/* If the reassembled skb has been freed in +* tipc_msg_validate() because of an invalid truesize, +* then head will point to a newly allocated reassembled +* skb, while *headbuf points to freed reassembled skb. +* In such cases, correct *headbuf for freeing the newly +* allocated reassembled skb later. +*/ +if (unlikely (!tipc_msg_validate (&head))) { +if (head != *headbuf) + *headbuf = head; goto err; + } + *buf = head;TIPC_SKB_CB (head)->tail =NULL ; *headbuf =NULL ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 498/666 vhost_net: fix sleeping with preempt-disabled in vhost_net_busy_poll()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kohei Enju <[email protected]>
[ Upstream commit e08a9fac5cf8c3fecf4755e7e3ac059f78b8f83d ]
syzbot reported "sleeping function called from invalid context" in vhost_net_busy_poll().
Commit 030881372460 ("vhost_net: basic polling support") introduced a busy-poll loop and preempt_{disable,enable}() around it, where each iteration calls a sleepable function inside the loop.
The purpose of disabling preemption was to keep local_clock()-based timeout accounting on a single CPU, rather than as a requirement of busy-poll itself:
https://lore.kernel.org/[email protected]
Quoted 1 line
From this perspective,
migrate_disable()is sufficient here, so replace
preempt_disable() with migrate_disable(), avoiding sleepable accesses from a preempt-disabled context.
--- drivers/vhost/net.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/vhost/net.c +2 -2
@@ -549,7 +549,7 @@ static void vhost_net_busy_poll(struct vhost_net *net, busyloop_timeout = poll_rx ? rvq->busyloop_timeout: tvq->busyloop_timeout; -preempt_disable (); +migrate_disable (); endtime =busy_clock () + busyloop_timeout;while (vhost_can_busy_poll (endtime)) {
@@ -566,7 +566,7 @@ static void vhost_net_busy_poll(struct vhost_net *net,cpu_relax (); } -preempt_enable (); +migrate_enable ();if (poll_rx ||sock_has_rx_data (sock))vhost_net_busy_poll_try_queue (net, vq);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 499/666 fs/adfs: validate nzones in adfs_validate_bblk()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bae Yeonju <[email protected]>
[ Upstream commit dd9d3e16c2d5fa166e13dce07413be51f42c8f5d ]
Reject ADFS disc records with a zero zone count during boot block validation, before the disc record is used.
When nzones is 0, adfs_read_map() passes it to kmalloc_array(0, ...) which returns ZERO_SIZE_PTR, and adfs_map_layout() then writes to dm[-1], causing an out-of-bounds write before the allocated buffer.
adfs_validate_dr0() already rejects nzones != 1 for old-format images. Add the equivalent check to adfs_validate_bblk() for new-format images so that a crafted image with nzones == 0 is rejected at probe time.
Found by syzkaller.
--- fs/adfs/super.c | 3 +++ 1 file changed, 3 insertions(+)
fs/adfs/super.c +3 -0
@@ -343,6 +343,9 @@ static int adfs_validate_bblk(struct super_block *sb, struct buffer_head *bh,if (adfs_checkdiscrecord (dr))return -EILSEQ ; +if ((dr->nzones | dr->nzones_high <<8 ) ==0 ) +return -EILSEQ ; + *drp = dr;return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 500/666 rtc: abx80x: Disable alarm feature if no interrupt attached
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Anthony Pighin (Nokia) <[email protected]>
[ Upstream commit 0fedce7244e4b85c049ce579c87e298a1b0b811d ]
Commit 795cda8338ea ("rtc: interface: Fix long-standing race when setting alarm") exposed an issue where the rtc-abx80x driver does not clear the alarm feature bit, but instead relies on the set_alarm operation to return invalid.
For example, when a RTC_UIE_ON ioctl is handled, it should abort at the feature validation. Instead, it proceeds to the rtc_timer_enqueue(), which used to return an error from the set_alarm call. However, following the race condition handling, which likely should not be discarding predecing errors, a success condition is returned to the ioctl() caller. This results in (for example):
hwclock: select() to /dev/rtc0 to wait for clock tick timed out
Notwithstanding the validity of the race condition handling, if an interrupt wasn't specified, or could not be attached, the driver should clear the alarm feature bit.
--- drivers/rtc/rtc-abx80x.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/rtc/rtc-abx80x.c +2 -0
@@ -933,6 +933,8 @@ static int abx80x_probe(struct i2c_client *client) client->irq =0 ; } } +if (client->irq <=0 ) +clear_bit (RTC_FEATURE_ALARM , priv->rtc->features); err =rtc_add_group (priv->rtc, &rtc_calib_attr_group);if (err) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 501/666 kbuild: builddeb - avoid recompiles for non-cross-compiles
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mathias Krause <[email protected]>
[ Upstream commit 2452dcf4d740effff5aa71b7f6529ee8c04fd8f6 ]
Commit e2c318225ac1 ("kbuild: deb-pkg: add pkg.linux-upstream.nokernelheaders build profile") changed how install-extmod-build gets called, making it always rebuild the host programs below scripts/ if HOSTCC wasn't specified with its full triplet on the make command line. That is, apparently, needed to fix up commit f1d87664b82a ("kbuild: cross-compile linux-headers package when possible") for cross-compiles. However, in the much more common case of non-cross-compile builds this will lead to unnecessary rebuilding of host tools including gcc plugins. This, in turn, will lead to a full kernel rebuild on the next 'make bindeb-pkg' which is unfortunate.
Avoid that by only triggering the rebuild of host tools for actual cross-compile builds.
--- scripts/package/builddeb | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
scripts/package/builddeb +7 -1
@@ -125,7 +125,13 @@ install_kernel_headers () { pdir=debian/$1 version=${1#linux-headers-} - CC="${DEB_HOST_GNU_TYPE}-gcc" "${srctree}/scripts/package/install-extmod-build" "${pdir}/usr/src/linux-headers-${version}" + # Override $CC only for cross-compiles, to not unnecessarily rebuild + # scripts/ including plugins, which may lead to a full kernel rebuild. + if [ -n "${CROSS_COMPILE}" ]; then + CC="${DEB_HOST_GNU_TYPE}-gcc" "${srctree}/scripts/package/install-extmod-build" "${pdir}/usr/src/linux-headers-${version}" + else + "${srctree}/scripts/package/install-extmod-build" "${pdir}/usr/src/linux-headers-${version}" + fi mkdir -p $pdir/lib/modules/$version/ ln -s /usr/src/linux-headers-$version $pdir/lib/modules/$version/build
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 502/666 fbdev: offb: fix PCI device reference leak on probe failure
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yuho Choi <[email protected]>
[ Upstream commit 869b93ba04088713596e68453c1146f52f713290 ]
offb_init_nodriver() gets a referenced PCI device with pci_get_device(). If pci_enable_device() fails, the function returns without dropping that reference.
Release the PCI device reference before returning from the pci_enable_device() failure path.
--- drivers/video/fbdev/offb.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
drivers/video/fbdev/offb.c +6 -1
@@ -640,8 +640,13 @@ static void offb_init_nodriver(struct platform_device *parent, struct device_nod vid =be32_to_cpup (vidp); did =be32_to_cpup (didp); pdev =pci_get_device (vid, did,NULL ); -if (!pdev ||pci_enable_device (pdev)) +if (!pdev)return ; + +if (pci_enable_device (pdev)) { +pci_dev_put (pdev); +return ; + } }#endif /* kludge for valkyrie */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 503/666 mailbox: mtk-cmdq: Fix CURR and END addr for task insert case
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jason-JH Lin <[email protected]>
[ Upstream commit d2591db9c8ef19fbb4d24ed15e0c6edfa6bc7917 ]
Fix CURR and END address calculation for inserting a cmdq task into the task list by using cmdq_reg_shift_addr() for proper address converting. This ensures both CURR and END addresses are set correctly when enabling the thread.
--- drivers/mailbox/mtk-cmdq-mailbox.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/mailbox/mtk-cmdq-mailbox.c +4 -4
@@ -434,14 +434,14 @@ static int cmdq_mbox_send_data(struct mbox_chan *chan, void *data)if (curr_pa == end_pa -CMDQ_INST_SIZE || curr_pa == end_pa) {/* set to this task directly */ -writel (task->pa_base >> cmdq->pdata->shift, - thread->base +CMDQ_THR_CURR_ADDR ); + gce_addr =cmdq_convert_gce_addr (task->pa_base, cmdq->pdata); +writel (gce_addr, thread->base +CMDQ_THR_CURR_ADDR ); }else {cmdq_task_insert_into_thread (task);smp_mb ();/* modify jump before enable thread */ } -writel ((task->pa_base + pkt->cmd_buf_size) >> cmdq->pdata->shift, - thread->base +CMDQ_THR_END_ADDR ); + gce_addr =cmdq_convert_gce_addr (task->pa_base + pkt->cmd_buf_size, cmdq->pdata); +writel (gce_addr, thread->base +CMDQ_THR_END_ADDR );cmdq_thread_resume (thread); }list_move_tail (&task->list_entry, &thread->task_busy_list);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 504/666 mailbox: mailbox-test: free channels on probe error
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wolfram Sang <[email protected]>
[ Upstream commit c02053a9055d5fdfd32432287cca8958db1d5bc5 ]
On probe error, free the previously obtained channels. This not only prevents a leak, but also UAF scenarios because the client structure will be removed nonetheless because it was allocated with devm.
--- drivers/mailbox/mailbox-test.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-)
drivers/mailbox/mailbox-test.c +12 -3
@@ -404,18 +404,27 @@ static int mbox_test_probe(struct platform_device *pdev)if (tdev->rx_channel) { tdev->rx_buffer =devm_kzalloc (&pdev->dev,MBOX_MAX_MSG_LEN ,GFP_KERNEL ); -if (!tdev->rx_buffer) -return -ENOMEM ; +if (!tdev->rx_buffer) { + ret = -ENOMEM ; + goto err_free_chans; + } } ret =mbox_test_add_debugfs (pdev, tdev);if (ret) -return ret; + goto err_free_chans;init_waitqueue_head (&tdev->waitq);dev_info (&pdev->dev,"Successfully registered\n" );return 0 ; + +err_free_chans: +if (tdev->tx_channel) +mbox_free_channel (tdev->tx_channel); +if (tdev->rx_channel) +mbox_free_channel (tdev->rx_channel); +return ret; }static void mbox_test_remove (struct platform_device *pdev)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 505/666 sched/psi: fix race between file release and pressure write
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Edward Adam Davis <[email protected]>
[ Upstream commit a5b98009f16d8a5fb4a8ff9a193f5735515c38fa ]
A potential race condition exists between pressure write and cgroup file release regarding the priv member of struct kernfs_open_file, which triggers the uaf reported in [1].
Consider the following scenario involving execution on two separate CPUs:
CPU0 CPU1
==== ====
vfs_rmdir() kernfs_iop_rmdir() cgroup_rmdir() cgroup_kn_lock_live() cgroup_destroy_locked() cgroup_addrm_files() cgroup_rm_file() kernfs_remove_by_name() kernfs_remove_by_name_ns() vfs_write() __kernfs_remove() new_sync_write() kernfs_drain() kernfs_fop_write_iter() kernfs_drain_open_files() cgroup_file_write() kernfs_release_file() pressure_write() cgroup_file_release() ctx = of->priv; kfree(ctx);
of->priv = NULL; cgroup_kn_unlock()
cgroup_kn_lock_live()
cgroup_get(cgrp)
cgroup_kn_unlock()
if (ctx->psi.trigger) // here, trigger uaf for ctx, that is of->priv
The cgroup_rmdir() is protected by the cgroup_mutex, it also safeguards the memory deallocation of of->priv performed within cgroup_file_release(). However, the operations involving of->priv executed within pressure_write() are not entirely covered by the protection of cgroup_mutex. Consequently, if the code in pressure_write(), specifically the section handling the ctx variable executes after cgroup_file_release() has completed, a uaf vulnerability involving of->priv is triggered.
Therefore, the issue can be resolved by extending the scope of the cgroup_mutex lock within pressure_write() to encompass all code paths involving of->priv, thereby properly synchronizing the race condition occurring between cgroup_file_release() and pressure_write().
And, if an live kn lock can be successfully acquired while executing the pressure write operation, it indicates that the cgroup deletion process has not yet reached its final stage; consequently, the priv pointer within open_file cannot be NULL. Therefore, the operation to retrieve the ctx value must be moved to a point *after* the live kn lock has been successfully acquired.
In another situation, specifically after entering cgroup_kn_lock_live() but before acquiring cgroup_mutex, there exists a different class of race condition:
CPU0: write memory.pressure CPU1: write cgroup.pressure=0
=========================== =============================
kernfs_fop_write_iter()
kernfs_get_active_of(of)
pressure_write()
cgroup_kn_lock_live(memory.pressure)
cgroup_tryget(cgrp)
kernfs_break_active_protection(kn)
... blocks on cgroup_mutex
cgroup_pressure_write() cgroup_kn_lock_live(cgroup.pressure) cgroup_file_show(memory.pressure, false)
kernfs_show(false)
kernfs_drain_open_files()
cgroup_file_release(of)
kfree(ctx)
of->priv = NULL
cgroup_kn_unlock()
... acquires cgroup_mutex
ctx = of->priv; // may now be NULL
if (ctx->psi.trigger) // NULL dereference
Consequently, there is a possibility that of->priv is NULL, the pressure write needs to check for this.
Now that the scope of the cgroup_mutex has been expanded, the original explicit cgroup_get/put operations are no longer necessary, this is because acquiring/releasing the live kn lock inherently executes a cgroup get/put operation.
[1]
BUG: KASAN: slab-use-after-free in pressure_write+0xa4/0x210 kernel/cgroup/cgroup.c:4011 Call Trace: pressure_write+0xa4/0x210 kernel/cgroup/cgroup.c:4011 cgroup_file_write+0x36f/0x790 kernel/cgroup/cgroup.c:4311 kernfs_fop_write_iter+0x3b0/0x540 fs/kernfs/file.c:352 Allocated by task 9352: cgroup_file_open+0x90/0x3a0 kernel/cgroup/cgroup.c:4256 kernfs_fop_open+0x9eb/0xcb0 fs/kernfs/file.c:724 do_dentry_open+0x83d/0x13e0 fs/open.c:949 Freed by task 9353: cgroup_file_release+0xd6/0x100 kernel/cgroup/cgroup.c:4283 kernfs_release_file fs/kernfs/file.c:764 [inline] kernfs_drain_open_files+0x392/0x720 fs/kernfs/file.c:834 kernfs_drain+0x470/0x600 fs/kernfs/dir.c:525
--- kernel/cgroup/cgroup.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-)
kernel/cgroup/cgroup.c +16 -8
@@ -3876,33 +3876,41 @@ static int cgroup_cpu_pressure_show(struct seq_file *seq, void *v)static ssize_t pressure_write (struct kernfs_open_file *of,char *buf,size_t nbytes,enum psi_res res) { -struct cgroup_file_ctx *ctx = of->priv; +struct cgroup_file_ctx *ctx;struct psi_trigger *new;struct cgroup *cgrp;struct psi_group *psi; +ssize_t ret =0 ; cgrp =cgroup_kn_lock_live (of->kn, false);if (!cgrp)return -ENODEV ; -cgroup_get (cgrp); -cgroup_kn_unlock (of->kn); + ctx = of->priv; +if (!ctx) { + ret = -ENODEV ; + goto out_unlock; + }/* Allow only one trigger per file descriptor */ if (ctx->psi.trigger) { -cgroup_put (cgrp); -return -EBUSY ; + ret = -EBUSY ; + goto out_unlock; } psi =cgroup_psi (cgrp); new =psi_trigger_create (psi, buf, res, of->file, of);if (IS_ERR (new)) { -cgroup_put (cgrp); -return PTR_ERR (new); + ret =PTR_ERR (new); + goto out_unlock; }smp_store_release (&ctx->psi.trigger, new); -cgroup_put (cgrp); + +out_unlock: +cgroup_kn_unlock (of->kn); +if (ret) +return ret;return nbytes; }
Signature · 1 line
2.53.0
Re: [PATCH 6.12 505/666] sched/psi: fix race between file release and pressure write
Hi Greg/Sasha,
Quoted 143 lines · Greg Kroah-Hartman
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Edward Adam Davis <[email protected]>
[ Upstream commit
a5b98009f16d8a5fb4a8ff9a193f5735515c38fa]A potential race condition exists between pressure write and cgroup file release regarding the priv member of struct
kernfs_open_file, which triggers the uaf reported in [1].Consider the following scenario involving execution on two separate CPUs:
CPU0 CPU1 ==== ==== vfs_rmdir() kernfs_iop_rmdir() cgroup_rmdir() cgroup_kn_lock_live() cgroup_destroy_locked() cgroup_addrm_files() cgroup_rm_file() kernfs_remove_by_name() kernfs_remove_by_name_ns() vfs_write() __kernfs_remove() new_sync_write() kernfs_drain() kernfs_fop_write_iter() kernfs_drain_open_files() cgroup_file_write() kernfs_release_file() pressure_write() cgroup_file_release() ctx = of->priv; kfree(ctx);
of->priv= NULL;cgroup_kn_unlock()
cgroup_kn_lock_live()
cgroup_get(cgrp)
cgroup_kn_unlock()
if (ctx->psi.trigger) // here, trigger uaf for ctx, that isof->privThe
cgroup_rmdir()is protected by thecgroup_mutex, it also safeguards the memory deallocation ofof->privperformed withincgroup_file_release(). However, the operations involvingof->privexecuted withinpressure_write()are not entirely covered by the protection ofcgroup_mutex. Consequently, if the code inpressure_write(), specifically the section handling the ctx variable executes aftercgroup_file_release()has completed, a uaf vulnerability involvingof->privis triggered.Therefore, the issue can be resolved by extending the scope of the
cgroup_mutexlock withinpressure_write()to encompass all code paths involvingof->priv, thereby properly synchronizing the race condition occurring betweencgroup_file_release()andpressure_write().And, if an live kn lock can be successfully acquired while executing the pressure write operation, it indicates that the cgroup deletion process has not yet reached its final stage; consequently, the priv pointer within
open_filecannot be NULL. Therefore, the operation to retrieve the ctx value must be moved to a point *after* the live kn lock has been successfully acquired.In another situation, specifically after entering
cgroup_kn_lock_live()but before acquiringcgroup_mutex, there exists a different class of race condition:CPU0: write memory.pressure CPU1: write cgroup.pressure=0
=========================== =============================
kernfs_fop_write_iter()
kernfs_get_active_of(of)
pressure_write()cgroup_kn_lock_live(memory.pressure) cgroup_tryget(cgrp) kernfs_break_active_protection(kn) ... blocks on cgroup_mutex cgroup_pressure_write() cgroup_kn_lock_live(cgroup.pressure) cgroup_file_show(memory.pressure, false) kernfs_show(false) kernfs_drain_open_files() cgroup_file_release(of) kfree(ctx) of->priv = NULL cgroup_kn_unlock() ... acquires cgroup_mutex ctx = of->priv; // may now be NULL if (ctx->psi.trigger) // NULL dereferenceConsequently, there is a possibility that
of->privis NULL, the pressure write needs to check for this.Now that the scope of the
cgroup_mutexhas been expanded, the original explicit cgroup_get/put operations are no longer necessary, this is because acquiring/releasing the live kn lock inherently executes a cgroup get/put operation.[1]
BUG: KASAN: slab-use-after-free in pressure_write+0xa4/0x210 kernel/cgroup/cgroup.c:4011 Call Trace: pressure_write+0xa4/0x210 kernel/cgroup/cgroup.c:4011 cgroup_file_write+0x36f/0x790 kernel/cgroup/cgroup.c:4311 kernfs_fop_write_iter+0x3b0/0x540 fs/kernfs/file.c:352 Allocated by task 9352: cgroup_file_open+0x90/0x3a0 kernel/cgroup/cgroup.c:4256 kernfs_fop_open+0x9eb/0xcb0 fs/kernfs/file.c:724 do_dentry_open+0x83d/0x13e0 fs/open.c:949 Freed by task 9353: cgroup_file_release+0xd6/0x100 kernel/cgroup/cgroup.c:4283 kernfs_release_file fs/kernfs/file.c:764 [inline] kernfs_drain_open_files+0x392/0x720 fs/kernfs/file.c:834 kernfs_drain+0x470/0x600 fs/kernfs/dir.c:525Fixes 0e94682b73bf ("psi: introduce psi monitor")Reported-by [email protected]Tested-by [email protected]Signed-off-by Edward Adam Davis <[email protected]>Reviewed-by Chen Ridong <[email protected]>Signed-off-by Tejun Heo <[email protected]>Signed-off-by Sasha Levin <[email protected]>--- kernel/cgroup/cgroup.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-)kernel/cgroup/cgroup.c +2
-1@@ -3876,33 +3876,41 @@ static int cgroup_cpu_pressure_show(struct seq_file *seq, void *v)static ssize_t pressure_write (struct kernfs_open_file *of,char *buf,size_t nbytes,enum psi_res res) { -struct cgroup_file_ctx *ctx = of->priv; +struct cgroup_file_ctx *ctx;struct psi_trigger *new;struct cgroup *cgrp;struct psi_group *psi; +ssize_t ret =0 ; cgrp =cgroup_kn_lock_live (of->kn, false);if (!cgrp)
kernel/cgroup/cgroup.c static int cgroup_cpu_pressure_show(struct seq_file *seq, void *v) · line 3894
Quoted 10 lines
kernel/cgroup/cgroup.c +5
-2return -ENODEV ; -cgroup_get (cgrp); -cgroup_kn_unlock (of->kn); + ctx = of->priv; +if (!ctx) { + ret = -ENODEV ; + goto out_unlock; + }
I have run an AI assisted backport review and it spotted an issue: I have taken a look and the issues goes like:
Upstream has:
static void cgroup_file_release(struct kernfs_open_file *of)
{
struct cftype *cft = of_cft(of);
struct cgroup_file_ctx *ctx = of->priv;
if (cft->release)
cft->release(of);
put_cgroup_ns(ctx->ns);
kfree(ctx);
of->priv = NULL;
}On 6.12.y:
static void cgroup_file_release(struct kernfs_open_file *of)
{
struct cftype *cft = of_cft(of);
struct cgroup_file_ctx *ctx = of->priv;
if (cft->release)
cft->release(of);
put_cgroup_ns(ctx->ns);
kfree(ctx);
}On 6.12.y, cgroup_file_release() frees ctx but does not clear of->priv. The posted backport adds
ctx = of->priv; if (!ctx)
in pressure_write(), but that only works if release turns of->priv into NULL. In the pressure_write() vs cgroup_pressure_write() race from the commit message, 6.12.y still leaves a dangling pointer there, so this backport alone is incomplete and can still hit UAF.
So upstream has commit: 94a4acfec146 ("cgroup/psi: Set of->priv to NULL upon file release") which might be needed here as well, without that I would suggest a drop.
Thanks,
Harshit
Greg Kroah-Hartman
maintainerRe: [PATCH 6.12 505/666] sched/psi: fix race between file release and pressure write
Quoted 191 lines · Harshit Mogalapalli
Hi Greg/Sasha,
Quoted 140 lines · Greg Kroah-Hartman
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Edward Adam Davis <[email protected]>
[ Upstream commit
a5b98009f16d8a5fb4a8ff9a193f5735515c38fa]A potential race condition exists between pressure write and cgroup file release regarding the priv member of struct
kernfs_open_file, which triggers the uaf reported in [1].Consider the following scenario involving execution on two separate CPUs:
CPU0 CPU1 ==== ==== vfs_rmdir() kernfs_iop_rmdir() cgroup_rmdir() cgroup_kn_lock_live() cgroup_destroy_locked() cgroup_addrm_files() cgroup_rm_file() kernfs_remove_by_name() kernfs_remove_by_name_ns() vfs_write() __kernfs_remove() new_sync_write() kernfs_drain() kernfs_fop_write_iter() kernfs_drain_open_files() cgroup_file_write() kernfs_release_file() pressure_write() cgroup_file_release() ctx = of->priv; kfree(ctx);
of->priv= NULL;cgroup_kn_unlock()
cgroup_kn_lock_live()
cgroup_get(cgrp)
cgroup_kn_unlock()
if (ctx->psi.trigger) // here, trigger uaf for ctx, that isof->privThe
cgroup_rmdir()is protected by thecgroup_mutex, it also safeguards the memory deallocation ofof->privperformed withincgroup_file_release(). However, the operations involvingof->privexecuted withinpressure_write()are not entirely covered by the protection ofcgroup_mutex. Consequently, if the code inpressure_write(), specifically the section handling the ctx variable executes aftercgroup_file_release()has completed, a uaf vulnerability involvingof->privis triggered.Therefore, the issue can be resolved by extending the scope of the
cgroup_mutexlock withinpressure_write()to encompass all code paths involvingof->priv, thereby properly synchronizing the race condition occurring betweencgroup_file_release()andpressure_write().And, if an live kn lock can be successfully acquired while executing the pressure write operation, it indicates that the cgroup deletion process has not yet reached its final stage; consequently, the priv pointer within
open_filecannot be NULL. Therefore, the operation to retrieve the ctx value must be moved to a point *after* the live kn lock has been successfully acquired.In another situation, specifically after entering
cgroup_kn_lock_live()but before acquiringcgroup_mutex, there exists a different class of race condition:CPU0: write memory.pressure CPU1: write cgroup.pressure=0
=========================== =============================
kernfs_fop_write_iter()
kernfs_get_active_of(of)
pressure_write()cgroup_kn_lock_live(memory.pressure) cgroup_tryget(cgrp) kernfs_break_active_protection(kn) ... blocks on cgroup_mutex cgroup_pressure_write() cgroup_kn_lock_live(cgroup.pressure) cgroup_file_show(memory.pressure, false) kernfs_show(false) kernfs_drain_open_files() cgroup_file_release(of) kfree(ctx) of->priv = NULL cgroup_kn_unlock() ... acquires cgroup_mutex ctx = of->priv; // may now be NULL if (ctx->psi.trigger) // NULL dereferenceConsequently, there is a possibility that
of->privis NULL, the pressure write needs to check for this.Now that the scope of the
cgroup_mutexhas been expanded, the original explicit cgroup_get/put operations are no longer necessary, this is because acquiring/releasing the live kn lock inherently executes a cgroup get/put operation.[1]
BUG: KASAN: slab-use-after-free in pressure_write+0xa4/0x210 kernel/cgroup/cgroup.c:4011 Call Trace: pressure_write+0xa4/0x210 kernel/cgroup/cgroup.c:4011 cgroup_file_write+0x36f/0x790 kernel/cgroup/cgroup.c:4311 kernfs_fop_write_iter+0x3b0/0x540 fs/kernfs/file.c:352 Allocated by task 9352: cgroup_file_open+0x90/0x3a0 kernel/cgroup/cgroup.c:4256 kernfs_fop_open+0x9eb/0xcb0 fs/kernfs/file.c:724 do_dentry_open+0x83d/0x13e0 fs/open.c:949 Freed by task 9353: cgroup_file_release+0xd6/0x100 kernel/cgroup/cgroup.c:4283 kernfs_release_file fs/kernfs/file.c:764 [inline] kernfs_drain_open_files+0x392/0x720 fs/kernfs/file.c:834 kernfs_drain+0x470/0x600 fs/kernfs/dir.c:525Fixes 0e94682b73bf ("psi: introduce psi monitor")Reported-by [email protected]Tested-by [email protected]Signed-off-by Edward Adam Davis <[email protected]>Reviewed-by Chen Ridong <[email protected]>Signed-off-by Tejun Heo <[email protected]>Signed-off-by Sasha Levin <[email protected]>--- kernel/cgroup/cgroup.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-)kernel/cgroup/cgroup.c +2
-1@@ -3876,33 +3876,41 @@ static int cgroup_cpu_pressure_show(struct seq_file *seq, void *v)static ssize_t pressure_write (struct kernfs_open_file *of,char *buf,size_t nbytes,enum psi_res res) { -struct cgroup_file_ctx *ctx = of->priv; +struct cgroup_file_ctx *ctx;struct psi_trigger *new;struct cgroup *cgrp;struct psi_group *psi; +ssize_t ret =0 ;kernel/cgroup/cgroup.c static int cgroup_cpu_pressure_show(struct seq_file *seq, void *v) · line 3891
Quoted 10 lines
kernel/cgroup/cgroup.c +5
-2cgrp =cgroup_kn_lock_live (of->kn, false);if (!cgrp)return -ENODEV ; -cgroup_get (cgrp); -cgroup_kn_unlock (of->kn); + ctx = of->priv; +if (!ctx) { + ret = -ENODEV ; + goto out_unlock; + }I have run an AI assisted backport review and it spotted an issue: I have taken a look and the issues goes like:
Upstream has:
static void
cgroup_file_release(struct kernfs_open_file *of){ struct cftype *cft = of_cft(of); struct cgroup_file_ctx *ctx = of->priv; if (cft->release) cft->release(of); put_cgroup_ns(ctx->ns); kfree(ctx); of->priv = NULL; }On 6.12.y:
static void
cgroup_file_release(struct kernfs_open_file *of){ struct cftype *cft = of_cft(of); struct cgroup_file_ctx *ctx = of->priv; if (cft->release) cft->release(of); put_cgroup_ns(ctx->ns); kfree(ctx); }On 6.12.y,
cgroup_file_release()frees ctx but does not clearof->priv. The posted backport addsctx = of->priv; if (!ctx)
Quoted 8 lines
in
pressure_write(), but that only works if release turnsof->privinto NULL. In thepressure_write()vscgroup_pressure_write()race from the commit message, 6.12.y still leaves a dangling pointer there, so this backport alone is incomplete and can still hit UAF.So upstream has commit:
94a4acfec146("cgroup/psi: Setof->privto NULL upon file release") which might be needed here as well, without that I would suggest a drop.
Dropped from 6.12 and older, thanks.
greg k-h
Greg Kroah-Hartman
maintainerPATCH 506/666 cgroup/rdma: fix integer overflow in rdmacg_try_charge()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: cuitao <[email protected]>
[ Upstream commit c802f460dd485c1332b5a35e7adcfb2bc22536a2 ]
The expression rpool->resources[index].usage + 1 is computed in int arithmetic before being assigned to s64 variable new. When usage equals INT_MAX (the default "max" value), the addition overflows to INT_MIN. This negative value then passes the new > max check incorrectly, allowing a charge that should be rejected and corrupting usage to negative.
Fix by casting usage to s64 before the addition so the arithmetic is done in 64-bit.
--- kernel/cgroup/rdma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/cgroup/rdma.c +1 -1
@@ -283,7 +283,7 @@ int rdmacg_try_charge(struct rdma_cgroup **rdmacg, ret =PTR_ERR (rpool); goto err; }else { - new = rpool->resources[index].usage +1 ; + new = (s64 )rpool->resources[index].usage +1 ;if (new > rpool->resources[index].max) { ret = -EAGAIN ; goto err;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 507/666 mailbox: add sanity check for channel array
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wolfram Sang <[email protected]>
[ Upstream commit c1aad75595fb67edc7fda8af249d3b886efa1be9 ]
Fail gracefully if there is no channel array attached to the mailbox controller. Otherwise the later dereference will cause an OOPS which might not be seen because mailbox controllers might instantiate very early. Remove the comment explaining the obvious while here.
--- drivers/mailbox/mailbox.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
drivers/mailbox/mailbox.c +1 -2
@@ -520,8 +520,7 @@ int mbox_controller_register(struct mbox_controller *mbox) {int i, txdone; -/* Sanity check */ -if (!mbox || !mbox->dev || !mbox->ops || !mbox->num_chans) +if (!mbox || !mbox->dev || !mbox->ops || !mbox->chans || !mbox->num_chans)return -EINVAL ;if (mbox->txdone_irq)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 508/666 mailbox: mailbox-test: dont free the reused channel
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wolfram Sang <[email protected]>
[ Upstream commit 88ebadbf0deefdaccdab868b44ff70a0a257f473 ]
The RX channel can be aliased to the TX channel if it has a different MMIO. This special case needs to be handled when freeing the channels otherwise a double-free occurs.
--- drivers/mailbox/mailbox-test.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/mailbox/mailbox-test.c +2 -2
@@ -422,7 +422,7 @@ static int mbox_test_probe(struct platform_device *pdev) err_free_chans:if (tdev->tx_channel)mbox_free_channel (tdev->tx_channel); -if (tdev->rx_channel) +if (tdev->rx_channel && tdev->rx_channel != tdev->tx_channel)mbox_free_channel (tdev->rx_channel);return ret; }
@@ -435,7 +435,7 @@ static void mbox_test_remove(struct platform_device *pdev)if (tdev->tx_channel)mbox_free_channel (tdev->tx_channel); -if (tdev->rx_channel) +if (tdev->rx_channel && tdev->rx_channel != tdev->tx_channel)mbox_free_channel (tdev->rx_channel); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 509/666 mailbox: mailbox-test: initialize struct earlier
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wolfram Sang <[email protected]>
[ Upstream commit bbcf9af68bfedb3d9cc3c7eae62f5c844d8b78b9 ]
The waitqueue must be initialized before the debugfs files are created because from that time, requests from userspace can already be made. Similarily, drvdata and spinlock needs to be initialized before we request the channel, otherwise dangling irqs might run into problems like a NULL pointer exception.
--- drivers/mailbox/mailbox-test.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-)
drivers/mailbox/mailbox-test.c +6 -7
@@ -366,6 +366,12 @@ static int mbox_test_probe(struct platform_device *pdev)if (!tdev)return -ENOMEM ; + tdev->dev = &pdev->dev; +spin_lock_init (&tdev->lock); +mutex_init (&tdev->mutex); +init_waitqueue_head (&tdev->waitq); +platform_set_drvdata (pdev, tdev); +/* It's okay for MMIO to be NULL */ tdev->tx_mmio =devm_platform_get_and_ioremap_resource (pdev,0 , &res);if (PTR_ERR (tdev->tx_mmio) == -EBUSY ) {
@@ -395,12 +401,6 @@ static int mbox_test_probe(struct platform_device *pdev)if (!tdev->rx_channel && (tdev->rx_mmio != tdev->tx_mmio)) tdev->rx_channel = tdev->tx_channel; - tdev->dev = &pdev->dev; -platform_set_drvdata (pdev, tdev); - -spin_lock_init (&tdev->lock); -mutex_init (&tdev->mutex); -if (tdev->rx_channel) { tdev->rx_buffer =devm_kzalloc (&pdev->dev,MBOX_MAX_MSG_LEN ,GFP_KERNEL );
@@ -414,7 +414,6 @@ static int mbox_test_probe(struct platform_device *pdev)if (ret) goto err_free_chans; -init_waitqueue_head (&tdev->waitq);dev_info (&pdev->dev,"Successfully registered\n" );return 0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 510/666 mailbox: mailbox-test: make data_ready a per-instance variable
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wolfram Sang <[email protected]>
[ Upstream commit 6e937f4e769e60947909e3525965f0137b9039e8 ]
While not the default case, multiple tests can be run simultaneously. Then, data_ready being a global variable will be overwritten and the per-instance lock will not help. Turn the global variable into a per-instance one to avoid this problem.
--- drivers/mailbox/mailbox-test.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-)
drivers/mailbox/mailbox-test.c +4 -5
@@ -28,8 +28,6 @@#define MBOX_HEXDUMP_MAX_LEN (MBOX_HEXDUMP_LINE_LEN * \ (MBOX_MAX_MSG_LEN / MBOX_BYTES_PER_LINE)) -static bool mbox_data_ready; -struct mbox_test_device {struct device *dev;void __iomem *tx_mmio;
@@ -42,6 +40,7 @@ struct mbox_test_device {spinlock_t lock;struct mutex mutex;wait_queue_head_t waitq; +bool data_ready;struct fasync_struct *async_queue;struct dentry *root_debugfs_dir; };
@@ -162,7 +161,7 @@ static bool mbox_test_message_data_ready(struct mbox_test_device *tdev)unsigned long flags;spin_lock_irqsave (&tdev->lock, flags); - data_ready = mbox_data_ready; + data_ready = tdev->data_ready;spin_unlock_irqrestore (&tdev->lock, flags);return data_ready;
@@ -227,7 +226,7 @@ static ssize_t mbox_test_message_read(struct file *filp, char __user *userbuf, *(touser + l) ='\0' ;memset (tdev->rx_buffer,0 ,MBOX_MAX_MSG_LEN ); - mbox_data_ready = false; + tdev->data_ready = false;spin_unlock_irqrestore (&tdev->lock, flags);
@@ -297,7 +296,7 @@ static void mbox_test_receive_message(struct mbox_client *client, void *message) message, MBOX_MAX_MSG_LEN);memcpy (tdev->rx_buffer, message,MBOX_MAX_MSG_LEN ); } - mbox_data_ready = true; + tdev->data_ready = true;spin_unlock_irqrestore (&tdev->lock, flags);wake_up_interruptible (&tdev->waitq);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 511/666 fsnotify: fix inode reference leak in fsnotify_recalc_mask()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Amir Goldstein <[email protected]>
[ Upstream commit 4aca914ac152f5d055ddcb36704d1e539ac08977 ]
fsnotify_recalc_mask() fails to handle the return value of __fsnotify_recalc_mask(), which may return an inode pointer that needs to be released via fsnotify_drop_object() when the connector's HAS_IREF flag transitions from set to cleared.
This manifests as a hung task with the following call trace:
INFO: task umount:1234 blocked for more than 120 seconds. Call Trace: __schedule schedule fsnotify_sb_delete generic_shutdown_super kill_anon_super cleanup_mnt task_work_run do_exit do_group_exit
The race window that triggers the iref leak:
Thread A (adding mark) Thread B (removing mark)
────────────────────── ────────────────────────
fsnotify_add_mark_locked():
fsnotify_add_mark_list():
spin_lock(conn->lock)
add mark_B(evictable) to list
spin_unlock(conn->lock)
return
/* ---- gap: no lock held ---- */
fsnotify_detach_mark(mark_A):
spin_lock(mark_A->lock)
clear ATTACHED flag on mark_A
spin_unlock(mark_A->lock)
fsnotify_put_mark(mark_A)
fsnotify_recalc_mask():
spin_lock(conn->lock)
__fsnotify_recalc_mask():
/* mark_A skipped: ATTACHED cleared */
/* only mark_B(evictable) remains */
want_iref = false
has_iref = true /* not yet cleared */
-> HAS_IREF transitions true -> false
-> returns inode pointer
spin_unlock(conn->lock)
/* BUG: return value discarded!
* iput() and fsnotify_put_sb_watched_objects()
* are never called */Fix this by deferring the transition true -> false of HAS_IREF flag from fsnotify_recalc_mask() (Thread A) to fsnotify_put_mark() (thread B).
--- fs/notify/mark.c | 39 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-)
fs/notify/mark.c +36 -3
@@ -233,7 +233,12 @@ static struct inode *fsnotify_update_iref(struct fsnotify_mark_connector *conn,return inode; } -static void *__fsnotify_recalc_mask (struct fsnotify_mark_connector *conn) +/* +* Calculate mask of events for a list of marks. +* +* Return true if any of the attached marks want to hold an inode reference. +*/ +static bool __fsnotify_recalc_mask (struct fsnotify_mark_connector *conn) {u32 new_mask =0 ;bool want_iref = false;
@@ -257,6 +262,34 @@ static void *__fsnotify_recalc_mask(struct fsnotify_mark_connector *conn)*/ WRITE_ONCE (*fsnotify_conn_mask_p (conn), new_mask); +return want_iref; +} + +/* +* Calculate mask of events for a list of marks after attach/modify mark +* and get an inode reference for the connector if needed. +* +* A concurrent add of evictable mark and detach of non-evictable mark can +* lead to __fsnotify_recalc_mask() returning false want_iref, but in this +* case we defer clearing iref to fsnotify_recalc_mask_clear_iref() called +* from fsnotify_put_mark(). +*/ +static void fsnotify_recalc_mask_set_iref (struct fsnotify_mark_connector *conn) +{ +bool has_iref = conn->flags &FSNOTIFY_CONN_FLAG_HAS_IREF ; +bool want_iref =__fsnotify_recalc_mask (conn) || has_iref; + + (void )fsnotify_update_iref (conn, want_iref); +} + +/* +* Calculate mask of events for a list of marks after detach mark +* and return the inode object if its reference is no longer needed. +*/ +static void *fsnotify_recalc_mask_clear_iref (struct fsnotify_mark_connector *conn) +{ +bool want_iref =__fsnotify_recalc_mask (conn); +return fsnotify_update_iref (conn, want_iref); }
@@ -293,7 +326,7 @@ void fsnotify_recalc_mask(struct fsnotify_mark_connector *conn)spin_lock (&conn->lock); update_children = !fsnotify_conn_watches_children (conn); -__fsnotify_recalc_mask (conn); +fsnotify_recalc_mask_set_iref (conn); update_children &=fsnotify_conn_watches_children (conn);spin_unlock (&conn->lock);/*
@@ -408,7 +441,7 @@ void fsnotify_put_mark(struct fsnotify_mark *mark)/* Update watched objects after detaching mark */ if (sb)fsnotify_update_sb_watchers (sb, conn); - objp =__fsnotify_recalc_mask (conn); + objp =fsnotify_recalc_mask_clear_iref (conn); type = conn->type; }WRITE_ONCE (mark->connector,NULL );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 512/666 btrfs: fix double-decrement of bytes_may_use in submit_one_async_extent()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mark Harmstone <[email protected]>
[ Upstream commit 82323b1a7088b7a5c3e528a5d634bff447fa286f ]
submit_one_async_extent() calls btrfs_reserve_extent(), which decrements bytes_may_use. If the call btrfs_create_io_em() fails, we jump to out_free_reserve, which calls extent_clear_unlock_delalloc().
Because we're specifying EXTENT_DO_ACCOUNTING, i.e. EXTENT_CLEAR_META_RESV | EXTENT_CLEAR_DATA_RESV, this decreases bytes_may_use again. This can lead to problems later on, as an initial write can fail only for the writeback to silently ENOSPC.
Fix this by replacing EXTENT_DO_ACCOUNTING with EXTENT_CLEAR_META_RESV. This parallels a4fe134fc1d8eb ("btrfs: fix a double release on reserved extents in cow_one_range()"), which is the same fix in cow_one_range().
--- fs/btrfs/inode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/btrfs/inode.c +1 -1
@@ -1288,7 +1288,7 @@ static void submit_one_async_extent(struct async_chunk *async_chunk,NULL , &cached,EXTENT_LOCKED |EXTENT_DELALLOC |EXTENT_DELALLOC_NEW | -EXTENT_DEFRAG |EXTENT_DO_ACCOUNTING , +EXTENT_DEFRAG |EXTENT_CLEAR_META_RESV ,PAGE_UNLOCK |PAGE_START_WRITEBACK | PAGE_END_WRITEBACK);free_async_extent_pages (async_extent);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 513/666 cgroup: Increment nr_dying_subsys_* from rmdir context
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Petr Malat <[email protected]>
[ Upstream commit 13e786b64bd3fd81c7eb22aa32bf8305c32f2ccf ]
Incrementing nr_dying_subsys_* in offline_css(), which is executed by cgroup_offline_wq worker, leads to a race where user can see the value to be 0 if he reads cgroup.stat after calling rmdir and before the worker executes. This makes the user wrongly expect resources released by the removed cgroup to be available for a new assignment.
Increment nr_dying_subsys_* from kill_css(), which is called from the cgroup_rmdir() context.
--- kernel/cgroup/cgroup.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-)
kernel/cgroup/cgroup.c +12 -10
@@ -5654,16 +5654,6 @@ static void offline_css(struct cgroup_subsys_state *css)RCU_INIT_POINTER (css->cgroup->subsys[ss->id],NULL );wake_up_all (&css->cgroup->offline_waitq); - - css->cgroup->nr_dying_subsys[ss->id]++; -/* -* Parent css and cgroup cannot be freed until after the freeing -* of child css, see css_free_rwork_fn(). -*/ -while ((css = css->parent)) { - css->nr_descendants--; - css->cgroup->nr_dying_subsys[ss->id]++; - } }/**
@@ -5965,6 +5955,8 @@ static void css_killed_ref_fn(struct percpu_ref *ref)*/ static void kill_css (struct cgroup_subsys_state *css) { +struct cgroup_subsys *ss = css->ss; +lockdep_assert_held (&cgroup_mutex);if (css->flags &CSS_DYING )
@@ -6001,6 +5993,16 @@ static void kill_css(struct cgroup_subsys_state *css)* css is confirmed to be seen as killed on all CPUs. */ percpu_ref_kill_and_confirm (&css->refcnt, css_killed_ref_fn); + + css->cgroup->nr_dying_subsys[ss->id]++; +/* +* Parent css and cgroup cannot be freed until after the freeing +* of child css, see css_free_rwork_fn(). +*/ +while ((css = css->parent)) { + css->nr_descendants--; + css->cgroup->nr_dying_subsys[ss->id]++; + } }/**
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 514/666 tracing: branch: Fix inverted check on stat tracer registration
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Breno Leitao <[email protected]>
[ Upstream commit 3b75dd76e64a04771861bb5647951c264919e563 ]
init_annotated_branch_stats() and all_annotated_branch_stats() check the return value of register_stat_tracer() with "if (!ret)", but register_stat_tracer() returns 0 on success and a negative errno on failure. The inverted check causes the warning to be printed on every successful registration, e.g.:
Warning: could not register annotated branches stats
while leaving real failures silent. The initcall also returned a hard-coded 1 instead of the actual error.
Invert the check and propagate ret so that the warning fires on real errors and the initcall reports the correct status.
--- kernel/trace/trace_branch.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
kernel/trace/trace_branch.c +4 -4
@@ -379,10 +379,10 @@ __init static int init_annotated_branch_stats(void)int ret; ret =register_stat_tracer (&annotated_branch_stats); -if (!ret) { +if (ret) {printk (KERN_WARNING "Warning: could not register " "annotated branches stats\n" ); -return 1 ; +return ret; }return 0 ; }
@@ -444,10 +444,10 @@ __init static int all_annotated_branch_stats(void)int ret; ret =register_stat_tracer (&all_branch_stats); -if (!ret) { +if (ret) {printk (KERN_WARNING "Warning: could not register " "all branches stats\n" ); -return 1 ; +return ret; }return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 515/666 nvmet-tcp: propagate nvmet_tcp_build_pdu_iovec() errors to its callers
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Maurizio Lombardi <[email protected]>
[ Upstream commit ea8e356acb165cb1fd75537a52e1f66e5e76c538 ]
Currently, when nvmet_tcp_build_pdu_iovec() detects an out-of-bounds PDU length or offset, it triggers nvmet_tcp_fatal_error(cmd->queue) and returns early. However, because the function returns void, the callers are entirely unaware that a fatal error has occurred and that the cmd->recv_msg.msg_iter was left uninitialized.
Callers such as nvmet_tcp_handle_h2c_data_pdu() proceed to blindly overwrite the queue state with queue->rcv_state = NVMET_TCP_RECV_DATA Consequently, the socket receiving loop may attempt to read incoming network data into the uninitialized iterator.
Fix this by shifting the error handling responsibility to the callers.
--- drivers/nvme/target/tcp.c | 51 ++++++++++++++++++++++----------------- 1 file changed, 29 insertions(+), 22 deletions(-)
drivers/nvme/target/tcp.c +29 -22
@@ -359,7 +359,7 @@ static void nvmet_tcp_free_cmd_buffers(struct nvmet_tcp_cmd *cmd)static void nvmet_tcp_fatal_error (struct nvmet_tcp_queue *queue); -static void nvmet_tcp_build_pdu_iovec (struct nvmet_tcp_cmd *cmd) +static int nvmet_tcp_build_pdu_iovec (struct nvmet_tcp_cmd *cmd) {struct bio_vec *iov = cmd->iov;struct scatterlist *sg;
@@ -372,22 +372,19 @@ static void nvmet_tcp_build_pdu_iovec(struct nvmet_tcp_cmd *cmd) offset = cmd->rbytes_done; cmd->sg_idx = offset /PAGE_SIZE ; sg_offset = offset %PAGE_SIZE ; -if (!cmd->req.sg_cnt || cmd->sg_idx >= cmd->req.sg_cnt) { -nvmet_tcp_fatal_error (cmd->queue); -return ; - } +if (!cmd->req.sg_cnt || cmd->sg_idx >= cmd->req.sg_cnt) +return -EPROTO ; + sg = &cmd->req.sg[cmd->sg_idx]; sg_remaining = cmd->req.sg_cnt - cmd->sg_idx;while (length) { -if (!sg_remaining) { -nvmet_tcp_fatal_error (cmd->queue); -return ; - } -if (!sg->length || sg->length <= sg_offset) { -nvmet_tcp_fatal_error (cmd->queue); -return ; - } +if (!sg_remaining) +return -EPROTO ; + +if (!sg->length || sg->length <= sg_offset) +return -EPROTO ; +u32 iov_len =min_t (u32, length, sg->length - sg_offset); bvec_set_page(iov, sg_page(sg), iov_len,
@@ -402,6 +399,7 @@ static void nvmet_tcp_build_pdu_iovec(struct nvmet_tcp_cmd *cmd)iov_iter_bvec (&cmd->recv_msg.msg_iter,ITER_DEST , cmd->iov, nr_pages, cmd->pdu_len); +return 0 ; }static void nvmet_tcp_fatal_error (struct nvmet_tcp_queue *queue)
@@ -997,7 +995,7 @@ static int nvmet_tcp_handle_icreq(struct nvmet_tcp_queue *queue)return 0 ; } -static void nvmet_tcp_handle_req_failure (struct nvmet_tcp_queue *queue, +static int nvmet_tcp_handle_req_failure (struct nvmet_tcp_queue *queue,struct nvmet_tcp_cmd *cmd,struct nvmet_req *req) {size_t data_len =le32_to_cpu (req->cmd->common.dptr.sgl.length);
@@ -1013,19 +1011,23 @@ static void nvmet_tcp_handle_req_failure(struct nvmet_tcp_queue *queue,if (!nvme_is_write (cmd->req.cmd) || !data_len || data_len > cmd->req.port->inline_data_size) {nvmet_prepare_receive_pdu (queue); -return ; +return 0 ; } ret =nvmet_tcp_map_data (cmd);if (unlikely (ret)) {pr_err ("queue %d: failed to map data\n" , queue->idx);nvmet_tcp_fatal_error (queue); -return ; +return -EPROTO ; } queue->rcv_state =NVMET_TCP_RECV_DATA ; -nvmet_tcp_build_pdu_iovec (cmd); cmd->flags |=NVMET_TCP_F_INIT_FAILED ; + ret =nvmet_tcp_build_pdu_iovec (cmd); +if (unlikely (ret)) +pr_err ("queue %d: failed to build PDU iovec\n" , queue->idx); + +return ret; }static int nvmet_tcp_handle_h2c_data_pdu (struct nvmet_tcp_queue *queue)
@@ -1077,7 +1079,10 @@ static int nvmet_tcp_handle_h2c_data_pdu(struct nvmet_tcp_queue *queue) goto err_proto; } cmd->pdu_recv =0 ; -nvmet_tcp_build_pdu_iovec (cmd); +if (unlikely (nvmet_tcp_build_pdu_iovec (cmd))) { +pr_err ("queue %d: failed to build PDU iovec\n" , queue->idx); + goto err_proto; + } queue->cmd = cmd; queue->rcv_state =NVMET_TCP_RECV_DATA ;
@@ -1140,8 +1145,7 @@ static int nvmet_tcp_done_recv_pdu(struct nvmet_tcp_queue *queue) req->cmd->common.opcode, le32_to_cpu(req->cmd->common.dptr.sgl.length)); -nvmet_tcp_handle_req_failure (queue, queue->cmd, req); -return 0 ; +return nvmet_tcp_handle_req_failure (queue, queue->cmd, req); } ret =nvmet_tcp_map_data (queue->cmd);
@@ -1158,8 +1162,11 @@ static int nvmet_tcp_done_recv_pdu(struct nvmet_tcp_queue *queue)if (nvmet_tcp_need_data_in (queue->cmd)) {if (nvmet_tcp_has_inline_data (queue->cmd)) { queue->rcv_state =NVMET_TCP_RECV_DATA ; -nvmet_tcp_build_pdu_iovec (queue->cmd); -return 0 ; + ret =nvmet_tcp_build_pdu_iovec (queue->cmd); +if (unlikely (ret)) +pr_err ("queue %d: failed to build PDU iovec\n" , + queue->idx); +return ret; }/* send back R2T */ nvmet_tcp_queue_response (&queue->cmd->req);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 516/666 netfilter: arp_tables: fix IEEE1394 ARP payload parsing
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pablo Neira Ayuso <[email protected]>
[ Upstream commit 1e8e3f449b1e73b73a843257635b9c50f0cc0f0a ]
Weiming Shi says:
"arp_packet_match() unconditionally parses the ARP payload assuming two hardware addresses are present (source and target). However, IPv4-over-IEEE1394 ARP (RFC 2734) omits the target hardware address field, and arp_hdr_len() already accounts for this by returning a shorter length for ARPHRD_IEEE1394 devices.
As a result, on IEEE1394 interfaces arp_packet_match() advances past a nonexistent target hardware address and reads the wrong bytes for both the target device address comparison and the target IP address. This causes arptables rules to match against garbage data, leading to incorrect filtering decisions: packets that should be accepted may be dropped and vice versa.
The ARP stack in net/ipv4/arp.c (arp_create and arp_process) already handles this correctly by skipping the target hardware address for ARPHRD_IEEE1394. Apply the same pattern to arp_packet_match()."
Mangle the original patch to always return 0 (no match) in case user matches on the target hardware address which is never present in IEEE1394.
Note that this returns 0 (no match) for either normal and inverse match because matching in the target hardware address in ARPHRD_IEEE1394 has never been supported by arptables. This is intentional, matching on the target hardware address should never evaluate true for ARPHRD_IEEE1394.
Moreover, adjust arpt_mangle to drop the packet too as AI suggests:
In arpt_mangle, the logic assumes a standard ARP layout. Because IEEE1394 (FireWire) omits the target hardware address, the linear pointer arithmetic miscalculates the offset for the target IP address. This causes mangling operations to write to the wrong location, leading to packet corruption. To ensure safety, this patch drops packets (NF_DROP) when mangling is requested for these fields on IEEE1394 devices, as the current implementation cannot correctly map the FireWire ARP payload.
This omits both mangling target hardware and IP address. Even if IP address mangling should be possible in IEEE1394, this would require to adjust arpt_mangle offset calculation, which has never been supported.
Based on patch from Weiming Shi <[email protected]>.
--- net/ipv4/netfilter/arp_tables.c | 18 +++++++++++++++--- net/ipv4/netfilter/arpt_mangle.c | 8 ++++++++ 2 files changed, 23 insertions(+), 3 deletions(-)
net/ipv4/netfilter/arp_tables.c +15 -3
@@ -110,13 +110,25 @@ static inline int arp_packet_match(const struct arphdr *arphdr, arpptr += dev->addr_len;memcpy (&src_ipaddr, arpptr,sizeof (u32)); arpptr +=sizeof (u32); - tgt_devaddr = arpptr; - arpptr += dev->addr_len; + +if (IS_ENABLED (CONFIG_FIREWIRE_NET ) && dev->type ==ARPHRD_IEEE1394 ) { +if (unlikely (memchr_inv (arpinfo->tgt_devaddr.mask,0 , +sizeof (arpinfo->tgt_devaddr.mask)))) +return 0 ; + + tgt_devaddr =NULL ; + }else { + tgt_devaddr = arpptr; + arpptr += dev->addr_len; + }memcpy (&tgt_ipaddr, arpptr,sizeof (u32));if (NF_INVF (arpinfo,ARPT_INV_SRCDEVADDR ,arp_devaddr_compare (&arpinfo->src_devaddr, src_devaddr, - dev->addr_len)) || + dev->addr_len))) +return 0 ; + +if (tgt_devaddr &&NF_INVF (arpinfo,ARPT_INV_TGTDEVADDR ,arp_devaddr_compare (&arpinfo->tgt_devaddr, tgt_devaddr, dev->addr_len)))
net/ipv4/netfilter/arpt_mangle.c +8 -0
@@ -40,6 +40,10 @@ target(struct sk_buff *skb, const struct xt_action_param *par) } arpptr += pln;if (mangle->flags &ARPT_MANGLE_TDEV ) { +if (unlikely (IS_ENABLED (CONFIG_FIREWIRE_NET ) && + skb->dev->type ==ARPHRD_IEEE1394 )) +return NF_DROP ; +if (ARPT_DEV_ADDR_LEN_MAX < hln || (arpptr + hln >skb_tail_pointer (skb)))return NF_DROP ;
@@ -47,6 +51,10 @@ target(struct sk_buff *skb, const struct xt_action_param *par) } arpptr += hln;if (mangle->flags &ARPT_MANGLE_TIP ) { +if (unlikely (IS_ENABLED (CONFIG_FIREWIRE_NET ) && + skb->dev->type ==ARPHRD_IEEE1394 )) +return NF_DROP ; +if (ARPT_MANGLE_ADDR_LEN_MAX < pln || (arpptr + pln >skb_tail_pointer (skb)))return NF_DROP ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 517/666 nvme-pci: fix missed admin queue sq doorbell write
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Keith Busch <[email protected]>
[ Upstream commit 1cc4cdae2a3b7730d462d69e30f213fd2efe7807 ]
We can batch admin commands submitted through io_uring_cmd passthrough, which means bd->last may be false and skips the doorbell write to aggregate multiple commands per write. If a subsequent command can't be dispatched for whatever reason, we have to provide the blk-mq ops' commit_rqs callback in order to ensure we properly update the doorbell.
--- drivers/nvme/host/pci.c | 1 + 1 file changed, 1 insertion(+)
drivers/nvme/host/pci.c +1 -0
@@ -1816,6 +1816,7 @@ static int nvme_create_queue(struct nvme_queue *nvmeq, int qid, bool polled)static const struct blk_mq_ops nvme_mq_admin_ops = { .queue_rq = nvme_queue_rq, .complete = nvme_pci_complete_rq, + .commit_rqs = nvme_commit_rqs, .init_hctx = nvme_admin_init_hctx, .init_request = nvme_pci_init_request, .timeout = nvme_timeout,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 518/666 drm/amdgpu/gmc: Fix AMDGPU_GART_PLACEMENT_LOW to not overlap with VRAM
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Timur Kristóf <[email protected]>
[ Upstream commit 36d65da7570bf72ce28504fa9a81abfc728e6d96 ]
When the GART placement is set to AMDGPU_GART_PLACEMENT_LOW:
Make sure that GART does not overlap with VRAM when VRAM is configured to be in the low address space.
Solve this according to the following logic:
- When GART fits before VRAM, use zero address for GART
- Otherwise, put GART after the end of VRAM, aligned to 4 GiB
Previously, I had assumed this was not possible so it was OK to not handle it, but now we got a report from a user who has a board that is configured this way.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c +4 -1
@@ -297,7 +297,10 @@ void amdgpu_gmc_gart_location(struct amdgpu_device *adev, struct amdgpu_gmc *mc, mc->gart_start = max_mc_address - mc->gart_size +1 ;break ;case AMDGPU_GART_PLACEMENT_LOW : - mc->gart_start =0 ; +if (size_bf >= mc->gart_size) + mc->gart_start =0 ; +else + mc->gart_start =ALIGN (mc->fb_end, four_gb);break ;case AMDGPU_GART_PLACEMENT_BEST_FIT :default :
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 519/666 drm/amdgpu: fix AMDGPU_INFO_READ_MMR_REG
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian König <[email protected]>
[ Upstream commit 0ef196a208385b7d7da79f411c161b04e97283e2 ]
There were multiple issues in that code.
First of all the order between the reset semaphore and the mm_lock was wrong (e.g. copy_to_user) was called while holding the lock.
Then we allocated memory while holding the reset semaphore which is also a pretty big bug and can deadlock.
Then we used down_read_trylock() instead of waiting for the reset to finish.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c | 57 +++++++++++-------------- 1 file changed, 24 insertions(+), 33 deletions(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_kms.c +24 -33
@@ -786,68 +786,59 @@ int amdgpu_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) ? -EFAULT :0 ; }case AMDGPU_INFO_READ_MMR_REG : { -int ret =0 ; -unsigned int n, alloc_size; -uint32_t *regs;unsigned int se_num = (info->read_mmr_reg.instance >>AMDGPU_INFO_MMR_SE_INDEX_SHIFT ) &AMDGPU_INFO_MMR_SE_INDEX_MASK ;unsigned int sh_num = (info->read_mmr_reg.instance >>AMDGPU_INFO_MMR_SH_INDEX_SHIFT ) &AMDGPU_INFO_MMR_SH_INDEX_MASK ; - -if (!down_read_trylock (&adev->reset_domain->sem)) -return -ENOENT ; +unsigned int alloc_size; +uint32_t *regs; +int ret;/* set full masks if the userspace set all bits * in the bitfields */ -if (se_num ==AMDGPU_INFO_MMR_SE_INDEX_MASK ) { +if (se_num ==AMDGPU_INFO_MMR_SE_INDEX_MASK ) se_num =0xffffffff ; - }else if (se_num >=AMDGPU_GFX_MAX_SE ) { - ret = -EINVAL ; - goto out; - } +else if (se_num >=AMDGPU_GFX_MAX_SE ) +return -EINVAL ; -if (sh_num ==AMDGPU_INFO_MMR_SH_INDEX_MASK ) { +if (sh_num ==AMDGPU_INFO_MMR_SH_INDEX_MASK ) sh_num =0xffffffff ; - }else if (sh_num >=AMDGPU_GFX_MAX_SH_PER_SE ) { - ret = -EINVAL ; - goto out; - } +else if (sh_num >=AMDGPU_GFX_MAX_SH_PER_SE ) +return -EINVAL ; -if (info->read_mmr_reg.count >128 ) { - ret = -EINVAL ; - goto out; - } +if (info->read_mmr_reg.count >128 ) +return -EINVAL ; - regs =kmalloc_array (info->read_mmr_reg.count,sizeof (*regs),GFP_KERNEL ); -if (!regs) { - ret = -ENOMEM ; - goto out; - } + regs =kmalloc_array (info->read_mmr_reg.count,sizeof (*regs), +GFP_KERNEL ); +if (!regs) +return -ENOMEM ; +down_read (&adev->reset_domain->sem); alloc_size = info->read_mmr_reg.count *sizeof (*regs); -amdgpu_gfx_off_ctrl (adev, false); + ret =0 ;for (i =0 ; i < info->read_mmr_reg.count; i++) {if (amdgpu_asic_read_register (adev, se_num, sh_num, info->read_mmr_reg.dword_offset + i, ®s[i])) {DRM_DEBUG_KMS ("unallowed offset %#x\n" , info->read_mmr_reg.dword_offset + i); -kfree (regs); -amdgpu_gfx_off_ctrl (adev, true); ret = -EFAULT ; - goto out; +break ; } }amdgpu_gfx_off_ctrl (adev, true); - n =copy_to_user (out, regs,min (size, alloc_size)); -kfree (regs); - ret = (n ? -EFAULT :0 ); -out:up_read (&adev->reset_domain->sem); + +if (!ret) { + ret =copy_to_user (out, regs,min (size, alloc_size)) + ? -EFAULT :0 ; + } +kfree (regs);return ret; }case AMDGPU_INFO_DEV_INFO : {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 520/666 drm/amdgpu: fix spelling typos
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alexandre Demers <[email protected]>
[ Upstream commit ce43abd7ec9464cf954f90e1c69e11768b02fa0a ]
Found some typos while exploring amdgpu code.
Stable-dep-of: 13e4cf116dbf ("drm/amdgpu/uvd3.1: Don't validate the firmware when already validated")
--- drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c | 2 +- drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c | 6 +++--- drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c | 3 ++- drivers/gpu/drm/amd/amdgpu/vce_v2_0.c | 2 +- 4 files changed, 7 insertions(+), 6 deletions(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c +1 -1
@@ -269,7 +269,7 @@ void amdgpu_gmc_sysvm_location(struct amdgpu_device *adev, struct amdgpu_gmc *mc* @mc: memory controller structure holding memory information * @gart_placement: GART placement policy with respect to VRAM * -* Function will place try to place GART before or after VRAM. +* Function will try to place GART before or after VRAM. * If GART size is bigger than space left then we ajust GART size. * Thus function will never fails. */
drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c +3 -3
@@ -98,7 +98,7 @@ static void uvd_v3_1_ring_emit_ib(struct amdgpu_ring *ring, }/** -* uvd_v3_1_ring_emit_fence - emit an fence & trap command +* uvd_v3_1_ring_emit_fence - emit a fence & trap command * * @ring: amdgpu_ring pointer * @addr: address
@@ -242,7 +242,7 @@ static void uvd_v3_1_mc_resume(struct amdgpu_device *adev)uint64_t addr;uint32_t size; -/* programm the VCPU memory controller bits 0-27 */ +/* program the VCPU memory controller bits 0-27 */ addr = (adev->uvd.inst->gpu_addr +AMDGPU_UVD_FIRMWARE_OFFSET ) >>3 ; size =AMDGPU_UVD_FIRMWARE_SIZE (adev) >>3 ;WREG32 (mmUVD_VCPU_CACHE_OFFSET0, addr);
@@ -416,7 +416,7 @@ static int uvd_v3_1_start(struct amdgpu_device *adev)/* Set the write pointer delay */ WREG32 (mmUVD_RBC_RB_WPTR_CNTL,0 ); -/* programm the 4GB memory segment for rptr and ring buffer */ +/* Program the 4GB memory segment for rptr and ring buffer */ WREG32 (mmUVD_LMI_EXT40_ADDR,upper_32_bits (ring->gpu_addr) | (0x7 <<16 ) | (0x1 <<31 ));
drivers/gpu/drm/amd/amdgpu/uvd_v4_2.c +2 -1
@@ -308,7 +308,7 @@ static int uvd_v4_2_start(struct amdgpu_device *adev)/* enable VCPU clock */ WREG32 (mmUVD_VCPU_CNTL,1 <<9 ); -/* disable interupt */ +/* disable interrupt */ WREG32_P (mmUVD_MASTINT_EN,0 , ~(1 <<1 ));#ifdef __BIG_ENDIAN
@@ -318,6 +318,7 @@ static int uvd_v4_2_start(struct amdgpu_device *adev)#endif WREG32 (mmUVD_LMI_SWAP_CNTL, lmi_swap_cntl);WREG32 (mmUVD_MP_SWAP_CNTL, mp_swap_cntl); +/* initialize UVD memory controller */ WREG32 (mmUVD_LMI_CTRL,0x203108 );
drivers/gpu/drm/amd/amdgpu/vce_v2_0.c +1 -1
@@ -278,7 +278,7 @@ static int vce_v2_0_stop(struct amdgpu_device *adev)int status;if (vce_v2_0_lmi_clean (adev)) { -DRM_INFO ("vce is not idle \n" ); +DRM_INFO ("VCE is not idle \n" );return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 521/666 drm/amdgpu/uvd3.1: Dont validate the firmware when already validated
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Timur Kristóf <[email protected]>
[ Upstream commit 13e4cf116dbf7a1fb8123a59bea2c098f30d3736 ]
UVD 3.1 firmware validation seems to always fail after attempting it when it had already been validated. (This works similarly with the VCE 1.0 as well.)
Don't attempt repeating the validation when it's already done.
This caused issues in situations when the system isn't able to suspend the GPU properly and so the GPU isn't actually powered down. Then amdgpu would fail when calling the IP block resume function.
--- drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
drivers/gpu/drm/amd/amdgpu/uvd_v3_1.c +10 -0
@@ -242,6 +242,10 @@ static void uvd_v3_1_mc_resume(struct amdgpu_device *adev)uint64_t addr;uint32_t size; +/* When the keyselect is already set, don't perturb it. */ +if (RREG32 (mmUVD_FW_START)) +return ; +/* program the VCPU memory controller bits 0-27 */ addr = (adev->uvd.inst->gpu_addr +AMDGPU_UVD_FIRMWARE_OFFSET ) >>3 ; size =AMDGPU_UVD_FIRMWARE_SIZE (adev) >>3 ;
@@ -284,6 +288,12 @@ static int uvd_v3_1_fw_validate(struct amdgpu_device *adev)int i;uint32_t keysel = adev->uvd.keyselect; +if (RREG32 (mmUVD_FW_START) &UVD_FW_STATUS__PASS_MASK ) { +dev_dbg (adev->dev,"UVD keyselect already set: 0x%x (on CPU: 0x%x)\n" , +RREG32 (mmUVD_FW_START), adev->uvd.keyselect); +return 0 ; + } +WREG32 (mmUVD_FW_START, keysel);for (i =0 ; i <10 ; ++i) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 522/666 drm/amdgpu/gfx6: Support harvested SI chips with disabled TCCs (v2)
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Timur Kristóf <[email protected]>
[ Upstream commit fe2b84f9228e2a0903221a4d0d8c350b018e9c0c ]
This commit fixes amdgpu to work on the Radeon HD 7870 XT which has never worked with the Linux open source drivers before.
Some boards have "harvested" chips, meaning that some parts of the chip are disabled and fused, and it's sold for cheaper and under a different marketing name.
On a harvested chip, any of the following can be disabled:
- CUs (Compute Units)
- RBs (Render Backend, aka. ROP)
- Memory channels (ie. the chip has a lower bandwidth)
- TCCs (ie. less L2 cache)
Handle chips with harvested TCCs by patching the registers that configure how TCCs are mapped.
If some TCCs are disabled, we need to make sure that the disabled TCCs are not used, and the remaining TCCs are used optimally.
TCP_CHAN_STEER_LO/HI control which TCC is used by TCP channels. TCP_ADDR_CONFIG.NUM_TCC_BANKS controls how many channels are used.
Note that the TCC configuration is highly relevant to performance. Suboptimal configuration (eg. CHAN_STEER=0) can significantly reduce gaming performance.
For optimal performance:
- Rely on the CHAN_STEER from the golden registers table, only skip disabled TCCs but keep the mapping order.
- Limit NUM_TCC_BANKS to number of active TCCs to avoid thrashing, which performs better than using the same TCC twice.
v2:
- Also consider CGTS_USER_TCC_DISABLE for disabled TCCs.
--- drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c | 66 +++++++++++++++++++++++++++ 1 file changed, 66 insertions(+)
drivers/gpu/drm/amd/amdgpu/gfx_v6_0.c +66 -0
@@ -1553,6 +1553,71 @@ static void gfx_v6_0_setup_spi(struct amdgpu_device *adev)mutex_unlock (&adev->grbm_idx_mutex); } +/** +* gfx_v6_0_setup_tcc() - setup which TCCs are used +* +* @adev: amdgpu_device pointer +* +* Verify whether the current GPU has any TCCs disabled, +* which can happen when the GPU is harvested and some +* memory channels are disabled, reducing the memory bus width. +* For example, on the Radeon HD 7870 XT (Tahiti LE). +* +* If some TCCs are disabled, we need to make sure that +* the disabled TCCs are not used, and the remaining TCCs +* are used optimally. +* +* TCP_CHAN_STEER_LO/HI control which TCC is used by TCP channels. +* TCP_ADDR_CONFIG.NUM_TCC_BANKS controls how many channels are used. +* +* For optimal performance: +* - Rely on the CHAN_STEER from the golden registers table, +* only skip disabled TCCs but keep the mapping order. +* - Limit NUM_TCC_BANKS to number of active TCCs to avoid thrashing, +* which performs better than using the same TCC twice. +*/ +static void gfx_v6_0_setup_tcc (struct amdgpu_device *adev) +{ +u32 i, tcc, tcp_addr_config, num_active_tcc =0 ; +u64 chan_steer, patched_chan_steer =0 ; +const u32 num_max_tcc = adev->gfx.config.max_texture_channel_caches; +const u32 dis_tcc_mask = +amdgpu_gfx_create_bitmask (num_max_tcc) & + (REG_GET_FIELD (RREG32 (mmCGTS_TCC_DISABLE), +CGTS_TCC_DISABLE ,TCC_DISABLE ) | +REG_GET_FIELD (RREG32 (mmCGTS_USER_TCC_DISABLE), +CGTS_USER_TCC_DISABLE ,TCC_DISABLE )); + +/* When no TCC is disabled, the golden registers table already has optimal TCC setup */ +if (!dis_tcc_mask) +return ; + +/* Each 4-bit nibble contains the index of a TCC used by all TCPs */ + chan_steer =RREG32 (mmTCP_CHAN_STEER_LO) | ((u64 )RREG32 (mmTCP_CHAN_STEER_HI) <<32ull ); + +/* Patch the TCP to TCC mapping to skip disabled TCCs */ +for (i =0 ; i < num_max_tcc; ++i) { + tcc = (chan_steer >> (u64)(4 * i)) &0xf ; + +if (!((1 << tcc) & dis_tcc_mask)) { +/* Copy enabled TCC indices to the patched register value. */ + patched_chan_steer |= (u64 )tcc << (u64)(4 * num_active_tcc); + ++num_active_tcc; + } + } + +WARN_ON (num_active_tcc != num_max_tcc -hweight32 (dis_tcc_mask)); + +/* Patch number of TCCs used by TCPs */ + tcp_addr_config =REG_SET_FIELD (RREG32 (mmTCP_ADDR_CONFIG), +TCP_ADDR_CONFIG ,NUM_TCC_BANKS , + num_active_tcc -1 ); + +WREG32 (mmTCP_ADDR_CONFIG, tcp_addr_config); +WREG32 (mmTCP_CHAN_STEER_HI,upper_32_bits (patched_chan_steer)); +WREG32 (mmTCP_CHAN_STEER_LO,lower_32_bits (patched_chan_steer)); +} +static void gfx_v6_0_config_init (struct amdgpu_device *adev) { adev->gfx.config.double_offchip_lds_buf =0 ;
@@ -1711,6 +1776,7 @@ static void gfx_v6_0_constants_init(struct amdgpu_device *adev)gfx_v6_0_tiling_mode_table_init (adev);gfx_v6_0_setup_rb (adev); +gfx_v6_0_setup_tcc (adev);gfx_v6_0_setup_spi (adev);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 523/666 netfilter: xt_policy: fix strict mode inbound policy matching
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jiexun Wang <[email protected]>
[ Upstream commit 4b2b4d7d4e203c92db8966b163edfacb1f0e1e29 ]
match_policy_in() walks sec_path entries from the last transform to the first one, but strict policy matching needs to consume info->pol[] in the same forward order as the rule layout.
Derive the strict-match policy position from the number of transforms already consumed so that multi-element inbound rules are matched consistently.
--- net/netfilter/xt_policy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/netfilter/xt_policy.c +1 -1
@@ -63,7 +63,7 @@ match_policy_in(const struct sk_buff *skb, const struct xt_policy_info *info,return 0 ;for (i = sp->len -1 ; i >=0 ; i--) { - pos = strict ? i - sp->len +1 :0 ; + pos = strict ? sp->len - i -1 :0 ;if (pos >= info->len)return 0 ; e = &info->pol[pos];
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 524/666 netfilter: nf_conntrack_sip: dont use simple_strtoul
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Florian Westphal <[email protected]>
[ Upstream commit 8cf6809cddcbe301aedfc6b51bcd4944d45795f6 ]
Replace unsafe port parsing in epaddr_len(), ct_sip_parse_header_uri(), and ct_sip_parse_request() with a new sip_parse_port() helper that validates each digit against the buffer limit, eliminating the use of simple_strtoul() which assumes NUL-terminated strings.
The previous code dereferenced pointers without bounds checks after sip_parse_addr() and relied on simple_strtoul() on non-NUL-terminated skb data. A port that reaches the buffer limit without a trailing character is also rejected as malformed.
Also get rid of all simple_strtoul() usage in conntrack, prefer a stricter version instead. There are intentional changes:
- Bail out if number is > UINT_MAX and indicate a failure, same for too long sequences.
While we do accept 05535 as port 5535, we will not accept e.g. 'sip:10.0.0.1:005060'. While its syntactically valid under RFC 3261, we should restrict this to not waste cycles when presented with malformed packets with 64k '0' characters.
- Force base 10 in ct_sip_parse_numerical_param(). This is used to fetch 'expire=' and 'rports='; both are expected to use base-10.
- In nf_nat_sip.c, only accept the parsed value if its within the 1k-64k range.
- epaddr_len now returns 0 if the port is invalid, as it already does for invalid ip addresses. This is intentional. nf_conntrack_sip performs lots of guesswork to find the right parts of the message to parse. Being stricter could break existing setups. Connection tracking helpers are designed to allow traffic to pass, not to block it.
Based on an earlier patch from Jenny Guanni Qu <[email protected]>.
--- net/netfilter/nf_conntrack_sip.c | 152 ++++++++++++++++++++++++------- net/netfilter/nf_nat_sip.c | 1 + 2 files changed, 119 insertions(+), 34 deletions(-)
net/netfilter/nf_conntrack_sip.c +118 -34
@@ -181,6 +181,57 @@ static int sip_parse_addr(const struct nf_conn *ct, const char *cp,return 1 ; } +/* Parse optional port number after IP address. +* Returns false on malformed input, true otherwise. +* If port is non-NULL, stores parsed port in network byte order. +* If no port is present, sets *port to default SIP port. +*/ +static bool sip_parse_port (const char *dptr,const char **endp, +const char *limit,__be16 *port) +{ +unsigned int p =0 ; +int len =0 ; + +if (dptr >= limit) +return false; + +if (*dptr !=':' ) { +if (port) + *port =htons (SIP_PORT ); +if (endp) + *endp = dptr; +return true; + } + + dptr++;/* skip ':' */ + +while (dptr < limit &&isdigit (*dptr)) { + p = p *10 + (*dptr -'0' ); + dptr++; + len++; +if (len >5 )/* max "65535" */ +return false; + } + +if (len ==0 ) +return false; + +/* reached limit while parsing port */ +if (dptr >= limit) +return false; + +if (p <1024 || p >65535 ) +return false; + +if (port) + *port =htons (p); + +if (endp) + *endp = dptr; + +return true; +} +/* skip ip address. returns its length. */ static int epaddr_len (const struct nf_conn *ct,const char *dptr,const char *limit,int *shift)
@@ -193,11 +244,8 @@ static int epaddr_len(const struct nf_conn *ct, const char *dptr,return 0 ; } -/* Port number */ -if (*dptr ==':' ) { - dptr++; - dptr +=digits_len (ct, dptr, limit, shift); - } +if (!sip_parse_port (dptr, &dptr, limit,NULL )) +return 0 ;return dptr - aux; }
@@ -228,6 +276,51 @@ static int skp_epaddr_len(const struct nf_conn *ct, const char *dptr,return epaddr_len (ct, dptr, limit, shift); } +/* simple_strtoul stops after first non-number character. +* But as we're not dealing with c-strings, we can't rely on +* hitting \r,\n,\0 etc. before moving past end of buffer. +* +* This is a variant of simple_strtoul, but doesn't require +* a c-string. +* +* If value exceeds UINT_MAX, 0 is returned. +*/ +static unsigned int sip_strtouint (const char *cp,unsigned int len,char **endp) +{ +const unsigned int max =sizeof ("4294967295" ); +unsigned int olen = len; +const char *s = cp; +u64 result =0 ; + +if (len > max) + len = max; + +while (olen >0 &&isdigit (*s)) { +unsigned int value; + +if (len ==0 ) + goto err; + + value = *s -'0' ; + result = result *10 + value; + +if (result >UINT_MAX ) + goto err; + s++; + len--; + olen--; + } + +if (endp) + *endp = (char *)s; + +return result; +err: +if (endp) + *endp = (char *)cp; +return 0 ; +} +/* Parse a SIP request line of the form: * * Request-Line = Method SP Request-URI SP SIP-Version CRLF
@@ -241,7 +334,6 @@ int ct_sip_parse_request(const struct nf_conn *ct, {const char *start = dptr, *limit = dptr + datalen, *end;unsigned int mlen; -unsigned int p;int shift =0 ;/* Skip method and following whitespace */
@@ -267,14 +359,8 @@ int ct_sip_parse_request(const struct nf_conn *ct,if (!sip_parse_addr (ct, dptr, &end, addr, limit, true))return -1 ; -if (end < limit && *end ==':' ) { - end++; - p =simple_strtoul (end, (char **)&end,10 ); -if (p <1024 || p >65535 ) -return -1 ; - *port =htons (p); - }else - *port =htons (SIP_PORT ); +if (!sip_parse_port (end, &end, limit, port)) +return -1 ;if (end == dptr)return 0 ;
@@ -509,7 +595,6 @@ int ct_sip_parse_header_uri(const struct nf_conn *ct, const char *dptr, union nf_inet_addr *addr, __be16 *port) { const char *c, *limit = dptr + datalen; -unsigned int p;int ret; ret = ct_sip_walk_headers(ct, dptr, dataoff ? *dataoff : 0, datalen,
@@ -520,14 +605,8 @@ int ct_sip_parse_header_uri(const struct nf_conn *ct, const char *dptr,if (!sip_parse_addr (ct, dptr + *matchoff, &c, addr, limit, true))return -1 ; -if (*c ==':' ) { - c++; - p =simple_strtoul (c, (char **)&c,10 ); -if (p <1024 || p >65535 ) -return -1 ; - *port =htons (p); - }else - *port =htons (SIP_PORT ); +if (!sip_parse_port (c, &c, limit, port)) +return -1 ;if (dataoff) *dataoff = c - dptr;
@@ -609,7 +688,7 @@ int ct_sip_parse_numerical_param(const struct nf_conn *ct, const char *dptr,return 0 ; start +=strlen (name); - *val =simple_strtoul (start, &end,0 ); + *val =sip_strtouint (start, limit - start, (char **)&end);if (start == end)return -1 ;if (matchoff && matchlen) {
@@ -1065,6 +1144,8 @@ static int process_sdp(struct sk_buff *skb, unsigned int protoff, mediaoff = sdpoff;for (i =0 ; i <ARRAY_SIZE (sdp_media_types); ) { +char *end; +if (ct_sip_get_sdp_header (ct, *dptr, mediaoff, *datalen,SDP_HDR_MEDIA ,SDP_HDR_UNSPEC , &mediaoff, &medialen) <=0 )
@@ -1080,8 +1161,8 @@ static int process_sdp(struct sk_buff *skb, unsigned int protoff, mediaoff += t->len; medialen -= t->len; - port =simple_strtoul (*dptr + mediaoff,NULL ,10 ); -if (port ==0 ) + port =sip_strtouint (*dptr + mediaoff, *datalen - mediaoff, (char **)&end); +if (port ==0 || *dptr + mediaoff == end)continue ;if (port <1024 || port >65535 ) {nf_ct_helper_log (skb, ct,"wrong port %u" , port);
@@ -1255,7 +1336,7 @@ static int process_register_request(struct sk_buff *skb, unsigned int protoff,*/ if (ct_sip_get_header (ct, *dptr,0 , *datalen,SIP_HDR_EXPIRES , &matchoff, &matchlen) >0 ) - expires =simple_strtoul (*dptr + matchoff,NULL ,10 ); + expires =sip_strtouint (*dptr + matchoff, *datalen - matchoff,NULL ); ret = ct_sip_parse_header_uri(ct, *dptr, NULL, *datalen, SIP_HDR_CONTACT, NULL,
@@ -1359,7 +1440,7 @@ static int process_register_response(struct sk_buff *skb, unsigned int protoff,if (ct_sip_get_header (ct, *dptr,0 , *datalen,SIP_HDR_EXPIRES , &matchoff, &matchlen) >0 ) - expires =simple_strtoul (*dptr + matchoff,NULL ,10 ); + expires =sip_strtouint (*dptr + matchoff, *datalen - matchoff,NULL );while (1 ) {unsigned int c_expires = expires;
@@ -1419,10 +1500,12 @@ static int process_sip_response(struct sk_buff *skb, unsigned int protoff,struct nf_conn *ct =nf_ct_get (skb, &ctinfo);unsigned int matchoff, matchlen, matchend;unsigned int code, cseq, i; +char *end;if (*datalen <strlen ("SIP/2.0 200" ))return NF_ACCEPT ; - code =simple_strtoul (*dptr +strlen ("SIP/2.0 " ),NULL ,10 ); + code =sip_strtouint (*dptr +strlen ("SIP/2.0 " ), + *datalen -strlen ("SIP/2.0 " ),NULL );if (!code) {nf_ct_helper_log (skb, ct,"cannot get code" );return NF_DROP ;
@@ -1433,8 +1516,8 @@ static int process_sip_response(struct sk_buff *skb, unsigned int protoff,nf_ct_helper_log (skb, ct,"cannot parse cseq" );return NF_DROP ; } - cseq =simple_strtoul (*dptr + matchoff,NULL ,10 ); -if (!cseq && *(*dptr + matchoff) !='0' ) { + cseq =sip_strtouint (*dptr + matchoff, *datalen - matchoff, (char **)&end); +if (*dptr + matchoff == end) {nf_ct_helper_log (skb, ct,"cannot get cseq" );return NF_DROP ; }
@@ -1483,6 +1566,7 @@ static int process_sip_request(struct sk_buff *skb, unsigned int protoff,for (i =0 ; i <ARRAY_SIZE (sip_handlers); i++) {const struct sip_handler *handler; +char *end; handler = &sip_handlers[i];if (handler->request ==NULL )
@@ -1499,8 +1583,8 @@ static int process_sip_request(struct sk_buff *skb, unsigned int protoff,nf_ct_helper_log (skb, ct,"cannot parse cseq" );return NF_DROP ; } - cseq =simple_strtoul (*dptr + matchoff,NULL ,10 ); -if (!cseq && *(*dptr + matchoff) !='0' ) { + cseq =sip_strtouint (*dptr + matchoff, *datalen - matchoff, (char **)&end); +if (*dptr + matchoff == end) {nf_ct_helper_log (skb, ct,"cannot get cseq" );return NF_DROP ; }
@@ -1576,7 +1660,7 @@ static int sip_help_tcp(struct sk_buff *skb, unsigned int protoff, &matchoff, &matchlen) <= 0)break ; - clen =simple_strtoul (dptr + matchoff, (char **)&end,10 ); + clen =sip_strtouint (dptr + matchoff, datalen - matchoff, (char **)&end);if (dptr + matchoff == end)break ;
net/netfilter/nf_nat_sip.c +1 -0
@@ -246,6 +246,7 @@ static unsigned int nf_nat_sip(struct sk_buff *skb, unsigned int protoff,if (ct_sip_parse_numerical_param (ct, *dptr, matchend, *datalen,"rport=" , &poff, &plen, &n) >0 && + n >=1024 && n <=65535 &&htons (n) == ct->tuplehash[dir].tuple.dst.u.udp.port &&htons (n) != ct->tuplehash[!dir].tuple.src.u.udp.port) {__be16 p = ct->tuplehash[!dir].tuple.src.u.udp.port;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 525/666 ASoC: amd: acp: Add DMI quirk for Valve Steam Deck OLED
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guilherme G. Piccoli <[email protected]>
[ Upstream commit b0f6f4ac7d5d04fe2adcdd63ed1cd1ad505b8958 ]
Commit 671dd2ffbd8b ("ASoC: amd: acp: Add new cpu dai and dailink creation for I2S BT instance") introduced a change that "broke" Steam Deck's audio probe, in the OLED
model, as observed in the following dmesg snippet:
[...]snd_sof_amd_vangogh 0000:04:00.5: Topology: ABI 3:26:0 Kernel ABI 3:23:1sof_mach nau8821-max: ASoC: physical link acp-bt-codec (id 2) not existsof_mach nau8821-max: ASoC: topology: could not load header: -22snd_sof_amd_vangogh 0000:04:00.5: tplg amd/sof-tplg/sof-vangogh-nau8821-max.tplg component load failed -22 snd_sof_amd_vangogh 0000:04:00.5: error: failed to load DSP topology -22 snd_sof_amd_vangogh 0000:04:00.5: ASoC error (-22): at snd_soc_component_probe() on 0000:04:00.5 sof_mach nau8821-max: ASoC: failed to instantiate card -22sof_mach nau8821-max: error -EINVAL: Failed to register card(sof-nau8821-max)sof_mach nau8821-max: probe with driver sof_mach failed with error -22
[...]
Notice the quotes in "broke": it's not really a bug in such commit, but instead a problem with a topology file from Steam Deck OLED. This was discussed to great extent in [1], and Cristian proposed a pretty simple and functional change that resolved the issue for the Deck's issue. That change, though, would break other devices, so it wasn't accepted upstream. And the proper suggested solution (fix the topology) was never implemented, so Valve's kernel (and anyone that wants to boot the mainline on Steam Deck OLED) is carrying that fix downstream.
So, we propose hereby a different approach: a DMI quirk, as many already present in the sound drivers, to address this issue solely on Steam Deck OLED, not breaking other devices and as a bonus, allowing simple patch up in case eventually the topology file gets fixed (we'd just need to check against any DMI info reflecting that or the topology/FW versions).
The motivation of such upstream quirk is related to users that want to test latest kernel trees on their devices and get no only non-working sound device, but seems some games (like Ori and the Blind Forest) can't properly work without a proper functional audio device. Example of such report can be seen at [2].
--- sound/soc/amd/acp/acp-legacy-mach.c | 2 +- sound/soc/amd/acp/acp-mach-common.c | 22 +++++++++++++++++++--- sound/soc/amd/acp/acp-mach.h | 4 ++++ sound/soc/amd/acp/acp-sof-mach.c | 2 +- 4 files changed, 25 insertions(+), 5 deletions(-)
sound/soc/amd/acp/acp-legacy-mach.c +1 -1
@@ -174,7 +174,7 @@ static int acp_asoc_probe(struct platform_device *pdev) acp_card_drvdata->platform = *((int *)dev->platform_data); dmi_id =dmi_first_match (acp_quirk_table); -if (dmi_id && dmi_id->driver_data) +if (dmi_id && dmi_id->driver_data == (void *)QUIRK_TDM_MODE_ENABLE ) acp_card_drvdata->tdm_mode = dmi_id->driver_data; ret =acp_legacy_dai_links_create (card);
sound/soc/amd/acp/acp-mach-common.c +19 -3
@@ -20,6 +20,7 @@#include <sound/soc.h> #include <linux/input.h> #include <linux/module.h> +#include <linux/dmi.h> #include "../../codecs/rt5682.h" #include "../../codecs/rt1019.h"
@@ -37,15 +38,21 @@#define NAU8821_FREQ_OUT 12288000#define MAX98388_CODEC_DAI "max98388-aif1" -#define TDM_MODE_ENABLE 1 -const struct dmi_system_id acp_quirk_table[] = { {/* Google skyrim proto-0 */ .matches = {DMI_EXACT_MATCH (DMI_PRODUCT_FAMILY ,"Google_Skyrim" ), }, - .driver_data = (void *)TDM_MODE_ENABLE , + .driver_data = (void *)QUIRK_TDM_MODE_ENABLE , + }, + { +/* Valve Steam Deck OLED */ + .matches = { +DMI_MATCH (DMI_SYS_VENDOR ,"Valve" ), +DMI_MATCH (DMI_PRODUCT_NAME ,"Galileo" ), + }, + .driver_data = (void *)QUIRK_REMAP_DMIC_BT , }, {} };
@@ -1385,6 +1392,7 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card)struct snd_soc_dai_link *links;struct device *dev = card->dev;struct acp_card_drvdata *drv_data = card->drvdata; +const struct dmi_system_id *dmi_id =dmi_first_match (acp_quirk_table);int i =0 , num_links =0 ;if (drv_data->hs_cpu_id)
@@ -1562,6 +1570,9 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card) links[i].codecs = &snd_soc_dummy_dlc; links[i].num_codecs =1 ; } + +if (dmi_id && dmi_id->driver_data == (void *)QUIRK_REMAP_DMIC_BT ) + links[i].id =DMIC_BE_ID ; i++; }
@@ -1577,6 +1588,11 @@ int acp_sofdsp_dai_links_create(struct snd_soc_card *card) links[i].dpcm_capture =1 ; links[i].nonatomic = true; links[i].no_pcm =1 ; + +if (dmi_id && dmi_id->driver_data == (void *)QUIRK_REMAP_DMIC_BT ) { + links[i].id =BT_BE_ID ; +dev_dbg (dev,"quirk REMAP_DMIC_BT enabled\n" ); + } } card->dai_link = links;
sound/soc/amd/acp/acp-mach.h +4 -0
@@ -24,6 +24,10 @@#define acp_get_drvdata (card) ((struct acp_card_drvdata *)(card)->drvdata) +/* List of DMI quirks - check acp-mach-common.c for usage. */ +#define QUIRK_TDM_MODE_ENABLE 1 +#define QUIRK_REMAP_DMIC_BT 2 +enum be_id {HEADSET_BE_ID =0 ,AMP_BE_ID ,
sound/soc/amd/acp/acp-sof-mach.c +1 -1
@@ -113,7 +113,7 @@ static int acp_sof_probe(struct platform_device *pdev) acp_card_drvdata = card->drvdata; dmi_id =dmi_first_match (acp_quirk_table); -if (dmi_id && dmi_id->driver_data) +if (dmi_id && dmi_id->driver_data == (void *)QUIRK_TDM_MODE_ENABLE ) acp_card_drvdata->tdm_mode = dmi_id->driver_data; ret =acp_sofdsp_dai_links_create (card);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 526/666 spi: rockchip: Read ISR, not IMR, to detect cs-inactive IRQ
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: John Madieu <[email protected]>
[ Upstream commit b4683a239a409d65f88052f5630c748a8ba070cd ]
rockchip_spi_isr() decides whether the current interrupt was the cs-inactive event by reading IMR:
if (rs->cs_inactive && readl_relaxed(rs->regs + ROCKCHIP_SPI_IMR) & INT_CS_INACTIVE) ctlr->target_abort(ctlr);
IMR is the interrupt mask register: it tells which sources are enabled, not which one fired. In the PIO path, rockchip_spi_prepare_irq() enables both INT_RF_FULL and INT_CS_INACTIVE in IMR when rs->cs_inactive is true:
if (rs->cs_inactive) writel_relaxed(INT_RF_FULL | INT_CS_INACTIVE, rs->regs + ROCKCHIP_SPI_IMR);
so the IMR check is always true once cs_inactive is enabled, and every PIO interrupt - including normal RF_FULL completions - is dispatched to ctlr->target_abort(), aborting the transfer. The bug is reachable on ROCKCHIP_SPI_VER2_TYPE2 in target mode with a DMA-capable controller when the transfer is short enough to fall back to PIO (rockchip_spi_can_dma() returns false below fifo_len).
Read ISR (which is RISR masked by IMR) so the check actually reflects which interrupt fired, and parenthesise the expression for clarity while at it.
--- drivers/spi/spi-rockchip.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/spi/spi-rockchip.c +2 -1
@@ -357,7 +357,8 @@ static irqreturn_t rockchip_spi_isr(int irq, void *dev_id)struct rockchip_spi *rs =spi_controller_get_devdata (ctlr);/* When int_cs_inactive comes, spi target abort */ -if (rs->cs_inactive &&readl_relaxed (rs->regs +ROCKCHIP_SPI_IMR ) &INT_CS_INACTIVE ) { +if (rs->cs_inactive && + (readl_relaxed (rs->regs +ROCKCHIP_SPI_ISR ) &INT_CS_INACTIVE )) { ctlr->target_abort (ctlr);writel_relaxed (0 , rs->regs +ROCKCHIP_SPI_IMR );writel_relaxed (0xffffffff , rs->regs +ROCKCHIP_SPI_ICR );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 527/666 drm/sysfb: ofdrm: fix PCI device reference leaks
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yuho Choi <[email protected]>
[ Upstream commit 4aa8110000b0d215deef8eed283565dd0c1def88 ]
display_get_pci_dev_of() gets a referenced PCI device via pci_get_device(). Drop that reference when pci_enable_device() fails and release it during the managed teardown path after pci_disable_device().
Without that, ofdrm leaks the pci_dev reference on both the error path and the normal cleanup path.
--- drivers/gpu/drm/tiny/ofdrm.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/gpu/drm/tiny/ofdrm.c +2 -0
@@ -350,6 +350,7 @@ static void ofdrm_pci_release(void *data)struct pci_dev *pcidev = data;pci_disable_device (pcidev); +pci_dev_put (pcidev); }static int ofdrm_device_init_pci (struct ofdrm_device *odev)
@@ -375,6 +376,7 @@ static int ofdrm_device_init_pci(struct ofdrm_device *odev)if (ret) {drm_err (dev,"pci_enable_device(%s) failed: %d\n" ,dev_name (&pcidev->dev), ret); +pci_dev_put (pcidev);return ret; } ret =devm_add_action_or_reset (&pdev->dev, ofdrm_pci_release, pcidev);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 528/666 arm64/scs: Fix potential sign extension issue of advance_loc4
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wentao Guan <[email protected]>
[ Upstream commit 4023b7424ecd5d38cc75b650d6c1bf630ef8cb40 ]
The expression (*opcode++ << 24) and exp * code_alignment_factor may overflow signed int and becomes negative.
Fix this by casting each byte to u64 before shifting. Also fix the misaligned break statement while we are here.
Example of the result can be seen here:
It maybe not a real problem, but could be a issue in future.
--- arch/arm64/kernel/pi/patch-scs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
arch/arm64/kernel/pi/patch-scs.c +2 -2
@@ -178,9 +178,9 @@ static int scs_handle_fde_frame(const struct eh_frame *frame, loc += *opcode++ * code_alignment_factor; loc += (*opcode++ <<8 ) * code_alignment_factor; loc += (*opcode++ <<16 ) * code_alignment_factor; - loc += (*opcode++ <<24 ) * code_alignment_factor; + loc += ((u64)*opcode++ <<24 ) * code_alignment_factor; size -=4 ; -break ; +break ;case DW_CFA_def_cfa:case DW_CFA_offset_extended:
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 529/666 cdrom, scsi: sr: propagate read-only status to block layer via set_disk_ro()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Daan De Meyer <[email protected]>
[ Upstream commit 0898a817621a2f0cddca8122d9b974003fe5036d ]
The cdrom core never calls set_disk_ro() for a registered device, so BLKROGET on a CD-ROM device always returns 0 (writable), even when the drive has no write capabilities and writes will inevitably fail. This causes problems for userspace that relies on BLKROGET to determine whether a block device is read-only. For example, systemd's loop device setup uses BLKROGET to decide whether to create a loop device with LO_FLAGS_READ_ONLY. Without the read-only flag, writes pass through the loop device to the CD-ROM and fail with I/O errors. systemd-fsck similarly checks BLKROGET to decide whether to run fsck in no-repair mode (-n).
The write-capability bits in cdi->mask come from two different sources:CDC_DVD_RAM and CDC_CD_RW are populated by the driver from the MODE SENSE capabilities page (page 0x2A) before register_cdrom() is called, while CDC_MRW_W and CDC_RAM require the MMC GET CONFIGURATION command and were only probed by cdrom_open_write() at device open time. This meant that any attempt to compute the writable state from the full mask at probe time was incorrect, because the GET CONFIGURATION bits were still unset (and cdi->mask is initialized such that capabilities are assumed present).
Fix this by factoring the GET CONFIGURATION probing out of cdrom_open_write() into a new exported helper, cdrom_probe_write_features(), and having sr call it from sr_probe() right after get_capabilities() has populated the MODE SENSE bits. register_cdrom() then calls set_disk_ro() based on the full write-capability mask (CDC_DVD_RAM | CDC_MRW_W | CDC_RAM | CDC_CD_RW) so the block layer reflects the drive's actual write support. The feature queries used (CDF_MRW and CDF_RWRT via GET CONFIGURATION with RT=00) report drive-level capabilities that are persistent across media, so a single probe before register_cdrom() is sufficient and the redundant probe at open time is dropped.
With set_disk_ro() now accurate, the long-vestigial cd->writeable flag in sr can go: get_capabilities() used to set cd->writeable based on the same four mask bits, but because CDC_MRW_W and CDC_RAM default to "capability present" in cdi->mask and aren't touched by MODE SENSE, the condition that gated cd->writeable was always true, making it unconditionally 1. Replace the corresponding gate in sr_init_command() with get_disk_ro(cd->disk), which turns a previously no-op check into a real one and also catches kernel-internal bio writers that bypass blkdev_write_iter()'s bdev_read_only() check.
The sd driver (SCSI disks) does not have this problem because it checks the MODE SENSE Write Protect bit and calls set_disk_ro() accordingly. The sr driver cannot use the same approach because the MMC specification does not define the WP bit in the MODE SENSE device-specific parameter byte for CD-ROM devices.
--- drivers/cdrom/cdrom.c | 73 ++++++++++++++++++++++++++++--------------- drivers/scsi/sr.c | 11 ++----- drivers/scsi/sr.h | 1 - include/linux/cdrom.h | 1 + 4 files changed, 51 insertions(+), 35 deletions(-)
drivers/cdrom/cdrom.c +48 -25
@@ -634,6 +634,16 @@ int register_cdrom(struct gendisk *disk, struct cdrom_device_info *cdi)WARN_ON (!cdo->generic_packet); +/* +* Propagate the drive's write support to the block layer so BLKROGET +* reflects actual write capability. Drivers that use GET CONFIGURATION +* features (CDC_MRW_W, CDC_RAM) must have called +* cdrom_probe_write_features() before register_cdrom() so the mask is +* complete here. +*/ +set_disk_ro (disk, !CDROM_CAN (CDC_DVD_RAM |CDC_MRW_W |CDC_RAM | +CDC_CD_RW )); +cd_dbg (CD_REG_UNREG ,"drive \"/dev/%s\" registered\n" , cdi->name);mutex_lock (&cdrom_mutex);list_add (&cdi->list, &cdrom_list);
@@ -748,6 +758,44 @@ static int cdrom_is_random_writable(struct cdrom_device_info *cdi, int *write)return 0 ; } +/* +* Probe write-related MMC features via GET CONFIGURATION and update +* cdi->mask accordingly. Drivers that populate cdi->mask from the MODE SENSE +* capabilities page (e.g. sr) should call this after those MODE SENSE bits +* have been set but before register_cdrom(), so that the full set of +* write-capability bits is known by the time register_cdrom() decides on the +* initial read-only state of the disk. +*/ +void cdrom_probe_write_features (struct cdrom_device_info *cdi) +{ +int mrw, mrw_write, ram_write; + + mrw =0 ; +if (!cdrom_is_mrw (cdi, &mrw_write)) + mrw =1 ; + +if (CDROM_CAN (CDC_MO_DRIVE )) + ram_write =1 ; +else + (void )cdrom_is_random_writable (cdi, &ram_write); + +if (mrw) + cdi->mask &= ~CDC_MRW ; +else + cdi->mask |=CDC_MRW ; + +if (mrw_write) + cdi->mask &= ~CDC_MRW_W ; +else + cdi->mask |=CDC_MRW_W ; + +if (ram_write) + cdi->mask &= ~CDC_RAM ; +else + cdi->mask |=CDC_RAM ; +} +EXPORT_SYMBOL (cdrom_probe_write_features); +static int cdrom_media_erasable (struct cdrom_device_info *cdi) {disc_information di;
@@ -900,33 +948,8 @@ static int cdrom_is_dvd_rw(struct cdrom_device_info *cdi)*/ static int cdrom_open_write (struct cdrom_device_info *cdi) { -int mrw, mrw_write, ram_write;int ret =1 ; - mrw =0 ; -if (!cdrom_is_mrw (cdi, &mrw_write)) - mrw =1 ; - -if (CDROM_CAN (CDC_MO_DRIVE )) - ram_write =1 ; -else - (void )cdrom_is_random_writable (cdi, &ram_write); - -if (mrw) - cdi->mask &= ~CDC_MRW ; -else - cdi->mask |=CDC_MRW ; - -if (mrw_write) - cdi->mask &= ~CDC_MRW_W ; -else - cdi->mask |=CDC_MRW_W ; - -if (ram_write) - cdi->mask &= ~CDC_RAM ; -else - cdi->mask |=CDC_RAM ; -if (CDROM_CAN (CDC_MRW_W )) ret =cdrom_mrw_open_write (cdi);else if (CDROM_CAN (CDC_DVD_RAM ))
drivers/scsi/sr.c +2 -9
@@ -395,7 +395,7 @@ static blk_status_t sr_init_command(struct scsi_cmnd *SCpnt)switch (req_op (rq)) {case REQ_OP_WRITE : -if (!cd->writeable) +if (get_disk_ro (cd->disk)) goto out; SCpnt->cmnd[0 ] =WRITE_10 ; cd->cdi.media_written =1 ;
@@ -681,6 +681,7 @@ static int sr_probe(struct device *dev) error = -ENOMEM ;if (get_capabilities (cd)) goto fail_minor; +cdrom_probe_write_features (&cd->cdi);sr_vendor_init (cd);set_capacity (disk, cd->capacity);
@@ -899,14 +900,6 @@ static int get_capabilities(struct scsi_cd *cd)/*else I don't think it can close its tray cd->cdi.mask |= CDC_CLOSE_TRAY; */ -/* -* if DVD-RAM, MRW-W or CD-RW, we are randomly writable -*/ -if ((cd->cdi.mask & (CDC_DVD_RAM |CDC_MRW_W |CDC_RAM |CDC_CD_RW )) != - (CDC_DVD_RAM |CDC_MRW_W |CDC_RAM |CDC_CD_RW )) { - cd->writeable =1 ; - } -kfree (buffer);return 0 ; }
drivers/scsi/sr.h +0 -1
@@ -35,7 +35,6 @@ typedef struct scsi_cd {struct scsi_device *device;unsigned int vendor;/* vendor code, see sr_vendor.c */ unsigned long ms_offset;/* for reading multisession-CD's */ - unsigned writeable : 1; unsigned use:1; /* is this device still supportable */ unsigned xa_flag:1; /* CD has XA sectors ? */ unsigned readcd_known:1; /* drive supports READ_CD (0xbe) */
include/linux/cdrom.h +1 -0
@@ -109,6 +109,7 @@ int cdrom_ioctl(struct cdrom_device_info *cdi, struct block_device *bdev,extern unsigned int cdrom_check_events (struct cdrom_device_info *cdi,unsigned int clearing); +extern void cdrom_probe_write_features (struct cdrom_device_info *cdi);extern int register_cdrom (struct gendisk *disk,struct cdrom_device_info *cdi);extern void unregister_cdrom (struct cdrom_device_info *cdi);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 530/666 netdevsim: zero initialize struct iphdr in dummy sk_buff
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nikola Z. Ivanov <[email protected]>
[ Upstream commit 35eaa6d8d6c2ee65e96f507add856e0eacf24591 ]
Syzbot reports a KMSAN uninit-value originating from nsim_dev_trap_skb_build, with the allocation also being performed in the same function.
Fix this by calling skb_put_zero instead of skb_put to guarantee zero initialization of the whole IP header.
--- drivers/net/netdevsim/dev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/netdevsim/dev.c +1 -1
@@ -758,7 +758,7 @@ static struct sk_buff *nsim_dev_trap_skb_build(void) skb->protocol =htons (ETH_P_IP );skb_set_network_header (skb, skb->len); - iph =skb_put (skb,sizeof (struct iphdr )); + iph =skb_put_zero (skb,sizeof (struct iphdr )); iph->protocol =IPPROTO_UDP ; iph->saddr =in_aton ("192.0.2.1" ); iph->daddr =in_aton ("198.51.100.1" );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 531/666 net/sched: netem: fix probability gaps in 4-state loss model
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stephen Hemminger <[email protected]>
[ Upstream commit 732b463449fd0ef90acd13cda68eab1c91adb00c ]
The 4-state Markov chain in loss_4state() has gaps at the boundaries between transition probability ranges. The comparisons use:
if (rnd < a4) else if (a4 < rnd && rnd < a1 + a4)
When rnd equals a boundary value exactly, neither branch matches and no state transition occurs. The redundant lower-bound check (a4 < rnd) is already implied by being in the else branch.
Remove the unnecessary lower-bound comparisons so the ranges are contiguous and every random value produces a transition, matching the GI (General and Intuitive) loss model specification.
This bug goes back to original implementation of this model.
--- net/sched/sch_netem.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
net/sched/sch_netem.c +4 -4
@@ -226,10 +226,10 @@ static bool loss_4state(struct netem_sched_data *q)if (rnd < clg->a4) { clg->state =LOST_IN_GAP_PERIOD ;return true; - }else if (clg->a4 < rnd && rnd < clg->a1 + clg->a4) { + }else if (rnd < clg->a1 + clg->a4) { clg->state =LOST_IN_BURST_PERIOD ;return true; - }else if (clg->a1 + clg->a4 < rnd) { + }else { clg->state =TX_IN_GAP_PERIOD ; }
@@ -246,9 +246,9 @@ static bool loss_4state(struct netem_sched_data *q)case LOST_IN_BURST_PERIOD :if (rnd < clg->a3) clg->state =TX_IN_BURST_PERIOD ; -else if (clg->a3 < rnd && rnd < clg->a2 + clg->a3) { +else if (rnd < clg->a2 + clg->a3) { clg->state =TX_IN_GAP_PERIOD ; - }else if (clg->a2 + clg->a3 < rnd) { + }else { clg->state =LOST_IN_BURST_PERIOD ;return true; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 532/666 net/sched: netem: fix queue limit check to include reordered packets
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stephen Hemminger <[email protected]>
[ Upstream commit 4185701fcce6b426b6c3630b25330dddd9c47b0d ]
The queue limit check in netem_enqueue() uses q->t_len which only counts packets in the internal tfifo. Packets placed in sch->q by the reorder path (__qdisc_enqueue_head) are not counted, allowing the total queue occupancy to exceed sch->limit under reordering.
Include sch->q.qlen in the limit check.
--- net/sched/sch_netem.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/sched/sch_netem.c +1 -1
@@ -522,7 +522,7 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch,1 <<get_random_u32_below (8 ); } -if (unlikely (q->t_len >= sch->limit)) { +if (unlikely (sch->q.qlen >= sch->limit)) {/* re-link segs, so that qdisc_drop_all() frees them all */ skb->next = segs;qdisc_drop_all (skb, sch, to_free);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 533/666 net/sched: netem: only reseed PRNG when seed is explicitly provided
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stephen Hemminger <[email protected]>
[ Upstream commit 986afaf809940577224a99c3a08d97a15eb37e93 ]
netem_change() unconditionally reseeds the PRNG on every tc change command. If TCA_NETEM_PRNG_SEED is not specified, a new random seed is generated, destroying reproducibility for users who set a deterministic seed on a previous change.
Move the initial random seed generation to netem_init() and only reseed in netem_change() when TCA_NETEM_PRNG_SEED is explicitly provided by the user.
--- net/sched/sch_netem.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-)
net/sched/sch_netem.c +6 -4
@@ -1110,11 +1110,10 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt,/* capping jitter to the range acceptable by tabledist() */ q->jitter =min_t (s64,abs (q->jitter),INT_MAX ); -if (tb[TCA_NETEM_PRNG_SEED ]) +if (tb[TCA_NETEM_PRNG_SEED ]) { q->prng.seed =nla_get_u64 (tb[TCA_NETEM_PRNG_SEED ]); -else - q->prng.seed =get_random_u64 (); -prandom_seed_state (&q->prng.prng_state, q->prng.seed); +prandom_seed_state (&q->prng.prng_state, q->prng.seed); + } unlock:sch_tree_unlock (sch);
@@ -1137,6 +1136,9 @@ static int netem_init(struct Qdisc *sch, struct nlattr *opt,return -EINVAL ; q->loss_model =CLG_RANDOM ; + q->prng.seed =get_random_u64 (); +prandom_seed_state (&q->prng.prng_state, q->prng.seed); + ret =netem_change (sch, opt, extack);if (ret)pr_info ("netem: change failed\n" );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 534/666 net/sched: netem: validate slot configuration
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stephen Hemminger <[email protected]>
[ Upstream commit 01801c359a74737b9b1aa28568b60374d857241a ]
Reject slot configurations that have no defensible meaning:
- negative min_delay or max_delay
- min_delay greater than max_delay
- negative dist_delay or dist_jitter
- negative max_packets or max_bytes
Negative or out-of-order delays underflow in get_slot_next(), producing garbage intervals. Negative limits trip the per-slot accounting (packets_left/bytes_left <= 0) on the first packet of every slot, defeating the rate-limiting half of the slot feature.
Note that dist_jitter has been silently coerced to its absolute value by get_slot() since the feature was introduced; rejecting negatives here converts that silent coercion into -EINVAL. The abs() can be removed in a follow-up.
--- net/sched/sch_netem.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+)
net/sched/sch_netem.c +29 -0
@@ -825,6 +825,29 @@ static int get_dist_table(struct disttable **tbl, const struct nlattr *attr)return 0 ; } +static int validate_slot (const struct nlattr *attr,struct netlink_ext_ack *extack) +{ +const struct tc_netem_slot *c =nla_data (attr); + +if (c->min_delay <0 || c->max_delay <0 ) { +NL_SET_ERR_MSG_ATTR (extack, attr,"negative slot delay" ); +return -EINVAL ; + } +if (c->min_delay > c->max_delay) { +NL_SET_ERR_MSG_ATTR (extack, attr,"slot min delay greater than max delay" ); +return -EINVAL ; + } +if (c->dist_delay <0 || c->dist_jitter <0 ) { +NL_SET_ERR_MSG_ATTR (extack, attr,"negative dist delay" ); +return -EINVAL ; + } +if (c->max_packets <0 || c->max_bytes <0 ) { +NL_SET_ERR_MSG_ATTR (extack, attr,"negative slot limit" ); +return -EINVAL ; + } +return 0 ; +} +static void get_slot (struct netem_sched_data *q,const struct nlattr *attr) {const struct tc_netem_slot *c =nla_data (attr);
@@ -1038,6 +1061,12 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt, goto table_free; } +if (tb[TCA_NETEM_SLOT ]) { + ret =validate_slot (tb[TCA_NETEM_SLOT ], extack); +if (ret) + goto table_free; + } +sch_tree_lock (sch);/* backup q->clg and q->loss_model */ old_clg = q->clg;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 535/666 net/sched: netem: fix slot delay calculation overflow
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stephen Hemminger <[email protected]>
[ Upstream commit 51e94e1e2fef351c74d69eb53666df808d26af95 ]
get_slot_next() computes a random delay between min_delay and max_delay using:
get_random_u32() * (max_delay - min_delay) >> 32
This overflows signed 64-bit arithmetic when the delay range exceeds approximately 2.1 seconds (2^31 nanoseconds), producing a negative result that effectively disables slot-based pacing. This is a realistic configuration for WAN emulation (e.g., slot 1s 5s).
Use mul_u64_u32_shr() which handles the widening multiply without overflow.
--- net/sched/sch_netem.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
net/sched/sch_netem.c +2 -3
@@ -657,9 +657,8 @@ static void get_slot_next(struct netem_sched_data *q, u64 now)if (!q->slot_dist) next_delay = q->slot_config.min_delay + - (get_random_u32 () * - (q->slot_config.max_delay - - q->slot_config.min_delay) >>32 ); +mul_u64_u32_shr (q->slot_config.max_delay - q->slot_config.min_delay, +get_random_u32 (),32 );else next_delay = tabledist(q->slot_config.dist_delay, (s32)(q->slot_config.dist_jitter),
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 536/666 net/sched: netem: check for negative latency and jitter
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stephen Hemminger <[email protected]>
[ Upstream commit 90be9fedb218ee95a1cf59050d1306fbfb0e8b87 ]
Reject requests with negative latency or jitter.
A negative value added to current timestamp (u64) wraps
to an enormous time_to_send, disabling dequeue.
The original UAPI used u32 for these values; the conversion to 64-bit time values via TCA_NETEM_LATENCY64 and TCA_NETEM_JITTER64 allowed signed values to reach the kernel without validation.
Jitter is already silently clamped by an abs() in netem_change(); that abs() can be removed in a follow-up once this rejection is in place.
--- net/sched/sch_netem.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+)
net/sched/sch_netem.c +22 -0
@@ -824,6 +824,16 @@ static int get_dist_table(struct disttable **tbl, const struct nlattr *attr)return 0 ; } +static int validate_time (const struct nlattr *attr,const char *name, +struct netlink_ext_ack *extack) +{ +if (nla_get_s64 (attr) <0 ) { +NL_SET_ERR_MSG_ATTR_FMT (extack, attr,"negative %s" , name); +return -EINVAL ; + } +return 0 ; +} +static int validate_slot (const struct nlattr *attr,struct netlink_ext_ack *extack) {const struct tc_netem_slot *c =nla_data (attr);
@@ -1066,6 +1076,18 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt, goto table_free; } +if (tb[TCA_NETEM_LATENCY64 ]) { + ret =validate_time (tb[TCA_NETEM_LATENCY64 ],"latency" , extack); +if (ret) + goto table_free; + } + +if (tb[TCA_NETEM_JITTER64 ]) { + ret =validate_time (tb[TCA_NETEM_JITTER64 ],"jitter" , extack); +if (ret) + goto table_free; + } +sch_tree_lock (sch);/* backup q->clg and q->loss_model */ old_clg = q->clg;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 537/666 net/sched: sch_choke: annotate data-races in choke_dump_stats()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit d3aeb889dcbd78e95f500d383799a23d949796e0 ]
choke_dump_stats() only runs with RTNL held. It reads fields that can be changed in qdisc fast path. Add READ_ONCE()/WRITE_ONCE() annotations.
--- net/sched/sch_choke.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-)
net/sched/sch_choke.c +16 -10
@@ -229,7 +229,7 @@ static int choke_enqueue(struct sk_buff *skb, struct Qdisc *sch,/* Draw a packet at random from queue and compare flow */ if (choke_match_random (q, skb, &idx)) { - q->stats.matched++; +WRITE_ONCE (q->stats.matched, q->stats.matched +1 );choke_drop_by_idx (sch, idx, to_free); goto congestion_drop; }
@@ -241,11 +241,13 @@ static int choke_enqueue(struct sk_buff *skb, struct Qdisc *sch,qdisc_qstats_overlimit (sch);if (use_harddrop (q) || !use_ecn (q) || !INET_ECN_set_ce (skb)) { - q->stats.forced_drop++; +WRITE_ONCE (q->stats.forced_drop, + q->stats.forced_drop +1 ); goto congestion_drop; } - q->stats.forced_mark++; +WRITE_ONCE (q->stats.forced_mark, + q->stats.forced_mark +1 ); }else if (++q->vars.qcount) {if (red_mark_probability (p, &q->vars, q->vars.qavg)) { q->vars.qcount =0 ;
@@ -253,11 +255,13 @@ static int choke_enqueue(struct sk_buff *skb, struct Qdisc *sch,qdisc_qstats_overlimit (sch);if (!use_ecn (q) || !INET_ECN_set_ce (skb)) { - q->stats.prob_drop++; +WRITE_ONCE (q->stats.prob_drop, + q->stats.prob_drop +1 ); goto congestion_drop; } - q->stats.prob_mark++; +WRITE_ONCE (q->stats.prob_mark, + q->stats.prob_mark +1 ); } }else q->vars.qR =red_random (p);
@@ -272,7 +276,7 @@ static int choke_enqueue(struct sk_buff *skb, struct Qdisc *sch,return NET_XMIT_SUCCESS ; } - q->stats.pdrop++; +WRITE_ONCE (q->stats.pdrop, q->stats.pdrop +1 );return qdisc_drop (skb, sch, to_free); congestion_drop:
@@ -461,10 +465,12 @@ static int choke_dump_stats(struct Qdisc *sch, struct gnet_dump *d) {struct choke_sched_data *q =qdisc_priv (sch);struct tc_choke_xstats st = { - .early = q->stats.prob_drop + q->stats.forced_drop, - .marked = q->stats.prob_mark + q->stats.forced_mark, - .pdrop = q->stats.pdrop, - .matched = q->stats.matched, + .early =READ_ONCE (q->stats.prob_drop) + +READ_ONCE (q->stats.forced_drop), + .marked =READ_ONCE (q->stats.prob_mark) + +READ_ONCE (q->stats.forced_mark), + .pdrop =READ_ONCE (q->stats.pdrop), + .matched =READ_ONCE (q->stats.matched), };return gnet_stats_copy_app (d, &st,sizeof (st));
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 538/666 net/sched: sch_fq_pie: annotate data-races in fq_pie_dump_stats()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit 59b145771c7982cfe9020d4e9e22da92d6b5ae31 ]
fq_codel_dump_stats() acquires the qdisc spinlock a bit too late.
Move this acquisition before we fill tc_fq_pie_xstats with live data.
Alternative would be to add READ_ONCE() and WRITE_ONCE() annotations, but the spinlock is needed anyway to scan q->new_flows and q->old_flows.
--- net/sched/sch_fq_pie.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-)
net/sched/sch_fq_pie.c +10 -9
@@ -506,18 +506,19 @@ static int fq_pie_dump(struct Qdisc *sch, struct sk_buff *skb)static int fq_pie_dump_stats (struct Qdisc *sch,struct gnet_dump *d) {struct fq_pie_sched_data *q =qdisc_priv (sch); -struct tc_fq_pie_xstats st = { - .packets_in = q->stats.packets_in, - .overlimit = q->stats.overlimit, - .overmemory = q->overmemory, - .dropped = q->stats.dropped, - .ecn_mark = q->stats.ecn_mark, - .new_flow_count = q->new_flow_count, - .memory_usage = q->memory_usage, - }; +struct tc_fq_pie_xstats st = {0 };struct list_head *pos;sch_tree_lock (sch); + + st.packets_in = q->stats.packets_in; + st.overlimit = q->stats.overlimit; + st.overmemory = q->overmemory; + st.dropped = q->stats.dropped; + st.ecn_mark = q->stats.ecn_mark; + st.new_flow_count = q->new_flow_count; + st.memory_usage = q->memory_usage; +list_for_each (pos, &q->new_flows) st.new_flows_len++;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 539/666 vrf: Fix a potential NPD when removing a port from a VRF
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ido Schimmel <[email protected]>
[ Upstream commit 2674d603a9e6970463b2b9ebcf8e31e90beae169 ]
RCU readers that identified a net device as a VRF port using netif_is_l3_slave() assume that a subsequent call to netdev_master_upper_dev_get_rcu() will return a VRF device. They then continue to dereference its l3mdev operations.
This assumption is not always correct and can result in a NPD [1]. There is no RCU synchronization when removing a port from a VRF, so it is possible for an RCU reader to see a new master device (e.g., a bridge) that does not have l3mdev operations.
Fix by adding RCU synchronization after clearing the IFF_L3MDEV_SLAVE flag. Skip this synchronization when a net device is removed from a VRF as part of its deletion and when the VRF device itself is deleted. In the latter case an RCU grace period will pass by the time RTNL is released.
[1]
BUG: kernel NULL pointer dereference, address: 0000000000000000 [...] RIP: 0010:l3mdev_fib_table_rcu (net/l3mdev/l3mdev.c:181) [...] Call Trace: <TASK> l3mdev_fib_table_by_index (net/l3mdev/l3mdev.c:201 net/l3mdev/l3mdev.c:189) __inet_bind (net/ipv4/af_inet.c:499 (discriminator 3)) inet_bind_sk (net/ipv4/af_inet.c:469) __sys_bind (./include/linux/file.h:62 (discriminator 1) ./include/linux/file.h:83 (discriminator 1) net/socket.c:1951 (discriminator 1)) __x64_sys_bind (net/socket.c:1969 (discriminator 1) net/socket.c:1967 (discriminator 1) net/socket.c:1967 (discriminator 1)) do_syscall_64 (arch/x86/entry/syscall_64.c:63 (discriminator 1) arch/x86/entry/syscall_64.c:94 (discriminator 1))
entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:130)
--- drivers/net/vrf.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-)
drivers/net/vrf.c +11 -4
@@ -1104,6 +1104,7 @@ static int do_vrf_add_slave(struct net_device *dev, struct net_device *port_dev, err: port_dev->priv_flags &= ~IFF_L3MDEV_SLAVE ; +synchronize_net ();return ret; }
@@ -1123,10 +1124,16 @@ static int vrf_add_slave(struct net_device *dev, struct net_device *port_dev, }/* inverse of do_vrf_add_slave */ -static int do_vrf_del_slave (struct net_device *dev,struct net_device *port_dev) +static int do_vrf_del_slave (struct net_device *dev,struct net_device *port_dev, +bool needs_sync) {netdev_upper_dev_unlink (port_dev, dev); port_dev->priv_flags &= ~IFF_L3MDEV_SLAVE ; +/* Make sure that concurrent RCU readers that identified the device +* as a VRF port see a VRF master or no master at all. +*/ +if (needs_sync) +synchronize_net ();cycle_netdev (port_dev,NULL );
@@ -1135,7 +1142,7 @@ static int do_vrf_del_slave(struct net_device *dev, struct net_device *port_dev)static int vrf_del_slave (struct net_device *dev,struct net_device *port_dev) { -return do_vrf_del_slave (dev, port_dev); +return do_vrf_del_slave (dev, port_dev, true); }static void vrf_dev_uninit (struct net_device *dev)
@@ -1691,7 +1698,7 @@ static void vrf_dellink(struct net_device *dev, struct list_head *head)struct list_head *iter;netdev_for_each_lower_dev (dev, port_dev, iter) -vrf_del_slave (dev, port_dev); +do_vrf_del_slave (dev, port_dev, false);vrf_map_unregister_dev (dev);
@@ -1822,7 +1829,7 @@ static int vrf_device_event(struct notifier_block *unused, goto out; vrf_dev =netdev_master_upper_dev_get (dev); -vrf_del_slave (vrf_dev, dev); +do_vrf_del_slave (vrf_dev, dev, false); } out:return NOTIFY_DONE ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 540/666 net: usb: rtl8150: fix use-after-free in rtl8150_start_xmit()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhan Jun <[email protected]>
[ Upstream commit 23f0e34c64acba15cad4d23e50f41f533da195fa ]
syzbot reported a KASAN slab-use-after-free read in rtl8150_start_xmit() when accessing skb->len for tx statistics after usb_submit_urb() has been called:
BUG: KASAN: slab-use-after-free in rtl8150_start_xmit+0x71f/0x760
drivers/net/usb/rtl8150.c:712
Read of size 4 at addr ffff88810eb7a930 by task kworker/0:4/5226The URB completion handler write_bulk_callback() frees the skb via dev_kfree_skb_irq(dev->tx_skb). The URB may complete on another CPU in softirq context before usb_submit_urb() returns in the submitter, so by the time the submitter reads skb->len the skb has already been queued to the per-CPU completion_queue and freed by net_tx_action():
CPU A (xmit) CPU B (USB completion softirq)
------------ ------------------------------
dev->tx_skb = skb;
usb_submit_urb() --+
|-------> write_bulk_callback()
| dev_kfree_skb_irq(dev->tx_skb)
| net_tx_action()
| napi_skb_cache_put() <-- free
netdev->stats.tx_bytes |
+= skb->len; <-- UAF readFix it by caching skb->len before submitting the URB and using the cached value when updating the tx_bytes counter.
The pre-existing tx_bytes semantics are preserved: the counter tracks the original frame length (skb->len), not the ETH_ZLEN/USB-alignment padded "count" value that is handed to the device. Changing that would be a user-visible accounting change and is out of scope for this UAF fix.
--- drivers/net/usb/rtl8150.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/net/usb/rtl8150.c +4 -1
@@ -685,6 +685,7 @@ static netdev_tx_t rtl8150_start_xmit(struct sk_buff *skb, struct net_device *netdev) {rtl8150_t *dev =netdev_priv (netdev); +unsigned int skb_len;int count, res;/* pad the frame and ensure terminating USB packet, datasheet 9.2.3 */
@@ -696,6 +697,8 @@ static netdev_tx_t rtl8150_start_xmit(struct sk_buff *skb,return NETDEV_TX_OK ; } + skb_len = skb->len; +netif_stop_queue (netdev); dev->tx_skb = skb; usb_fill_bulk_urb(dev->tx_urb, dev->udev, usb_sndbulkpipe(dev->udev, 2),
@@ -711,7 +714,7 @@ static netdev_tx_t rtl8150_start_xmit(struct sk_buff *skb, } }else { netdev->stats.tx_packets++; - netdev->stats.tx_bytes += skb->len; + netdev->stats.tx_bytes += skb_len;netif_trans_update (netdev); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 541/666 net: usb: rtl8150: free skb on usb_submit_urb() failure in xmit
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Morduan Zang <[email protected]>
[ Upstream commit adbe2cdf75461891e50dbe11896ac78e9af1f874 ]
When rtl8150_start_xmit() fails to submit the tx URB, the URB is never handed to the USB core and write_bulk_callback() will not run. The driver returns NETDEV_TX_OK, which tells the networking stack that the skb has been consumed, but nothing actually frees the skb on this error path:
dev->tx_skb = skb;
...
if ((res = usb_submit_urb(dev->tx_urb, GFP_ATOMIC))) {
...
/* no kfree_skb here */
}
return NETDEV_TX_OK;This leaks the skb on every submit failure and also leaves dev->tx_skb pointing at memory that the driver itself may later free, which is fragile.
Free the skb with dev_kfree_skb_any() in the error path and clear dev->tx_skb so no stale pointer is left behind.
--- drivers/net/usb/rtl8150.c | 7 +++++++ 1 file changed, 7 insertions(+)
drivers/net/usb/rtl8150.c +7 -0
@@ -712,6 +712,13 @@ static netdev_tx_t rtl8150_start_xmit(struct sk_buff *skb, netdev->stats.tx_errors++;netif_start_queue (netdev); } +/* +* The URB was not submitted, so write_bulk_callback() will +* never run to free dev->tx_skb. Drop the skb here and +* clear tx_skb to avoid leaving a stale pointer. +*/ + dev->tx_skb =NULL ; +dev_kfree_skb_any (skb); }else { netdev->stats.tx_packets++; netdev->stats.tx_bytes += skb_len;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 542/666 NFC: trf7970a: Ignore antenna noise when checking for RF field
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Paul Geurts <[email protected]>
[ Upstream commit a9bc28aa4e64320668131349436a650bf42591a5 ]
The main channel Received Signal Strength Indicator (RSSI) measurement is used to determine whether an RF field is present or not. RSSI != 0 is interpreted as an RF Field is present. This does not take RF noise and measurement inaccuracy into account, and results in false positives in the field.
Define a noise level and make sure the RF field is only interpreted as present when the RSSI is above the noise level.
--- drivers/nfc/trf7970a.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/nfc/trf7970a.c +2 -1
@@ -311,6 +311,7 @@#define TRF7970A_RSSI_OSC_STATUS_RSSI_MASK (BIT(2) | BIT(1) | BIT(0))#define TRF7970A_RSSI_OSC_STATUS_RSSI_X_MASK (BIT(5) | BIT(4) | BIT(3))#define TRF7970A_RSSI_OSC_STATUS_RSSI_OSC_OK BIT(6) +#define TRF7970A_RSSI_OSC_STATUS_RSSI_NOISE_LEVEL 1#define TRF7970A_SPECIAL_FCN_REG1_COL_7_6 BIT(0)#define TRF7970A_SPECIAL_FCN_REG1_14_ANTICOLL BIT(1)
@@ -1253,7 +1254,7 @@ static int trf7970a_is_rf_field(struct trf7970a *trf, bool *is_rf_field)if (ret)return ret; -if (rssi &TRF7970A_RSSI_OSC_STATUS_RSSI_MASK ) +if ((rssi &TRF7970A_RSSI_OSC_STATUS_RSSI_MASK ) >TRF7970A_RSSI_OSC_STATUS_RSSI_NOISE_LEVEL ) *is_rf_field = true;else *is_rf_field = false;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 543/666 net/sched: taprio: fix NULL pointer dereference in class dump
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Weiming Shi <[email protected]>
[ Upstream commit 3d07ca5c0fae311226f737963984bd94bb159a87 ]
When a TAPRIO child qdisc is deleted via RTM_DELQDISC, taprio_graft() is called with new == NULL and stores NULL into q->qdiscs[cl - 1]. Subsequent RTM_GETTCLASS dump operations walk all classes via taprio_walk() and call taprio_dump_class(), which calls taprio_leaf() returning the NULL pointer, then dereferences it to read child->handle, causing a kernel NULL pointer dereference.
The bug is reachable with namespace-scoped CAP_NET_ADMIN on any kernel with CONFIG_NET_SCH_TAPRIO enabled. On systems with unprivileged user namespaces enabled, an unprivileged local user can trigger a kernel panic by creating a taprio qdisc inside a new network namespace, grafting an explicit child qdisc, deleting it, and requesting a class dump. The RTM_GETTCLASS dump itself requires no capability.
Oops: general protection fault, probably for non-canonical address 0xdffffc0000000007: 0000 [#1] SMP KASAN NOPTI KASAN: null-ptr-deref in range [0x0000000000000038-0x000000000000003f] RIP: 0010:taprio_dump_class (net/sched/sch_taprio.c:2478) Call Trace: <TASK> tc_fill_tclass (net/sched/sch_api.c:1966) qdisc_class_dump (net/sched/sch_api.c:2326) taprio_walk (net/sched/sch_taprio.c:2514) tc_dump_tclass_qdisc (net/sched/sch_api.c:2352) tc_dump_tclass_root (net/sched/sch_api.c:2370) tc_dump_tclass (net/sched/sch_api.c:2431) rtnl_dumpit (net/core/rtnetlink.c:6864) netlink_dump (net/netlink/af_netlink.c:2325) rtnetlink_rcv_msg (net/core/rtnetlink.c:6959) netlink_rcv_skb (net/netlink/af_netlink.c:2550) </TASK>
Fix this by substituting &noop_qdisc when new is NULL in taprio_graft(), a common pattern used by other qdiscs (e.g., multiq_graft()) to ensure the q->qdiscs[] slots are never NULL. This makes control-plane dump paths safe without requiring individual NULL checks.
Since the data-plane paths (taprio_enqueue and taprio_dequeue_from_txq) previously had explicit NULL guards that would drop/skip the packet cleanly, update those checks to test for &noop_qdisc instead. Without this, packets would reach taprio_enqueue_one() which increments the root qdisc's qlen and backlog before calling the child's enqueue; noop_qdisc drops the packet but those counters are never rolled back, permanently inflating the root qdisc's statistics.
After this change *old can be a valid qdisc, NULL, or &noop_qdisc. Only call qdisc_put(*old) in the first case to avoid decreasing noop_qdisc's refcount, which was never increased.
--- net/sched/sch_taprio.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-)
net/sched/sch_taprio.c +8 -5
@@ -633,7 +633,7 @@ static int taprio_enqueue(struct sk_buff *skb, struct Qdisc *sch, queue =skb_get_queue_mapping (skb); child = q->qdiscs[queue]; -if (unlikely (!child)) +if (unlikely (child == &noop_qdisc))return qdisc_drop (skb, sch, to_free);if (taprio_skb_exceeds_queue_max_sdu (sch, skb)) {
@@ -716,7 +716,7 @@ static struct sk_buff *taprio_dequeue_from_txq(struct Qdisc *sch, int txq,int len;u8 tc; -if (unlikely (!child)) +if (unlikely (child == &noop_qdisc))return NULL ;if (TXTIME_ASSIST_IS_ENABLED (q->flags))
@@ -2191,6 +2191,9 @@ static int taprio_graft(struct Qdisc *sch, unsigned long cl,if (!dev_queue)return -EINVAL ; +if (!new) + new = &noop_qdisc; +if (dev->flags &IFF_UP )dev_deactivate (dev);
@@ -2204,14 +2207,14 @@ static int taprio_graft(struct Qdisc *sch, unsigned long cl, *old = q->qdiscs[cl -1 ];if (FULL_OFFLOAD_IS_ENABLED (q->flags)) {WARN_ON_ONCE (dev_graft_qdisc (dev_queue, new) != *old); -if (new) +if (new != &noop_qdisc)qdisc_refcount_inc (new); -if (*old) +if (*old && *old != &noop_qdisc)qdisc_put (*old); } q->qdiscs[cl -1 ] = new; -if (new) +if (new != &noop_qdisc) new->flags |=TCQ_F_ONETXQUEUE |TCQ_F_NOPARENT ;if (dev->flags &IFF_UP )
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 544/666 neigh: let neigh_xmit take skb ownership
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Florian Westphal <[email protected]>
[ Upstream commit 4438113be604ee67a7bf4f81da6e1cca41332ce4 ]
neigh_xmit always releases the skb, except when no neighbour table is found. But even the first added user of neigh_xmit (mpls) relied on neigh_xmit to release the skb (or queue it for tx).
sashiko reported:
If neigh_xmit() is called with an uninitialized neighbor table (for example, NEIGH_ND_TABLE when IPv6 is disabled), it returns -EAFNOSUPPORT and bypasses its internal out_kfree_skb error path. Because the return value of neigh_xmit() is ignored here, does this leak the SKB?
Assume full ownership and remove the last code path that doesn't xmit or free skb.
--- net/core/neighbour.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
net/core/neighbour.c +5 -5
@@ -3161,8 +3161,10 @@ int neigh_xmit(int index, struct net_device *dev,rcu_read_lock (); tbl =rcu_dereference (neigh_tables[index]); -if (!tbl) - goto out_unlock; +if (!tbl) { +rcu_read_unlock (); + goto out_kfree_skb; + }if (index ==NEIGH_ARP_TABLE ) {u32 key = *((u32 *)addr);
@@ -3178,7 +3180,6 @@ int neigh_xmit(int index, struct net_device *dev, goto out_kfree_skb; } err =READ_ONCE (neigh->output)(neigh, skb); -out_unlock:rcu_read_unlock (); }else if (index ==NEIGH_LINK_TABLE ) {
@@ -3188,11 +3189,10 @@ int neigh_xmit(int index, struct net_device *dev, goto out_kfree_skb; err =dev_queue_xmit (skb); } -out:return err; out_kfree_skb:kfree_skb (skb); - goto out; +return err; }EXPORT_SYMBOL (neigh_xmit);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 545/666 tcp: make probe0 timer handle expired user timeout
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Altan Hacigumus <[email protected]>
[ Upstream commit 2b9f6f7065d4cfb65ba19126e0b35ac4544c3f3a ]
tcp_clamp_probe0_to_user_timeout() computes remaining time in jiffies using subtraction with an unsigned lvalue. If elapsed probing time exceeds the configured TCP_USER_TIMEOUT, the underflow yields a large value.
This ends up re-arming the probe timer for a full backoff interval instead of expiring immediately, delaying connection teardown beyond the configured timeout.
Fix this by preventing underflow so user-set timeout expiration is handled correctly without extending the probe timer.
--- net/ipv4/tcp_timer.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
net/ipv4/tcp_timer.c +3 -2
@@ -49,7 +49,8 @@ static u32 tcp_clamp_rto_to_user_timeout(const struct sock *sk)u32 tcp_clamp_probe0_to_user_timeout (const struct sock *sk,u32 when) {const struct inet_connection_sock *icsk =inet_csk (sk); -u32 remaining, user_timeout; +u32 user_timeout; +s32 remaining;s32 elapsed; user_timeout =READ_ONCE (icsk->icsk_user_timeout);
@@ -60,7 +61,7 @@ u32 tcp_clamp_probe0_to_user_timeout(const struct sock *sk, u32 when)if (unlikely (elapsed <0 )) elapsed =0 ; remaining =msecs_to_jiffies (user_timeout) - elapsed; - remaining =max_t (u32, remaining,TCP_TIMEOUT_MIN ); + remaining =max_t (int, remaining,TCP_TIMEOUT_MIN );return min_t (u32, remaining, when); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 546/666 net, treewide: define and use MAC_ADDR_STR_LEN
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Uday Shankar <[email protected]>
[ Upstream commit 6d6c1ba7824022528dbe3e283fafbd0775424128 ]
There are a few places in the tree which compute the length of the string representation of a MAC address as 3 * ETH_ALEN - 1. Define a constant for this and use it where relevant. No functionality changes are expected.
Stable-dep-of: 3bc179bc7146 ("netpoll: fix IPv6 local-address corruption")
--- drivers/net/netconsole.c | 2 +- drivers/nvmem/brcm_nvram.c | 2 +- drivers/nvmem/layouts/u-boot-env.c | 2 +- include/linux/if_ether.h | 3 +++ lib/net_utils.c | 4 +--- net/mac80211/debugfs_sta.c | 7 ++++--- 6 files changed, 11 insertions(+), 9 deletions(-)
drivers/net/netconsole.c +1 -1
@@ -652,7 +652,7 @@ static ssize_t remote_mac_store(struct config_item *item, const char *buf,if (!mac_pton (buf, remote_mac)) goto out_unlock; -if (buf[3 *ETH_ALEN -1 ] && buf[3 *ETH_ALEN -1 ] !='\n' ) +if (buf[MAC_ADDR_STR_LEN ] && buf[MAC_ADDR_STR_LEN ] !='\n' ) goto out_unlock;memcpy (nt->np.remote_mac, remote_mac,ETH_ALEN );
drivers/nvmem/brcm_nvram.c +1 -1
@@ -100,7 +100,7 @@ static int brcm_nvram_read_post_process_macaddr(void *context, const char *id, i {u8 mac[ETH_ALEN ]; -if (bytes !=3 *ETH_ALEN -1 ) +if (bytes !=MAC_ADDR_STR_LEN )return -EINVAL ;if (!mac_pton (buf, mac))
drivers/nvmem/layouts/u-boot-env.c +1 -1
@@ -37,7 +37,7 @@ static int u_boot_env_read_post_process_ethaddr(void *context, const char *id, i {u8 mac[ETH_ALEN ]; -if (bytes !=3 *ETH_ALEN -1 ) +if (bytes !=MAC_ADDR_STR_LEN )return -EINVAL ;if (!mac_pton (buf, mac))
include/linux/if_ether.h +3 -0
@@ -19,6 +19,9 @@#include <linux/skbuff.h> #include <uapi/linux/if_ether.h> +/* XX:XX:XX:XX:XX:XX */ +#define MAC_ADDR_STR_LEN (3 * ETH_ALEN - 1) +static inline struct ethhdr *eth_hdr (const struct sk_buff *skb) {return (struct ethhdr *)skb_mac_header (skb);
lib/net_utils.c +1 -3
@@ -7,11 +7,9 @@bool mac_pton (const char *s,u8 *mac) { -size_t maxlen =3 *ETH_ALEN -1 ;int i; -/* XX:XX:XX:XX:XX:XX */ -if (strnlen (s, maxlen) < maxlen) +if (strnlen (s,MAC_ADDR_STR_LEN ) <MAC_ADDR_STR_LEN )return false;/* Don't dirty result unless string is valid MAC. */
net/mac80211/debugfs_sta.c +4 -3
@@ -454,11 +454,12 @@ static ssize_t link_sta_addr_read(struct file *file, char __user *userbuf, size_t count, loff_t *ppos) { struct link_sta_info *link_sta = file->private_data; -u8 mac[3 *ETH_ALEN +1 ]; +u8 mac[MAC_ADDR_STR_LEN +2 ];snprintf (mac,sizeof (mac),"%pM\n" , link_sta->pub->addr); -return simple_read_from_buffer (userbuf, count, ppos, mac,3 *ETH_ALEN ); +return simple_read_from_buffer (userbuf, count, ppos, mac, +MAC_ADDR_STR_LEN +1 ); }LINK_STA_OPS (addr);
@@ -1237,7 +1238,7 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta)struct ieee80211_local *local = sta->local;struct ieee80211_sub_if_data *sdata = sta->sdata;struct dentry *stations_dir = sta->sdata->debugfs.subdir_stations; -u8 mac[3 *ETH_ALEN ]; +u8 mac[MAC_ADDR_STR_LEN +1 ];if (!stations_dir)return ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 547/666 netconsole: allow selection of egress interface via MAC address
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Uday Shankar <[email protected]>
[ Upstream commit f8a10bed32f5fbede13a5f22fdc4ab8740ea213a ]
Currently, netconsole has two methods of configuration - module parameter and configfs. The former interface allows for netconsole activation earlier during boot (by specifying the module parameter on the kernel command line), so it is preferred for debugging issues which arise before userspace is up/the configfs interface can be used. The module parameter syntax requires specifying the egress interface name. This requirement makes it hard to use for a couple reasons:
- The egress interface name can be hard or impossible to predict. For example, installing a new network card in a system can change the interface names assigned by the kernel.
- When constructing the module parameter, one may have trouble determining the original (kernel-assigned) name of the interface (which is the name that should be given to netconsole) if some stable interface naming scheme is in effect. A human can usually look at kernel logs to determine the original name, but this is very painful if automation is constructing the parameter.
For these reasons, allow selection of the egress interface via MAC address when configuring netconsole using the module parameter. Update the netconsole documentation with an example of the new syntax. Selection of egress interface by MAC address via configfs is far less interesting (since when this interface can be used, one should be able to easily convert between MAC address and interface name), so it is left unimplemented.
Stable-dep-of: 3bc179bc7146 ("netpoll: fix IPv6 local-address corruption")
--- Documentation/networking/netconsole.rst | 6 ++- include/linux/netpoll.h | 6 +++ net/core/netpoll.c | 51 +++++++++++++++++++------ 3 files changed, 50 insertions(+), 13 deletions(-)
Documentation/networking/netconsole.rst +5 -1
@@ -45,7 +45,7 @@ following format:: r if present, prepend kernel version (release) to the message src-port source for UDP packets (defaults to 6665) src-ip source IP to use (interface address) - dev network interface (eth0) + dev network interface name (eth0) or MAC address tgt-port port for logging agent (6666) tgt-ip IP address for logging agent tgt-macaddr ethernet MAC address for logging agent (broadcast)
@@ -62,6 +62,10 @@ or using IPv6:: insmod netconsole netconsole=@/,@fd00:1:2:3::1/ +or using a MAC address to select the egress interface:: + + linux [email protected]/22:33:44:55:66:77,[email protected]/12:34:56:78:9a:bc + It also supports logging to multiple remote agents by specifying parameters for the multiple agents separated by semicolons and the complete string enclosed in "quotes", thusly::
include/linux/netpoll.h +6 -0
@@ -25,7 +25,13 @@ union inet_addr {struct netpoll {struct net_device *dev;netdevice_tracker dev_tracker; +/* +* Either dev_name or dev_mac can be used to specify the local +* interface - dev_name is used if it is a nonempty string, else +* dev_mac is used. +*/ char dev_name[IFNAMSIZ ]; +u8 dev_mac[ETH_ALEN ];const char *name;union inet_addr local_ip, remote_ip;
net/core/netpoll.c +39 -12
111 lines not on this page · raw message
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 548/666 netpoll: Extract carrier wait function
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Breno Leitao <[email protected]>
[ Upstream commit 76d30b51e818064e02917ce6328fb2c8adce5c87 ]
Extract the carrier waiting logic into a dedicated helper function netpoll_wait_carrier() to improve code readability and reduce duplication in netpoll_setup().
Stable-dep-of: 3bc179bc7146 ("netpoll: fix IPv6 local-address corruption")
--- net/core/netpoll.c | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-)
net/core/netpoll.c +16 -12
@@ -706,6 +706,21 @@ static char *egress_dev(struct netpoll *np, char *buf)return buf; } +static void netpoll_wait_carrier (struct netpoll *np,struct net_device *ndev, +unsigned int timeout) +{ +unsigned long atmost; + + atmost = jiffies + timeout *HZ ; +while (!netif_carrier_ok (ndev)) { +if (time_after (jiffies, atmost)) { +np_notice (np,"timeout waiting for carrier\n" ); +break ; + } +msleep (1 ); + } +} +int netpoll_setup (struct netpoll *np) {struct net *net = current->nsproxy->net_ns;
@@ -736,28 +751,17 @@ int netpoll_setup(struct netpoll *np) }if (!netif_running (ndev)) { -unsigned long atmost; -np_info (np,"device %s not up yet, forcing it\n" ,egress_dev (np, buf)); err =dev_open (ndev,NULL ); -if (err) {np_err (np,"failed to open %s\n" , ndev->name); goto put; }rtnl_unlock (); - atmost = jiffies + carrier_timeout *HZ ; -while (!netif_carrier_ok (ndev)) { -if (time_after (jiffies, atmost)) { -np_notice (np,"timeout waiting for carrier\n" ); -break ; - } -msleep (1 ); - } - +netpoll_wait_carrier (np, ndev, carrier_timeout);rtnl_lock (); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 549/666 netpoll: extract IPv4 address retrieval into helper function
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Breno Leitao <[email protected]>
[ Upstream commit 3699f992e8c22d3ce54d2c1a5774e2c49028f99c ]
Move the IPv4 address retrieval logic from netpoll_setup() into a separate netpoll_take_ipv4() function to improve code organization and readability. This change consolidates the IPv4-specific logic and error handling into a dedicated function while maintaining the same functionality.
No functional changes.
Stable-dep-of: 3bc179bc7146 ("netpoll: fix IPv6 local-address corruption")
--- net/core/netpoll.c | 48 ++++++++++++++++++++++++++++++---------------- 1 file changed, 31 insertions(+), 17 deletions(-)
net/core/netpoll.c +31 -17
@@ -721,13 +721,41 @@ static void netpoll_wait_carrier(struct netpoll *np, struct net_device *ndev, } } +/* +* Take the IPv4 from ndev and populate local_ip structure in netpoll +*/ +static int netpoll_take_ipv4 (struct netpoll *np,struct net_device *ndev) +{ +char buf[MAC_ADDR_STR_LEN +1 ]; +const struct in_ifaddr *ifa; +struct in_device *in_dev; + + in_dev =__in_dev_get_rtnl (ndev); +if (!in_dev) { +np_err (np,"no IP address for %s, aborting\n" , +egress_dev (np, buf)); +return -EDESTADDRREQ ; + } + + ifa =rtnl_dereference (in_dev->ifa_list); +if (!ifa) { +np_err (np,"no IP address for %s, aborting\n" , +egress_dev (np, buf)); +return -EDESTADDRREQ ; + } + + np->local_ip.ip = ifa->ifa_local; +np_info (np,"local IP %pI4\n" , &np->local_ip.ip); + +return 0 ; +} +int netpoll_setup (struct netpoll *np) {struct net *net = current->nsproxy->net_ns;char buf[MAC_ADDR_STR_LEN +1 ];struct net_device *ndev =NULL ;bool ip_overwritten = false; -struct in_device *in_dev;int err;rtnl_lock ();
@@ -767,24 +795,10 @@ int netpoll_setup(struct netpoll *np)if (!np->local_ip.ip) {if (!np->ipv6) { -const struct in_ifaddr *ifa; - - in_dev =__in_dev_get_rtnl (ndev); -if (!in_dev) - goto put_noaddr; - - ifa =rtnl_dereference (in_dev->ifa_list); -if (!ifa) { -put_noaddr: -np_err (np,"no IP address for %s, aborting\n" , -egress_dev (np, buf)); - err = -EDESTADDRREQ ; + err =netpoll_take_ipv4 (np, ndev); +if (err) goto put; - } - - np->local_ip.ip = ifa->ifa_local; ip_overwritten = true; -np_info (np,"local IP %pI4\n" , &np->local_ip.ip); }else {#if IS_ENABLED (CONFIG_IPV6 )struct inet6_dev *idev;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 550/666 netpoll: fix IPv6 local-address corruption
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Breno Leitao <[email protected]>
[ Upstream commit 3bc179bc7146c26c9dff75d2943d10528274e301 ]
netpoll_setup() decides whether to auto-populate the local source address by testing np->local_ip.ip, which only inspects the first 4 bytes of the union inet_addr storage.
For an IPv6 netpoll whose caller-supplied local address has a zero high-32 bits (::1, ::<suffix>, IPv4-mapped ::ffff:a.b.c.d, etc.), this misdetects the address as unset (which they are not, but the first 4 bytes are empty), calls netpoll_take_ipv6() and overwrites it with whatever matching link-local/global address the device happens to expose first.
Introduce a helper netpoll_local_ip_unset() that picks the correct family-aware test (ipv6_addr_any() for IPv6, !.ip for IPv4) and use it from netpoll_setup().
Reproducer is something like:
echo "::2" > local_ip
echo 1 > enabled
cat local_ip
# before this fix: 2001:db8::1 (caller-supplied ::2 was clobbered) # after this fix: ::2
--- net/core/netpoll.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-)
net/core/netpoll.c +18 -1
@@ -750,6 +750,23 @@ static int netpoll_take_ipv4(struct netpoll *np, struct net_device *ndev)return 0 ; } +/* +* Test whether the caller left np->local_ip unset, so that +* netpoll_setup() should auto-populate it from the egress device. +* +* np->local_ip is a union of __be32 (IPv4) and struct in6_addr (IPv6), +* so an IPv6 address whose first 4 bytes are zero (e.g. ::1, ::2, +* IPv4-mapped ::ffff:a.b.c.d) must not be tested via the IPv4 arm — +* doing so would misclassify a caller-supplied address as unset and +* silently overwrite it with whatever address the device exposes. +*/ +static bool netpoll_local_ip_unset (const struct netpoll *np) +{ +if (np->ipv6) +return ipv6_addr_any (&np->local_ip.in6); +return !np->local_ip.ip; +} +int netpoll_setup (struct netpoll *np) {struct net *net = current->nsproxy->net_ns;
@@ -793,7 +810,7 @@ int netpoll_setup(struct netpoll *np)rtnl_lock (); } -if (!np->local_ip.ip) { +if (netpoll_local_ip_unset (np)) {if (!np->ipv6) { err =netpoll_take_ipv4 (np, ndev);if (err)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 551/666 ALSA: usb-audio: Fix potential leak of pd at parsing UAC3 streams
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Takashi Iwai <[email protected]>
[ Upstream commit c39f0bc03f84ba64c9144c95714df1dc36150f6d ]
At parsing UAC3 streams, we allocate a PD object at each time, and either assign or free it. But there is a case where the PD object may be leaked; namely, in __snd_usb_parse_audio_interface() loop, when an audioformat shares the same endpoint with others, it's put to a link and returns from snd_usb_add_audio_stream(), but the PD is forgotten afterwards. Overall, the treatment of PD object in the parser code is a bit flaky, and we should be more careful about the object ownership.
This patch tries to fix the above case and improve the code a bit. The pd object is now managed with the auto-cleanup in the loop, and the ownership is updated when the pd object gets assigned to the stream, which guarantees the release of the leftover object.
--- sound/usb/quirks.c | 2 +- sound/usb/stream.c | 58 ++++++++++++++++++---------------------------- sound/usb/stream.h | 3 ++- 3 files changed, 25 insertions(+), 38 deletions(-)
sound/usb/quirks.c +1 -1
@@ -122,7 +122,7 @@ static int add_audio_stream_from_fixed_fmt(struct snd_usb_audio *chip,snd_usb_audioformat_set_sync_ep (chip, fp); - err =snd_usb_add_audio_stream (chip, stream, fp); + err =snd_usb_add_audio_stream (chip, stream, fp,NULL );if (err <0 )return err;
sound/usb/stream.c +22 -36
129 lines not on this page · raw message
sound/usb/stream.h +2 -1
@@ -7,7 +7,8 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip,int snd_usb_add_audio_stream (struct snd_usb_audio *chip,int stream, -struct audioformat *fp); +struct audioformat *fp, +struct snd_usb_power_domain **pdptr);#endif /* __USBAUDIO_STREAM_H */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 552/666 sched/fair: Clear rel_deadline when initializing forked entities
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zicheng Qu <[email protected]>
[ Upstream commit 3da56dc063cd77b9c0b40add930767fab4e389f3 ]
A yield-triggered crash can happen when a newly forked sched_entity enters the fair class with se->rel_deadline unexpectedly set.
The failing sequence is:
1. A task is forked while se->rel_deadline is still set.
2. __sched_fork() initializes vruntime, vlag and other sched_entity state, but does not clear rel_deadline.
3. On the first enqueue, enqueue_entity() calls place_entity().
4. Because se->rel_deadline is set, place_entity() treats se->deadline as a relative deadline and converts it to an absolute deadline by adding the current vruntime.
5. However, the forked entity's deadline is not a valid inherited relative deadline for this new scheduling instance, so the conversion produces an abnormally large deadline.
6. If the task later calls sched_yield(), yield_task_fair() advances
se->vruntime to se->deadline.
7. The inflated vruntime is then used by the following enqueue path, where the vruntime-derived key can overflow when multiplied by the entity weight.
8. This corrupts cfs_rq->sum_w_vruntime, breaks EEVDF eligibility calculation, and can eventually make all entities appear ineligible. pick_next_entity() may then return NULL unexpectedly, leading to a later NULL dereference.
A captured trace shows the effect clearly. Before yield, the entity's vruntime was around:
9834017729983308
After yield_task_fair() executed:
se->vruntime = se->deadline
the vruntime jumped to:
19668035460670230
and the deadline was later advanced further to:
19668035463470230
This shows that the deadline had already become abnormally large before yield_task_fair() copied it into vruntime.
rel_deadline is only meaningful when se->deadline really carries a relative deadline that still needs to be placed against vruntime. A freshly forked sched_entity should not inherit or retain this state. Clear se->rel_deadline in __sched_fork(), together with the other sched_entity runtime state, so that the first enqueue does not interpret the new entity's deadline as a stale relative deadline.
--- kernel/sched/core.c | 1 + 1 file changed, 1 insertion(+)
kernel/sched/core.c +1 -0
@@ -4453,6 +4453,7 @@ static void __sched_fork(unsigned long clone_flags, struct task_struct *p) p->se.nr_migrations =0 ; p->se.vruntime =0 ; p->se.vlag =0 ; + p->se.rel_deadline =0 ;INIT_LIST_HEAD (&p->se.group_node);/* A delayed task cannot be in clone(). */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 553/666 net: mctp i2c: check length before marking flow active
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: William A. Kennington III <[email protected]>
[ Upstream commit 4ca07b9239bd0478ae586632a2ed72be37ed8407 ]
Currently, mctp_i2c_get_tx_flow_state() is called before the packet length sanity check. This function marks a new flow as active in the MCTP core.
If the sanity check fails, mctp_i2c_xmit() returns early without calling mctp_i2c_lock_nest(). This results in a mismatched locking state: the flow is active, but the I2C bus lock was never acquired for it.
When the flow is later released, mctp_i2c_release_flow() will see the active state and queue an unlock marker. The TX thread will then decrement midev->i2c_lock_count from 0, causing it to underflow to -1.
This underflow permanently breaks the driver's locking logic, allowing future transmissions to occur without holding the I2C bus lock, leading to bus collisions and potential hardware hangs.
Move the mctp_i2c_get_tx_flow_state() call to after the length sanity check to ensure we only transition the flow state if we are actually going to proceed with the transmission and locking.
--- drivers/net/mctp/mctp-i2c.c | 4 ++-- net/sched/cls_flower.c | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-)
drivers/net/mctp/mctp-i2c.c +2 -2
@@ -497,8 +497,6 @@ static void mctp_i2c_xmit(struct mctp_i2c_dev *midev, struct sk_buff *skb)u8 *pecp;int rc; - fs =mctp_i2c_get_tx_flow_state (midev, skb); - hdr = (void *)skb_mac_header (skb);/* Sanity check that packet contents matches skb length, * and can't exceed MCTP_I2C_BUFSZ
@@ -510,6 +508,8 @@ static void mctp_i2c_xmit(struct mctp_i2c_dev *midev, struct sk_buff *skb)return ; } + fs =mctp_i2c_get_tx_flow_state (midev, skb); +if (skb_tailroom (skb) >=1 ) {/* Linear case with space, we can just append the PEC */ skb_put (skb,1 );
net/sched/cls_flower.c +3 -1
@@ -560,6 +560,7 @@ static int __fl_delete(struct tcf_proto *tp, struct cls_fl_filter *f, struct netlink_ext_ack *extack) {struct cls_fl_head *head =fl_head_dereference (tp); +struct fl_flow_mask *mask; *last = false;
@@ -576,11 +577,12 @@ static int __fl_delete(struct tcf_proto *tp, struct cls_fl_filter *f,list_del_rcu (&f->list);spin_unlock (&tp->lock); - *last =fl_mask_put (head, f->mask); + mask = f->mask;if (!tc_skip_hw (f->flags))fl_hw_destroy_filter (tp, f, rtnl_held, extack);tcf_unbind_filter (tp, &f->res);__fl_put (f); + *last =fl_mask_put (head, mask);return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 554/666 net: phy: dp83869: fix setting CLK_O_SEL field.
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Heiko Schocher <[email protected]>
[ Upstream commit 46f74a3f7d57d9cc0110b09cbc8163fa0a01afa2 ]
Table 7-121 in datasheet says we have to set register 0xc6 to value 0x10 before CLK_O_SEL can be modified. No more infos about this field found in datasheet. With this fix, setting of CLK_O_SEL field in IO_MUX_CFG register worked through dts property "ti,clk-output-sel" on a DP83869HMRGZR.
--- drivers/net/phy/dp83869.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-)
drivers/net/phy/dp83869.c +12 -1
@@ -31,6 +31,7 @@#define DP83869_RGMIICTL 0x0032#define DP83869_STRAP_STS1 0x006e#define DP83869_RGMIIDCTL 0x0086 +#define DP83869_ANA_PLL_PROG_PI 0x00c6#define DP83869_RXFCFG 0x0134#define DP83869_RXFPMD1 0x0136#define DP83869_RXFPMD2 0x0137
@@ -827,12 +828,22 @@ static int dp83869_config_init(struct phy_device *phydev)dp83869_config_port_mirroring (phydev);/* Clock output selection if muxing property is set */ -if (dp83869->clk_output_sel !=DP83869_CLK_O_SEL_REF_CLK ) +if (dp83869->clk_output_sel !=DP83869_CLK_O_SEL_REF_CLK ) { +/* +* Table 7-121 in datasheet says we have to set register 0xc6 +* to value 0x10 before CLK_O_SEL can be modified. +*/ + ret =phy_write_mmd (phydev,DP83869_DEVADDR , +DP83869_ANA_PLL_PROG_PI ,0x10 ); +if (ret) +return ret; + ret =phy_modify_mmd (phydev,DP83869_DEVADDR ,DP83869_IO_MUX_CFG ,DP83869_IO_MUX_CFG_CLK_O_SEL_MASK , dp83869->clk_output_sel <<DP83869_IO_MUX_CFG_CLK_O_SEL_SHIFT ); + }if (phy_interface_is_rgmii (phydev)) { ret = phy_write_mmd(phydev, DP83869_DEVADDR, DP83869_RGMIIDCTL,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 555/666 drm/amdgpu/vcn: set no_user_fence for VCN v2.0 enc/dec rings
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yinjie Yao <[email protected]>
[ Upstream commit 8d80b293b41fcb5e9396db93e788b0f4ebcbafb7 ]
VCN encoder and decoder rings do not support 64-bit user fence writes, reject CS submissions with user fences.
--- drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/gpu/drm/amd/amdgpu/vcn_v2_0.c +2 -0
@@ -2127,6 +2127,7 @@ static const struct amd_ip_funcs vcn_v2_0_ip_funcs = {static const struct amdgpu_ring_funcs vcn_v2_0_dec_ring_vm_funcs = { .type =AMDGPU_RING_TYPE_VCN_DEC , .align_mask =0xf , + .no_user_fence = true, .secure_submission_supported = true, .get_rptr = vcn_v2_0_dec_ring_get_rptr, .get_wptr = vcn_v2_0_dec_ring_get_wptr,
@@ -2158,6 +2159,7 @@ static const struct amdgpu_ring_funcs vcn_v2_0_enc_ring_vm_funcs = { .type = AMDGPU_RING_TYPE_VCN_ENC, .align_mask = 0x3f, .nop = VCN_ENC_CMD_NO_OP, + .no_user_fence = true, .get_rptr = vcn_v2_0_enc_ring_get_rptr, .get_wptr = vcn_v2_0_enc_ring_get_wptr, .set_wptr = vcn_v2_0_enc_ring_set_wptr,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 556/666 drm/amdgpu/vcn: set no_user_fence for VCN v2.5 enc/dec rings
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yinjie Yao <[email protected]>
[ Upstream commit 4f317863a3ab212a027d8c8c3cc3af4e3fb95704 ]
VCN encoder and decoder rings do not support 64-bit user fence writes, reject CS submissions with user fences.
--- drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/gpu/drm/amd/amdgpu/vcn_v2_5.c +2 -0
@@ -1628,6 +1628,7 @@ static void vcn_v2_5_dec_ring_set_wptr(struct amdgpu_ring *ring)static const struct amdgpu_ring_funcs vcn_v2_5_dec_ring_vm_funcs = { .type =AMDGPU_RING_TYPE_VCN_DEC , .align_mask =0xf , + .no_user_fence = true, .secure_submission_supported = true, .get_rptr = vcn_v2_5_dec_ring_get_rptr, .get_wptr = vcn_v2_5_dec_ring_get_wptr,
@@ -1728,6 +1729,7 @@ static const struct amdgpu_ring_funcs vcn_v2_5_enc_ring_vm_funcs = { .type = AMDGPU_RING_TYPE_VCN_ENC, .align_mask = 0x3f, .nop = VCN_ENC_CMD_NO_OP, + .no_user_fence = true, .get_rptr = vcn_v2_5_enc_ring_get_rptr, .get_wptr = vcn_v2_5_enc_ring_get_wptr, .set_wptr = vcn_v2_5_enc_ring_set_wptr,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 557/666 drm/amdgpu/vcn: set no_user_fence for VCN v3.0 enc/dec rings
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yinjie Yao <[email protected]>
[ Upstream commit f1e5a6660d7cbf006079126d9babbf0ccf538c6b ]
VCN encoder and decoder rings do not support 64-bit user fence writes, reject CS submissions with user fences.
--- drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/gpu/drm/amd/amdgpu/vcn_v3_0.c +3 -0
@@ -1791,6 +1791,7 @@ static const struct amdgpu_ring_funcs vcn_v3_0_dec_sw_ring_vm_funcs = { .type = AMDGPU_RING_TYPE_VCN_DEC, .align_mask = 0x3f, .nop = VCN_DEC_SW_CMD_NO_OP, + .no_user_fence = true, .secure_submission_supported = true, .get_rptr = vcn_v3_0_dec_ring_get_rptr, .get_wptr = vcn_v3_0_dec_ring_get_wptr,
@@ -1972,6 +1973,7 @@ static int vcn_v3_0_ring_patch_cs_in_place(struct amdgpu_cs_parser *p,static const struct amdgpu_ring_funcs vcn_v3_0_dec_ring_vm_funcs = { .type =AMDGPU_RING_TYPE_VCN_DEC , .align_mask =0xf , + .no_user_fence = true, .secure_submission_supported = true, .get_rptr = vcn_v3_0_dec_ring_get_rptr, .get_wptr = vcn_v3_0_dec_ring_get_wptr,
@@ -2073,6 +2075,7 @@ static const struct amdgpu_ring_funcs vcn_v3_0_enc_ring_vm_funcs = { .type = AMDGPU_RING_TYPE_VCN_ENC, .align_mask = 0x3f, .nop = VCN_ENC_CMD_NO_OP, + .no_user_fence = true, .get_rptr = vcn_v3_0_enc_ring_get_rptr, .get_wptr = vcn_v3_0_enc_ring_get_wptr, .set_wptr = vcn_v3_0_enc_ring_set_wptr,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 558/666 drm/amdgpu/vcn: set no_user_fence for VCN v4.0.3 enc ring
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yinjie Yao <[email protected]>
[ Upstream commit 4532b52b34e4e4310386e6fdf6a643368599f522 ]
VCN encoder and decoder rings do not support 64-bit user fence writes, reject CS submissions with user fences.
--- drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c | 1 + 1 file changed, 1 insertion(+)
drivers/gpu/drm/amd/amdgpu/vcn_v4_0_3.c +1 -0
@@ -1520,6 +1520,7 @@ static const struct amdgpu_ring_funcs vcn_v4_0_3_unified_ring_vm_funcs = { .type = AMDGPU_RING_TYPE_VCN_ENC, .align_mask = 0x3f, .nop = VCN_ENC_CMD_NO_OP, + .no_user_fence = true, .get_rptr = vcn_v4_0_3_unified_ring_get_rptr, .get_wptr = vcn_v4_0_3_unified_ring_get_wptr, .set_wptr = vcn_v4_0_3_unified_ring_set_wptr,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 559/666 drm/amdgpu/vcn: set no_user_fence for VCN v4.0.5 enc ring
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yinjie Yao <[email protected]>
[ Upstream commit 589a254bf3e88204c8402b9cbccd5e23a0af990f ]
VCN encoder and decoder rings do not support 64-bit user fence writes, reject CS submissions with user fences.
--- drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c | 1 + 1 file changed, 1 insertion(+)
drivers/gpu/drm/amd/amdgpu/vcn_v4_0_5.c +1 -0
@@ -1414,6 +1414,7 @@ static const struct amdgpu_ring_funcs vcn_v4_0_5_unified_ring_vm_funcs = { .type = AMDGPU_RING_TYPE_VCN_ENC, .align_mask = 0x3f, .nop = VCN_ENC_CMD_NO_OP, + .no_user_fence = true, .get_rptr = vcn_v4_0_5_unified_ring_get_rptr, .get_wptr = vcn_v4_0_5_unified_ring_get_wptr, .set_wptr = vcn_v4_0_5_unified_ring_set_wptr,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 560/666 drm/amdgpu/vcn: set no_user_fence for VCN v5.0.0 enc ring
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yinjie Yao <[email protected]>
[ Upstream commit 8cae0ce77de492d7c31c1532a2e80c0c6e7e58cb ]
VCN encoder and decoder rings do not support 64-bit user fence writes, reject CS submissions with user fences.
--- drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c | 1 + 1 file changed, 1 insertion(+)
drivers/gpu/drm/amd/amdgpu/vcn_v5_0_0.c +1 -0
@@ -1137,6 +1137,7 @@ static const struct amdgpu_ring_funcs vcn_v5_0_0_unified_ring_vm_funcs = { .type = AMDGPU_RING_TYPE_VCN_ENC, .align_mask = 0x3f, .nop = VCN_ENC_CMD_NO_OP, + .no_user_fence = true, .get_rptr = vcn_v5_0_0_unified_ring_get_rptr, .get_wptr = vcn_v5_0_0_unified_ring_get_wptr, .set_wptr = vcn_v5_0_0_unified_ring_set_wptr,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 561/666 drm/amdgpu/jpeg: set no_user_fence for JPEG v2.0 ring
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yinjie Yao <[email protected]>
[ Upstream commit e5f612dc91650561fe2b5b76dd6d2898ec9ad480 ]
JPEG rings do not support 64-bit user fence writes, reject CS submissions with user fences.
--- drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c | 1 + 1 file changed, 1 insertion(+)
drivers/gpu/drm/amd/amdgpu/jpeg_v2_0.c +1 -0
@@ -766,6 +766,7 @@ static const struct amd_ip_funcs jpeg_v2_0_ip_funcs = {static const struct amdgpu_ring_funcs jpeg_v2_0_dec_ring_vm_funcs = { .type =AMDGPU_RING_TYPE_VCN_JPEG , .align_mask =0xf , + .no_user_fence = true, .get_rptr = jpeg_v2_0_dec_ring_get_rptr, .get_wptr = jpeg_v2_0_dec_ring_get_wptr, .set_wptr = jpeg_v2_0_dec_ring_set_wptr,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 562/666 drm/amdgpu/jpeg: set no_user_fence for JPEG v2.5 ring
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yinjie Yao <[email protected]>
[ Upstream commit 79405e774ede411c6b47ed41c651e40b92de64a2 ]
JPEG rings do not support 64-bit user fence writes, reject CS submissions with user fences.
--- drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/gpu/drm/amd/amdgpu/jpeg_v2_5.c +2 -0
@@ -659,6 +659,7 @@ static const struct amd_ip_funcs jpeg_v2_6_ip_funcs = {static const struct amdgpu_ring_funcs jpeg_v2_5_dec_ring_vm_funcs = { .type =AMDGPU_RING_TYPE_VCN_JPEG , .align_mask =0xf , + .no_user_fence = true, .get_rptr = jpeg_v2_5_dec_ring_get_rptr, .get_wptr = jpeg_v2_5_dec_ring_get_wptr, .set_wptr = jpeg_v2_5_dec_ring_set_wptr,
@@ -689,6 +690,7 @@ static const struct amdgpu_ring_funcs jpeg_v2_5_dec_ring_vm_funcs = {static const struct amdgpu_ring_funcs jpeg_v2_6_dec_ring_vm_funcs = { .type =AMDGPU_RING_TYPE_VCN_JPEG , .align_mask =0xf , + .no_user_fence = true, .get_rptr = jpeg_v2_5_dec_ring_get_rptr, .get_wptr = jpeg_v2_5_dec_ring_get_wptr, .set_wptr = jpeg_v2_5_dec_ring_set_wptr,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 563/666 drm/amdgpu/jpeg: set no_user_fence for JPEG v3.0 ring
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yinjie Yao <[email protected]>
[ Upstream commit a2baf12eec41f246689e6a3f8619af1200031576 ]
JPEG rings do not support 64-bit user fence writes, reject CS submissions with user fences.
--- drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c | 1 + 1 file changed, 1 insertion(+)
drivers/gpu/drm/amd/amdgpu/jpeg_v3_0.c +1 -0
@@ -557,6 +557,7 @@ static const struct amd_ip_funcs jpeg_v3_0_ip_funcs = {static const struct amdgpu_ring_funcs jpeg_v3_0_dec_ring_vm_funcs = { .type =AMDGPU_RING_TYPE_VCN_JPEG , .align_mask =0xf , + .no_user_fence = true, .get_rptr = jpeg_v3_0_dec_ring_get_rptr, .get_wptr = jpeg_v3_0_dec_ring_get_wptr, .set_wptr = jpeg_v3_0_dec_ring_set_wptr,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 564/666 drm/amdgpu/jpeg: set no_user_fence for JPEG v4.0 ring
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yinjie Yao <[email protected]>
[ Upstream commit e7e90b5839aeb8805ec83bb4da610b8dab8e184d ]
JPEG rings do not support 64-bit user fence writes, reject CS submissions with user fences.
--- drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c | 1 + 1 file changed, 1 insertion(+)
drivers/gpu/drm/amd/amdgpu/jpeg_v4_0.c +1 -0
@@ -724,6 +724,7 @@ static const struct amd_ip_funcs jpeg_v4_0_ip_funcs = {static const struct amdgpu_ring_funcs jpeg_v4_0_dec_ring_vm_funcs = { .type =AMDGPU_RING_TYPE_VCN_JPEG , .align_mask =0xf , + .no_user_fence = true, .get_rptr = jpeg_v4_0_dec_ring_get_rptr, .get_wptr = jpeg_v4_0_dec_ring_get_wptr, .set_wptr = jpeg_v4_0_dec_ring_set_wptr,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 565/666 drm/amdgpu/jpeg: set no_user_fence for JPEG v4.0.3 ring
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yinjie Yao <[email protected]>
[ Upstream commit 83e37c0987ca92f9e87789b46dd311dcf5a4a6c8 ]
JPEG rings do not support 64-bit user fence writes, reject CS submissions with user fences.
--- drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c | 1 + 1 file changed, 1 insertion(+)
drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_3.c +1 -0
@@ -1122,6 +1122,7 @@ static const struct amd_ip_funcs jpeg_v4_0_3_ip_funcs = {static const struct amdgpu_ring_funcs jpeg_v4_0_3_dec_ring_vm_funcs = { .type =AMDGPU_RING_TYPE_VCN_JPEG , .align_mask =0xf , + .no_user_fence = true, .get_rptr = jpeg_v4_0_3_dec_ring_get_rptr, .get_wptr = jpeg_v4_0_3_dec_ring_get_wptr, .set_wptr = jpeg_v4_0_3_dec_ring_set_wptr,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 566/666 drm/amdgpu/jpeg: set no_user_fence for JPEG v4.0.5 ring
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yinjie Yao <[email protected]>
[ Upstream commit b65b7f3f3c18f797f81a2af7c97e2079900ad6db ]
JPEG rings do not support 64-bit user fence writes, reject CS submissions with user fences.
--- drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_5.c | 1 + 1 file changed, 1 insertion(+)
drivers/gpu/drm/amd/amdgpu/jpeg_v4_0_5.c +1 -0
@@ -765,6 +765,7 @@ static const struct amd_ip_funcs jpeg_v4_0_5_ip_funcs = {static const struct amdgpu_ring_funcs jpeg_v4_0_5_dec_ring_vm_funcs = { .type =AMDGPU_RING_TYPE_VCN_JPEG , .align_mask =0xf , + .no_user_fence = true, .get_rptr = jpeg_v4_0_5_dec_ring_get_rptr, .get_wptr = jpeg_v4_0_5_dec_ring_get_wptr, .set_wptr = jpeg_v4_0_5_dec_ring_set_wptr,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 567/666 drm/amdgpu/jpeg: set no_user_fence for JPEG v5.0.0 ring
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yinjie Yao <[email protected]>
[ Upstream commit ea7c61c5f895e8f9ea0ffffa180498ef9c740152 ]
JPEG rings do not support 64-bit user fence writes, reject CS submissions with user fences.
--- drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_0.c | 1 + 1 file changed, 1 insertion(+)
drivers/gpu/drm/amd/amdgpu/jpeg_v5_0_0.c +1 -0
@@ -644,6 +644,7 @@ static const struct amd_ip_funcs jpeg_v5_0_0_ip_funcs = {static const struct amdgpu_ring_funcs jpeg_v5_0_0_dec_ring_vm_funcs = { .type =AMDGPU_RING_TYPE_VCN_JPEG , .align_mask =0xf , + .no_user_fence = true, .get_rptr = jpeg_v5_0_0_dec_ring_get_rptr, .get_wptr = jpeg_v5_0_0_dec_ring_get_wptr, .set_wptr = jpeg_v5_0_0_dec_ring_set_wptr,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 568/666 ASoC: codecs: ab8500: Fix casting of private data
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian A. Ehrhardt <[email protected]>
[ Upstream commit a201aef1a88b675e9eb8487e27d14e2eef3cef80 ]
ab8500_filter_controls[i].private_value is initialized using
.private_value = (unsigned long)&(struct filter_control)
{.count = xcount, .min = xmin, .max = xmax}thus it's a pointer to a struct filter_control casted to unsigned long.
So to get back that pointer .private_data must be cast back, not its address.
--- sound/soc/codecs/ab8500-codec.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
sound/soc/codecs/ab8500-codec.c +3 -3
@@ -2496,13 +2496,13 @@ static int ab8500_codec_probe(struct snd_soc_component *component)return status; } fc = (struct filter_control *) - &ab8500_filter_controls[AB8500_FILTER_ANC_FIR ].private_value; + ab8500_filter_controls[AB8500_FILTER_ANC_FIR ].private_value; drvdata->anc_fir_values = (long *)fc->value; fc = (struct filter_control *) - &ab8500_filter_controls[AB8500_FILTER_ANC_IIR ].private_value; + ab8500_filter_controls[AB8500_FILTER_ANC_IIR ].private_value; drvdata->anc_iir_values = (long *)fc->value; fc = (struct filter_control *) - &ab8500_filter_controls[AB8500_FILTER_SID_FIR ].private_value; + ab8500_filter_controls[AB8500_FILTER_SID_FIR ].private_value; drvdata->sid_fir_values = (long *)fc->value;snd_soc_dapm_disable_pin (dapm,"ANC Configure Input" );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 569/666 netfilter: skip recording stale or retransmitted INIT
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xin Long <[email protected]>
[ Upstream commit 576a5d2bad4814c881a829576b1261b9b8159d2b ]
An INIT whose init_tag matches the peer's vtag does not provide new state information. It indicates either:
- a stale INIT (after INIT-ACK has already been seen on the same side), or
- a retransmitted INIT (after INIT has already been recorded on the same side).
In both cases, the INIT must not update ct->proto.sctp.init[] state, since it does not advance the handshake tracking and may otherwise corrupt INIT/INIT-ACK validation logic.
Allow INIT processing only when the conntrack entry is newly created (SCTP_CONNTRACK_NONE), or when the init_tag differs from the stored peer vtag.
Note it skips the check for the ct with old_state SCTP_CONNTRACK_NONE in nf_conntrack_sctp_packet(), as it is just created in sctp_new() where it set ct->proto.sctp.vtag[IP_CT_DIR_REPLY] = ih->init_tag.
--- net/netfilter/nf_conntrack_proto_sctp.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-)
net/netfilter/nf_conntrack_proto_sctp.c +7 -3
@@ -471,9 +471,13 @@ int nf_conntrack_sctp_packet(struct nf_conn *ct,if (!ih) goto out_unlock; -if (ct->proto.sctp.init[dir] && ct->proto.sctp.init[!dir]) - ct->proto.sctp.init[!dir] =0 ; - ct->proto.sctp.init[dir] =1 ; +/* Do not record INIT matching peer vtag (stale or retransmitted INIT). */ +if (old_state ==SCTP_CONNTRACK_NONE || + ct->proto.sctp.vtag[!dir] != ih->init_tag) { +if (ct->proto.sctp.init[dir] && ct->proto.sctp.init[!dir]) + ct->proto.sctp.init[!dir] =0 ; + ct->proto.sctp.init[dir] =1 ; + }pr_debug ("Setting vtag %x for dir %d\n" , ih->init_tag, !dir); ct->proto.sctp.vtag[!dir] = ih->init_tag;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 570/666 sctp: discard stale INIT after handshake completion
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xin Long <[email protected]>
[ Upstream commit 8a92cb475ca90d84db769e4d4383e631ace0d6e5 ]
After an association reaches ESTABLISHED, the peer’s init_tag is already known from the handshake. Any subsequent INIT with the same init_tag is not a valid restart, but a delayed or duplicate INIT.
Drop such INIT chunks in sctp_sf_do_unexpected_init() instead of processing them as new association attempts.
--- net/sctp/sm_statefuns.c | 6 ++++++ 1 file changed, 6 insertions(+)
net/sctp/sm_statefuns.c +6 -0
@@ -1556,6 +1556,12 @@ static enum sctp_disposition sctp_sf_do_unexpected_init(/* Tag the variable length parameters. */ chunk->param_hdr.v =skb_pull (chunk->skb,sizeof (struct sctp_inithdr )); +if (asoc->state >=SCTP_STATE_ESTABLISHED ) { +/* Discard INIT matching peer vtag after handshake completion (stale INIT). */ +if (ntohl (chunk->subh.init_hdr->init_tag) == asoc->peer.i.init_tag) +return sctp_sf_pdiscard (net, ep, asoc, type, arg, commands); + } +/* Verify the INIT chunk before processing it. */ err_chunk =NULL ; if (!sctp_verify_init(net, ep, asoc, chunk->chunk_hdr->type,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 571/666 bareudp: fix NULL pointer dereference in bareudp_fill_metadata_dst()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Weiming Shi <[email protected]>
[ Upstream commit aa6c6d9ee064aabfede4402fd1283424e649ca19 ]
bareudp_fill_metadata_dst() passes bareudp->sock to udp_tunnel6_dst_lookup() in the IPv6 path without a NULL check. The socket is only created in bareudp_open() and NULLed in bareudp_stop(), so calling this function while the device is down triggers a NULL dereference via sock->sk.
BUG: kernel NULL pointer dereference, address: 0000000000000018 RIP: 0010:udp_tunnel6_dst_lookup (net/ipv6/ip6_udp_tunnel.c:160) Call Trace: <TASK> bareudp_fill_metadata_dst (drivers/net/bareudp.c:532) do_execute_actions (net/openvswitch/actions.c:901) ovs_execute_actions (net/openvswitch/actions.c:1589) ovs_packet_cmd_execute (net/openvswitch/datapath.c:700) genl_family_rcv_msg_doit (net/netlink/genetlink.c:1114) genl_rcv_msg (net/netlink/genetlink.c:1209) netlink_rcv_skb (net/netlink/af_netlink.c:2550) </TASK>
Add a NULL check returning -ESHUTDOWN, consistent with the xmit paths in the same driver.
--- drivers/net/bareudp.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/net/bareudp.c +3 -0
@@ -528,6 +528,9 @@ static int bareudp_fill_metadata_dst(struct net_device *dev,struct in6_addr saddr;struct socket *sock =rcu_dereference (bareudp->sock); +if (!sock) +return -ESHUTDOWN ; + dst = udp_tunnel6_dst_lookup(skb, dev, bareudp->net, sock, 0, &saddr, &info->key, sport, bareudp->port, info->key.tos,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 572/666 net/sched: sch_cake: annotate data-races in cake_dump_stats() (V)
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit a6c95b833dc17e84d16a8ac0f40fd0931616a52d ]
cake_dump_stats() runs without qdisc spinlock being held.
In this final patch, I add READ_ONCE()/WRITE_ONCE() annotations for cparams.target and cparams.interval.
--- net/sched/sch_cake.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-)
net/sched/sch_cake.c +7 -6
@@ -2297,10 +2297,11 @@ static void cake_set_rate(struct cake_tin_data *b, u64 rate, u32 mtu, byte_target_ns = (byte_target * rate_ns) >> rate_shft; - b->cparams.target =max ((byte_target_ns *3 ) /2 , target_ns); - b->cparams.interval =max (rtt_est_ns + - b->cparams.target - target_ns, - b->cparams.target *2 ); +WRITE_ONCE (b->cparams.target, +max ((byte_target_ns *3 ) /2 , target_ns)); +WRITE_ONCE (b->cparams.interval, +max (rtt_est_ns + b->cparams.target - target_ns, + b->cparams.target *2 )); b->cparams.mtu_time = byte_target_ns; b->cparams.p_inc =1 <<24 ;/* 1/256 */ b->cparams.p_dec =1 <<20 ;/* 1/4096 */
@@ -2930,9 +2931,9 @@ static int cake_dump_stats(struct Qdisc *sch, struct gnet_dump *d)PUT_TSTAT_U32 (BACKLOG_BYTES , b->tin_backlog);PUT_TSTAT_U32 (TARGET_US , -ktime_to_us (ns_to_ktime (b->cparams.target))); +ktime_to_us (ns_to_ktime (READ_ONCE (b->cparams.target))));PUT_TSTAT_U32 (INTERVAL_US , -ktime_to_us (ns_to_ktime (b->cparams.interval))); +ktime_to_us (ns_to_ktime (READ_ONCE (b->cparams.interval))));PUT_TSTAT_U32 (SENT_PACKETS , b->packets);PUT_TSTAT_U32 (DROPPED_PACKETS , b->tin_dropped);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 573/666 netconsole: propagate device name truncation in dev_name_store()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Breno Leitao <[email protected]>
[ Upstream commit 92ceb7bff62c2606f664c204750eca0b85d44112 ]
dev_name_store() calls strscpy(nt->np.dev_name, buf, IFNAMSIZ) without checking the return value. If userspace writes an interface name longer than IFNAMSIZ - 1, strscpy() silently truncates and returns -E2BIG, but the function ignores it and reports a fully successful write back to userspace.
If a real interface happens to match the truncated name, netconsole will bind to the wrong device on the next enable, sending kernel logs and panic output to an unintended network segment with no indication to userspace that anything was rewritten.
Reject writes whose length cannot fit in nt->np.dev_name up front:
if (count >= IFNAMSIZ) return -ENAMETOOLONG;
This is not a big deal of a problem, but, it is still the correct approach.
--- drivers/net/netconsole.c | 7 +++++++ 1 file changed, 7 insertions(+)
drivers/net/netconsole.c +7 -0
@@ -502,6 +502,13 @@ static ssize_t dev_name_store(struct config_item *item, const char *buf, size_t count) {struct netconsole_target *nt =to_target (item); +size_t len = count; + +/* Account for a trailing newline appended by tools like echo */ +if (len && buf[len -1 ] =='\n' ) + len--; +if (len >=IFNAMSIZ ) +return -ENAMETOOLONG ;mutex_lock (&dynamic_netconsole_mutex);if (nt->enabled) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 574/666 ALSA: hda/conexant: Renaming the codec with device ID 0x1f86 and 0x1f87
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: wangdicheng <[email protected]>
[ Upstream commit 7f4c540e0859e2025675d2c5c5c6ab88eaf817e2 ]
Due to changes in the manufacturer's plan, all 0x14f11f86 will be named CX11880, and 0x14f11f87 will be named SN6140
Stable-dep-of: b0e2333a2311 ("ALSA: hda/conexant: Fix missing error check for jack detection")
--- sound/pci/hda/patch_conexant.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-)
sound/pci/hda/patch_conexant.c +6 -6
@@ -42,7 +42,7 @@ struct conexant_spec {unsigned int gpio_led;unsigned int gpio_mute_led_mask;unsigned int gpio_mic_led_mask; -bool is_cx8070_sn6140; +bool is_cx11880_sn6140; };
@@ -195,7 +195,7 @@ static int cx_auto_init(struct hda_codec *codec)cxt_init_gpio_led (codec);snd_hda_apply_fixup (codec,HDA_FIXUP_ACT_INIT ); -if (spec->is_cx8070_sn6140) +if (spec->is_cx11880_sn6140)cx_fixup_headset_recog (codec);return 0 ;
@@ -247,7 +247,7 @@ static void cx_update_headset_mic_vref(struct hda_codec *codec, struct hda_jack_ {unsigned int mic_present; -/* In cx8070 and sn6140, the node 16 can only be configured to headphone or disabled, +/* In cx11880 and sn6140, the node 16 can only be configured to headphone or disabled, * the node 19 can only be configured to microphone or disabled. * Check hp&mic tag to process headset plugin & plugout. */
@@ -1193,11 +1193,11 @@ static int patch_conexant_auto(struct hda_codec *codec) codec->spec = spec; codec->patch_ops = cx_auto_patch_ops; -/* init cx8070/sn6140 flag and reset headset_present_flag */ +/* init cx11880/sn6140 flag and reset headset_present_flag */ switch (codec->core.vendor_id) {case 0x14f11f86 :case 0x14f11f87 : - spec->is_cx8070_sn6140 = true; + spec->is_cx11880_sn6140 = true;snd_hda_jack_detect_enable_callback (codec,0x19 , cx_update_headset_mic_vref);break ; }
@@ -1285,7 +1285,7 @@ static int patch_conexant_auto(struct hda_codec *codec)*/ static const struct hda_device_id snd_hda_id_conexant[] = { -HDA_CODEC_ENTRY (0x14f11f86 ,"CX8070" , patch_conexant_auto), +HDA_CODEC_ENTRY (0x14f11f86 ,"CX11880" , patch_conexant_auto),HDA_CODEC_ENTRY (0x14f11f87 ,"SN6140" , patch_conexant_auto),HDA_CODEC_ENTRY (0x14f12008 ,"CX8200" , patch_conexant_auto),HDA_CODEC_ENTRY (0x14f120d0 ,"CX11970" , patch_conexant_auto),
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 575/666 ALSA: hda/conexant: Fix missing error check for jack detection
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: wangdicheng <[email protected]>
[ Upstream commit b0e2333a231107adedd38c6fcfe1adc6162716fc ]
In cx_probe(), the return value of snd_hda_jack_detect_enable_callback() is ignored. This function returns a pointer, and if it fails (e.g., due to memory allocation failure), it returns an error pointer which must be checked using IS_ERR().
If the registration fails, the driver continues to probe, but the jack detection callback will not be registered. This can lead to a kernel crash later when the driver attempts to handle jack events or accesses the uninitialized structure.
Check the return value using IS_ERR() and propagate the error via PTR_ERR() to the probe caller.
--- sound/pci/hda/patch_conexant.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
sound/pci/hda/patch_conexant.c +7 -1
@@ -1182,6 +1182,7 @@ static void add_cx5051_fake_mutes(struct hda_codec *codec)static int patch_conexant_auto (struct hda_codec *codec) {struct conexant_spec *spec; +struct hda_jack_callback *callback;int err;codec_info (codec,"%s: BIOS auto-probing.\n" , codec->core.chip_name);
@@ -1198,7 +1199,12 @@ static int patch_conexant_auto(struct hda_codec *codec)case 0x14f11f86 :case 0x14f11f87 : spec->is_cx11880_sn6140 = true; -snd_hda_jack_detect_enable_callback (codec,0x19 , cx_update_headset_mic_vref); + callback =snd_hda_jack_detect_enable_callback (codec,0x19 , + cx_update_headset_mic_vref); +if (IS_ERR (callback)) { + err =PTR_ERR (callback); + goto error; + }break ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 576/666 ALSA: hda: cs35l56: Fix uninitialized value in cs35l56_hda_read_acpi()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Richard Fitzgerald <[email protected]>
[ Upstream commit 90df4957a3271adf391b3432cd76a40887cf3273 ]
Eliminate the uninitialized 'nval' in cs35l56_hda_read_acpi() if a system-specific quirk overrides processing of the dev-index property. The value is now stored in a new 'num_amps' member of struct cs35l56_hda so that the quirk handler can set the value.
The quirk for the Lenovo Yoga Book 9i GenX replaces the values from the dev-index property with hardcoded indexes. So cs35l56_hda_read_acpi() would then skip reading the property. But this left the 'nval' local variable uninitialized when it is later passed to cirrus_scodec_get_speaker_id().
--- sound/pci/hda/cs35l56_hda.c | 12 +++++++----- sound/pci/hda/cs35l56_hda.h | 1 + 2 files changed, 8 insertions(+), 5 deletions(-)
sound/pci/hda/cs35l56_hda.c +7 -5
@@ -888,6 +888,7 @@ static int cs35l56_hda_system_resume(struct device *dev)static int cs35l56_hda_fixup_yoga9 (struct cs35l56_hda *cs35l56,int *bus_addr) {/* The cirrus,dev-index property has the wrong values */ + cs35l56->num_amps =2 ;switch (*bus_addr) {case 0x30 : cs35l56->index =1 ;
@@ -937,7 +938,6 @@ static int cs35l56_hda_read_acpi(struct cs35l56_hda *cs35l56, int hid, int id)char hid_string[8 ];struct acpi_device *adev;const char *property, *sub; -size_t nval;int i, ret;/*
@@ -973,13 +973,14 @@ static int cs35l56_hda_read_acpi(struct cs35l56_hda *cs35l56, int hid, int id) ret = -EINVAL ; goto err; } - nval = ret; + cs35l56->num_amps = ret; - ret =device_property_read_u32_array (cs35l56->base.dev, property, values, nval); + ret =device_property_read_u32_array (cs35l56->base.dev, property, values, + cs35l56->num_amps);if (ret) goto err; -for (i =0 ; i < nval; i++) { +for (i =0 ; i < cs35l56->num_amps; i++) {if (values[i] == id) { cs35l56->index = i;break ;
@@ -1002,7 +1003,8 @@ static int cs35l56_hda_read_acpi(struct cs35l56_hda *cs35l56, int hid, int id)"Read ACPI _SUB failed(%ld): fallback to generic firmware\n" , PTR_ERR(sub)); }else { - ret =cirrus_scodec_get_speaker_id (cs35l56->base.dev, cs35l56->index, nval,-1 ); + ret =cirrus_scodec_get_speaker_id (cs35l56->base.dev, cs35l56->index, + cs35l56->num_amps,-1 );if (ret == -ENOENT ) { cs35l56->system_name = sub; }else if (ret >=0 ) {
sound/pci/hda/cs35l56_hda.h +1 -0
@@ -25,6 +25,7 @@ struct cs35l56_hda {struct work_struct dsp_work;int index; +int num_amps;const char *system_name;const char *amp_name;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 577/666 futex: Prevent lockup in requeue-PI during signal/ timeout wakeup
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sebastian Andrzej Siewior <[email protected]>
[ Upstream commit bc7304f3ae20972d11db6e0b1b541c63feda5f05 ]
During wait-requeue-pi (task A) and requeue-PI (task B) the following race can happen:
Task A Task B
futex_wait_requeue_pi()
futex_setup_timer()
futex_do_wait()
futex_requeue()
CLASS(hb, hb1)(&key1);
CLASS(hb, hb2)(&key2);
*timeout*
futex_requeue_pi_wakeup_sync()
requeue_state = Q_REQUEUE_PI_IGNORE
*blocks on hb->lock*
futex_proxy_trylock_atomic()
futex_requeue_pi_prepare()
Q_REQUEUE_PI_IGNORE => -EAGAIN
double_unlock_hb(hb1, hb2)
*retry*Task B acquires both hb locks and attempts to acquire the PI-lock of the top most waiter (task B). Task A is leaving early due to a signal/ timeout and started removing itself from the queue. It updates its requeue_state but can not remove it from the list because this requires the hb lock which is owned by task B.
Usually task A is able to swoop the lock after task B unlocked it. However if task B is of higher priority then task A may not be able to wake up in time and acquire the lock before task B gets it again. Especially on a UP system where A is never scheduled.
As a result task A blocks on the lock and task B busy loops, trying to make progress but live locks the system instead. Tragic.
This can be fixed by removing the top most waiter from the list in this case. This allows task B to grab the next top waiter (if any) in the next iteration and make progress.
Remove the top most waiter if futex_requeue_pi_prepare() fails. Let the waiter conditionally remove itself from the list in handle_early_requeue_pi_wakeup().
--- kernel/futex/requeue.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-)
kernel/futex/requeue.c +9 -4
@@ -309,8 +309,11 @@ futex_proxy_trylock_atomic(u32 __user *pifutex, struct futex_hash_bucket *hb1,return -EINVAL ;/* Ensure that this does not race against an early wakeup */ -if (!futex_requeue_pi_prepare (top_waiter,NULL )) +if (!futex_requeue_pi_prepare (top_waiter,NULL )) { +plist_del (&top_waiter->list, &hb1->chain); +futex_hb_waiters_dec (hb1);return -EAGAIN ; + }/* * Try to take the lock for top_waiter and set the FUTEX_WAITERS bit
@@ -711,10 +714,12 @@ int handle_early_requeue_pi_wakeup(struct futex_hash_bucket *hb,/* * We were woken prior to requeue by a timeout or a signal. -* Unqueue the futex_q and determine which it was. +* Conditionally unqueue the futex_q and determine which it was. */ -plist_del (&q->list, &hb->chain); -futex_hb_waiters_dec (hb); +if (!plist_node_empty (&q->list)) { +plist_del (&q->list, &hb->chain); +futex_hb_waiters_dec (hb); + }/* Handle spurious wakeups gracefully */ ret = -EWOULDBLOCK ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 578/666 drm/amd/display: Allow DCE link encoder without AUX registers
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Timur Kristóf <[email protected]>
[ Upstream commit ac27e3f99035f132f23bc0409d0e57f11f054c70 ]
Allow constructing the DCE link encoder without DDC, which means the AUX registers array will be NULL.
This is necessary to support embedded connectors without DDC.
--- drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c +3 -1
@@ -989,7 +989,9 @@ void dce110_link_encoder_hw_init(ASSERT (result ==BP_RESULT_OK ); } -aux_initialize (enc110); + +if (enc110->aux_regs) +aux_initialize (enc110);/* reinitialize HPD. * hpd_initialize() will pass DIG_FE id to HW context.
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 579/666 drm/amd/display: Read EDID from VBIOS embedded panel info
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Timur Kristóf <[email protected]>
[ Upstream commit 9ea16f64189bf7b6ba50fc7f0325b3c1f836d105 ]
Some board manufacturers hardcode the EDID for the embedded panel in the VBIOS. This EDID should be used when the panel doesn't have a DDC.
For reference, see the legacy non-DC display code:amdgpu_atombios_encoder_get_lcd_info()
This is necessary to support embedded connectors without DDC.
--- .../gpu/drm/amd/display/dc/bios/bios_parser.c | 62 +++++++++++++++++++ .../display/include/grph_object_ctrl_defs.h | 4 ++ 2 files changed, 66 insertions(+)
drivers/gpu/drm/amd/display/dc/bios/bios_parser.c +62 -0
@@ -1215,6 +1215,60 @@ static enum bp_result bios_parser_get_embedded_panel_info(return BP_RESULT_FAILURE ; } +static enum bp_result get_embedded_panel_extra_info ( +struct bios_parser *bp, +struct embedded_panel_info *info, +const uint32_t table_offset) +{ +uint8_t *record =bios_get_image (&bp->base, table_offset,1 ); +ATOM_PANEL_RESOLUTION_PATCH_RECORD *panel_res_record; +ATOM_FAKE_EDID_PATCH_RECORD *fake_edid_record; + +while (*record !=ATOM_RECORD_END_TYPE ) { +switch (*record) { +case LCD_MODE_PATCH_RECORD_MODE_TYPE : + record +=sizeof (ATOM_PATCH_RECORD_MODE ); +break ; +case LCD_RTS_RECORD_TYPE : + record +=sizeof (ATOM_LCD_RTS_RECORD ); +break ; +case LCD_CAP_RECORD_TYPE : + record +=sizeof (ATOM_LCD_MODE_CONTROL_CAP ); +break ; +case LCD_FAKE_EDID_PATCH_RECORD_TYPE : + fake_edid_record = (ATOM_FAKE_EDID_PATCH_RECORD *)record; +if (fake_edid_record->ucFakeEDIDLength) { +if (fake_edid_record->ucFakeEDIDLength ==128 ) + info->fake_edid_size = + fake_edid_record->ucFakeEDIDLength; +else + info->fake_edid_size = + fake_edid_record->ucFakeEDIDLength *128 ; + + info->fake_edid = fake_edid_record->ucFakeEDIDString; + + record +=struct_size (fake_edid_record, + ucFakeEDIDString, + info->fake_edid_size); + }else { +/* empty fake edid record must be 3 bytes long */ + record +=sizeof (ATOM_FAKE_EDID_PATCH_RECORD ) +1 ; + } +break ; +case LCD_PANEL_RESOLUTION_RECORD_TYPE : + panel_res_record = (ATOM_PANEL_RESOLUTION_PATCH_RECORD *)record; + info->panel_width_mm = panel_res_record->usHSize; + info->panel_height_mm = panel_res_record->usVSize; + record +=sizeof (ATOM_PANEL_RESOLUTION_PATCH_RECORD ); +break ; +default : +return BP_RESULT_BADBIOSTABLE ; + } + } + +return BP_RESULT_OK ; +} +static enum bp_result get_embedded_panel_info_v1_2 (struct bios_parser *bp,struct embedded_panel_info *info)
@@ -1331,6 +1385,10 @@ static enum bp_result get_embedded_panel_info_v1_2(if (ATOM_PANEL_MISC_API_ENABLED & lvds->ucLVDS_Misc) info->lcd_timing.misc_info.API_ENABLED = true; +if (lvds->usExtInfoTableOffset) +return get_embedded_panel_extra_info (bp, info, +le16_to_cpu (lvds->usExtInfoTableOffset) +DATA_TABLES (LCD_Info)); +return BP_RESULT_OK ; }
@@ -1456,6 +1514,10 @@ static enum bp_result get_embedded_panel_info_v1_3( (uint32_t ) (ATOM_PANEL_MISC_V13_GREY_LEVEL & lvds->ucLCD_Misc) >>ATOM_PANEL_MISC_V13_GREY_LEVEL_SHIFT ; +if (lvds->usExtInfoTableOffset) +return get_embedded_panel_extra_info (bp, info, +le16_to_cpu (lvds->usExtInfoTableOffset) +DATA_TABLES (LCD_Info)); +return BP_RESULT_OK ; }
drivers/gpu/drm/amd/display/include/grph_object_ctrl_defs.h +4 -0
@@ -153,6 +153,10 @@ struct embedded_panel_info {uint32_t drr_enabled;uint32_t min_drr_refresh_rate;bool realtek_eDPToLVDS; +uint16_t panel_width_mm; +uint16_t panel_height_mm; +uint16_t fake_edid_size; +const uint8_t *fake_edid; };struct dc_firmware_info {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 580/666 drm/xe/debugfs: Correct printing of register whitelist ranges
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Matt Roper <[email protected]>
[ Upstream commit 03f2499c51dffce611b065b2894406beb9f2ebe0 ]
The register-save-restore debugfs prints whitelist entries as offset ranges. E.g.,
REG[0x39319c-0x39319f]: allow read access
for a single dword-sized register. However the GENMASK value used to set the lower bits to '1' for the upper bound of the whitelist range incorrectly included one more bit than it should have, causing the whitelist ranges to sometimes appear twice as large as they really were. For example,
REG[0x6210-0x6217]: allow rw access
was also intended to be a single dword-sized register whitelist (with a range 0x6210-0x6213) but was printed incorrectly as a qword-sized range because one too many bits was flipped on. Similar 'off by one' logic was applied when printing 4-dword register ranges and 64-dword register ranges as well.
Correct the GENMASK logic to print these ranges in debugfs correctly. No impact outside of correcting the misleading debugfs output.
--- drivers/gpu/drm/xe/xe_reg_whitelist.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/xe/xe_reg_whitelist.c +1 -1
@@ -137,7 +137,7 @@ void xe_reg_whitelist_print_entry(struct drm_printer *p, unsigned int indent, } range_start = reg ®_GENMASK (25 , range_bit); - range_end = range_start |REG_GENMASK (range_bit,0 ); + range_end = range_start |REG_GENMASK (range_bit -1 ,0 );switch (val &RING_FORCE_TO_NONPRIV_ACCESS_MASK ) {case RING_FORCE_TO_NONPRIV_ACCESS_RW :
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 581/666 drm/xe: Fix error cleanup in xe_exec_queue_create_ioctl()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shuicheng Lin <[email protected]>
[ Upstream commit f3cc22d4df3ed58439ea7e21daa54c3608e03b78 ]
Two error handling issues exist in xe_exec_queue_create_ioctl():
1. When xe_hw_engine_group_add_exec_queue() fails, the error path jumps to put_exec_queue which skips xe_exec_queue_kill(). If the VM is in preempt fence mode, xe_vm_add_compute_exec_queue() has already added the queue to the VM's compute exec queue list. Skipping the kill leaves the queue on that list, leading to a dangling pointer after the queue is freed.
2. When xa_alloc() fails after xe_hw_engine_group_add_exec_queue() has succeeded, the error path does not call xe_hw_engine_group_del_exec_queue() to remove the queue from the hw engine group list. The queue is then freed while still linked into the hw engine group, causing a use-after-free.
Fix both by:
- Changing the xe_hw_engine_group_add_exec_queue() failure path to jump to kill_exec_queue so that xe_exec_queue_kill() properly removes the queue from the VM's compute list.
- Adding a del_hw_engine_group label before kill_exec_queue for the xa_alloc() failure path, which removes the queue from the hw engine group before proceeding with the rest of the cleanup.
--- drivers/gpu/drm/xe/xe_exec_queue.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
drivers/gpu/drm/xe/xe_exec_queue.c +5 -2
@@ -638,7 +638,7 @@ int xe_exec_queue_create_ioctl(struct drm_device *dev, void *data,if (q->vm && q->hwe->hw_engine_group) { err =xe_hw_engine_group_add_exec_queue (q->hwe->hw_engine_group, q);if (err) - goto put_exec_queue; + goto kill_exec_queue; } }
@@ -647,12 +647,15 @@ int xe_exec_queue_create_ioctl(struct drm_device *dev, void *data,/* user id alloc must always be last in ioctl to prevent UAF */ err =xa_alloc (&xef->exec_queue.xa, &id, q, xa_limit_32b,GFP_KERNEL );if (err) - goto kill_exec_queue; + goto del_hw_engine_group; args->exec_queue_id = id;return 0 ; +del_hw_engine_group: +if (q->vm && q->hwe && q->hwe->hw_engine_group) +xe_hw_engine_group_del_exec_queue (q->hwe->hw_engine_group, q); kill_exec_queue:xe_exec_queue_kill (q); put_exec_queue:
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 582/666 drm/xe/gsc: Fix BO leak on error in query_compatibility_version()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shuicheng Lin <[email protected]>
[ Upstream commit 3762d6c36549accea7068c4a175483fafdd03657 ]
When xe_gsc_read_out_header() fails, query_compatibility_version() returns directly instead of jumping to the out_bo label. This skips the xe_bo_unpin_map_no_vm() call, leaving the BO pinned and mapped with no remaining reference to free it.
Fix by using goto out_bo so the error path properly cleans up the BO, consistent with the other error handling in the same function.
--- drivers/gpu/drm/xe/xe_gsc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/xe/xe_gsc.c +1 -1
@@ -163,7 +163,7 @@ static int query_compatibility_version(struct xe_gsc *gsc) &rd_offset);if (err) {xe_gt_err (gt,"HuC: invalid GSC reply for version query (err=%d)\n" , err); -return err; + goto out_bo; } compat->major =version_query_rd (xe, &bo->vmap, rd_offset, proj_major);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 583/666 page_pool: Set `dma_sync` to false for devmem memory provider
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Samiullah Khawaja <[email protected]>
[ Upstream commit b400f4b87430c105d92550cee5a72aea01fdf3d6 ]
Move the dma_map and dma_sync checks to page_pool_init to make them generic. Set dma_sync to false for devmem memory provider because the dma_sync APIs should not be used for dma_buf backed devmem memory provider.
Stable-dep-of: 5ef343614db7 ("page_pool: fix memory-provider leak in page_pool_create_percpu() error path")
--- net/core/devmem.c | 9 ++++----- net/core/page_pool.c | 3 +++ 2 files changed, 7 insertions(+), 5 deletions(-)
net/core/devmem.c +4 -5
@@ -333,11 +333,10 @@ int mp_dmabuf_devmem_init(struct page_pool *pool)if (!binding)return -EINVAL ; -if (!pool->dma_map) -return -EOPNOTSUPP ; - -if (pool->dma_sync) -return -EOPNOTSUPP ; +/* dma-buf dma addresses do not need and should not be used with +* dma_sync_for_cpu/device. Force disable dma_sync. +*/ + pool->dma_sync = false;if (pool->p.order !=0 )return -E2BIG ;
net/core/page_pool.c +3 -0
@@ -283,6 +283,9 @@ static int page_pool_init(struct page_pool *pool, }if (pool->mp_priv) { +if (!pool->dma_map || !pool->dma_sync) +return -EOPNOTSUPP ; + err =mp_dmabuf_devmem_init (pool);if (err) { pr_warn("%s() mem-provider init failed %d\n", __func__,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 584/666 net: page_pool: create hooks for custom memory providers
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pavel Begunkov <[email protected]>
[ Upstream commit 57afb483015768903029c8336ee287f4b03c1235 ]
A spin off from the original page pool memory providers patch by Jakub, which allows extending page pools with custom allocators. One of such providers is devmem TCP, and the other is io_uring zerocopy added in following patches.
Stable-dep-of: 5ef343614db7 ("page_pool: fix memory-provider leak in page_pool_create_percpu() error path")
--- include/net/page_pool/memory_provider.h | 15 +++++++++++++++ include/net/page_pool/types.h | 4 ++++ net/core/devmem.c | 15 ++++++++++++++- net/core/page_pool.c | 23 +++++++++++++++-------- 4 files changed, 48 insertions(+), 9 deletions(-) create mode 100644 include/net/page_pool/memory_provider.h
include/net/page_pool/memory_provider.h new file +15 -0
@@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _NET_PAGE_POOL_MEMORY_PROVIDER_H +#define _NET_PAGE_POOL_MEMORY_PROVIDER_H + +#include <net/netmem.h> +#include <net/page_pool/types.h> + +struct memory_provider_ops { +netmem_ref (*alloc_netmems)(struct page_pool *pool,gfp_t gfp); +bool (*release_netmem)(struct page_pool *pool,netmem_ref netmem); +int (*init)(struct page_pool *pool); +void (*destroy)(struct page_pool *pool); +}; + +#endif
include/net/page_pool/types.h +4 -0
@@ -156,8 +156,11 @@ struct page_pool_stats {*/ #define PAGE_POOL_FRAG_GROUP_ALIGN (4 * sizeof(long)) +struct memory_provider_ops ; +struct pp_memory_provider_params {void *mp_priv; +const struct memory_provider_ops *mp_ops; };struct page_pool {
@@ -219,6 +222,7 @@ struct page_pool {struct ptr_ring ring;void *mp_priv; +const struct memory_provider_ops *mp_ops;struct xarray dma_mapped;
net/core/devmem.c +14 -1
@@ -15,6 +15,7 @@#include <net/netdev_queues.h> #include <net/netdev_rx_queue.h> #include <net/page_pool/helpers.h> +#include <net/page_pool/memory_provider.h> #include <trace/events/page_pool.h> #include "devmem.h"
@@ -26,6 +27,8 @@/* Protected by rtnl_lock() */ static DEFINE_XARRAY_FLAGS(net_devmem_dmabuf_bindings, XA_FLAGS_ALLOC1); +static const struct memory_provider_ops dmabuf_devmem_ops; +static void net_devmem_dmabuf_free_chunk_owner (struct gen_pool *genpool,struct gen_pool_chunk *chunk,void *not_used)
@@ -117,6 +120,7 @@ void net_devmem_unbind_dmabuf(struct net_devmem_dmabuf_binding *binding)WARN_ON (rxq->mp_params.mp_priv != binding); rxq->mp_params.mp_priv =NULL ; + rxq->mp_params.mp_ops =NULL ; rxq_idx =get_netdev_rx_queue_index (rxq);
@@ -143,7 +147,7 @@ int net_devmem_bind_dmabuf_to_queue(struct net_device *dev, u32 rxq_idx, } rxq =__netif_get_rx_queue (dev, rxq_idx); -if (rxq->mp_params.mp_priv) { +if (rxq->mp_params.mp_ops) {NL_SET_ERR_MSG (extack,"designated queue already memory provider bound" );return -EEXIST ; }
@@ -161,6 +165,7 @@ int net_devmem_bind_dmabuf_to_queue(struct net_device *dev, u32 rxq_idx,return err; rxq->mp_params.mp_priv = binding; + rxq->mp_params.mp_ops = &dmabuf_devmem_ops; err =netdev_rx_queue_restart (dev, rxq_idx);if (err)
@@ -170,6 +175,7 @@ int net_devmem_bind_dmabuf_to_queue(struct net_device *dev, u32 rxq_idx, err_xa_erase: rxq->mp_params.mp_priv =NULL ; + rxq->mp_params.mp_ops =NULL ;xa_erase (&binding->bound_rxqs, xa_idx);return err;
@@ -388,3 +394,10 @@ bool mp_dmabuf_devmem_release_page(struct page_pool *pool, netmem_ref netmem)/* We don't want the page pool put_page()ing our net_iovs. */ return false; } + +static const struct memory_provider_ops dmabuf_devmem_ops = { + .init = mp_dmabuf_devmem_init, + .destroy = mp_dmabuf_devmem_destroy, + .alloc_netmems = mp_dmabuf_devmem_alloc_netmems, + .release_netmem = mp_dmabuf_devmem_release_page, +};
net/core/page_pool.c +15 -8
@@ -13,6 +13,7 @@#include <net/netdev_rx_queue.h> #include <net/page_pool/helpers.h> +#include <net/page_pool/memory_provider.h> #include <net/xdp.h> #include <linux/dma-direction.h>
@@ -280,13 +281,19 @@ static int page_pool_init(struct page_pool *pool, rxq =__netif_get_rx_queue (pool->slow.netdev, pool->slow.queue_idx); pool->mp_priv = rxq->mp_params.mp_priv; + pool->mp_ops = rxq->mp_params.mp_ops; } -if (pool->mp_priv) { +if (pool->mp_ops) {if (!pool->dma_map || !pool->dma_sync)return -EOPNOTSUPP ; - err =mp_dmabuf_devmem_init (pool); +if (WARN_ON (!is_kernel_rodata ((unsigned long )pool->mp_ops))) { + err = -EFAULT ; + goto free_ptr_ring; + } + + err = pool->mp_ops->init (pool);if (err) {pr_warn ("%s() mem-provider init failed %d\n" , __func__, err);
@@ -651,8 +658,8 @@ netmem_ref page_pool_alloc_netmem(struct page_pool *pool, gfp_t gfp)return netmem;/* Slow-path: cache empty, do real allocation */ -if (static_branch_unlikely (&page_pool_mem_providers) && pool->mp_priv) - netmem =mp_dmabuf_devmem_alloc_netmems (pool, gfp); +if (static_branch_unlikely (&page_pool_mem_providers) && pool->mp_ops) + netmem = pool->mp_ops->alloc_netmems (pool, gfp);else netmem =__page_pool_alloc_pages_slow (pool, gfp);return netmem;
@@ -746,8 +753,8 @@ void page_pool_return_page(struct page_pool *pool, netmem_ref netmem)bool put; put = true; -if (static_branch_unlikely (&page_pool_mem_providers) && pool->mp_priv) - put =mp_dmabuf_devmem_release_page (pool, netmem); +if (static_branch_unlikely (&page_pool_mem_providers) && pool->mp_ops) + put = pool->mp_ops->release_netmem (pool, netmem);else __page_pool_release_page_dma (pool, netmem);
@@ -1081,8 +1088,8 @@ static void __page_pool_destroy(struct page_pool *pool)page_pool_unlist (pool);page_pool_uninit (pool); -if (pool->mp_priv) { -mp_dmabuf_devmem_destroy (pool); +if (pool->mp_ops) { + pool->mp_ops->destroy (pool);static_branch_dec (&page_pool_mem_providers); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 585/666 page_pool: fix memory-provider leak in page_pool_create_percpu() error path
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hasan Basbunar <[email protected]>
[ Upstream commit 5ef343614db766acdc01c56d66e780a1b43c6ac6 ]
When page_pool_create_percpu() fails on page_pool_list(), it falls through to its err_uninit: label, which calls page_pool_uninit(). At that point page_pool_init() has already taken two references when the user requested PP_FLAG_ALLOW_UNREADABLE_NETMEM:
pool->mp_ops->init(pool) static_branch_inc(&page_pool_mem_providers);
Neither is undone by page_pool_uninit(); both are only undone by __page_pool_destroy() (success-side teardown). The error path therefore leaks the per-provider reference taken by mp_ops->init (io_zcrx_ifq->refs in the io_uring zcrx provider, the dmabuf binding refcount in the devmem provider) plus one increment of the page_pool_mem_providers static branch on every failure of xa_alloc_cyclic() inside page_pool_list().
The leaked io_zcrx_ifq->refs in turn pins everything io_zcrx_ifq_free() would release on cleanup: ifq->user (uid), ifq->mm_account (mmdrop), ifq->dev (device refcount), ifq->netdev_tracker (netdev refcount), and the rbuf region. The leaked static branch increment forces all subsequent page_pool_alloc_netmems() and page_pool_return_page() callers to take the slow mp_ops branch for the lifetime of the kernel.
Reachable via the io_uring zcrx path:
io_uring_register(IORING_REGISTER_ZCRX_IFQ) /* CAP_NET_ADMIN */ -> __io_uring_register -> io_register_zcrx -> zcrx_register_netdev -> netif_mp_open_rxq -> driver ndo_queue_mem_alloc -> page_pool_create_percpu -> page_pool_init succeeds (mp_ops->init runs, branch++) -> page_pool_list fails (xa_alloc_cyclic -ENOMEM) -> goto err_uninit <-- leak
The same shape applies to the devmem dmabuf provider via mp_dmabuf_devmem_init()/mp_dmabuf_devmem_destroy().
Restore the cleanup symmetry by moving the mp_ops->destroy() and static_branch_dec() calls out of __page_pool_destroy() and into page_pool_uninit(), so page_pool_uninit() is again the strict inverse of page_pool_init(). page_pool_uninit() has only two callers (the err_uninit: path and __page_pool_destroy()), so this preserves the single-call invariant on the success path while fixing the err path. The error path of page_pool_init() itself still skips the mp_ops cleanup correctly: mp_ops->init is the last action that takes a reference before page_pool_init() returns 0, so when it returns an error neither the refcount nor the static branch has been touched.
Triggering the bug requires xa_alloc_cyclic() to fail with -ENOMEM, which under normal GFP_KERNEL retry behaviour is rare. It is deterministic under CONFIG_FAULT_INJECTION with fail_page_alloc / xa fault injection, or under sustained memory pressure. The leak is silent: there is no warning, and the released kernel build continues running with a permanently-incremented static branch.
--- net/core/page_pool.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
net/core/page_pool.c +5 -5
@@ -323,6 +323,11 @@ static void page_pool_uninit(struct page_pool *pool)if (!pool->system)free_percpu (pool->recycle_stats);#endif + +if (pool->mp_ops) { + pool->mp_ops->destroy (pool); +static_branch_dec (&page_pool_mem_providers); + } }/**
@@ -1088,11 +1093,6 @@ static void __page_pool_destroy(struct page_pool *pool)page_pool_unlist (pool);page_pool_uninit (pool); -if (pool->mp_ops) { - pool->mp_ops->destroy (pool); -static_branch_dec (&page_pool_mem_providers); - } -kfree (pool); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 586/666 iavf: rename IAVF_VLAN_IS_NEW to IAVF_VLAN_ADDING
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Petr Oros <[email protected]>
[ Upstream commit 70d62b669f1f9080a25278fc90b64309f4ae8959 ]
Rename the IAVF_VLAN_IS_NEW state to IAVF_VLAN_ADDING to better describe what the state represents: an ADD request has been sent to the PF and is waiting for a response.
This is a pure rename with no behavioral change, preparing for a cleanup of the VLAN filter state machine.
Stable-dep-of: f2ce65b9b917 ("iavf: stop removing VLAN filters from PF on interface down")
--- drivers/net/ethernet/intel/iavf/iavf.h | 2 +- drivers/net/ethernet/intel/iavf/iavf_virtchnl.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-)
drivers/net/ethernet/intel/iavf/iavf.h +1 -1
@@ -158,7 +158,7 @@ struct iavf_vlan {enum iavf_vlan_state_t {IAVF_VLAN_INVALID ,IAVF_VLAN_ADD ,/* filter needs to be added */ -IAVF_VLAN_IS_NEW ,/* filter is new, wait for PF answer */ +IAVF_VLAN_ADDING ,/* ADD sent to PF, waiting for response */ IAVF_VLAN_ACTIVE ,/* filter is accepted by PF */ IAVF_VLAN_DISABLE ,/* filter needs to be deleted by PF, then marked INACTIVE */ IAVF_VLAN_INACTIVE ,/* filter is inactive, we are in IFF_DOWN */
drivers/net/ethernet/intel/iavf/iavf_virtchnl.c +4 -4
@@ -636,7 +636,7 @@ static void iavf_vlan_add_reject(struct iavf_adapter *adapter)spin_lock_bh (&adapter->mac_vlan_list_lock);list_for_each_entry_safe (f, ftmp, &adapter->vlan_filter_list, list) { -if (f->state ==IAVF_VLAN_IS_NEW ) { +if (f->state ==IAVF_VLAN_ADDING ) {list_del (&f->list);kfree (f); adapter->num_vlan_filters--;
@@ -701,7 +701,7 @@ void iavf_add_vlans(struct iavf_adapter *adapter)if (f->state ==IAVF_VLAN_ADD ) { vvfl->vlan_id[i] = f->vlan.vid; i++; - f->state =IAVF_VLAN_IS_NEW ; + f->state =IAVF_VLAN_ADDING ;if (i == count)break ; }
@@ -762,7 +762,7 @@ void iavf_add_vlans(struct iavf_adapter *adapter) vlan->tpid = f->vlan.tpid; i++; - f->state =IAVF_VLAN_IS_NEW ; + f->state =IAVF_VLAN_ADDING ; } }
@@ -2549,7 +2549,7 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,spin_lock_bh (&adapter->mac_vlan_list_lock);list_for_each_entry (f, &adapter->vlan_filter_list, list) { -if (f->state ==IAVF_VLAN_IS_NEW ) +if (f->state ==IAVF_VLAN_ADDING ) f->state =IAVF_VLAN_ACTIVE ; }spin_unlock_bh (&adapter->mac_vlan_list_lock);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 587/666 iavf: stop removing VLAN filters from PF on interface down
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Petr Oros <[email protected]>
[ Upstream commit f2ce65b9b917474a1a6ce68d357e15fac2aca0f2 ]
When a VF goes down, the driver currently sends DEL_VLAN to the PF for every VLAN filter (ACTIVE -> DISABLE -> send DEL -> INACTIVE), then re-adds them all on UP (INACTIVE -> ADD -> send ADD -> ADDING -> ACTIVE). This round-trip is unnecessary because:
1. The PF disables the VF's queues via VIRTCHNL_OP_DISABLE_QUEUES, which already prevents all RX/TX traffic regardless of VLAN filter state.
2. The VLAN filters remaining in PF HW while the VF is down is harmless - packets matching those filters have nowhere to go with queues disabled.
3. The DEL+ADD cycle during down/up creates race windows where the VLAN filter list is incomplete. With spoofcheck enabled, the PF enables TX VLAN filtering on the first non-zero VLAN add, blocking traffic for any VLANs not yet re-added.
Remove the entire DISABLE/INACTIVE state machinery:
- Remove IAVF_VLAN_DISABLE and IAVF_VLAN_INACTIVE enum values
- Remove iavf_restore_filters() and its call from iavf_open()
- Remove VLAN filter handling from iavf_clear_mac_vlan_filters(), rename it to iavf_clear_mac_filters()
- Remove DEL_VLAN_FILTER scheduling from iavf_down()
- Remove all DISABLE/INACTIVE handling from iavf_del_vlans()
VLAN filters now stay ACTIVE across down/up cycles. Only explicit user removal (ndo_vlan_rx_kill_vid) or PF/VF reset triggers VLAN filter deletion/re-addition.
--- drivers/net/ethernet/intel/iavf/iavf.h | 6 +-- drivers/net/ethernet/intel/iavf/iavf_main.c | 39 ++----------------- .../net/ethernet/intel/iavf/iavf_virtchnl.c | 33 +++------------- 3 files changed, 12 insertions(+), 66 deletions(-)
drivers/net/ethernet/intel/iavf/iavf.h +2 -4
@@ -159,10 +159,8 @@ enum iavf_vlan_state_t {IAVF_VLAN_INVALID ,IAVF_VLAN_ADD ,/* filter needs to be added */ IAVF_VLAN_ADDING ,/* ADD sent to PF, waiting for response */ -IAVF_VLAN_ACTIVE ,/* filter is accepted by PF */ -IAVF_VLAN_DISABLE ,/* filter needs to be deleted by PF, then marked INACTIVE */ -IAVF_VLAN_INACTIVE ,/* filter is inactive, we are in IFF_DOWN */ - IAVF_VLAN_REMOVE, /* filter needs to be removed from list */ +IAVF_VLAN_ACTIVE ,/* PF confirmed, filter is in HW */ + IAVF_VLAN_REMOVE, /* filter queued for DEL from PF */ }; struct iavf_vlan_filter {
drivers/net/ethernet/intel/iavf/iavf_main.c +4 -35
@@ -818,27 +818,6 @@ static void iavf_del_vlan(struct iavf_adapter *adapter, struct iavf_vlan vlan)spin_unlock_bh (&adapter->mac_vlan_list_lock); } -/** -* iavf_restore_filters -* @adapter: board private structure -* -* Restore existing non MAC filters when VF netdev comes back up -**/ -static void iavf_restore_filters (struct iavf_adapter *adapter) -{ -struct iavf_vlan_filter *f; - -/* re-add all VLAN filters */ -spin_lock_bh (&adapter->mac_vlan_list_lock); - -list_for_each_entry (f, &adapter->vlan_filter_list, list) { -if (f->state ==IAVF_VLAN_INACTIVE ) - f->state =IAVF_VLAN_ADD ; - } - -spin_unlock_bh (&adapter->mac_vlan_list_lock); - adapter->aq_required |=IAVF_FLAG_AQ_ADD_VLAN_FILTER ; -}/** * iavf_get_num_vlans_added - get number of VLANs added
@@ -1257,13 +1236,12 @@ static void iavf_up_complete(struct iavf_adapter *adapter) }/** -* iavf_clear_mac_vlan_filters - Remove mac and vlan filters not sent to PF -* yet and mark other to be removed. +* iavf_clear_mac_filters - Remove MAC filters not sent to PF yet and mark +* others to be removed. * @adapter: board private structure **/ -static void iavf_clear_mac_vlan_filters (struct iavf_adapter *adapter) +static void iavf_clear_mac_filters (struct iavf_adapter *adapter) { -struct iavf_vlan_filter *vlf, *vlftmp;struct iavf_mac_filter *f, *ftmp;spin_lock_bh (&adapter->mac_vlan_list_lock);
@@ -1282,11 +1260,6 @@ static void iavf_clear_mac_vlan_filters(struct iavf_adapter *adapter) } } -/* disable all VLAN filters */ -list_for_each_entry_safe (vlf, vlftmp, &adapter->vlan_filter_list, - list) - vlf->state =IAVF_VLAN_DISABLE ; -spin_unlock_bh (&adapter->mac_vlan_list_lock); }
@@ -1382,7 +1355,7 @@ void iavf_down(struct iavf_adapter *adapter)iavf_napi_disable_all (adapter);iavf_irq_disable (adapter); -iavf_clear_mac_vlan_filters (adapter); +iavf_clear_mac_filters (adapter);iavf_clear_cloud_filters (adapter);iavf_clear_fdir_filters (adapter);iavf_clear_adv_rss_conf (adapter);
@@ -1399,8 +1372,6 @@ void iavf_down(struct iavf_adapter *adapter)*/ if (!list_empty (&adapter->mac_filter_list)) adapter->aq_required |=IAVF_FLAG_AQ_DEL_MAC_FILTER ; -if (!list_empty (&adapter->vlan_filter_list)) - adapter->aq_required |=IAVF_FLAG_AQ_DEL_VLAN_FILTER ;if (!list_empty (&adapter->cloud_filter_list)) adapter->aq_required |=IAVF_FLAG_AQ_DEL_CLOUD_FILTER ;if (!list_empty (&adapter->fdir_list_head))
@@ -4363,8 +4334,6 @@ static int iavf_open(struct net_device *netdev)spin_unlock_bh (&adapter->mac_vlan_list_lock); -/* Restore filters that were removed with IFF_DOWN */ -iavf_restore_filters (adapter);iavf_restore_fdir_filters (adapter);iavf_configure (adapter);
drivers/net/ethernet/intel/iavf/iavf_virtchnl.c +6 -27
@@ -799,22 +799,12 @@ void iavf_del_vlans(struct iavf_adapter *adapter)spin_lock_bh (&adapter->mac_vlan_list_lock);list_for_each_entry_safe (f, ftmp, &adapter->vlan_filter_list, list) { -/* since VLAN capabilities are not allowed, we dont want to send -* a VLAN delete request because it will most likely fail and -* create unnecessary errors/noise, so just free the VLAN -* filters marked for removal to enable bailing out before -* sending a virtchnl message -*/ if (f->state ==IAVF_VLAN_REMOVE && !VLAN_FILTERING_ALLOWED (adapter)) {list_del (&f->list);kfree (f); adapter->num_vlan_filters--; - }else if (f->state ==IAVF_VLAN_DISABLE && - !VLAN_FILTERING_ALLOWED (adapter)) { - f->state =IAVF_VLAN_INACTIVE ; - }else if (f->state ==IAVF_VLAN_REMOVE || - f->state ==IAVF_VLAN_DISABLE ) { + }else if (f->state ==IAVF_VLAN_REMOVE ) { count++; } }
@@ -846,13 +836,7 @@ void iavf_del_vlans(struct iavf_adapter *adapter) vvfl->vsi_id = adapter->vsi_res->vsi_id; vvfl->num_elements = count;list_for_each_entry_safe (f, ftmp, &adapter->vlan_filter_list, list) { -if (f->state ==IAVF_VLAN_DISABLE ) { - vvfl->vlan_id[i] = f->vlan.vid; - f->state =IAVF_VLAN_INACTIVE ; - i++; -if (i == count) -break ; - }else if (f->state ==IAVF_VLAN_REMOVE ) { +if (f->state ==IAVF_VLAN_REMOVE ) { vvfl->vlan_id[i] = f->vlan.vid;list_del (&f->list);kfree (f);
@@ -893,8 +877,7 @@ void iavf_del_vlans(struct iavf_adapter *adapter) vvfl_v2->vport_id = adapter->vsi_res->vsi_id; vvfl_v2->num_elements = count;list_for_each_entry_safe (f, ftmp, &adapter->vlan_filter_list, list) { -if (f->state ==IAVF_VLAN_DISABLE || - f->state ==IAVF_VLAN_REMOVE ) { +if (f->state ==IAVF_VLAN_REMOVE ) {struct virtchnl_vlan_supported_caps *filtering_support = &adapter->vlan_v2_caps.filtering.filtering_support;struct virtchnl_vlan *vlan;
@@ -908,13 +891,9 @@ void iavf_del_vlans(struct iavf_adapter *adapter) vlan->tci = f->vlan.vid; vlan->tpid = f->vlan.tpid; -if (f->state ==IAVF_VLAN_DISABLE ) { - f->state =IAVF_VLAN_INACTIVE ; - }else { -list_del (&f->list); -kfree (f); - adapter->num_vlan_filters--; - } +list_del (&f->list); +kfree (f); + adapter->num_vlan_filters--; i++;if (i == count)break ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 588/666 iavf: wait for PF confirmation before removing VLAN filters
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Petr Oros <[email protected]>
[ Upstream commit bbcbe4ed70dea948849549af7edf44bd42bbd695 ]
The VLAN filter DELETE path was asymmetric with the ADD path: ADD waits for PF confirmation (ADD -> ADDING -> ACTIVE), but DELETE immediately frees the filter struct after sending the DEL message without waiting for the PF response.
This is problematic because:
- If the PF rejects the DEL, the filter remains in HW but the driver has already freed the tracking structure, losing sync.
- Race conditions between DEL pending and other operations (add, reset) cannot be properly resolved if the filter struct is already gone.
Add IAVF_VLAN_REMOVING state to make the DELETE path symmetric:
REMOVE -> REMOVING (send DEL) -> PF confirms -> kfree
-> PF rejects -> ACTIVE
In iavf_del_vlans(), transition filters from REMOVE to REMOVING instead of immediately freeing them. The new DEL completion handler in iavf_virtchnl_completion() frees filters on success or reverts them to ACTIVE on error.
Update iavf_add_vlan() to handle the REMOVING state: if a DEL is pending and the user re-adds the same VLAN, queue it for ADD so it gets re-programmed after the PF processes the DEL.
The !VLAN_FILTERING_ALLOWED early-exit path still frees filters directly since no PF message is sent in that case.
Also update iavf_del_vlan() to skip filters already in REMOVING
state: DEL has been sent to PF and the completion handler will free the filter when PF confirms. Without this guard, the sequence DEL(pending) -> user-del -> second DEL could cause the PF to return an error for the second DEL (filter already gone), causing the completion handler to incorrectly revert a deleted filter back to ACTIVE.
--- drivers/net/ethernet/intel/iavf/iavf.h | 1 + drivers/net/ethernet/intel/iavf/iavf_main.c | 13 ++++--- .../net/ethernet/intel/iavf/iavf_virtchnl.c | 37 +++++++++++++------ 3 files changed, 34 insertions(+), 17 deletions(-)
drivers/net/ethernet/intel/iavf/iavf.h +1 -0
@@ -161,6 +161,7 @@ enum iavf_vlan_state_t {IAVF_VLAN_ADDING ,/* ADD sent to PF, waiting for response */ IAVF_VLAN_ACTIVE ,/* PF confirmed, filter is in HW */ IAVF_VLAN_REMOVE ,/* filter queued for DEL from PF */ + IAVF_VLAN_REMOVING, /* DEL sent to PF, waiting for response */ }; struct iavf_vlan_filter {
drivers/net/ethernet/intel/iavf/iavf_main.c +8 -5
@@ -774,10 +774,10 @@ iavf_vlan_filter *iavf_add_vlan(struct iavf_adapter *adapter, adapter->num_vlan_filters++;iavf_schedule_aq_request (adapter,IAVF_FLAG_AQ_ADD_VLAN_FILTER ); }else if (f->state ==IAVF_VLAN_REMOVE ) { -/* Re-add the filter since we cannot tell whether the -* pending delete has already been processed by the PF. -* A duplicate add is harmless. -*/ +/* DEL not yet sent to PF, cancel it */ + f->state =IAVF_VLAN_ACTIVE ; + }else if (f->state ==IAVF_VLAN_REMOVING ) { +/* DEL already sent to PF, re-add after completion */ f->state =IAVF_VLAN_ADD ;iavf_schedule_aq_request (adapter,IAVF_FLAG_AQ_ADD_VLAN_FILTER );
@@ -808,11 +808,14 @@ static void iavf_del_vlan(struct iavf_adapter *adapter, struct iavf_vlan vlan)list_del (&f->list);kfree (f); adapter->num_vlan_filters--; - }else { + }else if (f->state !=IAVF_VLAN_REMOVING ) { f->state =IAVF_VLAN_REMOVE ;iavf_schedule_aq_request (adapter,IAVF_FLAG_AQ_DEL_VLAN_FILTER ); } +/* If REMOVING, DEL is already sent to PF; completion +* handler will free the filter when PF confirms. +*/ }spin_unlock_bh (&adapter->mac_vlan_list_lock);
drivers/net/ethernet/intel/iavf/iavf_virtchnl.c +25 -12
@@ -835,12 +835,10 @@ void iavf_del_vlans(struct iavf_adapter *adapter) vvfl->vsi_id = adapter->vsi_res->vsi_id; vvfl->num_elements = count; -list_for_each_entry_safe (f, ftmp, &adapter->vlan_filter_list, list) { +list_for_each_entry (f, &adapter->vlan_filter_list, list) {if (f->state ==IAVF_VLAN_REMOVE ) { vvfl->vlan_id[i] = f->vlan.vid; -list_del (&f->list); -kfree (f); - adapter->num_vlan_filters--; + f->state =IAVF_VLAN_REMOVING ; i++;if (i == count)break ;
@@ -876,7 +874,7 @@ void iavf_del_vlans(struct iavf_adapter *adapter) vvfl_v2->vport_id = adapter->vsi_res->vsi_id; vvfl_v2->num_elements = count; -list_for_each_entry_safe (f, ftmp, &adapter->vlan_filter_list, list) { +list_for_each_entry (f, &adapter->vlan_filter_list, list) {if (f->state ==IAVF_VLAN_REMOVE ) {struct virtchnl_vlan_supported_caps *filtering_support = &adapter->vlan_v2_caps.filtering.filtering_support;
@@ -891,9 +889,7 @@ void iavf_del_vlans(struct iavf_adapter *adapter) vlan->tci = f->vlan.vid; vlan->tpid = f->vlan.tpid; -list_del (&f->list); -kfree (f); - adapter->num_vlan_filters--; + f->state =IAVF_VLAN_REMOVING ; i++;if (i == count)break ;
@@ -2040,10 +2036,6 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,ether_addr_copy (adapter->hw.mac.addr, netdev->dev_addr);wake_up (&adapter->vc_waitqueue);break ; -case VIRTCHNL_OP_DEL_VLAN : -dev_err (&adapter->pdev->dev,"Failed to delete VLAN filter, error %s\n" , -iavf_stat_str (&adapter->hw, v_retval)); -break ;case VIRTCHNL_OP_DEL_ETH_ADDR :dev_err (&adapter->pdev->dev,"Failed to delete MAC filter, error %s\n" ,iavf_stat_str (&adapter->hw, v_retval));
@@ -2534,6 +2526,27 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,spin_unlock_bh (&adapter->mac_vlan_list_lock); }break ; +case VIRTCHNL_OP_DEL_VLAN : +case VIRTCHNL_OP_DEL_VLAN_V2 : { +struct iavf_vlan_filter *f, *ftmp; + +spin_lock_bh (&adapter->mac_vlan_list_lock); +list_for_each_entry_safe (f, ftmp, &adapter->vlan_filter_list, + list) { +if (f->state ==IAVF_VLAN_REMOVING ) { +if (v_retval) { +/* PF rejected DEL, keep filter */ + f->state =IAVF_VLAN_ACTIVE ; + }else { +list_del (&f->list); +kfree (f); + adapter->num_vlan_filters--; + } + } + } +spin_unlock_bh (&adapter->mac_vlan_list_lock); + } +break ;case VIRTCHNL_OP_ENABLE_VLAN_STRIPPING :/* PF enabled vlan strip on this VF. * Update netdev->features if needed to be in sync with ethtool.
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 589/666 iavf: add VIRTCHNL_OP_ADD_VLAN to success completion handler
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Petr Oros <[email protected]>
[ Upstream commit 34d33313b52eeac3a97ad2e3176d523ec70d9283 ]
The V1 ADD_VLAN opcode had no success handler; filters sent via V1 stayed in ADDING state permanently. Add a fallthrough case so V1 filters also transition ADDING -> ACTIVE on PF confirmation.
Critically, add an if (v_retval) break guard: the error switch in iavf_virtchnl_completion() does NOT return after handling errors, it falls through to the success switch. Without this guard, a PF-rejected ADD would incorrectly mark ADDING filters as ACTIVE, creating a driver/HW mismatch where the driver believes the filter is installed but the PF never accepted it.
For V2, this is harmless: iavf_vlan_add_reject() in the error block already kfree'd all ADDING filters, so the success handler finds nothing to transition.
--- drivers/net/ethernet/intel/iavf/iavf_virtchnl.c | 4 ++++ 1 file changed, 4 insertions(+)
drivers/net/ethernet/intel/iavf/iavf_virtchnl.c +4 -0
@@ -2515,9 +2515,13 @@ void iavf_virtchnl_completion(struct iavf_adapter *adapter,spin_unlock_bh (&adapter->adv_rss_lock); }break ; +case VIRTCHNL_OP_ADD_VLAN :case VIRTCHNL_OP_ADD_VLAN_V2 : {struct iavf_vlan_filter *f; +if (v_retval) +break ; +spin_lock_bh (&adapter->mac_vlan_list_lock);list_for_each_entry (f, &adapter->vlan_filter_list, list) {if (f->state ==IAVF_VLAN_ADDING )
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 590/666 ice: fix NULL pointer dereference in ice_reset_all_vfs()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Petr Oros <[email protected]>
[ Upstream commit 54ef02487914c24170c7e1c061e45212dc55365e ]
ice_reset_all_vfs() ignores the return value of ice_vf_rebuild_vsi(). When the VSI rebuild fails (e.g. during NVM firmware update via nvmupdate64e), ice_vsi_rebuild() tears down the VSI on its error path, leaving txq_map and rxq_map as NULL. The subsequent unconditional call to ice_vf_post_vsi_rebuild() leads to a NULL pointer dereference in ice_ena_vf_q_mappings() when it accesses vsi->txq_map[0].
The single-VF reset path in ice_reset_vf() already handles this correctly by checking the return value of ice_vf_reconfig_vsi() and skipping ice_vf_post_vsi_rebuild() on failure.
Apply the same pattern to ice_reset_all_vfs(): check the return value of ice_vf_rebuild_vsi() and skip ice_vf_post_vsi_rebuild() and ice_eswitch_attach_vf() on failure. The VF is left safely disabled (ICE_VF_STATE_INIT not set, VFGEN_RSTAT not set to VFACTIVE) and can be recovered via a VFLR triggered by a PCI reset of the VF (sysfs reset or driver rebind).
Note that this patch does not prevent the VF VSI rebuild from failing during NVM update — the underlying cause is firmware being in a transitional state while the EMP reset is processed, which can cause Admin Queue commands (ice_add_vsi, ice_cfg_vsi_lan) to fail. This patch only prevents the subsequent NULL pointer dereference that crashes the kernel when the rebuild does fail.
crash> bt
PID: 50795 TASK: ff34c9ee708dc680 CPU: 1 COMMAND: "kworker/u512:5"
#0 [ff72159bcfe5bb50] machine_kexec at ffffffffaa8850ee
#1 [ff72159bcfe5bba8] __crash_kexec at ffffffffaaa15fba
#2 [ff72159bcfe5bc68] crash_kexec at ffffffffaaa16540
#3 [ff72159bcfe5bc70] oops_end at ffffffffaa837eda
#4 [ff72159bcfe5bc90] page_fault_oops at ffffffffaa893997
#5 [ff72159bcfe5bce8] exc_page_fault at ffffffffab528595
#6 [ff72159bcfe5bd10] asm_exc_page_fault at ffffffffab600bb2
[exception RIP: ice_ena_vf_q_mappings+0x79]
RIP: ffffffffc0a85b29 RSP: ff72159bcfe5bdc8 RFLAGS: 00010206
RAX: 00000000000f0000 RBX: ff34c9efc9c00000 RCX: 0000000000000000
RDX: 0000000000000000 RSI: 0000000000000010 RDI: ff34c9efc9c00000
RBP: ff34c9efc27d4828 R8: 0000000000000093 R9: 0000000000000040
R10: ff34c9efc27d4828 R11: 0000000000000040 R12: 0000000000100000
R13: 0000000000000010 R14: R15:
ORIG_RAX: ffffffffffffffff CS: 0010 SS: 0018
#7 [ff72159bcfe5bdf8] ice_sriov_post_vsi_rebuild at ffffffffc0a85e2e [ice]
#8 [ff72159bcfe5be08] ice_reset_all_vfs at ffffffffc0a920b4 [ice]
#9 [ff72159bcfe5be48] ice_service_task at ffffffffc0a31519 [ice]
#10 [ff72159bcfe5be88] process_one_work at ffffffffaa93dca4
#11 [ff72159bcfe5bec8] worker_thread at ffffffffaa93e9de
#12 [ff72159bcfe5bf18] kthread at ffffffffaa946663
#13 [ff72159bcfe5bf50] ret_from_fork at ffffffffaa8086b9 The panic occurs attempting to dereference the NULL pointer in RDX at ice_sriov.c:294, which loads vsi->txq_map (offset 0x4b8 in ice_vsi).
The faulting VSI is an allocated slab object but not fully initialized after a failed ice_vsi_rebuild():
crash> struct ice_vsi 0xff34c9efc27d4828
netdev = 0x0,
rx_rings = 0x0,
tx_rings = 0x0,
q_vectors = 0x0,
txq_map = 0x0,
rxq_map = 0x0,
alloc_txq = 0x10,
num_txq = 0x10,
alloc_rxq = 0x10,
num_rxq = 0x10,The nvmupdate64e process was performing NVM firmware update:
crash> bt 0xff34c9edd1a30000
PID: 49858 TASK: ff34c9edd1a30000 CPU: 1 COMMAND: "nvmupdate64e"
#0 [ff72159bcd617618] __schedule at ffffffffab5333f8
#4 [ff72159bcd617750] ice_sq_send_cmd at ffffffffc0a35347 [ice] #5 [ff72159bcd6177a8] ice_sq_send_cmd_retry at ffffffffc0a35b47 [ice] #6 [ff72159bcd617810] ice_aq_send_cmd at ffffffffc0a38018 [ice] #7 [ff72159bcd617848] ice_aq_read_nvm at ffffffffc0a40254 [ice] #8 [ff72159bcd6178b8] ice_read_flat_nvm at ffffffffc0a4034c [ice] #9 [ff72159bcd617918] ice_devlink_nvm_snapshot at ffffffffc0a6ffa5 [ice]
dmesg:
ice 0000:13:00.0: firmware recommends not updating fw.mgmt, as it
may result in a downgrade. continuing anyways
ice 0000:13:00.1: ice_init_nvm failed -5
ice 0000:13:00.1: Rebuild failed, unload and reload driver
--- drivers/net/ethernet/intel/ice/ice_vf_lib.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
drivers/net/ethernet/intel/ice/ice_vf_lib.c +6 -1
@@ -803,7 +803,12 @@ void ice_reset_all_vfs(struct ice_pf *pf)ice_vf_ctrl_invalidate_vsi (vf);ice_vf_pre_vsi_rebuild (vf); -ice_vf_rebuild_vsi (vf); +if (ice_vf_rebuild_vsi (vf)) { +dev_err (dev,"VF %u VSI rebuild failed, leaving VF disabled\n" , + vf->vf_id); +mutex_unlock (&vf->cfg_lock); +continue ; + }ice_vf_post_vsi_rebuild (vf);ice_eswitch_attach_vf (pf, vf);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 591/666 net: tls: fix strparser anchor skb leak on offload RX setup failure
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jakub Kicinski <[email protected]>
[ Upstream commit 58689498ca3384851145a754dbb1d8ed1cf9fb54 ]
When tls_set_device_offload_rx() fails at tls_dev_add(), the error path calls tls_sw_free_resources_rx() to clean up the SW context that was initialized by tls_set_sw_offload(). This function calls tls_sw_release_resources_rx() (which stops the strparser via tls_strp_stop()) and tls_sw_free_ctx_rx() (which kfrees the context), but never frees the anchor skb that was allocated by alloc_skb(0) in tls_strp_init().
Note that tls_sw_free_resources_rx() is exclusively used for this "failed to start offload" code path, there's no other caller.
The leak did not exist before commit 84c61fe1a75b ("tls: rx: do not use the standard strparser"), because the standard strparser doesn't try to pre-allocate an skb.
The normal close path in tls_sk_proto_close() handles cleanup by calling tls_sw_strparser_done() (which calls tls_strp_done()) after dropping the socket lock, because tls_strp_done() does cancel_work_sync() and the strparser work handler takes the socket lock.
--- net/tls/tls.h | 1 + net/tls/tls_strp.c | 6 ++++++ net/tls/tls_sw.c | 4 ++++ 3 files changed, 11 insertions(+)
net/tls/tls.h +1 -0
@@ -186,6 +186,7 @@ int tls_strp_dev_init(void);void tls_strp_dev_exit (void );void tls_strp_done (struct tls_strparser *strp); +void __tls_strp_done (struct tls_strparser *strp);void tls_strp_stop (struct tls_strparser *strp);int tls_strp_init (struct tls_strparser *strp,struct sock *sk);void tls_strp_data_ready (struct tls_strparser *strp);
net/tls/tls_strp.c +6 -0
@@ -624,6 +624,12 @@ void tls_strp_done(struct tls_strparser *strp)WARN_ON (!strp->stopped);cancel_work_sync (&strp->work); +__tls_strp_done (strp); +} + +/* For setup error paths where the strparser was initialized but never armed. */ +void __tls_strp_done (struct tls_strparser *strp) +{tls_strp_anchor_free (strp); }
net/tls/tls_sw.c +4 -0
@@ -2591,8 +2591,12 @@ void tls_sw_free_ctx_rx(struct tls_context *tls_ctx)void tls_sw_free_resources_rx (struct sock *sk) {struct tls_context *tls_ctx =tls_get_ctx (sk); +struct tls_sw_context_rx *ctx; + + ctx =tls_sw_ctx_rx (tls_ctx);tls_sw_release_resources_rx (sk); +__tls_strp_done (&ctx->strp);tls_sw_free_ctx_rx (tls_ctx); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 592/666 sfc: fix error code in efx_devlink_info_running_versions()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dan Carpenter <[email protected]>
[ Upstream commit 051ffb001b8a232cfa6e72f38bb5f51c4270a60b ]
Return -EIO if efx_mcdi_rpc() doesn't return enough space.
--- drivers/net/ethernet/sfc/efx_devlink.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/ethernet/sfc/efx_devlink.c +1 -1
@@ -530,7 +530,7 @@ static int efx_devlink_info_running_versions(struct efx_nic *efx,if (rc || outlength <MC_CMD_GET_VERSION_OUT_LEN ) {netif_err (efx, drv, efx->net_dev,"mcdi MC_CMD_GET_VERSION failed\n" ); -return rc; +return rc ?: -EIO ; }/* Handle previous output */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 593/666 net/sched: cls_flower: revert unintended changes
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Paolo Abeni <[email protected]>
[ Upstream commit 1e01abec856593e02cd69fd95b784c10dd46880c ]
While applying the blamed commit 4ca07b9239bd ("net: mctp i2c: check length before marking flow active"), I unintentionally included unrelated and unacceptable changes.
Revert them.
--- net/sched/cls_flower.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-)
net/sched/cls_flower.c +1 -3
@@ -560,7 +560,6 @@ static int __fl_delete(struct tcf_proto *tp, struct cls_fl_filter *f, struct netlink_ext_ack *extack) {struct cls_fl_head *head =fl_head_dereference (tp); -struct fl_flow_mask *mask; *last = false;
@@ -577,12 +576,11 @@ static int __fl_delete(struct tcf_proto *tp, struct cls_fl_filter *f,list_del_rcu (&f->list);spin_unlock (&tp->lock); - mask = f->mask; + *last =fl_mask_put (head, f->mask);if (!tc_skip_hw (f->flags))fl_hw_destroy_filter (tp, f, rtnl_held, extack);tcf_unbind_filter (tp, &f->res);__fl_put (f); - *last =fl_mask_put (head, mask);return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 594/666 arm64: Reserve an extra page for early kernel mapping
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhaoyang Huang <[email protected]>
[ Upstream commit 4d8e74ad4585672489da6145b3328d415f50db82 ]
The final part of [data, end) segment may overflow into the next page of init_pg_end[1] which is the gap page before early_init_stack[2]:
[1]
crash_arm64_v9.0.1> vtop ffffffed00601000
VIRTUAL PHYSICALffffffed00601000 83401000
PAGE DIRECTORY: ffffffecffd62000
PGD: ffffffecffd62da0 => 10000000833fb003
PMD: ffffff80033fb018 => 10000000833fe003
PTE: ffffff80033fe008 => 68000083401f03
PAGE: 83401000
PTE PHYSICAL FLAGS 68000083401f03 83401000 (VALID|SHARED|AF|NG|PXN|UXN)
PAGE PHYSICAL MAPPING INDEX CNT FLAGSfffffffec00d0040 83401000 0 0 1 4000 reserved
[2]ffffffed002c8000 (r) __pi__dataffffffed0054e000 (d) __pi___bss_startffffffed005f5000 (b) __pi_init_pg_dirffffffed005fe000 (b) __pi_init_pg_endffffffed005ff000 (B) early_init_stackffffffed00608000 (b) __pi__end
For 4K pages, the early kernel mapping may use 2MB block entries but the kernel segments are only 64KB aligned. Segment boundaries that fall within a 2MB block therefore require a PTE table so that different attributes can be applied on either side of the boundary.
KERNEL_SEGMENT_COUNT still correctly counts the five permanent kernel VMAs registered by declare_kernel_vmas(). However, since commit 5973a62efa34 ("arm64: map [_text, _stext) virtual address range non-executable+read-only"), the early mapper also maps [_text, _stext) separately from [_stext, _etext). This adds one more early-only split and can require one more page-table page than the existing EARLY_SEGMENT_EXTRA_PAGES allowance reserves.
Increase the 4K-page early mapping allowance by one page to cover that additional split.
--- arch/arm64/include/asm/kernel-pgtable.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
arch/arm64/include/asm/kernel-pgtable.h +6 -1
@@ -69,7 +69,12 @@#define KERNEL_SEGMENT_COUNT 5#if SWAPPER_BLOCK_SIZE >SEGMENT_ALIGN -#define EARLY_SEGMENT_EXTRA_PAGES (KERNEL_SEGMENT_COUNT + 1) +/* +* KERNEL_SEGMENT_COUNT counts the permanent kernel VMAs. The early mapping +* has one additional split, [_text, _stext). Reserve one more page for the +* SWAPPER_BLOCK_SIZE-unaligned boundaries. +*/ +#define EARLY_SEGMENT_EXTRA_PAGES (KERNEL_SEGMENT_COUNT + 2)/* * The initial ID map consists of the kernel image, mapped as two separate * segments, and may appear misaligned wrt the swapper block size. This means
Signature · 1 line
2.53.0