6.12.111-rc1 review
Subsystems (3)
Greg Kroah-Hartman
maintainerPATCH 631/1102 net/rds: clear cp_flags bits individually in rds_conn_path_reset()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Allison Henderson <[email protected]>
[ Upstream commit 103c4b13c4f50322910078d1c02f29334a574122 ]
rds_conn_path_reset() wipes the whole flag word with a plain cp->cp_flags = 0 store. Every other accessor of that word uses atomic bitops, and some of them can run concurrently with the reset:RDS_LL_SEND_FULL is set from rds_send_xmit() and cleared from the transport completion paths, neither of which holds anything that excludes the shutdown worker. A plain store racing an atomic read-modify-write on the same word is a data race, and whichever side loses has its update silently discarded.
Clear the two bits the reset is actually responsible for instead. RDS_IN_XMIT and RDS_RECV_REFILL need no store at all here: they belong to the caller, rds_conn_shutdown(), which waits for both to be clear before calling the transport shutdown and this reset.
This also gives every bit in cp_flags a single well-defined writer discipline, which the following patches rely on when they turn RDS_IN_XMIT and RDS_RECV_REFILL into bit locks held across the
teardown: a blanket store mid-teardown would destroy lock ownership that an atomic clear preserves.
Oracle UEK carries the same conversion ("net/rds: Preserve essential connection state flags"), motivated by its asynchronous shutdown state machine, whose progress and destroy flags must survive the reset. UEK's variant also clears RDS_IN_XMIT and RDS_RECV_REFILL because there the reset runs as the final step of a teardown that owns both bits, making those clears its unlock. Upstream that release belongs in rds_conn_shutdown(): once a later patch in this series turns the two bits into locks held across the teardown, ending ownership needs release semantics and a wake-up that a plain clear inside the reset would not provide.
Based on Oracle UEK commit "net/rds: Preserve essential connection state flags" by Gerd Rausch.
--- net/rds/connection.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-)
net/rds/connection.c +9 -1
@@ -119,7 +119,15 @@ static void rds_conn_path_reset(struct rds_conn_path *cp)rds_stats_inc (s_conn_reset);rds_send_path_reset (cp); - cp->cp_flags =0 ; + +/* Clear the bits the reset is responsible for individually: a +* blanket cp_flags = 0 is a plain store that can clobber a +* concurrent atomic read-modify-write on the same word. +* RDS_IN_XMIT and RDS_RECV_REFILL belong to the caller, +* rds_conn_shutdown(), and are left alone here. +*/ +clear_bit (RDS_LL_SEND_FULL , &cp->cp_flags); +clear_bit (RDS_RECONNECT_PENDING , &cp->cp_flags);/* Do not clear next_rx_seq here, else we cannot distinguish * retransmitted packets from new packets, and will hand all
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 632/1102 net/rds: tcp: dont force RDS_CONN_RESETTING over a concurrent shutdown
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Gerd Rausch <[email protected]>
[ Upstream commit e8e60d74fec49ccae2aea9b04a6eb162feb8d9af ]
rds_tcp_reset_callbacks() resolves a duelling SYN by storing RDS_CONN_RESETTING into cp_state unconditionally. Nothing serializes that store against the shutdown path: rds_tcp_accept_one() checks for RDS_CONN_CONNECTING or RDS_CONN_ERROR under t_conn_path_lock, but neither rds_conn_path_drop(), which forces RDS_CONN_ERROR, nor rds_conn_shutdown(), which moves the path to RDS_CONN_DISCONNECTING under cp_cm_lock, takes that lock. The store can therefore land on top of a shutdown that is already in progress, or that gets queued right after the accept-side check.
When it does, the shutdown worker's final DISCONNECTING -> DOWN transition fails and the path goes through rds_conn_path_error() and a second drop/shutdown cycle instead of a clean reconnect, tearing down the socket the accept path has just installed. Before commit ad22d24be635 ("net/rds: No shortcut out of RDS_CONN_ERROR") a path found in RDS_CONN_RESETTING even made rds_conn_shutdown() bail out altogether.
Make the transition conditional: move CONNECTING -> RESETTING (or stay in RESETTING from an earlier duel), and drop the path in any other state. The drop has side effects of its own: it replaces the shutdown's RDS_CONN_DISCONNECTING (or RDS_CONN_ERROR) with RDS_CONN_ERROR and queues one more cp_down_w run. The difference is that rds_conn_shutdown() accepts RDS_CONN_ERROR in its final transition to RDS_CONN_DOWN, so the shutdown in flight completes normally instead of through rds_conn_path_error(); the extra down-work pass then finds the path already down and falls through to the reconnect check, or catches a reconnect that has already started and restarts it. The accept path still installs the new socket, rds_connect_path_complete() then fails its RESETTING -> UP transition and drops it: the raced socket ends up torn down as it does today. The comment at that call site, which promised that rds_connect_path_complete() marks the path RDS_CONN_UP, is updated to name this outcome as well.
The state can change again between the failed transitions and the drop. That is inherent to rds_conn_path_drop(), which the socket state-change callbacks also call unconditionally, and costs at most one extra drop/reconnect cycle.
Based on Oracle UEK commit "net/rds: Don't force state RDS_CONN_RESETTING" by Gerd Rausch.
[achender: port to net-next: use the two-argument
rds_conn_path_transition()/rds_conn_path_drop() and rewrite the changelog for the upstream shutdown path]
--- net/rds/tcp.c | 17 +++++++++++++++-- net/rds/tcp_listen.c | 6 +++++- 2 files changed, 20 insertions(+), 3 deletions(-)
net/rds/tcp.c +15 -2
@@ -150,9 +150,22 @@ void rds_tcp_reset_callbacks(struct socket *sock,* end up deadlocking with tcp_sendmsg(), and the RDS_IN_XMIT * would not get set. As a result, we set c_state to * RDS_CONN_RESETTTING, to ensure that rds_tcp_state_change -* cannot mark rds_conn_path_up() in the window before lock_sock() +* cannot mark rds_conn_path_up() in the window before lock_sock(). +* +* Only make that transition if the path is still connecting +* (or already resetting from an earlier duel). A path in any +* other state - typically RDS_CONN_DISCONNECTING or +* RDS_CONN_ERROR with a shutdown in flight - is dropped +* instead. That still replaces its state, with RDS_CONN_ERROR, +* and queues one more shutdown pass, but rds_conn_shutdown() +* accepts RDS_CONN_ERROR in its final transition to +* RDS_CONN_DOWN, so the shutdown in flight completes normally. */ -atomic_set (&cp->cp_state,RDS_CONN_RESETTING ); +if (!rds_conn_path_transition (cp,RDS_CONN_CONNECTING , +RDS_CONN_RESETTING ) && + !rds_conn_path_transition (cp,RDS_CONN_RESETTING , +RDS_CONN_RESETTING )) +rds_conn_path_drop (cp,0 );wait_event (cp->cp_waitq, !test_bit (RDS_IN_XMIT , &cp->cp_flags));/* reset receive side state for rds_tcp_data_recv() for osock */ cancel_delayed_work_sync (&cp->cp_send_w);
net/rds/tcp_listen.c +5 -1
@@ -201,7 +201,11 @@ int rds_tcp_accept_one(struct socket *sock)if (rs_tcp->t_sock) {/* Duelling SYN has been handled in rds_tcp_accept_one() */ rds_tcp_reset_callbacks (new_sock, cp); -/* rds_connect_path_complete() marks RDS_CONN_UP */ +/* rds_connect_path_complete() marks RDS_CONN_UP, or, +* if a concurrent shutdown won the duel, drops the +* path again and the pass that drop queues reaps the +* socket installed above. +*/ rds_connect_path_complete (cp,RDS_CONN_RESETTING ); }else {rds_tcp_set_callbacks (new_sock, cp);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 633/1102 net/rds: acquire RDS_IN_XMIT in rds_tcp_reset_callbacks()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Allison Henderson <[email protected]>
[ Upstream commit 02c5f9dc2efd823e061954d564ce00bacd1bebeb ]
rds_tcp_reset_callbacks() quiesces the transmit path by setting the path state to RDS_CONN_RESETTING and then waiting for RDS_IN_XMIT to be sampled clear before swapping the underlying socket and calling rds_send_path_reset().
Sampling the bit clear is not the same as owning it: rds_send_xmit() can re-acquire RDS_IN_XMIT right after the wait_event() returns. Its state recheck after taking the lock is a store-buffering pattern (the resetter writes the state and reads the bit, the sender writes the bit and reads the state) and acquire_in_xmit() is only an acquire operation, so on weakly ordered architectures both sides can miss each other's write and the transmit path then runs concurrently with rds_send_path_reset() rewriting cp_xmit_* state - which is exactly what the comment above rds_send_path_reset() tells its callers to prevent.
Take the lock instead, hold it across the socket swap and rds_send_path_reset(), and release it with a wake-up at the end. The lock-ordering constraint documented above the wait still holds: the lock is acquired before lock_sock(), so a sender inside tcp_sendmsg() can never be waited on while we hold the socket lock.
Two details of the old code go away with the same change:
- t_sock is now read only after the lock is acquired. The old code cached it before waiting; the teardown in rds_conn_shutdown() releases that socket and clears t_sock, so a pointer cached before the wait can be stale by the time the accept path resumes. Reading it under RDS_IN_XMIT is what makes the exclusion complete once the teardown owns the same lock, which the next patch arranges; until then the teardown still only samples the bit, and the two paths remain as exposed to each other as they are today.
- The old !osock early path called rds_send_path_reset() with no serialization at all. It now runs under the lock like the normal path. The conditional RDS_CONN_RESETTING transition of the previous patch happens before the socket check either way: a path found without a socket is either still connecting (its reconnect worker blocked on t_conn_path_lock) and legitimately goes RESETTING -> UP on the new socket, or it has been torn down meanwhile and is dropped.
The in-function comment describing the old wait-based quiesce is rewritten to describe the lock-based one, and the stale block comment above the function (which still described a return value and an incomplete list of t_sock writers) is refreshed to name all four writers - the connect, accept, teardown and swap paths - and what serializes each of them.
--- net/rds/tcp.c | 70 +++++++++++++++++++++++++++++++++------------------ 1 file changed, 45 insertions(+), 25 deletions(-)
net/rds/tcp.c +45 -25
@@ -115,42 +115,48 @@ void rds_tcp_restore_callbacks(struct socket *sock, }/* -* rds_tcp_reset_callbacks() switches the to the new sock and -* returns the existing tc->t_sock. +* rds_tcp_reset_callbacks() switches a path to a new socket and +* releases the old one it finds in tc->t_sock, resolving a duelling +* SYN. * -* The only functions that set tc->t_sock are rds_tcp_set_callbacks -* and rds_tcp_reset_callbacks. Send and receive trust that -* it is set. The absence of RDS_CONN_UP bit protects those paths -* from being called while it isn't set. +* tc->t_sock is set by rds_tcp_set_callbacks() and cleared by +* rds_tcp_restore_callbacks(). Four paths write it: the active +* connect in rds_tcp_conn_path_connect(), which sets it and clears it +* again on failure; the accept path in rds_tcp_accept_one(), which +* sets it for a path with no socket yet; the teardown in +* rds_tcp_conn_path_shutdown(), which clears it; and the swap done +* here, which does both. The connect and accept paths are serialized +* against each other by t_conn_path_lock. Send and receive trust +* that it is set: the absence of RDS_CONN_UP protects those paths +* from being called while it isn't, and the swap done here runs under +* RDS_IN_XMIT so that it cannot interleave with a sender already +* inside rds_send_xmit(). */ void rds_tcp_reset_callbacks (struct socket *sock,struct rds_conn_path *cp) {struct rds_tcp_connection *tc = cp->cp_transport_data; -struct socket *osock = tc->t_sock; - -if (!osock) - goto newsock; +struct socket *osock;/* Need to resolve a duelling SYN between peers. * We have an outstanding SYN to this peer, which may * potentially have transitioned to the RDS_CONN_UP state, * so we must quiesce any send threads before resetting -* cp_transport_data. We quiesce these threads by setting -* cp_state to something other than RDS_CONN_UP, and then -* waiting for any existing threads in rds_send_xmit to -* complete release_in_xmit(). (Subsequent threads entering -* rds_send_xmit() will bail on !rds_conn_up(). +* cp_transport_data. Setting cp_state to something other +* than RDS_CONN_UP stops new senders, and owning RDS_IN_XMIT +* excludes any thread already inside rds_send_xmit() for the +* whole socket swap and the rds_send_path_reset() below. * -* However an incoming syn-ack at this point would end up -* marking the conn as RDS_CONN_UP, and would again permit -* rds_send_xmi() threads through, so ideally we would -* synchronize on RDS_CONN_UP after lock_sock(), but cannot -* do that: waiting on !RDS_IN_XMIT after lock_sock() may -* end up deadlocking with tcp_sendmsg(), and the RDS_IN_XMIT -* would not get set. As a result, we set c_state to -* RDS_CONN_RESETTTING, to ensure that rds_tcp_state_change -* cannot mark rds_conn_path_up() in the window before lock_sock(). +* An incoming syn-ack at this point would end up marking the +* conn as RDS_CONN_UP, and would again permit rds_send_xmit() +* threads through, so ideally we would synchronize on +* RDS_CONN_UP after lock_sock(), but cannot do that: acquiring +* RDS_IN_XMIT after lock_sock() may end up deadlocking with +* tcp_sendmsg(), which takes the socket lock while holding +* RDS_IN_XMIT. As a result, we set c_state to +* RDS_CONN_RESETTING, to ensure that rds_tcp_state_change +* cannot mark rds_conn_path_up() in the window before +* lock_sock(). * * Only make that transition if the path is still connecting * (or already resetting from an earlier duel). A path in any
@@ -166,7 +172,18 @@ void rds_tcp_reset_callbacks(struct socket *sock, !rds_conn_path_transition(cp, RDS_CONN_RESETTING, RDS_CONN_RESETTING))rds_conn_path_drop (cp,0 ); -wait_event (cp->cp_waitq, !test_bit (RDS_IN_XMIT , &cp->cp_flags)); +wait_event (cp->cp_waitq, + !test_and_set_bit_lock (RDS_IN_XMIT , &cp->cp_flags)); + +/* Read t_sock only while owning RDS_IN_XMIT, never before the +* wait: the teardown in rds_conn_shutdown() releases the old +* socket and clears t_sock, so a pointer sampled earlier can +* be stale by the time we wake up. +*/ + osock = tc->t_sock; +if (!osock) + goto newsock; +/* reset receive side state for rds_tcp_data_recv() for osock */ cancel_delayed_work_sync (&cp->cp_send_w);cancel_delayed_work_sync (&cp->cp_recv_w);
@@ -185,6 +202,9 @@ void rds_tcp_reset_callbacks(struct socket *sock,lock_sock (sock->sk);rds_tcp_set_callbacks (sock, cp);release_sock (sock->sk); + +clear_bit_unlock (RDS_IN_XMIT , &cp->cp_flags); +wake_up_all (&cp->cp_waitq); }/* Add tc to rds_tcp_tc_list and set tc->t_sock. See comments
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 634/1102 net/rds: acquire the fastpath locks in rds_conn_shutdown()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Håkon Bugge <[email protected]>
[ Upstream commit 813f3582ac7ae9f60f917937d54660e0952d5f2d ]
rds_conn_shutdown() quiesces the transmit and receive-refill paths by waiting for RDS_IN_XMIT and RDS_RECV_REFILL to be sampled clear, and then runs the transport shutdown and rds_conn_path_reset(). Sampling the bits clear is not the same as owning them: the moment after the wait_event() returns, rds_send_xmit() can re-acquire RDS_IN_XMIT (or rds_ib_recv_refill() can re-acquire RDS_RECV_REFILL) and run concurrently with the teardown.
The sender does recheck the connection state after taking the lock, but that recheck is a classic store-buffering pattern: teardown writes the state and reads the bit while the sender writes the bit and reads the state. acquire_in_xmit() is only an acquire operation, so on weakly ordered architectures both sides can miss each other's write, and the transmit path then runs while the transport zeroes its rings (e.g. rds_ib_ring_init()) and rds_send_path_reset() rewrites the transmit state under it.
Oracle UEK fixed the same class of crashes - a 14-year tail of BUG_ON()s in rds_ib_sub_signaled(), unexpected op-codes and NULL dereferences in rds_ib_send_cqe_handler() during failover testing - by making the teardown path *acquire* the fastpath bit locks instead of testing them ("rds: Make sure transmit path and connection tear-down does not run concurrently"). Ownership of a single word is decided by RMW atomicity, so no cross-variable ordering is needed.
Do the same here: take both locks before calling the transport shutdown, hold them across rds_conn_path_reset(), and release them explicitly with a wake-up afterwards. Both are released with clear_bit_unlock(), so that the ring re-initialization done by the transport shutdown and the transmit state rewritten by rds_send_path_reset() are ordered before either bit is seen clear by the next acquire_in_xmit() or acquire_refill().
The fastpath users of these bits - rds_send_xmit() and rds_ib_recv_refill() - are trylock style and back off while teardown owns the locks, so no new lock dependency is introduced for them. rds_tcp_reset_callbacks() is different: since the previous patch it acquires RDS_IN_XMIT as well, and it blocks doing so, so its wait now spans the teardown instead of at most one send batch. That waiter runs from rds_tcp_accept_one() on the single-threaded krdsd workqueue and holds rds_tcp_accept_lock and t_conn_path_lock while it waits, so a duelling SYN accepted while its path is being torn down parks accept processing for the duration of the teardown - for TCP bounded by the (up to 5 s) drain loop in rds_tcp_conn_path_shutdown(). An IB path's drain in rds_ib_conn_path_shutdown() has no round cap, but no blocking waiter either: rds_tcp_reset_callbacks() is the only blocking acquirer of these bits and waits only on its own TCP path, and the fastpaths are trylock-and-back-off on both transports, so a long IB drain lengthens only that path's own quiesce. The
window is narrow: the accept-side state check has to pass before the teardown moves the path to RDS_CONN_DISCONNECTING.
Because krdsd is a single global workqueue, everything else queued there - accept processing for other connections and network namespaces, and the flush_workqueue(rds_wq) in rds_tcp_listen_stop() during namespace teardown - waits behind the parked accept worker for that time. It cannot deadlock, although the waits do point at each
other: the teardown blocks until the bit's holder releases it, and the holder may be that krdsd accept worker. The holder finishes without needing anything the teardown owns: the sync cancels rds_tcp_reset_callbacks() issues target cp_send_w and cp_recv_w on the path's ordered cp_wq, whose only execution slot is occupied by the blocked cp_down_w itself, so they are pending at most and cancel without flushing - a reliance on cp_wq being ordered that is now noted next to those cancels (on the allocation-failure fallback where a path shares rds_wq, the work items simply serialize). Nor is the blocking wait itself new: rds_tcp_reset_callbacks() has waited on RDS_IN_XMIT from the krdsd work item since commit 335b48d980f6 ("RDS: TCP: Add/use rds_tcp_reset_callbacks to reset tcp socket safely"); this patch stretches its worst case from a sender's batch to the teardown's drain. The alternative to parking is the accept path racing the teardown, which is what these patches close; making the teardown itself non-blocking is a separate item.
One observable side effect: the SENDING flag reported by rds-info has always mirrored RDS_IN_XMIT, so it now also covers the window where teardown owns the bit.
The comments that describe the old sample-based handshake or name rds_send_xmit() as the only other holder of these bits - in rds_send_xmit(), above rds_conn_path_reset(), in rds_ib_recv_refill() and in rds_tcp_reset_callbacks() - are updated to match.
For anyone backporting this patch standalone: it depends on "net/rds: clear cp_flags bits individually in rds_conn_path_reset()" and "net/rds: acquire RDS_IN_XMIT in rds_tcp_reset_callbacks()" earlier in this series. Without the former, the blanket cp_flags clear in rds_conn_path_reset() would drop both held bits in the middle of the teardown; without the latter, rds_tcp_reset_callbacks() would still sample t_sock without owning RDS_IN_XMIT. "net/rds: use clear_bit_unlock() in release_refill()" is needed for the refill side's release to pair with the acquire added here, and the follow-up "net/rds: don't let rds_conn_shutdown() consume a concurrent drop" completes the teardown-state handling for the waiter this patch parks; a backport should carry all four.
[achender: reimplement for net-next shutdown path: acquire the existing
RDS_IN_XMIT/RDS_RECV_REFILL bit locks in rds_conn_shutdown() and release after teardown; update comments and commit message]
--- net/rds/connection.c | 40 ++++++++++++++++++++++++++++++++-------- net/rds/ib_recv.c | 4 +++- net/rds/send.c | 7 +++++-- net/rds/tcp.c | 19 +++++++++++++++---- 4 files changed, 55 insertions(+), 15 deletions(-)
net/rds/connection.c +32 -8
@@ -105,10 +105,12 @@ static struct rds_connection *rds_conn_lookup(struct net *net, }/* -* This is called by transports as they're bringing down a connection. -* It clears partial message state so that the transport can start sending -* and receiving over this connection again in the future. It is up to -* the transport to have serialized this call with its send and recv. +* This is called by rds_conn_shutdown() once the transport has brought +* a path down. It clears partial message state so that the transport +* can start sending and receiving over this path again in the future. +* The caller owns RDS_IN_XMIT and RDS_RECV_REFILL across this call, +* which is what serializes it against the send and receive-refill +* paths. */ static void rds_conn_path_reset (struct rds_conn_path *cp) {
@@ -123,8 +125,9 @@ static void rds_conn_path_reset(struct rds_conn_path *cp)/* Clear the bits the reset is responsible for individually: a * blanket cp_flags = 0 is a plain store that can clobber a * concurrent atomic read-modify-write on the same word. -* RDS_IN_XMIT and RDS_RECV_REFILL belong to the caller, -* rds_conn_shutdown(), and are left alone here. +* RDS_IN_XMIT and RDS_RECV_REFILL are held as locks by the +* caller, rds_conn_shutdown(), which releases them once the +* teardown is complete. */ clear_bit (RDS_LL_SEND_FULL , &cp->cp_flags);clear_bit (RDS_RECONNECT_PENDING , &cp->cp_flags);
@@ -400,14 +403,35 @@ void rds_conn_shutdown(struct rds_conn_path *cp) }mutex_unlock (&cp->cp_cm_lock); +/* Quiesce the transmit and receive-refill paths by +* acquiring their bit locks, not merely waiting for +* them to be released: with a plain wait, either path +* can re-take its lock the instant after we sample it +* clear and then run concurrently with the transport +* shutdown and the path reset below. Holding both +* locks across the teardown makes that structurally +* impossible. +*/ wait_event (cp->cp_waitq, - !test_bit (RDS_IN_XMIT , &cp->cp_flags)); + !test_and_set_bit_lock (RDS_IN_XMIT , &cp->cp_flags));wait_event (cp->cp_waitq, - !test_bit (RDS_RECV_REFILL , &cp->cp_flags)); + !test_and_set_bit (RDS_RECV_REFILL , &cp->cp_flags)); conn->c_trans->conn_path_shutdown (cp);rds_conn_path_reset (cp); +/* Release the two locks and wake any waiter (e.g. +* rds_tcp_reset_callbacks()) that blocked on them while +* we held them. The unlock orders the transport's ring +* re-initialization and the path reset above before +* either bit is seen clear. rds_conn_path_reset() leaves +* both bits alone: ownership ends here, not inside the +* reset. +*/ +clear_bit_unlock (RDS_IN_XMIT , &cp->cp_flags); +clear_bit_unlock (RDS_RECV_REFILL , &cp->cp_flags); +wake_up_all (&cp->cp_waitq); +if (!rds_conn_path_transition (cp,RDS_CONN_DISCONNECTING ,RDS_CONN_DOWN ) && !rds_conn_path_transition(cp, RDS_CONN_ERROR,
net/rds/ib_recv.c +3 -1
@@ -391,7 +391,9 @@ void rds_ib_recv_refill(struct rds_connection *conn, int prefill, gfp_t gfp)/* the goal here is to just make sure that someone, somewhere * is posting buffers. If we can't get the refill lock, -* let them do their thing +* let them do their thing. The holder may also be +* rds_conn_shutdown() tearing the path down, in which case +* there is nothing to post. */ if (!acquire_refill (conn))return ;
net/rds/send.c +5 -2
@@ -185,8 +185,11 @@ int rds_send_xmit(struct rds_conn_path *cp)WRITE_ONCE (cp->cp_send_gen, send_gen);/* -* rds_conn_shutdown() sets the conn state and then tests RDS_IN_XMIT, -* we do the opposite to avoid races. +* rds_conn_shutdown() sets the conn state and then acquires +* RDS_IN_XMIT; we take the lock first and then check the state. +* Ownership is decided by the atomic RMW on the cp_flags word: +* if the teardown won the bit we back off here, and if we won +* it the teardown waits until we release it. */ if (!rds_conn_path_up (cp)) {release_in_xmit (cp);
net/rds/tcp.c +15 -4
@@ -144,8 +144,10 @@ void rds_tcp_reset_callbacks(struct socket *sock,* so we must quiesce any send threads before resetting * cp_transport_data. Setting cp_state to something other * than RDS_CONN_UP stops new senders, and owning RDS_IN_XMIT -* excludes any thread already inside rds_send_xmit() for the -* whole socket swap and the rds_send_path_reset() below. +* excludes any thread already inside rds_send_xmit() - or a +* teardown in rds_conn_shutdown(), which holds the same lock +* for the duration of the transport shutdown - for the whole +* socket swap and the rds_send_path_reset() below. * * An incoming syn-ack at this point would end up marking the * conn as RDS_CONN_UP, and would again permit rds_send_xmit()
@@ -178,13 +180,22 @@ void rds_tcp_reset_callbacks(struct socket *sock,/* Read t_sock only while owning RDS_IN_XMIT, never before the * wait: the teardown in rds_conn_shutdown() releases the old * socket and clears t_sock, so a pointer sampled earlier can -* be stale by the time we wake up. +* be stale by the time we wake up. The teardown holds the +* same lock while it does so, so what we read here cannot +* change under us until we release it. */ osock = tc->t_sock;if (!osock) goto newsock; -/* reset receive side state for rds_tcp_data_recv() for osock */ +/* reset receive side state for rds_tcp_data_recv() for osock. +* +* The sync cancels while owning RDS_IN_XMIT rely on cp_wq +* being ordered: a teardown blocked on the bit occupies +* cp_wq's only execution slot, so cp_send_w and cp_recv_w are +* pending at most and the cancels never flush. Nothing here +* may flush or wait on cp_wq itself. +*/ cancel_delayed_work_sync (&cp->cp_send_w);cancel_delayed_work_sync (&cp->cp_recv_w);lock_sock (osock->sk);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 635/1102 net/rds: dont let rds_conn_shutdown() consume a concurrent drop
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Allison Henderson <[email protected]>
[ Upstream commit 260c6308fe2e19ad519389d44d582e292aecc3af ]
rds_conn_shutdown() finishes by moving the path from RDS_CONN_DISCONNECTING to RDS_CONN_DOWN, and also accepts RDS_CONN_ERROR as the starting state of that final transition, so that a FIN processed in softirq context during the teardown does not derail the shutdown into a noisy error path.
But consuming that RDS_CONN_ERROR also consumes the shutdown pass that came with it: rds_conn_path_drop() sets RDS_CONN_ERROR and then queues cp_down_w, and a pass that starts on a path already in RDS_CONN_DOWN is a no-op. For the FIN case that is harmless - the socket the FIN arrived on is the very socket the teardown just released. It is not harmless for a dropper that attached something to the path first.
rds_tcp_accept_one() is such a dropper. Its path claim in rds_tcp_accept_one_path() transitions RDS_CONN_DOWN -> RDS_CONN_CONNECTING, and a concurrent drop - a FIN on a previous socket in softirq context, an administrative reset - can put the path into RDS_CONN_ERROR between that claim and the state check that follows, which accepts RDS_CONN_ERROR. The accept then installs the freshly accepted socket with rds_tcp_set_callbacks() while the queued teardown - which sampled tc->t_sock before this socket existed - is still running. rds_connect_path_complete() fails its transition to RDS_CONN_UP and drops the path again, queueing the pass that should reap the socket it just installed. If the in-flight shutdown's final transition consumes that drop's RDS_CONN_ERROR, the queued pass finds the path in RDS_CONN_DOWN and does nothing. The installed socket is never torn down: it sits established with its callbacks armed and its rds_tcp_connection on rds_tcp_tc_list, the peer sees a connection that nothing ever reads, and the path is wedged in RDS_CONN_DOWN until some later event drops it again. Reproduced with widened race windows as an ever-growing receive queue on a socket owned by a path stuck in RDS_CONN_DOWN, with the peer's send path wedged behind it.
Make the final transition only DISCONNECTING -> DOWN. If it fails because the path is in RDS_CONN_ERROR, a drop raced the teardown:
cancel the reconnect timer and clear RDS_RECONNECT_PENDING - the one piece of the skipped tail that must not be left behind - and return, letting the pass the drop queued finish the job: it tears down whatever attached to the path in the meantime, completes the transition to RDS_CONN_DOWN, and re-arms the reconnect from its own tail.
The timer quiesce in that branch matters because the racing drop does not always queue that pass: rds_conn_path_drop() returns without queueing when a destroy is pending - exactly the situation during a netns teardown or module unload, when a FIN on the dying socket is processed while rds_conn_path_destroy() flushes cp_down_w. If the flushed pass is the one that takes this return, no later pass exists, and rds_conn_path_destroy() would find cp_conn_w still armed (WARN_ON) and then free a path whose reconnect timer can still fire. With the cancel in the branch, every exit of a shutdown pass leaves the timer quiesced no matter which pass completes the transition.
The FIN case keeps making progress, one pass later and still without noisy logging. Any other state keeps today's rds_conn_path_error() handling; no current cp_state writer can leave a DISCONNECTING path in anything but RDS_CONN_ERROR (every other writer is a cmpxchg from a non-DISCONNECTING state), so that branch is defensive.
On kernels without the preceding patches the same hazard exists with the sample-based quiesce; the fix applies there equally.
--- net/rds/connection.c | 43 ++++++++++++++++++++++++++++++++----------- net/rds/tcp.c | 9 ++++++--- 2 files changed, 38 insertions(+), 14 deletions(-)
net/rds/connection.c +32 -11
@@ -433,19 +433,40 @@ void rds_conn_shutdown(struct rds_conn_path *cp)wake_up_all (&cp->cp_waitq);if (!rds_conn_path_transition (cp,RDS_CONN_DISCONNECTING , -RDS_CONN_DOWN ) && - !rds_conn_path_transition (cp,RDS_CONN_ERROR ,RDS_CONN_DOWN )) { -/* This can happen - eg when we're in the middle of tearing -* down the connection, and someone unloads the rds module. -* Quite reproducible with loopback connections. -* Mostly harmless. +/* The path was dropped again while we tore it +* down: by a socket state-change callback in +* irq context on receipt of a FIN, or by an +* accept that claimed the path just before a +* drop put it back to RDS_CONN_ERROR and then +* installed a fresh socket on it. Unless a +* pending destroy suppressed it, the drop also +* queued another shutdown pass, and that pass +* must run, because it is what tears down +* whatever attached to the path after the +* transport shutdown above sampled its state. +* Consuming the RDS_CONN_ERROR here would turn +* that pass into a no-op: leave the state +* alone, and let the pass finish the job. * -* Note that this also happens with rds-tcp because -* we could have triggered rds_conn_path_drop in irq -* mode from rds_tcp_state change on the receipt of -* a FIN, thus we need to recheck for RDS_CONN_ERROR -* here. +* Quiesce the reconnect timer before bailing +* out, though. When a pending destroy did +* suppress the queue, no later pass runs, and +* rds_conn_path_destroy() is about to flush +* cp_down_w and free the path: it must not +* find cp_conn_w still armed. A successor +* pass, when there is one, re-arms the +* reconnect from its own tail. +*/ +cancel_delayed_work_sync (&cp->cp_conn_w); +clear_bit (RDS_RECONNECT_PENDING , &cp->cp_flags); + +if (rds_conn_path_state (cp) ==RDS_CONN_ERROR ) +return ; +/* No current cp_state writer leaves a +* DISCONNECTING path in any state but +* RDS_CONN_ERROR; report loudly if one ever +* does. */ rds_conn_path_error (cp,"%s: failed to transition " "to state DOWN, current state "
net/rds/tcp.c +6 -3
@@ -165,9 +165,12 @@ void rds_tcp_reset_callbacks(struct socket *sock,* other state - typically RDS_CONN_DISCONNECTING or * RDS_CONN_ERROR with a shutdown in flight - is dropped * instead. That still replaces its state, with RDS_CONN_ERROR, -* and queues one more shutdown pass, but rds_conn_shutdown() -* accepts RDS_CONN_ERROR in its final transition to -* RDS_CONN_DOWN, so the shutdown in flight completes normally. +* and, unless a pending destroy is about to reap the whole +* connection anyway, queues one more shutdown pass. A shutdown +* already in flight leaves that RDS_CONN_ERROR alone when it +* finishes; the queued pass then completes the transition to +* RDS_CONN_DOWN and tears down anything that attached to the +* path in the meantime. */ if (!rds_conn_path_transition(cp, RDS_CONN_CONNECTING, RDS_CONN_RESETTING) &&
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 636/1102 net: stmmac: reconfigure RX packet parser table in stmmac_hw_setup() after reset
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 6b8fed2675fb75d23e6cf2b7e49c94926e884b34 ]
The core software reset issued in stmmac_init_dma_engine() during ndo_open() callback clears the MTL RX packet parser registers, but stmmac_rxp_config() is only invoked from the cls_u32 add/delete paths. After an ifdown/ifup cycle the hardware therefore runs with the default all-pass table while priv->tc_entries still reports the filters as installed. Re-apply the RX packet parser table from priv->tc_entries in stmmac_hw_setup(), right after the software reset, so the filters are restored when the interface is brought up again.
--- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 8 ++++++++ 1 file changed, 8 insertions(+)
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +8 -0
@@ -3423,6 +3423,14 @@ static int stmmac_hw_setup(struct net_device *dev, bool ptp_register)/* Initialize MTL*/ stmmac_mtl_configuration (priv); +/* Apply the RX packet parser table */ +if (priv->tc_entries) { + ret =stmmac_rxp_config (priv, priv->hw->pcsr, priv->tc_entries, + priv->tc_entries_max); +if (ret) +return ret; + } +/* Initialize Safety Features */ stmmac_safety_feat_configuration (priv);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 637/1102 net: gro: Fix nesting of TCP GSO SKBs in skb_gro_receive_list()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: HW He <[email protected]>
[ Upstream commit 66817a9794263cd2a5dc4e99bf8e5fcc5ff7181e ]
Fraglist GRO and hardware GRO can create an fraglist of HW-GRO packets. This cannot be segmented back into the original form on TCP tethering scenario.
Avoid constructing such a GSO packet, by flushing an already built fraglist GRO packet if a hardware GRO packet arrives.
Scenario (Tethering/Forwarding):
1.Driver submits a single TCP packet, P1. P1 is kept in the gro_list as the first packet.
2. The driver submits a TCP GSO skb, P2. P2 has already aggregated multiple TCP packets by HW_GRO, and its non-linear data is stored in frags[].
3. P1 and P2 match the GRO rules, and since there is no local socket, they are aggregated by skb_gro_receive_list(). The resulting skb, P3, has a frag_list entry that still contains frags[]:
P3: [ Linear Data ] -> frag_list -> [ Linear Data ]
[ frag[1] ]
[ frag[2] ]
...4. Later, tcp4_gso_segment() or tcp6_gso_segment() calls skb_segment_list() to segment P3. However, skb_segment_list() only segments the entries in frag_list. It does not segment the frags[] inside P2, so P3 is not restored to the original packets, which leads to IP fragmentation or packet drop in the following path.
Check skb_is_gso(skb) and current GRO method, make sure fraglist GRO applies to consecutive non-GSO skb, others adopt regular GRO path.
--- net/ipv4/tcp_offload.c | 22 ++++++++++++++++------ net/ipv6/tcpv6_offload.c | 15 +++++++++++++-- 2 files changed, 29 insertions(+), 8 deletions(-)
net/ipv4/tcp_offload.c +16 -6
@@ -356,6 +356,7 @@ struct sk_buff *tcp_gro_receive(struct list_head *head, struct sk_buff *skb, flush |= skb->ip_summed != p->ip_summed; flush |= skb->csum_level != p->csum_level; flush |=NAPI_GRO_CB (p)->count >=64 ; + flush |=NAPI_GRO_CB (p)->is_flist !=NAPI_GRO_CB (skb)->is_flist;skb_set_network_header (skb,skb_gro_receive_network_offset (skb));if (flush ||skb_gro_receive_list (p, skb))
@@ -419,12 +420,20 @@ static void tcp4_check_fraglist_gro(struct list_head *head, struct sk_buff *skb,struct net *net;int iif, sdif; -if (likely (!(skb->dev->features &NETIF_F_GRO_FRAGLIST ))) -return ; - p =tcp_gro_lookup (head, th);if (p) { -NAPI_GRO_CB (skb)->is_flist =NAPI_GRO_CB (p)->is_flist; +/* flist GRO applies to consecutive non-GSO skbs */ +if (!skb_is_gso (skb) || !NAPI_GRO_CB (p)->is_flist) { +NAPI_GRO_CB (skb)->is_flist =NAPI_GRO_CB (p)->is_flist; +return ; + } + +/* Fall back to the regular GRO path */ +if (NAPI_GRO_CB (p)->count ==1 ) +NAPI_GRO_CB (p)->is_flist =0 ; + +NAPI_GRO_CB (skb)->is_flist =0 ; +return ; }
@@ -435,7 +444,7 @@ static void tcp4_check_fraglist_gro(struct list_head *head, struct sk_buff *skb, iph->saddr, th->source, iph->daddr,ntohs (th->dest), iif, sdif); -NAPI_GRO_CB (skb)->is_flist = !sk; +NAPI_GRO_CB (skb)->is_flist = !sk && !skb_is_gso (skb);if (sk)sock_gen_put (sk); }
@@ -455,7 +464,8 @@ struct sk_buff *tcp4_gro_receive(struct list_head *head, struct sk_buff *skb)if (!th) goto flush; -tcp4_check_fraglist_gro (head, skb, th); +if (unlikely (skb->dev->features &NETIF_F_GRO_FRAGLIST )) +tcp4_check_fraglist_gro (head, skb, th);return tcp_gro_receive (head, skb, th);
net/ipv6/tcpv6_offload.c +13 -2
@@ -29,7 +29,18 @@ static void tcp6_check_fraglist_gro(struct list_head *head, struct sk_buff *skb, p =tcp_gro_lookup (head, th);if (p) { -NAPI_GRO_CB (skb)->is_flist =NAPI_GRO_CB (p)->is_flist; +/* flist GRO applies to consecutive non-GSO skbs */ +if (!skb_is_gso (skb) || !NAPI_GRO_CB (p)->is_flist) { +NAPI_GRO_CB (skb)->is_flist =NAPI_GRO_CB (p)->is_flist; +return ; + } + +/* Fall back to the regular GRO path */ +if (NAPI_GRO_CB (p)->count ==1 ) +NAPI_GRO_CB (p)->is_flist =0 ; + +NAPI_GRO_CB (skb)->is_flist =0 ; +return ; }
@@ -40,7 +51,7 @@ static void tcp6_check_fraglist_gro(struct list_head *head, struct sk_buff *skb, &hdr->saddr, th->source, &hdr->daddr,ntohs (th->dest), iif, sdif); -NAPI_GRO_CB (skb)->is_flist = !sk; +NAPI_GRO_CB (skb)->is_flist = !sk && !skb_is_gso (skb);if (sk)sock_gen_put (sk);#endif /* IS_ENABLED(CONFIG_IPV6) */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 638/1102 arm64: trans_pgd: clone only the linear map that exists at runtime
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 1537e55728ec2bc506c74ea69b93cd859da58fb8 ]
kexec_file_load() fails on arm64 if we have CONFIG_ARM64_VA_BITS_52 but it runs on a !FEAT_LPA2 host (such as my loving Grace machine).
That is because trans_pgd_create_copy() uses the compile time PAGE_OFFSET (VA 52) instead of the actual VA size (48 -- due to the lack of LPA2). With the fifth level folded, pgd_none() is always false, so the walk cannot skip the 15 extra PGDIR_SIZE slots, and they all alias back to the same table: the whole kernel page table gets cloned 16 times, KASAN shadow included. Without KASAN it does not blow up, it just wastes ~RAM/32 in page tables.
Fix it by copying the linear map that is the actual one, not the compiled one.
--- arch/arm64/kernel/machine_kexec.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
arch/arm64/kernel/machine_kexec.c +2 -1
@@ -129,7 +129,8 @@ int machine_kexec_post_load(struct kimage *kimage) }/* Create a copy of the linear map */ - rc =trans_pgd_create_copy (&info, &trans_pgd,PAGE_OFFSET ,PAGE_END ); + rc =trans_pgd_create_copy (&info, &trans_pgd, +_PAGE_OFFSET (vabits_actual),PAGE_END );if (rc)return rc; kimage->arch.ttbr1 =__pa (trans_pgd);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 639/1102 selftests/alsa: Fix the step check for INTEGER controls
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: HyeongJun An <[email protected]>
[ Upstream commit 8efd5f623c63584c2e284a837a7795d95a0491cb ]
The modulo sits inside the subtraction, so the check evaluates int_val - (min % step) rather than (int_val - min) % step. The INTEGER64 branch below it is parenthesised correctly.
The written form passes only when the value equals min % step, and such a value is always on a step boundary, so it never misses a real violation. It only reports valid values as invalid.
snd-aloop declares step 1 on four controls, so every non-zero value on them is reported. Before:
# PCM Rate Shift 100000.0 value 100000 invalid for step 1 minimum 80000 # Totals: pass:660 fail:101 xfail:0 xpass:0 skip:296 error:0
After, same card, nothing else changed:
# Totals: pass:740 fail:21 xfail:0 xpass:0 skip:296 error:0
Eighteen files under sound/ declare a non-zero step.
--- tools/testing/selftests/alsa/mixer-test.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
tools/testing/selftests/alsa/mixer-test.c +2 -2
@@ -319,8 +319,8 @@ static bool ctl_value_index_valid(struct ctl_data *ctl,/* Only check step size if there is one and we're in bounds */ if (snd_ctl_elem_info_get_step (ctl->info) && - (int_val -snd_ctl_elem_info_get_min (ctl->info) % -snd_ctl_elem_info_get_step (ctl->info))) { + (int_val -snd_ctl_elem_info_get_min (ctl->info)) % +snd_ctl_elem_info_get_step (ctl->info)) { ksft_print_msg("%s.%d value %ld invalid for step %ld minimum %ld\n", ctl->name, index, int_val, snd_ctl_elem_info_get_step(ctl->info),
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 640/1102 ALSA: caiaq: Fix potential double-free at error path
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 3b26ceef88c110f4d188387cffa0df78657be904 ]
The fix for caiaq driver's resource management to handle the errors tries to release the resources in a common destructor call, but as a sashiko review for another patch suggested, some of the audio resources such as URBs have been already freed, and this may lead to a double-free.
For addressing the double-free, call the common destructor function from each place, and assure that the resource pointers get cleared.
--- sound/usb/caiaq/audio.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
sound/usb/caiaq/audio.c +5 -5
@@ -842,16 +842,13 @@ int snd_usb_caiaq_audio_init(struct snd_usb_caiaqdev *cdev) cdev->data_urbs_in =alloc_urbs (cdev,SNDRV_PCM_STREAM_CAPTURE , &ret);if (ret <0 ) { -kfree (cdev->data_cb_info); -free_urbs (cdev->data_urbs_in); +snd_usb_caiaq_audio_free (cdev);return ret; } cdev->data_urbs_out =alloc_urbs (cdev,SNDRV_PCM_STREAM_PLAYBACK , &ret);if (ret <0 ) { -kfree (cdev->data_cb_info); -free_urbs (cdev->data_urbs_in); -free_urbs (cdev->data_urbs_out); +snd_usb_caiaq_audio_free (cdev);return ret; }
@@ -872,6 +869,9 @@ void snd_usb_caiaq_audio_free(struct snd_usb_caiaqdev *cdev)dev_dbg (dev,"%s(%p)\n" , __func__, cdev);free_urbs (cdev->data_urbs_in); + cdev->data_urbs_in =NULL ;free_urbs (cdev->data_urbs_out); + cdev->data_urbs_out =NULL ;kfree (cdev->data_cb_info); + cdev->data_cb_info =NULL ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 641/1102 bpf: Fix NULL-ptr-deref when showing a void BTF type
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jiayuan Chen <[email protected]>
[ Upstream commit 4ea508b9ebd78bce7f212166d2e2cba66b875f08 ]
btf_modifier_show() resolves the modifier and then calls btf_type_ops(t)->show() unconditionally. For the void type (type_id 0, BTF_KIND_UNKN) kind_ops[] has no entry, so ->show is NULL.
A "const void" (a modifier resolving to void) cannot be a map key or value - map_check_btf() rejects it because void has no size - so the map dump path does not reach it. But bpf_snprintf_btf() takes a type_id straight from the BPF program, and passing such a "const void" from the vmlinux BTF NULL-derefs:
KASAN: null-ptr-deref in range [0x0000000000000028-0x000000000000002f] RIP: 0010:btf_modifier_show (kernel/bpf/btf.c:2914) Call Trace: <TASK> btf_type_show (kernel/bpf/btf.c:8251) btf_type_snprintf_show (kernel/bpf/btf.c:8321) bpf_snprintf_btf (kernel/trace/bpf_trace.c:1047) bpf_prog_test_run_raw_tp (net/bpf/test_run.c:829) __sys_bpf (kernel/bpf/syscall.c:4804) do_syscall_64 (arch/x86/entry/syscall_64.c:94) entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:121) </TASK>
Fall back to btf_df_show() when the resolved type has no show op; it emits the "<unsupported kind:N>" placeholder already used for kinds like FWD and FUNC. bpf_snprintf_btf() then returns the length as usual.
--- kernel/bpf/btf.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
kernel/bpf/btf.c +8 -1
@@ -2776,7 +2776,14 @@ static void btf_modifier_show(const struct btf *btf,else t =btf_type_skip_modifiers (btf, type_id,NULL ); -btf_type_ops (t)->show (btf, t, type_id, data, bits_offset, show); +/* +* A modifier can resolve to void, which has no show op; print a +* placeholder rather than dereferencing NULL. +*/ +if (!btf_type_ops (t)) +btf_df_show (btf, t, type_id, data, bits_offset, show); +else +btf_type_ops (t)->show (btf, t, type_id, data, bits_offset, show); } static void btf_var_show(const struct btf *btf, const struct btf_type *t,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 642/1102 bpf: Fix NULL-ptr-deref in btf_var_show()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jiayuan Chen <[email protected]>
[ Upstream commit 5403a383f52fc0905703b488f7c3db4b2447dc58 ]
btf_var_show() calls btf_type_id_resolve() unconditionally, which dereferences btf->resolved_ids. That is NULL for a base BTF - e.g. the vmlinux BTF that bpf_snprintf_btf() renders against - since base BTF is not resolved during parsing. btf_modifier_show() guards this with 'if (btf->resolved_ids)', but btf_var_show() does not.
A BPF program that passes the type_id of a BTF_KIND_VAR from the vmlinux BTF to bpf_snprintf_btf() thus NULL-derefs:
KASAN: probably user-memory-access in range [0x46638-0x4663f] RIP: 0010:btf_var_show (kernel/bpf/btf.c:2929) Call Trace: <TASK> btf_type_show (kernel/bpf/btf.c:8259) btf_type_snprintf_show (kernel/bpf/btf.c:8329) bpf_snprintf_btf (kernel/trace/bpf_trace.c:1047) bpf_prog_test_run_raw_tp (net/bpf/test_run.c:829) __sys_bpf (kernel/bpf/syscall.c:4804) do_syscall_64 (arch/x86/entry/syscall_64.c:84) entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:121) </TASK>
Resolve the var's type directly with btf_type_skip_modifiers() when resolved_ids is NULL, mirroring btf_modifier_show().
--- kernel/bpf/btf.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-)
kernel/bpf/btf.c +9 -1
@@ -2790,7 +2790,15 @@ static void btf_var_show(const struct btf *btf, const struct btf_type *t, u32 type_id, void *data, u8 bits_offset, struct btf_show *show) { - t =btf_type_id_resolve (btf, &type_id); + /* + * btf_type_id_resolve() dereferences btf->resolved_ids, which is NULL + * for a base BTF (e.g. the vmlinux BTF that bpf_snprintf_btf() uses). + * Resolve the var's type directly in that case. + */ + if (btf->resolved_ids) + t =btf_type_id_resolve (btf, &type_id); + else + t =btf_type_skip_modifiers (btf, t->type, &type_id);btf_type_ops (t)->show (btf, t, type_id, data, bits_offset, show); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 643/1102 bpf: Mark sched_process_wait argument as nullable
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kumar Kartikeya Dwivedi <[email protected]>
[ Upstream commit a453d6e3b8e8e1a321c8744d6189d763af9287d0 ]
do_wait() passes wo->wo_pid to the sched_process_wait tracepoint. kernel_wait4() leaves wo_pid NULL for wait4(-1), and kernel_waitid_prepare() does likewise for waitid(P_ALL).
btf_ctx_access() currently types argument 0 as PTR_TO_BTF_ID | PTR_TRUSTED. Without PTR_MAYBE_NULL, the verifier accepts an unchecked dereference. Trusted pointer loads have no fault protection, so a wait for any child can then cause a NULL pointer dereference in JITed BPF code.
Add sched_process_wait to raw_tp_null_args[] with argument 0 marked nullable. The verifier rejects an unchecked dereference while preserving access after the program checks the pointer for NULL.
--- kernel/bpf/btf.c | 4 ++++ 1 file changed, 4 insertions(+)
kernel/bpf/btf.c +4 -0
@@ -6443,6 +6443,10 @@ struct bpf_raw_tp_null_args {static const struct bpf_raw_tp_null_args raw_tp_null_args[] = {/* sched */ {"sched_pi_setprio" ,0x10 }, +/* +* do_wait() passes NULL for wait4(-1) and waitid(P_ALL). +*/ + {"sched_process_wait" ,0x1 },/* ... from sched_numa_pair_template event class */ {"sched_stick_numa" ,0x100 }, {"sched_swap_numa" ,0x100 },
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 644/1102 ring-buffer: Add checking nr_subbufs to persistent ring buffer validation
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Steven Rostedt <[email protected]>
[ Upstream commit 6c001a62c34f13fe1c6a24304c289b387d9e697d ]
Sashiko reported that the code was using meta->nr_subbufs without making sure that it matched the nr_pages + 1 on data that was assuming the two were the same.
Add a check to the persistent ring buffer validation code to make sure that the saved nr_subbufs matches what we expect.
--- kernel/trace/ring_buffer.c | 5 +++++ 1 file changed, 5 insertions(+)
kernel/trace/ring_buffer.c +5 -0
@@ -1743,6 +1743,11 @@ static bool rb_meta_valid(struct ring_buffer_meta *meta, int cpu,return false; } +if (meta->nr_subbufs != nr_pages +1 ) { +pr_info ("Ring buffer boot meta [%d] invalid nr_subbufs\n" , cpu); +return false; + } + buffers_start = meta->first_buffer; buffers_end = meta->first_buffer + (subbuf_size * meta->nr_subbufs);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 645/1102 nvme: remove stale namespaces by NSID range during scan
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mohamed Khalfella <[email protected]>
[ Upstream commit 4ed7f3d7d435bf5b63da2814dc9270f5ba896011 ]
nvme_scan_ns_list() drops the stale namespaces in each gap in the reported NSID list one NSID at a time. Every iteration calls nvme_find_get_ns() to look the namespace up and removes it if it is present. The loop runs once per NSID in the gap rather than once per namespace actually present.
NSIDs are 32-bit, so a target with a sparse NSID space can make a single gap spin the loop billions of times with nothing to remove.
watchdog: BUG: soft lockup - CPU#4 stuck for 26s! Workqueue: nvme-wq nvme_scan_work [nvme_core] RIP: 0010:__srcu_read_unlock+0xb/0x20 Call Trace: nvme_find_get_ns+0x7d/0xb0 [nvme_core] nvme_scan_ns_list+0xe8/0x280 [nvme_core] nvme_scan_work+0x18a/0x280 [nvme_core] process_one_work+0x197/0x380 worker_thread+0x2fe/0x410 kthread+0xe0/0x100
Rename nvme_remove_invalid_namespaces() to nvme_remove_nsid_range() and give it an open (start, end) NSID range. ctrl->namespaces is sorted by NSID, so the whole gap is dropped in a single walk that stops once end is reached. This bounds the work by the namespaces that are present instead of by the size of the gap.
--- drivers/nvme/host/core.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-)
drivers/nvme/host/core.c +9 -9
@@ -144,8 +144,6 @@ static const struct class nvme_ns_chr_class = { };static void nvme_put_subsystem (struct nvme_subsystem *subsys); -static void nvme_remove_invalid_namespaces (struct nvme_ctrl *ctrl, -unsigned nsid);static void nvme_update_keep_alive (struct nvme_ctrl *ctrl,struct nvme_command *cmd);
@@ -4135,15 +4133,16 @@ static void nvme_scan_ns_async(void *data, async_cookie_t cookie)nvme_scan_ns (scan_info->ctrl, nsid); } -static void nvme_remove_invalid_namespaces (struct nvme_ctrl *ctrl, -unsigned nsid) +static void nvme_remove_nsid_range (struct nvme_ctrl *ctrl,u32 start,u32 end) {struct nvme_ns *ns, *next;LIST_HEAD (rm_list);mutex_lock (&ctrl->namespaces_lock);list_for_each_entry_safe (ns, next, &ctrl->namespaces, list) { -if (ns->head->ns_id > nsid) { +if (ns->head->ns_id >= end) +break ; +if (ns->head->ns_id > start) {list_del_rcu (&ns->list);synchronize_srcu (&ctrl->srcu);list_add_tail_rcu (&ns->list, &rm_list);
@@ -4193,13 +4192,14 @@ static int nvme_scan_ns_list(struct nvme_ctrl *ctrl) goto out;async_schedule_domain (nvme_scan_ns_async, &scan_info, &domain); -while (++prev < nsid) -nvme_ns_remove_by_nsid (ctrl, prev); +if (prev +1 < nsid) +nvme_remove_nsid_range (ctrl, prev, nsid); + prev =max (prev +1 , nsid); }async_synchronize_full_domain (&domain); } out: -nvme_remove_invalid_namespaces (ctrl, prev); +nvme_remove_nsid_range (ctrl, prev,UINT_MAX ); free:async_synchronize_full_domain (&domain);kfree (ns_list);
@@ -4219,7 +4219,7 @@ static void nvme_scan_ns_sequential(struct nvme_ctrl *ctrl)for (i =1 ; i <= nn; i++)nvme_scan_ns (ctrl, i); -nvme_remove_invalid_namespaces (ctrl, nn); +nvme_remove_nsid_range (ctrl, nn,UINT_MAX ); }static void nvme_clear_changed_ns_log (struct nvme_ctrl *ctrl)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 646/1102 nvme-tcp: open-code nvme_tcp_queue_request() for R2T
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hannes Reinecke <[email protected]>
[ Upstream commit 674f872b7cefab4564ec8b34c799a4a653e34513 ]
When handling an R2T PDU we short-circuit nvme_tcp_queue_request() as we should not attempt to send consecutive PDUs. So open-code nvme_tcp_queue_request() for R2T and drop the last argument.
Stable-dep-of: 08acb54b063a ("nvme-tcp: defer TLS inline send to io_work")
--- drivers/nvme/host/tcp.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-)
drivers/nvme/host/tcp.c +7 -5
@@ -406,7 +406,7 @@ static inline bool nvme_tcp_queue_more(struct nvme_tcp_queue *queue) }static inline void nvme_tcp_queue_request (struct nvme_tcp_request *req, -bool sync,bool last) +bool last) {struct nvme_tcp_queue *queue = req->queue;bool empty;
@@ -420,7 +420,7 @@ static inline void nvme_tcp_queue_request(struct nvme_tcp_request *req,* are on the same cpu, so we don't introduce contention. */ if (queue->io_cpu ==raw_smp_processor_id () && - sync && empty &&mutex_trylock (&queue->send_mutex)) { + empty &&mutex_trylock (&queue->send_mutex)) {nvme_tcp_send_all (queue);mutex_unlock (&queue->send_mutex); }
@@ -828,7 +828,9 @@ static int nvme_tcp_handle_r2t(struct nvme_tcp_queue *queue, req->ttag = pdu->ttag;nvme_tcp_setup_h2c_data_pdu (req); -nvme_tcp_queue_request (req, false, true); + +llist_add (&req->lentry, &queue->req_list); +queue_work_on (queue->io_cpu, nvme_tcp_wq, &queue->io_work);return 0 ; }
@@ -2678,7 +2680,7 @@ static void nvme_tcp_submit_async_event(struct nvme_ctrl *arg)init_llist_node (&ctrl->async_req.lentry);INIT_LIST_HEAD (&ctrl->async_req.entry); -nvme_tcp_queue_request (&ctrl->async_req, true, true); +nvme_tcp_queue_request (&ctrl->async_req, true); }static void nvme_tcp_complete_timed_out (struct request *rq)
@@ -2831,7 +2833,7 @@ static blk_status_t nvme_tcp_queue_rq(struct blk_mq_hw_ctx *hctx,nvme_start_request (rq); -nvme_tcp_queue_request (req, true, bd->last); +nvme_tcp_queue_request (req, bd->last);return BLK_STS_OK ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 647/1102 nvme-tcp: defer TLS inline send to io_work
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xixin Liu <[email protected]>
[ Upstream commit 08acb54b063a33730eb1ae1e0f89bf36542bac9f ]
blk_mq holds set->srcu while queuing and running requests. The kTLS software send path takes ctx->tx_lock. lockdep knows that tx_lock nests under elevator_lock which then waits on srcu, so an inline send from that path under TLS triggers circular locking.
Skip the inline send optimization for TLS queues so the send runs from the workqueue instead. The same workqueue already retries TLS sends on write-space notifications. Plain TCP keeps the inline path.
--- drivers/nvme/host/tcp.c | 5 +++++ 1 file changed, 5 insertions(+)
drivers/nvme/host/tcp.c +5 -0
@@ -418,8 +418,13 @@ static inline void nvme_tcp_queue_request(struct nvme_tcp_request *req,* if we're the first on the send_list and we can try to send * directly, otherwise queue io_work. Also, only do that if we * are on the same cpu, so we don't introduce contention. +* +* TLS kTLS send takes ctx->tx_lock while blk_mq holds set->srcu. +* lockdep reports circular locking via elevator_lock. Defer TLS +* sends to the io workqueue instead of inline from this path. */ if (queue->io_cpu ==raw_smp_processor_id () && + !nvme_tcp_queue_tls (queue) && empty &&mutex_trylock (&queue->send_mutex)) {nvme_tcp_send_all (queue);mutex_unlock (&queue->send_mutex);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 648/1102 ASoC: Intel: avs: Clean up the bus when fetching ML caps fails
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cezary Rojewski <[email protected]>
[ Upstream commit 559ea14b7ae7c7562b48759fa545b64958f35b73 ]
snd_hdac_ext_bus_get_ml_capabilities() may fail and its return code shall be checked and accounted for. Address the issue by updating the error-path for avs_pci_probe().
At the same time, if the function in question succeeds but the next part of avs_pci_probe() fails, the hlink list shall be cleaned up before leaving the scope.
--- sound/soc/intel/avs/core.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-)
sound/soc/intel/avs/core.c +9 -2
@@ -467,8 +467,13 @@ static int avs_pci_probe(struct pci_dev *pci, const struct pci_device_id *id) }snd_hdac_bus_parse_capabilities (bus); -if (bus->mlcap) -snd_hdac_ext_bus_get_ml_capabilities (bus); +if (bus->mlcap) { + ret =snd_hdac_ext_bus_get_ml_capabilities (bus); +if (ret <0 ) { +dev_err (dev,"failed to get ml capabilities: %d\n" , ret); + goto err_ml_cap; + } + }if (dma_set_mask_and_coherent (dev,DMA_BIT_MASK (64 )))dma_set_mask_and_coherent (dev,DMA_BIT_MASK (32 ));
@@ -510,6 +515,8 @@ static int avs_pci_probe(struct pci_dev *pci, const struct pci_device_id *id)snd_hdac_bus_free_stream_pages (bus);snd_hdac_ext_stream_free_all (bus); err_init_streams: +snd_hdac_ext_link_free_all (bus); +err_ml_cap:iounmap (adev->dsp_ba); err_remap_bar4:iounmap (bus->remap_addr);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 649/1102 ASoC: Intel: avs: Clean up streams if their initialization fails
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cezary Rojewski <[email protected]>
[ Upstream commit f4ba00bb56a8511bafbd19826501d27157141c6d ]
When streams are being initialized the memory allocation may fail. Have an error path and return early if that is the case.
--- sound/soc/intel/avs/core.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-)
sound/soc/intel/avs/core.c +15 -3
@@ -85,16 +85,28 @@ static int avs_hdac_bus_init_streams(struct hdac_bus *bus) {unsigned int cp_streams, pb_streams;unsigned int gcap; +int ret; gcap =snd_hdac_chip_readw (bus,GCAP ); cp_streams = (gcap >>8 ) &0x0F ; pb_streams = (gcap >>12 ) &0x0F ; bus->num_streams = cp_streams + pb_streams; -snd_hdac_ext_stream_init_all (bus,0 , cp_streams,SNDRV_PCM_STREAM_CAPTURE ); -snd_hdac_ext_stream_init_all (bus, cp_streams, pb_streams,SNDRV_PCM_STREAM_PLAYBACK ); + ret =snd_hdac_ext_stream_init_all (bus,0 , cp_streams,SNDRV_PCM_STREAM_CAPTURE ); +if (ret) +return ret; + ret =snd_hdac_ext_stream_init_all (bus, cp_streams, pb_streams,SNDRV_PCM_STREAM_PLAYBACK ); +if (ret) + goto err; + + ret =snd_hdac_bus_alloc_stream_pages (bus); +if (ret) + goto err; -return snd_hdac_bus_alloc_stream_pages (bus); +return 0 ; +err: +snd_hdac_ext_stream_free_all (bus); +return ret; }static bool avs_hdac_bus_init_chip (struct hdac_bus *bus,bool full_reset)
Signature · 1 line
2.53.0
Re: [PATCH 6.12 0649/1102] ASoC: Intel: avs: Clean up streams if their initialization fails
Quoted 42 lines · Greg Kroah-Hartman
6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cezary Rojewski <[email protected]>
[ Upstream commit
f4ba00bb56a8511bafbd19826501d27157141c6d]When streams are being initialized the memory allocation may fail. Have an error path and return early if that is the case.
Fixes 1affc44ea5dd ("ASoC: Intel: avs: PCI driver implementation")Co-developed-by Amadeusz Sławiński <[email protected]>Signed-off-by Amadeusz Sławiński <[email protected]>Signed-off-by Cezary Rojewski <[email protected]>Signed-off-by Mark Brown <[email protected]>Signed-off-by Sasha Levin <[email protected]>--- sound/soc/intel/avs/core.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-)sound/soc/intel/avs/core.c +4
-2@@ -85,16 +85,28 @@ static int avs_hdac_bus_init_streams(struct hdac_bus *bus) {unsigned int cp_streams, pb_streams;unsigned int gcap; +int ret; gcap =snd_hdac_chip_readw (bus,GCAP ); cp_streams = (gcap >>8 ) &0x0F ; pb_streams = (gcap >>12 ) &0x0F ; bus->num_streams = cp_streams + pb_streams; -snd_hdac_ext_stream_init_all (bus,0 , cp_streams,SNDRV_PCM_STREAM_CAPTURE ); -snd_hdac_ext_stream_init_all (bus, cp_streams, pb_streams,SNDRV_PCM_STREAM_PLAYBACK ); + ret =snd_hdac_ext_stream_init_all (bus,0 , cp_streams,SNDRV_PCM_STREAM_CAPTURE ); +if (ret) +return ret;
sound/soc/intel/avs/core.c static int avs_hdac_bus_init_streams(struct hdac_bus *bus) · line 106
Quoted 10 lines
sound/soc/intel/avs/core.c +8
-1+ ret =snd_hdac_ext_stream_init_all (bus, cp_streams, pb_streams,SNDRV_PCM_STREAM_PLAYBACK ); +if (ret) + goto err; + + ret =snd_hdac_bus_alloc_stream_pages (bus); +if (ret) + goto err; -return snd_hdac_bus_alloc_stream_pages (bus); +return 0 ;
^^^
Hi Greg/Sasha,
I ran an AI-assisted review of 8dac807fb313 and verified two missing HDA cleanup dependencies in 6.12.y.
Upstream has:
if (!hext_stream) {
snd_hdac_ext_stream_free_all(bus);
return -ENOMEM;
}
...
if (err < 0)
goto error_bdl;6.12.y has:
if (!hext_stream)
return -ENOMEM;
...
if (err < 0)
return -ENOMEM;The AVS patch matches upstream f4ba00bb56a8, whose source tree already contains:
48afc07c4f1b9c3cdbe66ddc3e7677ed395ce75f
("ALSA: hda: ext: Clean up streams if their initialization fails")
f16eaa38ea640884f66d24865c770c3f6c43bd42
("ALSA: hda/core: add cleanup insnd_hdac_bus_alloc_stream_pages()")
Without the first commit, a capture allocation failure can return while partial stream objects remain. Without the second, a stream-page failure can leave DMA allocations behind even though AVS frees the stream objects.
They are in a series: https://lore.kernel.org/all/[email protected]/
I think both prerequisite cleanups should be applied before retrying 8dac807fb313, thoughts?
thanks,
Harshit> +err:
Quoted 5 lines
sound/soc/intel/avs/core.c +2
-0+snd_hdac_ext_stream_free_all (bus); +return ret; }static bool avs_hdac_bus_init_chip (struct hdac_bus *bus,bool full_reset)
Sasha Levin
maintainerRe: [PATCH 6.12 0649/1102] ASoC: Intel: avs: Clean up streams if their initialization fails
Quoted 2 lines · Harshit Mogalapalli
Without the first commit, a capture allocation failure can return while partial stream objects remain.
[...]
Quoted 2 lines
I think both prerequisite cleanups should be applied before retrying
8dac807fb313, thoughts?
Agreed, and dropped from all five queues.
Signature · 2 lines
Thanks, Sasha
Greg Kroah-Hartman
maintainerPATCH 650/1102 ASoC: Intel: avs: Do not ignore -ENOENT when loading a topology
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cezary Rojewski <[email protected]>
[ Upstream commit c6dceca9f78fbd478c41735457c4de9c25a6b1c8 ]
avs_load_topology() combines request_firmware() and snd_soc_tplg_component_load(). The fallback mechanism introduced for the HDAudio based boards honors -ENOENT and checks for a generic topology if no specific is found before giving up and failing the component probing.
However, if -ENOENT is returned by the latter function - snd_soc_tplg_component_load() - is shall not be ignored. That means there is an actual problem with the topology file and no fallback shall be attempted.
--- sound/soc/intel/avs/pcm.c | 34 ++++++++++++++++++++-------------- sound/soc/intel/avs/topology.c | 2 +- sound/soc/intel/avs/topology.h | 1 + 3 files changed, 22 insertions(+), 15 deletions(-)
sound/soc/intel/avs/pcm.c +20 -14
@@ -6,6 +6,7 @@// Amadeusz Slawinski <[email protected]> // +#include <linux/cleanup.h> #include <linux/debugfs.h> #include <linux/device.h> #include <sound/hda_register.h>
@@ -887,13 +888,25 @@ static int avs_component_load_libraries(struct avs_soc_component *acomp)return ret; } +static int avs_request_topology (struct snd_soc_component *component,const char *name, +const struct firmware **fw) +{ + char *fullname __free(kfree) = NULL; + + fullname =kasprintf (GFP_KERNEL ,"%s/%s" , component->driver->topology_name_prefix, name); +if (!fullname) +return -ENOMEM ; + +return request_firmware (fw, fullname, component->dev); +} +static int avs_component_probe (struct snd_soc_component *component) {struct snd_soc_card *card = component->card;struct snd_soc_acpi_mach *mach;struct avs_soc_component *acomp; +const struct firmware *fw;struct avs_dev *adev; -char *filename;int ret;dev_dbg (card->dev,"probing %s card %s\n" , component->name, card->name);
@@ -909,13 +922,7 @@ static int avs_component_probe(struct snd_soc_component *component) goto finalize;/* Load specified topology and create debugfs for it. */ - filename =kasprintf (GFP_KERNEL ,"%s/%s" , component->driver->topology_name_prefix, - mach->tplg_filename); -if (!filename) -return -ENOMEM ; - - ret =avs_load_topology (component, filename); -kfree (filename); + ret =avs_request_topology (component, mach->tplg_filename, &fw);if (ret == -ENOENT && !strncmp (mach->tplg_filename,"hda-" ,4 )) {unsigned int vendor_id;
@@ -930,18 +937,17 @@ static int avs_component_probe(struct snd_soc_component *component) "hda-generic-tplg.bin");if (!mach->tplg_filename)return -ENOMEM ; - filename =kasprintf (GFP_KERNEL ,"%s/%s" , component->driver->topology_name_prefix, - mach->tplg_filename); -if (!filename) -return -ENOMEM ;dev_info (card->dev,"trying to load fallback topology %s\n" , mach->tplg_filename); - ret =avs_load_topology (component, filename); -kfree (filename); + ret =avs_request_topology (component, mach->tplg_filename, &fw); }if (ret <0 )return ret; + ret =snd_soc_tplg_component_load (component, &avs_tplg_ops, fw); +if (ret) +return ret; + ret =avs_component_load_libraries (acomp);if (ret <0 ) {dev_err (card->dev,"libraries loading failed: %d\n" , ret);
sound/soc/intel/avs/topology.c +1 -1
@@ -1900,7 +1900,7 @@ avs_control_load(struct snd_soc_component *comp, int index, struct snd_kcontrol_return 0 ; } -static const struct snd_soc_tplg_ops avs_tplg_ops = { +const struct snd_soc_tplg_ops avs_tplg_ops = { .io_ops = avs_control_ops, .io_ops_count =ARRAY_SIZE (avs_control_ops), .control_load = avs_control_load,
sound/soc/intel/avs/topology.h +1 -0
@@ -202,6 +202,7 @@ struct avs_tplg_module {struct list_head node; }; +extern const struct snd_soc_tplg_ops avs_tplg_ops;struct avs_tplg *avs_tplg_new (struct snd_soc_component *comp);int avs_load_topology (struct snd_soc_component *comp,const char *filename);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 651/1102 ASoC: Intel: avs: Fix unbalanced module reference count
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cezary Rojewski <[email protected]>
[ Upstream commit d4fa6f94b91137e329ea3f5b360e140b227bb696 ]
strace_open() invokes try_module_get() which on success takes the module reference. If any follow up operation causes strace_open() to fail, the refcount shall be put down.
--- sound/soc/intel/avs/debugfs.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-)
sound/soc/intel/avs/debugfs.c +9 -3
@@ -8,6 +8,7 @@#include <linux/debugfs.h> #include <linux/kfifo.h> +#include <linux/module.h> #include <linux/wait.h> #include <linux/sched/signal.h> #include <sound/soc.h>
@@ -236,15 +237,20 @@ static int strace_open(struct inode *inode, struct file *file)if (!try_module_get (adev->dev->driver->owner))return -ENODEV ; -if (kfifo_initialized (&adev->trace_fifo)) -return -EBUSY ; +if (kfifo_initialized (&adev->trace_fifo)) { + ret = -EBUSY ; + goto err; + } ret =kfifo_alloc (&adev->trace_fifo,PAGE_SIZE ,GFP_KERNEL );if (ret <0 ) -return ret; + goto err; file->private_data = adev;return 0 ; +err: +module_put (adev->dev->driver->owner); +return ret; }static int strace_release (struct inode *inode,struct file *file)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 652/1102 net: bcmasp: clear txcb->last before writing each descriptor
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Justin Chen <[email protected]>
[ Upstream commit 18e5e0ec0e9282c897e2aa81a3e43ccaee03b003 ]
bcmasp_xmit() only wrote txcb->last = true for the final fragment of an SKB; non-final fragments left the field untouched. If a descriptor slot was reused while it still held a stale true from a previous SKB (possible when tx_spb_ring_full() underreported fullness), bcmasp_tx_reclaim() would see last == true mid-SKB and call dev_consume_skb_any() prematurely, freeing the sk_buff while its remaining fragments were still in flight.
Unconditionally clear txcb->last before the conditional set so every descriptor slot starts from a known false state regardless of what a prior transmission left behind.
--- drivers/net/ethernet/broadcom/asp2/bcmasp_intf.c | 1 + 1 file changed, 1 insertion(+)
drivers/net/ethernet/broadcom/asp2/bcmasp_intf.c +1 -0
@@ -333,6 +333,7 @@ static netdev_tx_t bcmasp_xmit(struct sk_buff *skb, struct net_device *dev) txcb->bytes_sent = total_bytes;dma_unmap_addr_set (txcb, dma_addr, mapping);dma_unmap_len_set (txcb, dma_len, size); + txcb->last = false;if (!i) { desc->flags |=DESC_SOF ;if (csum_hw)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 653/1102 net: bcmasp: fix tx_spb_ring_full() checking same slot cnt times
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Justin Chen <[email protected]>
[ Upstream commit 0c5cf62e72d7a666ee4da757e122dc1600df1ecc ]
The loop initialised next_index from intf->tx_spb_index on every iteration, so incr_ring() always produced the same result and only one slot was ever tested. Move the initialisation before the loop so each iteration advances next_index and the function correctly checks that cnt consecutive descriptor slots are available before allowing a new transmission.
--- drivers/net/ethernet/broadcom/asp2/bcmasp_intf.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/net/ethernet/broadcom/asp2/bcmasp_intf.c +2 -1
@@ -147,8 +147,9 @@ static int tx_spb_ring_full(struct bcmasp_intf *intf, int cnt)int next_index, i;/* Check if we have enough room for cnt descriptors */ + next_index = intf->tx_spb_index;for (i =0 ; i < cnt; i++) { - next_index =incr_ring (intf->tx_spb_index,DESC_RING_COUNT ); + next_index =incr_ring (next_index,DESC_RING_COUNT );if (next_index == intf->tx_spb_clean_index)return 1 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 654/1102 bpf: Mark bpf_btf_find_by_name_kind() as sleepable
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kumar Kartikeya Dwivedi <[email protected]>
[ Upstream commit 620614bf7672130c43b3cff375525a2202f61979 ]
When bpf_btf_find_by_name_kind() finds a type in module BTF, it returns a new BTF object fd through __btf_new_fd(). This reaches anon_inode_getfd(), which can sleep while allocating or expanding the current task fd table.
The helper prototype does not set might_sleep, so the verifier allows the helper in non-sleepable contexts such as BPF timer callbacks. The fd allocation can then sleep in softirq context and install the fd into the interrupted task.
Mark the helper as sleepable. This preserves calls from the main body of a sleepable syscall program while rejecting calls from its non-sleepable regions.
--- kernel/bpf/btf.c | 1 + 1 file changed, 1 insertion(+)
kernel/bpf/btf.c +1 -0
@@ -8253,6 +8253,7 @@ BPF_CALL_4(bpf_btf_find_by_name_kind, char *, name, int, name_sz, u32, kind, intconst struct bpf_func_proto bpf_btf_find_by_name_kind_proto = { .func = bpf_btf_find_by_name_kind, .gpl_only = false, + .might_sleep = true, .ret_type =RET_INTEGER , .arg1_type =ARG_PTR_TO_MEM |MEM_RDONLY , .arg2_type =ARG_CONST_SIZE ,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 655/1102 bpf: Mark faultable stack helpers as sleepable
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kumar Kartikeya Dwivedi <[email protected]>
[ Upstream commit 9d02927fdf4e930893c92e35fed01a2704496900 ]
The faultable variants of bpf_get_stack() and bpf_get_task_stack() pass may_fault=true into the common stack collection code. Resolving user-space build IDs may then call build_id_parse_file() and block on filesystem reads.
Neither helper prototype sets might_sleep. Since prototype selection uses the sleepability of the whole program, the verifier can still allow these helpers from a non-sleepable region within that program, such as an explicit RCU or preemption-disabled region. The task-stack helper can also be called from a non-sleepable timer callback of a sleepable program.
Mark both faultable prototypes as sleepable. The existing helper context check then rejects these calls while continuing to allow them in genuinely sleepable contexts.
--- kernel/bpf/stackmap.c | 2 ++ 1 file changed, 2 insertions(+)
kernel/bpf/stackmap.c +2 -0
@@ -539,6 +539,7 @@ BPF_CALL_4(bpf_get_stack_sleepable, struct pt_regs *, regs, void *, buf, u32, siconst struct bpf_func_proto bpf_get_stack_sleepable_proto = { .func = bpf_get_stack_sleepable, .gpl_only = true, + .might_sleep = true, .ret_type =RET_INTEGER , .arg1_type =ARG_PTR_TO_CTX , .arg2_type =ARG_PTR_TO_UNINIT_MEM ,
@@ -589,6 +590,7 @@ BPF_CALL_4(bpf_get_task_stack_sleepable, struct task_struct *, task, void *, bufconst struct bpf_func_proto bpf_get_task_stack_sleepable_proto = { .func = bpf_get_task_stack_sleepable, .gpl_only = false, + .might_sleep = true, .ret_type =RET_INTEGER , .arg1_type =ARG_PTR_TO_BTF_ID , .arg1_btf_id = &btf_tracing_ids[BTF_TRACING_TYPE_TASK ],
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 656/1102 bpf: Dont predict JMP32 pointer vs zero comparisons
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eduard Zingerman <[email protected]>
[ Upstream commit e51179a4e09846f8fd0f26a05068520de2b301bf ]
Consider the following program:
r1 = map_value; /* low 32 bits are zero at runtime */
r6 = 0xdead000000000000;
if w1 != 0 goto l1;
l0: r1 += r6;
r2 = *(u64 *)(r1 + 0);
exit;
l1: r6 = 0;
goto l0;At the moment is_branch_taken() reports the jump as always taken, because it does not distinguish between BPF_JMP and BPF_JMP32 comparisons when processing 'if w1 != 0 ...'.
--- kernel/bpf/verifier.c | 7 +++++++ 1 file changed, 7 insertions(+)
kernel/bpf/verifier.c +7 -0
@@ -15109,6 +15109,13 @@ static int is_branch_taken(struct bpf_reg_state *reg1, struct bpf_reg_state *regif (__is_pointer_value (false, reg1) ||__is_pointer_value (false, reg2)) {u64 val; +/* +* The low 32 bits of a valid pointer may well be zero, hence +* nothing below applies to a 32-bit comparison. +*/ +if (is_jmp32) +return -1 ; +/* arrange that reg2 is a scalar, and reg1 is a pointer */ if (!is_reg_const (reg2, is_jmp32)) { opcode =flip_opcode (opcode);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 657/1102 thermal: sysfs: switch to use scnprintf() to suppress truncation warning
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Andy Shevchenko <[email protected]>
[ Upstream commit 5ad0af4f4367202b1bc71813052fe39b5116cdb9 ]
Switch the sysfs code to use scnprintf() to avoid warnings about potential truncation of the names of the sysfs attributes. We can't increase the buffer size because the size is the part of an ABI for some reason. Note, with the current size of buffer the affected attributes have a room for up to 1000 names, which ought to be enough for all cases. There is no functional change, as the same limitation was implied before.
--- drivers/thermal/thermal_sysfs.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-)
drivers/thermal/thermal_sysfs.c +6 -6
@@ -410,8 +410,8 @@ static int create_trip_attrs(struct thermal_zone_device *tz)struct thermal_trip_attrs *trip_attrs = &td->trip_attrs;/* create trip type attribute */ -snprintf (trip_attrs->type.name,THERMAL_NAME_LENGTH , -"trip_point_%d_type" , i); +scnprintf (trip_attrs->type.name,sizeof (trip_attrs->type.name), +"trip_point_%d_type" , i);sysfs_attr_init (&trip_attrs->type.attr.attr); trip_attrs->type.attr.attr.name = trip_attrs->type.name;
@@ -420,8 +420,8 @@ static int create_trip_attrs(struct thermal_zone_device *tz) attrs[i] = &trip_attrs->type.attr.attr;/* create trip temp attribute */ -snprintf (trip_attrs->temp.name,THERMAL_NAME_LENGTH , -"trip_point_%d_temp" , i); +scnprintf (trip_attrs->temp.name,sizeof (trip_attrs->temp.name), +"trip_point_%d_temp" , i);sysfs_attr_init (&trip_attrs->temp.attr.attr); trip_attrs->temp.attr.attr.name = trip_attrs->temp.name;
@@ -433,8 +433,8 @@ static int create_trip_attrs(struct thermal_zone_device *tz) } attrs[i + tz->num_trips] = &trip_attrs->temp.attr.attr; -snprintf (trip_attrs->hyst.name,THERMAL_NAME_LENGTH , -"trip_point_%d_hyst" , i); +scnprintf (trip_attrs->hyst.name,sizeof (trip_attrs->hyst.name), +"trip_point_%d_hyst" , i);sysfs_attr_init (&trip_attrs->hyst.attr.attr); trip_attrs->hyst.attr.attr.name = trip_attrs->hyst.name;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 658/1102 bpf: Require MEM_PERCPU for percpu kptr stores
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kumar Kartikeya Dwivedi <[email protected]>
[ Upstream commit 048029ba1c793f8cabc4ad5eea765da01903f8f1 ]
map_kptr_match_type() treats perm_flags as the set of register type flags that a kptr field permits. Adding MEM_PERCPU to that set for BPF_KPTR_PERCPU does not require the source register to carry it, however. The subset test consequently accepts both a plain bpf_obj_new() allocation and a referenced kernel pointer into a __percpu_kptr map field.
Loads from the field are always marked MEM_PERCPU. Consumers then treat the stored value as the cookie returned by bpf_percpu_obj_new(): per-CPU pointer helpers relocate it, and map teardown selects the per-CPU free path. A plain allocation can therefore provide an arbitrary kernel read/write, while a kernel pointer can be relocated into an invalid address or sent through a missing destructor.
Require the source MEM_PERCPU flag to match the destination field kind. This preserves valid bpf_percpu_obj_new() stores and rejects both the program-BTF and kernel-BTF variants.
--- kernel/bpf/verifier.c | 7 +++++++ 1 file changed, 7 insertions(+)
kernel/bpf/verifier.c +7 -0
@@ -5495,6 +5495,13 @@ static int map_kptr_match_type(struct bpf_verifier_env *env,if (type_flag (reg->type) & ~perm_flags) goto bad_type; +/* +* A BPF_KPTR_PERCPU field is read back as MEM_PERCPU, so the value +* stored in it must carry the same flag. +*/ +if ((kptr_field->type ==BPF_KPTR_PERCPU ) != !!(reg->type &MEM_PERCPU )) + goto bad_type; +/* We need to verify reg->type and reg->btf, before accessing reg->btf */ reg_name =btf_type_name (reg->btf, reg->btf_id);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 659/1102 bpf: Reject untrusted allocated-object pointers
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ning Ding <[email protected]>
[ Upstream commit 7441ee8276641bddaf1cba7bb75ef9c1458ceb3b ]
When the final RCU read-side critical section ends, a local kptr is demoted to PTR_UNTRUSTED but retains MEM_ALLOC. The pointer may be NULL or may refer to an object whose lifetime is no longer protected.
type_is_ptr_alloc_obj() nevertheless recognizes any PTR_TO_BTF_ID with MEM_ALLOC as a live allocated object. In particular, a refcount-only local kptr never carries NON_OWN_REF, so it still passes the bpf_refcount_acquire() argument check after RCU protection ends. The kfunc can then dereference NULL or stale memory.
Make type_is_ptr_alloc_obj() reject PTR_UNTRUSTED pointers. Since type_is_non_owning_ref() is based on the same predicate, graph kfunc arguments obey the same live-object requirement. Fault-protected reads of the demoted pointer remain valid: writes are already rejected, and read fixups use bpf_may_fault_on_deref() rather than this predicate.
--- include/linux/bpf_verifier.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
include/linux/bpf_verifier.h +3 -1
@@ -919,7 +919,9 @@ static inline bool bpf_type_has_unsafe_modifiers(u32 type)static inline bool type_is_ptr_alloc_obj (u32 type) { -return base_type (type) ==PTR_TO_BTF_ID &&type_flag (type) &MEM_ALLOC ; +return base_type (type) ==PTR_TO_BTF_ID && +type_flag (type) &MEM_ALLOC && + !(type_flag (type) &PTR_UNTRUSTED ); }static inline bool type_is_non_owning_ref (u32 type)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 660/1102 selftests/bpf: Fix flaky bpf_nf test when random NAT port is 0
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jiayuan Chen <[email protected]>
[ Upstream commit 5e8c349bc8d790fe031a4332e502f5d4f9878644 ]
The bpf_nf test allocs a ct, sets snat and dnat with random addr and port via bpf_ct_set_nat_info(), then looks the ct up and checks the reply tuple against what was set.
The port comes from bpf_get_prandom_u32() and can be 0. For bpf_ct_set_nat_info(), port 0 means "port not specified", so only the addr is mapped and the kernel keeps the original port. The check then compares that port with 0 and fails, which shows up as a flaky "Test for source natting" failure in CI [1][2].
Keep the random port in 1..65535 so it is always specified.
[1] https://github.com/kernel-patches/bpf/actions/runs/33830002889/job/100893868791
[2] https://github.com/kernel-patches/bpf/actions/runs/33829976794/job/100893220999
--- tools/testing/selftests/bpf/progs/test_bpf_nf.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
tools/testing/selftests/bpf/progs/test_bpf_nf.c +4 -4
@@ -171,8 +171,8 @@ nf_ct_test(struct nf_conn *(*lookup_fn)(void *, struct bpf_sock_tuple *, u32, ct =alloc_fn (ctx, &bpf_tuple,sizeof (bpf_tuple.ipv4), &opts_def,sizeof (opts_def));if (ct) { -__u16 sport =bpf_get_prandom_u32 (); -__u16 dport =bpf_get_prandom_u32 (); +__u16 sport =bpf_get_prandom_u32 () %65535 +1 ; +__u16 dport =bpf_get_prandom_u32 () %65535 +1 ;union nf_inet_addr saddr = {};union nf_inet_addr daddr = {};struct nf_conn *ct_ins;
@@ -274,8 +274,8 @@ nf_ct_opts_new_test(struct nf_conn *(*lookup_fn)(void *, struct bpf_sock_tuple * ct =alloc_fn (ctx, &bpf_tuple,sizeof (bpf_tuple.ipv4), &opts_def,sizeof (opts_def));if (ct) { -__u16 sport =bpf_get_prandom_u32 (); -__u16 dport =bpf_get_prandom_u32 (); +__u16 sport =bpf_get_prandom_u32 () %65535 +1 ; +__u16 dport =bpf_get_prandom_u32 () %65535 +1 ;union nf_inet_addr saddr = {};union nf_inet_addr daddr = {};struct nf_conn *ct_ins;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 661/1102 nexthop: Initialize extack in remove_nh_grp_entry()
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 5bd9e4e7cdaa03879e9b73b12ab52cceb1edd55b ]
remove_nh_grp_entry() prints the extack message when a listener fails to replace the reduced nexthop group. However, extack is not initialized and listeners are not required to set a message when returning an error. Neither netdevsim nor mlxsw do so when an allocation fails, resulting in the dereference of an uninitialized stack pointer.
Fix by zero-initializing extack, as was done in commit 6347c5314cee ("nexthop: initialize extack in nh_res_bucket_migrate()").
--- net/ipv4/nexthop.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/ipv4/nexthop.c +1 -1
@@ -2012,7 +2012,7 @@ static void remove_nh_grp_entry(struct net *net, struct nh_grp_entry *nhge, {struct nh_grp_entry *nhges, *new_nhges;struct nexthop *nhp = nhge->nh_parent; -struct netlink_ext_ack extack; +struct netlink_ext_ack extack = {};struct nexthop *nh = nhge->nh;struct nh_group *nhg, *newg;int i, j, err;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 662/1102 bonding: use skb_cow_head() in bond_do_alb_xmit() and rlb_arp_xmit()
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 1746ef2e2df2ad71c66eca56364d56bde284523b ]
In bond_do_alb_xmit() and rlb_arp_xmit(), make sure to unclone skb head via skb_cow_head() before modifying the source MAC address (Ethernet header and ARP payload) to avoid silent corruption if the skb is shared or cloned. Avoid caching the header pointers across skb_cow_head().
In rlb_arp_xmit(), only modify arp->mac_src if it differs from tx_slave->dev->dev_addr to avoid an unnecessary copy and head reallocation.
Also, we should not assume mac header is set in output path.
Use skb_eth_hdr() instead of eth_hdr() to fix the issue, and remove now redundant skb_reset_mac_header() calls.
--- drivers/net/bonding/bond_alb.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-)
drivers/net/bonding/bond_alb.c +12 -7
@@ -678,9 +678,15 @@ static struct slave *rlb_arp_xmit(struct sk_buff *skb, struct bonding *bond)if (arp->op_code ==htons (ARPOP_REPLY )) {/* the arp must be sent on the selected rx channel */ tx_slave =rlb_choose_channel (skb, bond, arp); -if (tx_slave) +if (tx_slave && + !ether_addr_equal_64bits (arp->mac_src, + tx_slave->dev->dev_addr)) { +if (unlikely (skb_cow_head (skb,0 ))) +return NULL ; + arp = (struct arp_pkt *)skb_network_header (skb);bond_hw_addr_copy (arp->mac_src, tx_slave->dev->dev_addr, tx_slave->dev->addr_len); + }netdev_dbg (bond->dev,"(slave %s): Server sent ARP Reply packet\n" , tx_slave ? tx_slave->dev->name :"NULL" ); }else if (arp->op_code ==htons (ARPOP_REQUEST )) {
@@ -1341,7 +1347,6 @@ static netdev_tx_t bond_do_alb_xmit(struct sk_buff *skb, struct bonding *bond, struct slave *tx_slave) {struct alb_bond_info *bond_info = &(BOND_ALB_INFO (bond)); -struct ethhdr *eth_data =eth_hdr (skb);if (!tx_slave) {/* unbalanced or unassigned, send through primary */
@@ -1352,7 +1357,9 @@ static netdev_tx_t bond_do_alb_xmit(struct sk_buff *skb, struct bonding *bond,if (tx_slave &&bond_slave_can_tx (tx_slave)) {if (tx_slave !=rcu_access_pointer (bond->curr_active_slave)) { -ether_addr_copy (eth_data->h_source, +if (unlikely (skb_cow_head (skb,0 ))) +return bond_tx_drop (bond->dev, skb); +ether_addr_copy (skb_eth_hdr (skb)->h_source, tx_slave->dev->dev_addr); }
@@ -1376,8 +1383,7 @@ struct slave *bond_xmit_tlb_slave_get(struct bonding *bond,struct ethhdr *eth_data;u32 hash_index; -skb_reset_mac_header (skb); - eth_data =eth_hdr (skb); + eth_data =skb_eth_hdr (skb);/* Do not TX balance any multicast or broadcast */ if (!is_multicast_ether_addr (eth_data->h_dest)) {
@@ -1429,8 +1435,7 @@ struct slave *bond_xmit_alb_slave_get(struct bonding *bond,u32 hash_index =0 ;int hash_size =0 ; -skb_reset_mac_header (skb); - eth_data =eth_hdr (skb); + eth_data =skb_eth_hdr (skb);switch (ntohs (skb->protocol)) {case ETH_P_IP : {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 663/1102 net: dsa: bcm_sf2: bound the CFP rule dump by the callers buffer size
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 cdb719f4b8596d9ccee2d56d204c2c4dce982f46 ]
bcm_sf2_cfp_rule_get_all() walks the whole cfp.unique bitmap into rule_locs[] without consulting nfc->rule_cnt, which is how many entries the caller had room for. ETHTOOL_GRXCLSRLALL requires no CAP_NET_ADMIN and the ioctl sizes the buffer from the rule_cnt userspace passes in, so once an admin has installed CFP rules any user can ask for fewer slots than there are rules and run off the end of the allocation. A rule_cnt of 0 leaves the buffer pointer NULL and the walk dereferences it.
--- drivers/net/dsa/bcm_sf2_cfp.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/net/dsa/bcm_sf2_cfp.c +2 -0
@@ -1088,6 +1088,8 @@ static int bcm_sf2_cfp_rule_get_all(struct bcm_sf2_priv *priv,unsigned int index =1 , rules_cnt =0 ;for_each_set_bit_from (index, priv->cfp.unique, priv->num_cfp_rules) { +if (rules_cnt == nfc->rule_cnt) +return -EMSGSIZE ; rule_locs[rules_cnt] = index; rules_cnt++; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 664/1102 ethtool: Symmetric OR-XOR RSS hash
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Gal Pressman <[email protected]>
[ Upstream commit ecdff893384cf169a55a66ca68c9d8917f8417a9 ]
Add an additional type of symmetric RSS hash type: OR-XOR. The "Symmetric-OR-XOR" algorithm transforms the input as follows:
(SRC_IP | DST_IP, SRC_IP ^ DST_IP, SRC_PORT | DST_PORT, SRC_PORT ^ DST_PORT)
Change 'cap_rss_sym_xor_supported' to 'supported_input_xfrm', a bitmap of supported RXH_XFRM_* types.
Stable-dep-of: f1986bf87b07 ("eth: nfp: bound the ntuple rule dump by the caller's buffer size")
--- Documentation/networking/ethtool-netlink.rst | 2 +- Documentation/networking/scaling.rst | 15 +++++++++++---- drivers/net/ethernet/intel/iavf/iavf_ethtool.c | 2 +- drivers/net/ethernet/intel/ice/ice_ethtool.c | 2 +- include/linux/ethtool.h | 5 ++--- include/uapi/linux/ethtool.h | 4 ++++ net/ethtool/ioctl.c | 8 ++++---- 7 files changed, 24 insertions(+), 14 deletions(-)
Documentation/networking/ethtool-netlink.rst +1 -1
@@ -1909,7 +1909,7 @@ ETHTOOL_A_RSS_INDIR attribute returns RSS indirection table where each byte indicates queue number. ETHTOOL_A_RSS_INPUT_XFRM attribute is a bitmap indicating the type of transformation applied to the input protocol fields before given to the RSS -hfunc. Current supported option is symmetric-xor. +hfunc. Current supported options are symmetric-xor and symmetric-or-xor. PLCA_GET_CFG ============
Documentation/networking/scaling.rst +11 -4
@@ -49,14 +49,21 @@ destination address) and TCP/UDP (source port, destination port) tuples are swapped, the computed hash is the same. This is beneficial in some applications that monitor TCP/IP flows (IDS, firewalls, ...etc) and need both directions of the flow to land on the same Rx queue (and CPU). The -"Symmetric-XOR" is a type of RSS algorithms that achieves this hash -symmetry by XORing the input source and destination fields of the IP -and/or L4 protocols. This, however, results in reduced input entropy and -could potentially be exploited. Specifically, the algorithm XORs the input +"Symmetric-XOR" and "Symmetric-OR-XOR" are types of RSS algorithms that +achieve this hash symmetry by XOR/ORing the input source and destination +fields of the IP and/or L4 protocols. This, however, results in reduced +input entropy and could potentially be exploited. + +Specifically, the "Symmetric-XOR" algorithm XORs the input as follows:: # (SRC_IP ^ DST_IP, SRC_IP ^ DST_IP, SRC_PORT ^ DST_PORT, SRC_PORT ^ DST_PORT) +The "Symmetric-OR-XOR" algorithm, on the other hand, transforms the input as +follows:: + + # (SRC_IP | DST_IP, SRC_IP ^ DST_IP, SRC_PORT | DST_PORT, SRC_PORT ^ DST_PORT) + The result is then fed to the underlying RSS algorithm. Some advanced NICs allow steering packets to queues based on
drivers/net/ethernet/intel/iavf/iavf_ethtool.c +1 -1
@@ -1807,7 +1807,7 @@ static int iavf_set_rxfh(struct net_device *netdev,static const struct ethtool_ops iavf_ethtool_ops = { .supported_coalesce_params =ETHTOOL_COALESCE_USECS |ETHTOOL_COALESCE_USE_ADAPTIVE , - .cap_rss_sym_xor_supported = true, + .supported_input_xfrm =RXH_XFRM_SYM_XOR , .get_drvinfo = iavf_get_drvinfo, .get_link = ethtool_op_get_link, .get_ringparam = iavf_get_ringparam,
drivers/net/ethernet/intel/ice/ice_ethtool.c +1 -1
@@ -4705,7 +4705,7 @@ static const struct ethtool_ops ice_ethtool_ops = { .supported_coalesce_params = ETHTOOL_COALESCE_USECS |ETHTOOL_COALESCE_USE_ADAPTIVE | ETHTOOL_COALESCE_RX_USECS_HIGH, - .cap_rss_sym_xor_supported = true, + .supported_input_xfrm = RXH_XFRM_SYM_XOR, .rxfh_per_ctx_key = true, .get_link_ksettings = ice_get_link_ksettings, .set_link_ksettings = ice_set_link_ksettings,
include/linux/ethtool.h +2 -3
@@ -747,13 +747,12 @@ struct kernel_ethtool_ts_info {/** * struct ethtool_ops - optional netdev operations +* @supported_input_xfrm: supported types of input xfrm from %RXH_XFRM_*. * @cap_link_lanes_supported: indicates if the driver supports lanes * parameter. * @cap_rss_ctx_supported: indicates if the driver supports RSS * contexts via legacy API, drivers implementing @create_rxfh_context * do not have to set this bit. -* @cap_rss_sym_xor_supported: indicates if the driver supports symmetric-xor -* RSS. * @rxfh_per_ctx_key: device supports setting different RSS key for each * additional context. Netlink API should report hfunc, key, and input_xfrm * for every context, not just context 0.
@@ -978,9 +977,9 @@ struct kernel_ethtool_ts_info {* of the generic netdev features interface. */ struct ethtool_ops { +u32 supported_input_xfrm:8 ;u32 cap_link_lanes_supported:1 ;u32 cap_rss_ctx_supported:1 ; -u32 cap_rss_sym_xor_supported:1 ;u32 rxfh_per_ctx_key:1 ;u32 cap_rss_rxnfc_adds:1 ;u32 rxfh_indir_space;
include/uapi/linux/ethtool.h +4 -0
@@ -2267,6 +2267,10 @@ static inline int ethtool_validate_duplex(__u8 duplex)* be exploited to reduce the RSS queue spread. */ #define RXH_XFRM_SYM_XOR (1 << 0) +/* Similar to SYM_XOR, except that one copy of the XOR'ed fields is replaced by +* an OR of the same fields +*/ +#define RXH_XFRM_SYM_OR_XOR (1 << 1)#define RXH_XFRM_NO_CHANGE 0xff/* L2-L4 network traffic flow types */
net/ethtool/ioctl.c +4 -4
@@ -1005,11 +1005,11 @@ static noinline_for_stack int ethtool_set_rxnfc(struct net_device *dev,if (rc)return rc; -/* Sanity check: if symmetric-xor is set, then: +/* Sanity check: if symmetric-xor/symmetric-or-xor is set, then: * 1 - no other fields besides IP src/dst and/or L4 src/dst * 2 - If src is set, dst must also be set */ - if ((rxfh.input_xfrm & RXH_XFRM_SYM_XOR) && + if ((rxfh.input_xfrm & (RXH_XFRM_SYM_XOR | RXH_XFRM_SYM_OR_XOR)) && ((info.data & ~(RXH_IP_SRC | RXH_IP_DST | RXH_L4_B_0_1 | RXH_L4_B_2_3)) || (!!(info.data & RXH_IP_SRC) ^ !!(info.data & RXH_IP_DST)) ||
@@ -1382,11 +1382,11 @@ static noinline_for_stack int ethtool_set_rxfh(struct net_device *dev,return -EOPNOTSUPP ;/* Check input data transformation capabilities */ if (rxfh.input_xfrm && rxfh.input_xfrm !=RXH_XFRM_SYM_XOR && + rxfh.input_xfrm !=RXH_XFRM_SYM_OR_XOR && rxfh.input_xfrm !=RXH_XFRM_NO_CHANGE )return -EINVAL ;if (rxfh.input_xfrm !=RXH_XFRM_NO_CHANGE && - (rxfh.input_xfrm &RXH_XFRM_SYM_XOR ) && - !ops->cap_rss_sym_xor_supported) + rxfh.input_xfrm & ~ops->supported_input_xfrm)return -EOPNOTSUPP ; create = rxfh.rss_context ==ETH_RXFH_CONTEXT_ALLOC ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 665/1102 ethtool: Block setting of symmetric RSS when non-symmetric rx-flow-hash is requested
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Gal Pressman <[email protected]>
[ Upstream commit 1b2900db0119c02e6445bb61ec3fba982d10cc8d ]
Symmetric RSS hash requires that:
* No other fields besides IP src/dst and/or L4 src/dst are set
* If src is set, dst must also be set
This restriction was only enforced when RXNFC was configured after symmetric hash was enabled. In the opposite order of operations (RXNFC then symmetric enablement) the check was not performed.
Perform the sanity check on set_rxfh as well, by iterating over all flow types hash fields and making sure they are all symmetric.
Introduce a function that returns whether a flow type is hashable (not spec only) and needs to be iterated over. To make sure that no one forgets to update the list of hashable flow types when adding new flow types, a static assert is added to draw the developer's attention.
The conversion of uapi #defines to enum is not ideal, but as Jakub mentioned [1], we have precedent for that.
[1] https://lore.kernel.org/netdev/[email protected]/
Stable-dep-of: f1986bf87b07 ("eth: nfp: bound the ntuple rule dump by the caller's buffer size")
--- include/uapi/linux/ethtool.h | 134 ++++++++++++++++++----------------- net/ethtool/ioctl.c | 99 +++++++++++++++++++++++--- 2 files changed, 158 insertions(+), 75 deletions(-)
include/uapi/linux/ethtool.h +69 -65
@@ -2273,71 +2273,75 @@ static inline int ethtool_validate_duplex(__u8 duplex)#define RXH_XFRM_SYM_OR_XOR (1 << 1)#define RXH_XFRM_NO_CHANGE 0xff -/* L2-L4 network traffic flow types */ -#define TCP_V4_FLOW 0x01/* hash or spec (tcp_ip4_spec) */ -#define UDP_V4_FLOW 0x02/* hash or spec (udp_ip4_spec) */ -#define SCTP_V4_FLOW 0x03/* hash or spec (sctp_ip4_spec) */ -#define AH_ESP_V4_FLOW 0x04/* hash only */ -#define TCP_V6_FLOW 0x05/* hash or spec (tcp_ip6_spec; nfc only) */ -#define UDP_V6_FLOW 0x06/* hash or spec (udp_ip6_spec; nfc only) */ -#define SCTP_V6_FLOW 0x07/* hash or spec (sctp_ip6_spec; nfc only) */ -#define AH_ESP_V6_FLOW 0x08/* hash only */ -#define AH_V4_FLOW 0x09/* hash or spec (ah_ip4_spec) */ -#define ESP_V4_FLOW 0x0a/* hash or spec (esp_ip4_spec) */ -#define AH_V6_FLOW 0x0b/* hash or spec (ah_ip6_spec; nfc only) */ -#define ESP_V6_FLOW 0x0c/* hash or spec (esp_ip6_spec; nfc only) */ -#define IPV4_USER_FLOW 0x0d/* spec only (usr_ip4_spec) */ -#define IP_USER_FLOW IPV4_USER_FLOW -#define IPV6_USER_FLOW 0x0e/* spec only (usr_ip6_spec; nfc only) */ -#define IPV4_FLOW 0x10/* hash only */ -#define IPV6_FLOW 0x11/* hash only */ -#define ETHER_FLOW 0x12/* spec only (ether_spec) */ - -/* Used for GTP-U IPv4 and IPv6. -* The format of GTP packets only includes -* elements such as TEID and GTP version. -* It is primarily intended for data communication of the UE. -*/ -#define GTPU_V4_FLOW 0x13/* hash only */ -#define GTPU_V6_FLOW 0x14/* hash only */ - -/* Use for GTP-C IPv4 and v6. -* The format of these GTP packets does not include TEID. -* Primarily expected to be used for communication -* to create sessions for UE data communication, -* commonly referred to as CSR (Create Session Request). -*/ -#define GTPC_V4_FLOW 0x15/* hash only */ -#define GTPC_V6_FLOW 0x16/* hash only */ - -/* Use for GTP-C IPv4 and v6. -* Unlike GTPC_V4_FLOW, the format of these GTP packets includes TEID. -* After session creation, it becomes this packet. -* This is mainly used for requests to realize UE handover. -*/ -#define GTPC_TEID_V4_FLOW 0x17/* hash only */ -#define GTPC_TEID_V6_FLOW 0x18/* hash only */ - -/* Use for GTP-U and extended headers for the PSC (PDU Session Container). -* The format of these GTP packets includes TEID and QFI. -* In 5G communication using UPF (User Plane Function), -* data communication with this extended header is performed. -*/ -#define GTPU_EH_V4_FLOW 0x19/* hash only */ -#define GTPU_EH_V6_FLOW 0x1a/* hash only */ - -/* Use for GTP-U IPv4 and v6 PSC (PDU Session Container) extended headers. -* This differs from GTPU_EH_V(4|6)_FLOW in that it is distinguished by -* UL/DL included in the PSC. -* There are differences in the data included based on Downlink/Uplink, -* and can be used to distinguish packets. -* The functions described so far are useful when you want to -* handle communication from the mobile network in UPF, PGW, etc. -*/ -#define GTPU_UL_V4_FLOW 0x1b/* hash only */ -#define GTPU_UL_V6_FLOW 0x1c/* hash only */ -#define GTPU_DL_V4_FLOW 0x1d/* hash only */ -#define GTPU_DL_V6_FLOW 0x1e/* hash only */ +enum { +/* L2-L4 network traffic flow types */ +TCP_V4_FLOW =0x01 ,/* hash or spec (tcp_ip4_spec) */ +UDP_V4_FLOW =0x02 ,/* hash or spec (udp_ip4_spec) */ +SCTP_V4_FLOW =0x03 ,/* hash or spec (sctp_ip4_spec) */ +AH_ESP_V4_FLOW =0x04 ,/* hash only */ +TCP_V6_FLOW =0x05 ,/* hash or spec (tcp_ip6_spec; nfc only) */ +UDP_V6_FLOW =0x06 ,/* hash or spec (udp_ip6_spec; nfc only) */ +SCTP_V6_FLOW =0x07 ,/* hash or spec (sctp_ip6_spec; nfc only) */ +AH_ESP_V6_FLOW =0x08 ,/* hash only */ +AH_V4_FLOW =0x09 ,/* hash or spec (ah_ip4_spec) */ +ESP_V4_FLOW =0x0a ,/* hash or spec (esp_ip4_spec) */ +AH_V6_FLOW =0x0b ,/* hash or spec (ah_ip6_spec; nfc only) */ +ESP_V6_FLOW =0x0c ,/* hash or spec (esp_ip6_spec; nfc only) */ +IPV4_USER_FLOW =0x0d ,/* spec only (usr_ip4_spec) */ +IP_USER_FLOW =IPV4_USER_FLOW , +IPV6_USER_FLOW =0x0e ,/* spec only (usr_ip6_spec; nfc only) */ +IPV4_FLOW =0x10 ,/* hash only */ +IPV6_FLOW =0x11 ,/* hash only */ +ETHER_FLOW =0x12 ,/* spec only (ether_spec) */ + +/* Used for GTP-U IPv4 and IPv6. +* The format of GTP packets only includes +* elements such as TEID and GTP version. +* It is primarily intended for data communication of the UE. +*/ +GTPU_V4_FLOW =0x13 ,/* hash only */ +GTPU_V6_FLOW =0x14 ,/* hash only */ + +/* Use for GTP-C IPv4 and v6. +* The format of these GTP packets does not include TEID. +* Primarily expected to be used for communication +* to create sessions for UE data communication, +* commonly referred to as CSR (Create Session Request). +*/ +GTPC_V4_FLOW =0x15 ,/* hash only */ +GTPC_V6_FLOW =0x16 ,/* hash only */ + +/* Use for GTP-C IPv4 and v6. +* Unlike GTPC_V4_FLOW, the format of these GTP packets includes TEID. +* After session creation, it becomes this packet. +* This is mainly used for requests to realize UE handover. +*/ +GTPC_TEID_V4_FLOW =0x17 ,/* hash only */ +GTPC_TEID_V6_FLOW =0x18 ,/* hash only */ + +/* Use for GTP-U and extended headers for the PSC (PDU Session Container). +* The format of these GTP packets includes TEID and QFI. +* In 5G communication using UPF (User Plane Function), +* data communication with this extended header is performed. +*/ +GTPU_EH_V4_FLOW =0x19 ,/* hash only */ +GTPU_EH_V6_FLOW =0x1a ,/* hash only */ + +/* Use for GTP-U IPv4 and v6 PSC (PDU Session Container) extended headers. +* This differs from GTPU_EH_V(4|6)_FLOW in that it is distinguished by +* UL/DL included in the PSC. +* There are differences in the data included based on Downlink/Uplink, +* and can be used to distinguish packets. +* The functions described so far are useful when you want to +* handle communication from the mobile network in UPF, PGW, etc. +*/ +GTPU_UL_V4_FLOW =0x1b ,/* hash only */ +GTPU_UL_V6_FLOW =0x1c ,/* hash only */ +GTPU_DL_V4_FLOW =0x1d ,/* hash only */ +GTPU_DL_V6_FLOW =0x1e ,/* hash only */ + + __FLOW_TYPE_COUNT, +};/* Flag to enable additional fields in struct ethtool_rx_flow_spec */ #define FLOW_EXT 0x80000000
net/ethtool/ioctl.c +89 -10
117 lines not on this page · raw message
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 666/1102 net: ethtool: copy the rxfh flow handling
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 f4f126535546e275ffd89cdb9cc2fd581ebf3670 ]
RX Flow Hash configuration uses the same argument structure as flow filters. This is probably why ethtool IOCTL handles them together. The more checks we add the more convoluted this code is getting (as some of the checks apply only to flow filters and others only to the hashing).
Copy the code to separate the handling. This is an exact copy, the next change will remove unnecessary handling.
Stable-dep-of: f1986bf87b07 ("eth: nfp: bound the ntuple rule dump by the caller's buffer size")
--- net/ethtool/ioctl.c | 93 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 92 insertions(+), 1 deletion(-)
net/ethtool/ioctl.c +92 -1
@@ -1059,6 +1059,93 @@ static int ethtool_check_flow_types(struct net_device *dev, u32 input_xfrm)return 0 ; } +static noinline_for_stack int +ethtool_set_rxfh_fields (struct net_device *dev,u32 cmd,void __user *useraddr) +{ +const struct ethtool_ops *ops = dev->ethtool_ops; +struct ethtool_rxnfc info; +size_t info_size =sizeof (info); +int rc; + +if (!ops->set_rxnfc) +return -EOPNOTSUPP ; + + rc =ethtool_rxnfc_copy_struct (cmd, &info, &info_size, useraddr); +if (rc) +return rc; + +if (cmd ==ETHTOOL_SRXCLSRLINS && info.fs.flow_type &FLOW_RSS ) { +/* Nonzero ring with RSS only makes sense +* if NIC adds them together +*/ +if (!ops->cap_rss_rxnfc_adds && +ethtool_get_flow_spec_ring (info.fs.ring_cookie)) +return -EINVAL ; + +if (!xa_load (&dev->ethtool->rss_ctx, info.rss_context)) +return -EINVAL ; + } + +if (cmd ==ETHTOOL_SRXFH && ops->get_rxfh) { +struct ethtool_rxfh_param rxfh = {}; + + rc = ops->get_rxfh (dev, &rxfh); +if (rc) +return rc; + + rc =ethtool_check_xfrm_rxfh (rxfh.input_xfrm, info.data); +if (rc) +return rc; + } + + rc = ops->set_rxnfc (dev, &info); +if (rc) +return rc; + +if (cmd ==ETHTOOL_SRXCLSRLINS && +ethtool_rxnfc_copy_to_user (useraddr, &info, info_size,NULL )) +return -EFAULT ; + +return 0 ; +} + +static noinline_for_stack int +ethtool_get_rxfh_fields (struct net_device *dev,u32 cmd,void __user *useraddr) +{ +struct ethtool_rxnfc info; +size_t info_size =sizeof (info); +const struct ethtool_ops *ops = dev->ethtool_ops; +int ret; +void *rule_buf =NULL ; + +if (!ops->get_rxnfc) +return -EOPNOTSUPP ; + + ret =ethtool_rxnfc_copy_struct (cmd, &info, &info_size, useraddr); +if (ret) +return ret; + +if (info.cmd ==ETHTOOL_GRXCLSRLALL ) { +if (info.rule_cnt >0 ) { +if (info.rule_cnt <=KMALLOC_MAX_SIZE /sizeof (u32)) + rule_buf =kcalloc (info.rule_cnt,sizeof (u32), +GFP_USER ); +if (!rule_buf) +return -ENOMEM ; + } + } + + ret = ops->get_rxnfc (dev, &info, rule_buf); +if (ret <0 ) + goto err_out; + + ret =ethtool_rxnfc_copy_to_user (useraddr, &info, info_size, rule_buf); +err_out: +kfree (rule_buf); + +return ret; +} + static noinline_for_stack int ethtool_set_rxnfc(struct net_device *dev,u32 cmd,void __user *useraddr) {
@@ -3336,13 +3423,17 @@ __dev_ethtool(struct net *net, struct ifreq *ifr, void __user *useraddr, dev->ethtool_ops->set_priv_flags);break ;case ETHTOOL_GRXFH : + rc =ethtool_get_rxfh_fields (dev, ethcmd, useraddr); +break ; +case ETHTOOL_SRXFH : + rc =ethtool_set_rxfh_fields (dev, ethcmd, useraddr); +break ;case ETHTOOL_GRXRINGS :case ETHTOOL_GRXCLSRLCNT :case ETHTOOL_GRXCLSRULE :case ETHTOOL_GRXCLSRLALL : rc =ethtool_get_rxnfc (dev, ethcmd, useraddr);break ; -case ETHTOOL_SRXFH :case ETHTOOL_SRXCLSRLDEL :case ETHTOOL_SRXCLSRLINS : rc =ethtool_set_rxnfc (dev, ethcmd, useraddr);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 667/1102 net: ethtool: remove the duplicated handling from rxfh and rxnfc
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 2a644c5cecc028c4fcd6545dd736b4dee949b090 ]
Now that the handles have been separated - remove the RX Flow Hash handling from rxnfc functions and vice versa.
Stable-dep-of: f1986bf87b07 ("eth: nfp: bound the ntuple rule dump by the caller's buffer size")
--- net/ethtool/ioctl.c | 57 ++++----------------------------------------- 1 file changed, 5 insertions(+), 52 deletions(-)
net/ethtool/ioctl.c +5 -52
@@ -1074,19 +1074,7 @@ ethtool_set_rxfh_fields(struct net_device *dev, u32 cmd, void __user *useraddr)if (rc)return rc; -if (cmd ==ETHTOOL_SRXCLSRLINS && info.fs.flow_type &FLOW_RSS ) { -/* Nonzero ring with RSS only makes sense -* if NIC adds them together -*/ -if (!ops->cap_rss_rxnfc_adds && -ethtool_get_flow_spec_ring (info.fs.ring_cookie)) -return -EINVAL ; - -if (!xa_load (&dev->ethtool->rss_ctx, info.rss_context)) -return -EINVAL ; - } - -if (cmd ==ETHTOOL_SRXFH && ops->get_rxfh) { +if (ops->get_rxfh) {struct ethtool_rxfh_param rxfh = {}; rc = ops->get_rxfh (dev, &rxfh);
@@ -1098,15 +1086,7 @@ ethtool_set_rxfh_fields(struct net_device *dev, u32 cmd, void __user *useraddr)return rc; } - rc = ops->set_rxnfc (dev, &info); -if (rc) -return rc; - -if (cmd ==ETHTOOL_SRXCLSRLINS && -ethtool_rxnfc_copy_to_user (useraddr, &info, info_size,NULL )) -return -EFAULT ; - -return 0 ; +return ops->set_rxnfc (dev, &info); }static noinline_for_stack int
@@ -1116,7 +1096,6 @@ ethtool_get_rxfh_fields(struct net_device *dev, u32 cmd, void __user *useraddr)size_t info_size =sizeof (info);const struct ethtool_ops *ops = dev->ethtool_ops;int ret; -void *rule_buf =NULL ;if (!ops->get_rxnfc)return -EOPNOTSUPP ;
@@ -1125,25 +1104,11 @@ ethtool_get_rxfh_fields(struct net_device *dev, u32 cmd, void __user *useraddr)if (ret)return ret; -if (info.cmd ==ETHTOOL_GRXCLSRLALL ) { -if (info.rule_cnt >0 ) { -if (info.rule_cnt <=KMALLOC_MAX_SIZE /sizeof (u32)) - rule_buf =kcalloc (info.rule_cnt,sizeof (u32), -GFP_USER ); -if (!rule_buf) -return -ENOMEM ; - } - } - - ret = ops->get_rxnfc (dev, &info, rule_buf); + ret = ops->get_rxnfc (dev, &info,NULL );if (ret <0 ) - goto err_out; - - ret =ethtool_rxnfc_copy_to_user (useraddr, &info, info_size, rule_buf); -err_out: -kfree (rule_buf); +return ret; -return ret; +return ethtool_rxnfc_copy_to_user (useraddr, &info, info_size,NULL ); } static noinline_for_stack int ethtool_set_rxnfc(struct net_device *dev,
@@ -1167,18 +1132,6 @@ static noinline_for_stack int ethtool_set_rxnfc(struct net_device *dev, ethtool_get_flow_spec_ring(info.fs.ring_cookie))return -EINVAL ; -if (cmd ==ETHTOOL_SRXFH && ops->get_rxfh) { -struct ethtool_rxfh_param rxfh = {}; - - rc = ops->get_rxfh (dev, &rxfh); -if (rc) -return rc; - - rc =ethtool_check_xfrm_rxfh (rxfh.input_xfrm, info.data); -if (rc) -return rc; - } - rc = ops->set_rxnfc (dev, &info);if (rc)return rc;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 668/1102 net: ethtool: require drivers to opt into the per-RSS ctx RXFH
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 fac4b41741b5cd0826cf0fa5b14e177f70a6b509 ]
RX Flow Hashing supports using different configuration for different RSS contexts. Only two drivers seem to support it. Make sure we uniformly error out for drivers which don't.
Stable-dep-of: f1986bf87b07 ("eth: nfp: bound the ntuple rule dump by the caller's buffer size")
--- drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c | 1 + drivers/net/ethernet/sfc/ethtool.c | 1 + include/linux/ethtool.h | 3 +++ net/ethtool/ioctl.c | 8 ++++++++ 4 files changed, 13 insertions(+)
drivers/net/ethernet/mellanox/mlx5/core/en_ethtool.c +1 -0
@@ -2606,6 +2606,7 @@ static void mlx5e_get_ts_stats(struct net_device *netdev,const struct ethtool_ops mlx5e_ethtool_ops = { .cap_rss_ctx_supported = true, + .rxfh_per_ctx_fields = true, .rxfh_per_ctx_key = true, .supported_coalesce_params =ETHTOOL_COALESCE_USECS | ETHTOOL_COALESCE_MAX_FRAMES |
drivers/net/ethernet/sfc/ethtool.c +1 -0
@@ -262,6 +262,7 @@ const struct ethtool_ops efx_ethtool_ops = { .set_rxnfc = efx_ethtool_set_rxnfc, .get_rxfh_indir_size = efx_ethtool_get_rxfh_indir_size, .get_rxfh_key_size = efx_ethtool_get_rxfh_key_size, + .rxfh_per_ctx_fields = true, .rxfh_per_ctx_key = true, .cap_rss_rxnfc_adds = true, .rxfh_priv_size = sizeof(struct efx_rss_context_priv),
include/linux/ethtool.h +3 -0
@@ -753,6 +753,8 @@ struct kernel_ethtool_ts_info {* @cap_rss_ctx_supported: indicates if the driver supports RSS * contexts via legacy API, drivers implementing @create_rxfh_context * do not have to set this bit. +* @rxfh_per_ctx_fields: device supports selecting different header fields +* for Rx hash calculation and RSS for each additional context. * @rxfh_per_ctx_key: device supports setting different RSS key for each * additional context. Netlink API should report hfunc, key, and input_xfrm * for every context, not just context 0.
@@ -980,6 +982,7 @@ struct ethtool_ops { u32 supported_input_xfrm:8; u32 cap_link_lanes_supported:1; u32 cap_rss_ctx_supported:1; + u32 rxfh_per_ctx_fields:1; u32 rxfh_per_ctx_key:1; u32 cap_rss_rxnfc_adds:1;u32 rxfh_indir_space;
net/ethtool/ioctl.c +8 -0
@@ -1074,6 +1074,10 @@ ethtool_set_rxfh_fields(struct net_device *dev, u32 cmd, void __user *useraddr)if (rc)return rc; +if (info.flow_type &FLOW_RSS && info.rss_context && + !ops->rxfh_per_ctx_fields) +return -EINVAL ; +if (ops->get_rxfh) {struct ethtool_rxfh_param rxfh = {};
@@ -1104,6 +1108,10 @@ ethtool_get_rxfh_fields(struct net_device *dev, u32 cmd, void __user *useraddr)if (ret)return ret; +if (info.flow_type &FLOW_RSS && info.rss_context && + !ops->rxfh_per_ctx_fields) +return -EINVAL ; + ret = ops->get_rxnfc (dev, &info,NULL );if (ret <0 )return ret;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 669/1102 net: ethtool: add dedicated callbacks for getting and setting rxfh fields
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 9bb00786fc61e865e121aa20dd12aa4d1311a990 ]
We mux multiple calls to the drivers via the .get_nfc and .set_nfc callbacks. This is slightly inconvenient to the drivers as they have to de-mux them back. It will also be awkward for netlink code to construct struct ethtool_rxnfc when it wants to get info about RX Flow Hash, from the RSS module.
Add dedicated driver callbacks. Create struct ethtool_rxfh_fields which contains only data relevant to RXFH. Maintain the names of the fields to avoid having to heavily modify the drivers.
For now support both callbacks, once all drivers are converted ethtool_*et_rxfh_fields() will stop using the rxnfc callbacks.
Stable-dep-of: f1986bf87b07 ("eth: nfp: bound the ntuple rule dump by the caller's buffer size")
--- include/linux/ethtool.h | 20 +++++++++++++++ net/ethtool/ioctl.c | 55 +++++++++++++++++++++++++++++++++-------- 2 files changed, 65 insertions(+), 10 deletions(-)
include/linux/ethtool.h +20 -0
@@ -729,6 +729,19 @@ struct ethtool_rxfh_param {u8 input_xfrm; }; +/** +* struct ethtool_rxfh_fields - Rx Flow Hashing (RXFH) header field config +* @data: which header fields are used for hashing, bitmask of RXH_* defines +* @flow_type: L2-L4 network traffic flow type +* @rss_context: RSS context, will only be used if rxfh_per_ctx_fields is +* set in struct ethtool_ops +*/ +struct ethtool_rxfh_fields { +u32 data; +u32 flow_type; +u32 rss_context; +}; +/** * struct kernel_ethtool_ts_info - kernel copy of struct ethtool_ts_info * @cmd: command number = %ETHTOOL_GET_TS_INFO
@@ -867,6 +880,8 @@ struct kernel_ethtool_ts_info {* will remain unchanged. * Returns a negative error code or zero. An error code must be returned * if at least one unsupported change was requested. +* @get_rxfh_fields: Get header fields used for flow hashing. +* @set_rxfh_fields: Set header fields used for flow hashing. * @create_rxfh_context: Create a new RSS context with the specified RX flow * hash indirection table, hash key, and hash function. * The &struct ethtool_rxfh_context for this context is passed in @ctx;
@@ -1051,6 +1066,11 @@ struct ethtool_ops {int (*get_rxfh)(struct net_device *,struct ethtool_rxfh_param *);int (*set_rxfh)(struct net_device *,struct ethtool_rxfh_param *,struct netlink_ext_ack *extack); +int (*get_rxfh_fields)(struct net_device *, +struct ethtool_rxfh_fields *); +int (*set_rxfh_fields)(struct net_device *, +const struct ethtool_rxfh_fields *, +struct netlink_ext_ack *extack); int (*create_rxfh_context)(struct net_device *, struct ethtool_rxfh_context *ctx, const struct ethtool_rxfh_param *rxfh,
net/ethtool/ioctl.c +45 -10
95 lines not on this page · raw message
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 670/1102 eth: nfp: migrate to new RXFH callbacks
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 6bfd8cf33859ae23ec9e07a5bdbb55315305962a ]
Migrate to new callbacks added by commit 9bb00786fc61 ("net: ethtool:
add dedicated callbacks for getting and setting rxfh fields").
Stable-dep-of: f1986bf87b07 ("eth: nfp: bound the ntuple rule dump by the caller's buffer size")
--- .../ethernet/netronome/nfp/nfp_net_ethtool.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-)
drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c +9 -8
@@ -1303,9 +1303,10 @@ static u32 ethtool_flow_to_nfp_flag(u32 flow_type)return xlate_ethtool_to_nfp[flow_type]; } -static int nfp_net_get_rss_hash_opts (struct nfp_net *nn, -struct ethtool_rxnfc *cmd) +static int nfp_net_get_rxfh_fields (struct net_device *netdev, +struct ethtool_rxfh_fields *cmd) { +struct nfp_net *nn =netdev_priv (netdev);u32 nfp_rss_flag; cmd->data =0 ;
@@ -1451,16 +1452,16 @@ static int nfp_net_get_rxnfc(struct net_device *netdev,case ETHTOOL_GRXCLSRLALL : cmd->data =NFP_FS_MAX_ENTRY ;return nfp_net_get_fs_loc (nn, rule_locs); -case ETHTOOL_GRXFH : -return nfp_net_get_rss_hash_opts (nn, cmd);default :return -EOPNOTSUPP ; } } -static int nfp_net_set_rss_hash_opt (struct nfp_net *nn, -struct ethtool_rxnfc *nfc) +static int nfp_net_set_rxfh_fields (struct net_device *netdev, +const struct ethtool_rxfh_fields *nfc, +struct netlink_ext_ack *extack) { +struct nfp_net *nn =netdev_priv (netdev);u32 new_rss_cfg = nn->rss_cfg;u32 nfp_rss_flag;int err;
@@ -1763,8 +1764,6 @@ static int nfp_net_set_rxnfc(struct net_device *netdev,struct nfp_net *nn =netdev_priv (netdev);switch (cmd->cmd) { -case ETHTOOL_SRXFH : -return nfp_net_set_rss_hash_opt (nn, cmd);case ETHTOOL_SRXCLSRLINS :return nfp_net_fs_add (nn, cmd);case ETHTOOL_SRXCLSRLDEL :
@@ -2506,6 +2505,8 @@ static const struct ethtool_ops nfp_net_ethtool_ops = { .get_rxfh_key_size = nfp_net_get_rxfh_key_size, .get_rxfh = nfp_net_get_rxfh, .set_rxfh = nfp_net_set_rxfh, + .get_rxfh_fields = nfp_net_get_rxfh_fields, + .set_rxfh_fields = nfp_net_set_rxfh_fields, .get_regs_len = nfp_net_get_regs_len, .get_regs = nfp_net_get_regs, .set_dump = nfp_app_set_dump,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 671/1102 eth: nfp: bound the ntuple rule dump by the callers buffer size
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 f1986bf87b0709c95126fe196cf39e5b8c8453a1 ]
nfp_net_get_fs_loc() dumps every entry of nn->fs.list into rule_locs[] without consulting cmd->rule_cnt, which is how many entries the caller had room for. ETHTOOL_GRXCLSRLALL requires no CAP_NET_ADMIN and the ioctl sizes the buffer from the rule_cnt userspace passes in, so once an admin has installed flow steering rules any user can ask for fewer slots than there are rules and run off the end of the allocation. A rule_cnt of 0 leaves the buffer pointer NULL and the walk dereferences it.
Bail out with -EMSGSIZE when the buffer fills up, the way the other ntuple capable drivers do, and report how many locations were filled so a shrinking rule list does not leave the caller reading stale slots.
--- drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-)
drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c +8 -3
@@ -1421,7 +1421,8 @@ static int nfp_net_get_fs_rule(struct nfp_net *nn, struct ethtool_rxnfc *cmd)return -ENOENT ; } -static int nfp_net_get_fs_loc (struct nfp_net *nn,u32 *rule_locs) +static int nfp_net_get_fs_loc (struct nfp_net *nn,struct ethtool_rxnfc *cmd, +u32 *rule_locs) {struct nfp_fs_entry *entry;u32 count =0 ;
@@ -1429,8 +1430,12 @@ static int nfp_net_get_fs_loc(struct nfp_net *nn, u32 *rule_locs)if (!(nn->cap_w1 &NFP_NET_CFG_CTRL_FLOW_STEER ))return -EOPNOTSUPP ; -list_for_each_entry (entry, &nn->fs.list, node) +list_for_each_entry (entry, &nn->fs.list, node) { +if (count == cmd->rule_cnt) +return -EMSGSIZE ; rule_locs[count++] = entry->loc; + } + cmd->rule_cnt = count;return 0 ; }
@@ -1451,7 +1456,7 @@ static int nfp_net_get_rxnfc(struct net_device *netdev,return nfp_net_get_fs_rule (nn, cmd);case ETHTOOL_GRXCLSRLALL : cmd->data =NFP_FS_MAX_ENTRY ; -return nfp_net_get_fs_loc (nn, rule_locs); +return nfp_net_get_fs_loc (nn, cmd, rule_locs);default :return -EOPNOTSUPP ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 672/1102 eth: nfp: drop the replaced rule from the list when reprogramming fails
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 108bb2142e3a12c9ad625ad662973127a113ddc6 ]
nfp_net_fs_add() replaces an existing rule by deleting it from the hardware, decrementing nn->fs.count and programming the new one. If nfp_net_fs_add_hw() fails the old entry stays on nn->fs.list - only the success path reaches list_replace() - so the list is one longer than nn->fs.count, and it advertises a rule whose hardware entry has already been torn down.
nn->fs.count is what ETHTOOL_GRXCLSRLCNT reports, so userspace then sizes its buffer one entry short of what the GRXCLSRLALL walk wants to write. That used to overwrite one u32 past the allocation; since the walk is bounded it is a permanent -EMSGSIZE instead, as nothing ever resyncs the counter.
--- drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
drivers/net/ethernet/netronome/nfp/nfp_net_ethtool.c +7 -1
@@ -1699,8 +1699,14 @@ static int nfp_net_fs_add(struct nfp_net *nn, struct ethtool_rxnfc *cmd) nn->fs.count--; err =nfp_net_fs_add_hw (nn, new); -if (err) +if (err) { +/* mbox broken, adding the old rule back will +* likely also fail. +*/ +list_del (&entry->node); +kfree (entry); goto err; + } nn->fs.count++;list_replace (&entry->node, &new->node);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 673/1102 net: dsa: mv88e6xxx: bound the policy rule dump by the callers buffer size
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 b1fffc273112e7284c5b705e186b43b5770cd3d5 ]
mv88e6xxx_get_rxnfc() uses rxnfc->rule_cnt as the write index while dumping the policy IDR, clobbering the input value before it has been looked at. That input is the number of entries the caller had room for. ETHTOOL_GRXCLSRLALL requires no CAP_NET_ADMIN and the ioctl sizes the buffer from the rule_cnt userspace passes in, so once an admin has installed policy rules any user can ask for fewer slots than there are rules and run off the end of the allocation. A rule_cnt of 0 leaves the buffer pointer NULL and the walk dereferences it.
Count into a local so the caller's limit survives the walk, and stop with -EMSGSIZE once it is reached.
--- drivers/net/dsa/mv88e6xxx/chip.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-)
drivers/net/dsa/mv88e6xxx/chip.c +12 -4
@@ -2492,6 +2492,7 @@ static int mv88e6xxx_get_rxnfc(struct dsa_switch *ds, int port,struct ethtool_rx_flow_spec *fs = &rxnfc->fs;struct mv88e6xxx_chip *chip = ds->priv;struct mv88e6xxx_policy *policy; +u32 cnt =0 ;int err;int id;
@@ -2517,11 +2518,18 @@ static int mv88e6xxx_get_rxnfc(struct dsa_switch *ds, int port,break ;case ETHTOOL_GRXCLSRLALL : rxnfc->data =0 ; - rxnfc->rule_cnt =0 ; -idr_for_each_entry (&chip->policies, policy, id) -if (policy->port == port) - rule_locs[rxnfc->rule_cnt++] = id; err =0 ; +idr_for_each_entry (&chip->policies, policy, id) { +if (policy->port != port) +continue ; +if (cnt == rxnfc->rule_cnt) { + err = -EMSGSIZE ; +break ; + } + rule_locs[cnt++] = id; + } +if (!err) + rxnfc->rule_cnt = cnt;break ;default : err = -EOPNOTSUPP ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 674/1102 net: bridge: mcast: properly convert mglist to rcu
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nikolay Aleksandrov <[email protected]>
[ Upstream commit 4b772869a1e5f9da5cef5b9c722ec0aa424ee0a0 ]
Sashiko reported a bug [1] that br_multicast_del_port_group unlists the port group not using proper rcu helper that preserves the next pointer and after that immediately frees the port group without waiting for rcu grace period. The only rcu walker of mglist is br_multicast_list_adjacent() and it turns out that function has always been buggy because mglist was never properly converted to RCU. Fix it by converting it to rcu and moving its initialization after eth_addr's. Initializing p->next can use RCU_INIT_POINTER because we have a barrier from the hlist_add_head_rcu call later, besides we're initializing an unpublished structure anyway.
[1] https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260826014200.362304-1-littleddfu%40gmail.com
--- net/bridge/br_multicast.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-)
net/bridge/br_multicast.c +5 -4
@@ -1437,16 +1437,17 @@ struct net_bridge_port_group *br_multicast_new_port_group( goto free_out; } -rcu_assign_pointer (p->next, next);timer_setup (&p->timer, br_multicast_port_group_expired,0 );timer_setup (&p->rexmit_timer, br_multicast_port_group_rexmit,0 ); -hlist_add_head (&p->mglist, &port->mglist);if (src)memcpy (p->eth_addr, src,ETH_ALEN );else eth_broadcast_addr (p->eth_addr); +RCU_INIT_POINTER (p->next, next); +hlist_add_head_rcu (&p->mglist, &port->mglist); +return p; free_out:
@@ -1461,11 +1462,11 @@ void br_multicast_del_port_group(struct net_bridge_port_group *p)struct net_bridge_port *port = p->key.port;__u16 vid = p->key.addr.vid; -hlist_del_init (&p->mglist); +hlist_del_init_rcu (&p->mglist);if (!br_multicast_is_star_g (&p->key.addr))rhashtable_remove_fast (&port->br->sg_port_tbl, &p->rhnode, br_sg_port_rht_params); -kfree (p); +kfree_rcu (p, rcu);br_multicast_port_ngroups_dec (port, vid); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 675/1102 octeontx2-af: mcs: Clear stale X2P calibration state before calibration
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Viswajith Murali <[email protected]>
[ Upstream commit 1f29543126dde307e8b5fb6a740c54e59deaa2ff ]
Some firmware versions leave MCSX_MIL_GLOBAL bit 5 set on boot. If the bit is already set when the driver attempts X2P calibration, the hardware sees no rising edge and calibration never triggers. Clear the bit and wait briefly before starting calibration to ensure a clean rising edge.
--- drivers/net/ethernet/marvell/octeontx2/af/mcs.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
drivers/net/ethernet/marvell/octeontx2/af/mcs.c +10 -0
@@ -1417,6 +1417,16 @@ static int mcs_x2p_calibration(struct mcs *mcs)int i, err =0 ;u64 val; +/* Clear any stale calibration state left by firmware/bootloader. +* Some firmware versions may leave MCSX_MIL_GLOBAL bit 5 set, +* preventing the hardware from detecting the rising edge needed to +* trigger X2P calibration. +*/ + val =mcs_reg_read (mcs,MCSX_MIL_GLOBAL ); + val &= ~BIT_ULL (5 ); +mcs_reg_write (mcs,MCSX_MIL_GLOBAL , val); +usleep_range (100 ,200 ); +/* set X2P calibration */ val =mcs_reg_read (mcs,MCSX_MIL_GLOBAL ); val |=BIT_ULL (5 );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 676/1102 ionic: use netif_txq_maybe_stop() in ionic_tx()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nikhil P. Rao <[email protected]>
[ Upstream commit c91b4d6e5cc30ceea3f23ebe29aec012709a065f ]
Commit 061b9bedbef1 ("ionic: Rework Tx start/stop flow") replaced ionic_maybe_stop_tx() with netif_txq_maybe_stop() to get the memory barriers around the stop/start bits right, but did not cover the stop in ionic_tx() added by commit 138506ab249b ("ionic: Check stop no restart"). Convert the remaining site.
netif_txq_maybe_stop() requires the ring indexes to be updated before it is invoked, so the post has to come first. But ring_dbell comes from __netdev_tx_sent_queue(), which runs after that and reads the stop bit, so it is not known in time to pass to ionic_txq_post(). Post without the doorbell and ring it separately.
The stop condition is unchanged. The re-check only clears the stop bit when space has become available, so the doorbell starvation fixed by commit 138506ab249b ("ionic: Check stop no restart") cannot recur.
--- drivers/net/ethernet/pensando/ionic/ionic_txrx.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-)
drivers/net/ethernet/pensando/ionic/ionic_txrx.c +10 -3
@@ -1668,15 +1668,22 @@ static int ionic_tx(struct net_device *netdev, struct ionic_queue *q, stats->pkts++; stats->bytes += skb->len; +ionic_txq_post (q, false); +if (likely (!ionic_txq_hwstamp_enabled (q))) {struct netdev_queue *ndq =q_to_ndq (netdev, q); -if (unlikely (!ionic_q_has_space (q,MAX_SKB_FRAGS +1 ))) -netif_tx_stop_queue (ndq); +netif_txq_maybe_stop (ndq,ionic_q_space_avail (q), +MAX_SKB_FRAGS +1 ,MAX_SKB_FRAGS +1 ); ring_dbell =__netdev_tx_sent_queue (ndq, skb->len,netdev_xmit_more ()); } -ionic_txq_post (q, ring_dbell); + +if (ring_dbell) { +ionic_dbell_ring (q->lif->kern_dbpage, q->hw_type, + q->dbval | q->head_idx); + q->dbell_jiffies = jiffies; + }return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 677/1102 net: usb: cx82310_eth: drop URB after 0xffff reboot sentinel to prevent partial_data heap overflow
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jason Winter <[email protected]>
[ Upstream commit 5d50e90add8b4a978395e893e81954d19d58a7c5 ]
The 0xffff length sentinel detects a router reboot and schedules re-enabling of ethernet mode, but then falls through to the rest of the loop body. The next check is
} else if (len > CX82310_MTU) {which is the else of the just-matched if -- it never fires for len == 0xffff. The MTU bound that normally caps the incomplete-packet save path is silently bypassed.
With 0xffff > skb->len always true (rx_urb_size is 4096), the incomplete-packet branch saves dev->partial_len = skb->len bytes into dev->partial_data. partial_data is kmalloc(hard_mtu) = kmalloc(CX82310_MTU + 2) = 1516 bytes, but skb->len after the 2-byte header pull can be up to 4094. A device that sends a 4096-byte URB starting with [0xff 0xff] therefore copies 4094 device-provided bytes into a buffer allocated for 1516 bytes, exceeding its requested size by 2578 bytes.
The next URB then reads dev->partial_len (4094) back from the same 1516-byte buffer and dev->partial_rem (65535 - 4094 = 61441) from the new URB's ~4KB skb, both well past their allocations, and delivers the spliced result as a 64KB "frame" to the network stack.
Bail out of rx_fixup after scheduling the re-enable work; the remainder of a reboot-marker URB is not meaningful packet data. This restores the invariant that partial_len < CX82310_MTU + 2 on the save path, since every other route there has already passed the MTU check.
--- drivers/net/usb/cx82310_eth.c | 1 + 1 file changed, 1 insertion(+)
drivers/net/usb/cx82310_eth.c +1 -0
@@ -282,6 +282,7 @@ static int cx82310_rx_fixup(struct usbnet *dev, struct sk_buff *skb)if (len ==0xffff ) {netdev_info (dev->net,"router was rebooted, re-enabling ethernet mode" );schedule_work (&priv->reenable_work); +return 0 ; }else if (len >CX82310_MTU ) {netdev_err (dev->net,"RX packet too long: %d B\n" , len);return 0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 678/1102 s390/ism: folio_put() after error
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alexandra Winter <[email protected]>
[ Upstream commit 907a56ab3eb8a58500a58daa76087f17bb2b6826 ]
dmb->cpu_addr was allocated via folio_alloc(). Use folio_put() instead of kfree() in the error exit of ism_alloc_dmb() to avoid slab allocator corruption.
While at it, reset dmb->cpu_addr after folio_put to avoid unintentional UAF by future callers.
--- drivers/s390/net/ism_drv.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/s390/net/ism_drv.c +3 -1
@@ -297,6 +297,7 @@ static void ism_free_dmb(struct ism_dev *ism, struct ism_dmb *dmb)dma_unmap_page (&ism->pdev->dev, dmb->dma_addr, dmb->dmb_len,DMA_FROM_DEVICE );folio_put (virt_to_folio (dmb->cpu_addr)); + dmb->cpu_addr =NULL ; }static int ism_alloc_dmb (struct ism_dev *ism,struct ism_dmb *dmb)
@@ -340,7 +341,8 @@ static int ism_alloc_dmb(struct ism_dev *ism, struct ism_dmb *dmb)return 0 ; out_free: -kfree (dmb->cpu_addr); +folio_put (folio); + dmb->cpu_addr =NULL ; out_bit:clear_bit (dmb->sba_idx, ism->sba_bitmap);return rc;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 679/1102 vxlan: reject dynamic fdb entries that reference a nexthop id
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Seungwon Bae <[email protected]>
[ Upstream commit 98fc57d167446b95b4e719815fe79edef93f8e7a ]
The commit cited in the Fixes tag allowed VXLAN FDB entries to point to FDB nexthops so that overlay traffic could be load balanced across multiple VTEPs. Such entries can only be configured from user space, cannot be learned and cannot roam. They only make sense with a user space control plane such as E-VPN where data plane learning is disabled.
Despite that, the VXLAN driver does not currently prevent such entries from being configured with the "dynamic" flag. The per-nexthop FDB list is only protected by the per-device hash lock, which is not sufficient when two VXLAN devices point to the same FDB nexthop and therefore share the list. Aging runs in softirq context without RTNL, so an entry deleted by one device can race with an addition or deletion from the other, leading to list corruption:
list_del corruption. next->prev should be ffff8881069d9548, but was dead000000000122. (next=ffff8881069d9448)
WARNING: CPU: 0 PID: 90 at lib/list_debug.c:65 __list_del_entry_valid_or_report+0x1aa/0x210 ... vxlan_fdb_destroy+0x5b8/0xad0 vxlan_cleanup+0x328/0x450 call_timer_fn+0x2a/0x1c0 run_timer_softirq+0x18c/0x210 BUG: KASAN: slab-use-after-free in vxlan_fdb_destroy
Fix this by rejecting the bogus configuration of dynamic FDB entries that point to FDB nexthops, both when created and when an existing entry is updated. As such, the per-nexthop FDB list is only ever mutated under the RTNL lock. Add test cases to make sure that this does not regress in the future.
--- drivers/net/vxlan/vxlan_core.c | 11 ++++++++ tools/testing/selftests/net/fib_nexthops.sh | 28 +++++++++++++++++++++ 2 files changed, 39 insertions(+)
drivers/net/vxlan/vxlan_core.c +11 -0
@@ -1006,6 +1006,12 @@ static int vxlan_fdb_update_existing(struct vxlan_dev *vxlan,return -EOPNOTSUPP ; } +if (rcu_access_pointer (f->nh) && + !(state & (NUD_PERMANENT |NUD_NOARP ))) { +NL_SET_ERR_MSG (extack,"Cannot make a nexthop fdb dynamic" ); +return -EOPNOTSUPP ; + } +/* Do not allow an externally learned entry to take over an entry added * by the user. */
@@ -1273,6 +1279,11 @@ static int vxlan_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],if (err)return err; +if (nhid && !(ndm->ndm_state & (NUD_PERMANENT |NUD_NOARP ))) { +NL_SET_ERR_MSG (extack,"A nexthop fdb cannot be dynamic" ); +return -EINVAL ; + } +if (vxlan->default_dst.remote_ip.sa.sa_family != ip.sa.sa_family)return -EAFNOSUPPORT ;
tools/testing/selftests/net/fib_nexthops.sh +28 -0
@@ -500,6 +500,20 @@ ipv6_fdb_grp_fcnal() run_cmd "$BRIDGE fdb add 02:02:00:00:00:14 dev vx10 nhid 61 self" log_test $? 255 "Fdb mac add with nexthop" + # fdb entries with a nexthop group cannot be aged out + run_cmd "$BRIDGE fdb add 02:02:00:00:00:15 dev vx10 nhid 102 self static" + log_test $? 0 "Fdb mac add with nexthop group and static state" + + run_cmd "$BRIDGE fdb add 02:02:00:00:00:16 dev vx10 nhid 102 self dynamic" + log_test $? 255 "Fdb mac add with nexthop group and dynamic state" + + run_cmd "$BRIDGE fdb add 02:02:00:00:00:17 dev vx10 nhid 102 self" + run_cmd "$BRIDGE fdb replace 02:02:00:00:00:17 dev vx10 dst 2001:db8:91::11 self dynamic" + log_test $? 255 "Fdb mac replace with nexthop group and dynamic state" + + run_cmd "$BRIDGE fdb append 02:02:00:00:00:17 dev vx10 dst 2001:db8:91::11 self dynamic" + log_test $? 255 "Fdb mac append with nexthop group and dynamic state" + run_cmd "$IP -6 ro add 2001:db8:101::1/128 nhid 66" log_test $? 2 "Route add with fdb nexthop"
@@ -580,6 +594,20 @@ ipv4_fdb_grp_fcnal() run_cmd "$BRIDGE fdb add 02:02:00:00:00:14 dev vx10 nhid 12 self" log_test $? 255 "Fdb mac add with nexthop" + # fdb entries with a nexthop group cannot be aged out + run_cmd "$BRIDGE fdb add 02:02:00:00:00:15 dev vx10 nhid 102 self static" + log_test $? 0 "Fdb mac add with nexthop group and static state" + + run_cmd "$BRIDGE fdb add 02:02:00:00:00:16 dev vx10 nhid 102 self dynamic" + log_test $? 255 "Fdb mac add with nexthop group and dynamic state" + + run_cmd "$BRIDGE fdb add 02:02:00:00:00:17 dev vx10 nhid 102 self" + run_cmd "$BRIDGE fdb replace 02:02:00:00:00:17 dev vx10 dst 10.0.0.3 self dynamic" + log_test $? 255 "Fdb mac replace with nexthop group and dynamic state" + + run_cmd "$BRIDGE fdb append 02:02:00:00:00:17 dev vx10 dst 10.0.0.3 self dynamic" + log_test $? 255 "Fdb mac append with nexthop group and dynamic state" + run_cmd "$IP ro add 172.16.0.0/22 nhid 16" log_test $? 2 "Route add with fdb nexthop"
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 680/1102 net: cap tx_queue_len at S16_MAX to prevent oversized ring allocations
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jamal Hadi Salim <[email protected]>
[ Upstream commit 66ab4c59b74db7ab53a1c9083feaaede393a96a0 ]
Several subsystems allocate ring buffers sized by dev->tx_queue_len with no upper bound. An unprivileged user (via unshare -Urn) can set a huge tx_queue_len and exhaust global memory with ring allocations:
- pfifo_fast: pfifo_fast_init() and pfifo_fast_change_tx_queue_len() allocate 3 skb_array rings of tx_queue_len entries each.
- tun: tun_queue_resize() and the queue-attach path resize ptr_rings to tx_queue_len on the NETDEV_CHANGE_TX_QUEUE_LEN notifier.
- tap (macvtap/ipvtap): tap_queue_resize() and tap_init() resize/init ptr_rings to tx_queue_len on the same notifier.
netif_change_tx_queue_len() is the single entry point for IFLA_TXQLEN, sysfs, and the SIOCSIFTXQLEN ioctl. Cap new_len at S16_MAX (32767) there so the oversized value is rejected at set time. This takes effect whether the device is up or down, before dev->tx_queue_len is written, before any notifier fires, and before any ring is allocated. The "> S16_MAX" check also subsumes the previous unsigned-long truncation test, and a negative ifr_qlen from the ioctl lands far above the cap after conversion, so both old failure modes are covered by the one comparison.
tx_queue_len is ambigious: both a per-ring sizing multiplier and a default queue-length/limit knob for consumers that allocate nothing at set time (pfifo/bfifo/gred/plug/sfb limits, htb direct_qlen, qfq max_classes, teql). 32767 is chosen as the largest value NLA_POLICY_FULL_RANGE can express for the u32 IFLA_TXQLEN policy in patch 2/3 while staying a legitimate queue length on high-BDP paths; the ring-memory trade-off of a shared knob is disclosed below.
Conditions to recreate the bug:
- CONFIG_NET_SCHED=y, CONFIG_VETH=y, CONFIG_USER_NS=y, CONFIG_NET_NS=y.
- Unprivileged user in a fresh user+net namespace (unshare -Urn).
- pfifo_fast: create veth pairs, set tx_queue_len to 500000, attach mq+pfifo_fast. ~28 iterations OOMs a 2GB guest.
- tun: create 50 tun devices with IFF_MULTI_QUEUE, set tx_queue_len to 500000, open 8 queues each. ~1.6GB of ptr_ring allocations OOMs a 512MB guest.
- tap: same as tun with IFF_TAP. ~960MB OOMs a 512MB guest.
- On the fixed kernel the oversized tx_queue_len is rejected with -ERANGE at set time (all four paths: RTM_SETLINK, RTM_NEWLINK create, sysfs, ioctl - the latter two via this check, the former two via this check and the 2/3 parse policy respectively).
--- net/core/dev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/core/dev.c +1 -1
@@ -9144,7 +9144,7 @@ int dev_change_tx_queue_len(struct net_device *dev, unsigned long new_len)unsigned int orig_len = dev->tx_queue_len;int res; -if (new_len != (unsigned int )new_len) +if (new_len >S16_MAX )return -ERANGE ;if (new_len != orig_len) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 681/1102 net: reject oversized tx_queue_len at netlink parse time
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jamal Hadi Salim <[email protected]>
[ Upstream commit 1aa9e143bf51405665a793d4cc925e1c4f0c5922 ]
rtnl_create_link() assigns IFLA_TXQLEN directly to dev->tx_queue_len without going through netif_change_tx_queue_len(), so a device created with "ip link add ... txqueuelen 500000" bypasses the S16_MAX cap and still triggers the oversized ring allocations in pfifo_fast, tun and tap. The veth peer nest (rtnl_nla_parse_ifinfomsg()) and the RTM_NEWLINK-on-existing-device path reach the same sinks.
Enforce the cap in ifla_policy instead: IFLA_TXQLEN becomes NLA_POLICY_FULL_RANGE(NLA_U32, &txqlen_range) with txqlen_range = { .min = 0, .max = S16_MAX }. All netlink consumers parse against this policy - rtnl_setlink(), rtnl_newlink() (create and change), and the veth peer nest - so every netlink path is capped at parse time and rejects the attribute with -ERANGE plus a proper "integer out of range" extack message before any device state is modified (the RTM_SETLINK half-application wart is gone with it).
Document the bound in the rt-link.yaml netlink spec.
Conditions to recreate the bug:
- CONFIG_NET_SCHED=y, CONFIG_VETH=y, CONFIG_USER_NS=y, CONFIG_NET_NS=y.
- Unprivileged user in a fresh user+net namespace (unshare -Urn):
ip link add v0 txqueuelen 500000 type veth peer name v1
-> on the fixed kernel this is rejected with -ERANGE ("integer out of range" extack) instead of installing an oversized tx_queue_len that later inflates pfifo_fast/tun/tap ring allocations.
- ip link set v0 txqueuelen 500000 is likewise rejected at parse time.
--- Documentation/netlink/specs/rt_link.yaml | 2 ++ net/core/rtnetlink.c | 7 ++++++- 2 files changed, 8 insertions(+), 1 deletion(-)
Documentation/netlink/specs/rt_link.yaml +2 -0
@@ -967,6 +967,8 @@ attribute-sets: - name: txqlen type: u32 + checks: + max: 32767 - name: map type: binary
net/core/rtnetlink.c +6 -1
@@ -2091,6 +2091,11 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb,return -EMSGSIZE ; } +static const struct netlink_range_validation txqlen_range = { + .min =0 , + .max =S16_MAX , +}; +static const struct nla_policy ifla_policy[IFLA_MAX +1 ] = { [IFLA_IFNAME ] = { .type =NLA_STRING , .len =IFNAMSIZ -1 }, [IFLA_ADDRESS ] = { .type =NLA_BINARY , .len =MAX_ADDR_LEN },
@@ -2100,7 +2105,7 @@ static const struct nla_policy ifla_policy[IFLA_MAX+1] = { [IFLA_LINK] = { .type = NLA_U32 }, [IFLA_MASTER] = { .type = NLA_U32 }, [IFLA_CARRIER] = { .type = NLA_U8 }, - [IFLA_TXQLEN] = { .type = NLA_U32 }, + [IFLA_TXQLEN] = NLA_POLICY_FULL_RANGE(NLA_U32, &txqlen_range), [IFLA_WEIGHT] = { .type = NLA_U32 }, [IFLA_OPERSTATE] = { .type = NLA_U8 }, [IFLA_LINKMODE] = { .type = NLA_U8 },
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 682/1102 pds_core: fix cmd_regs access racing BAR unmap on reset
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nikhil P. Rao <[email protected]>
[ Upstream commit 7980325b2f71e3f65c1323c39792e2455da6fab6 ]
pdsc_reset_prepare() and pdsc_reset_done()'s pdsc_map_bars() error path clear/iounmap cmd_regs without devcmd_lock, and pdsc_legacy_firmware_update()'s download loop derefs cmd_regs after dropping and retaking the lock without re-checking. An FLR concurrent with a devlink flash can unmap cmd_regs under an in-flight devcmd, causing a NULL deref or a write to unmapped MMIO.
Take devcmd_lock across the BAR unmap/remap, and re-check cmd_regs in the download loop. Only the PF maps cmd_regs and runs devcmd, so skip the unmap on a VF, as pdsc_remove() and pdsc_reset_done() already do.
A reset that completes entirely within the unlocked window is not a correctness problem for the image: the device clears its update session, so a resumed download is rejected, and it verifies the staged image before writing a flash slot, reporting PDS_RC_BAD_FW rather than activating it.
pdsc_unmap_bars() also clears info_regs, intr_status and intr_ctrl. The interrupt and start/stop readers of those are quiesced before the unmap by pdsc_fw_down(), which frees the interrupts and tears down the queues. The debugfs readers are not, since those files outlive a reset; that is pre-existing and out of scope here.
--- drivers/net/ethernet/amd/pds_core/fw.c | 10 +++++++++- drivers/net/ethernet/amd/pds_core/main.c | 8 +++++++- 2 files changed, 16 insertions(+), 2 deletions(-)
drivers/net/ethernet/amd/pds_core/fw.c +9 -1
@@ -107,8 +107,10 @@ int pdsc_firmware_update(struct pdsc *pdsc, const struct firmware *fw,dev_info (pdsc->dev,"Installing firmware\n" ); -if (!pdsc->cmd_regs) +if (!pdsc->cmd_regs) { +NL_SET_ERR_MSG_MOD (extack,"BARs not mapped" );return -ENXIO ; + } dl =priv_to_devlink (pdsc); devlink_flash_update_status_notify(dl, "Preparing to flash",
@@ -134,6 +136,12 @@ int pdsc_firmware_update(struct pdsc *pdsc, const struct firmware *fw, copy_sz = min_t(unsigned int, buf_sz, fw->size - offset);mutex_lock (&pdsc->devcmd_lock); +if (!pdsc->cmd_regs) { +mutex_unlock (&pdsc->devcmd_lock); + err = -ENXIO ; +NL_SET_ERR_MSG_MOD (extack,"Device reset during flash" ); + goto err_out; + }memcpy_toio (&pdsc->cmd_regs->data, fw->data + offset, copy_sz); err =pdsc_devcmd_fw_download_locked (pdsc, data_addr, offset, copy_sz);
drivers/net/ethernet/amd/pds_core/main.c +7 -1
@@ -499,7 +499,11 @@ static void pdsc_reset_prepare(struct pci_dev *pdev) &pf->vfs[pdsc->vf_id].padev); } -pdsc_unmap_bars (pdsc); +if (!pdev->is_virtfn) { +mutex_lock (&pdsc->devcmd_lock); +pdsc_unmap_bars (pdsc); +mutex_unlock (&pdsc->devcmd_lock); + }pci_release_regions (pdev);if (pci_is_enabled (pdev))pci_disable_device (pdev);
@@ -528,7 +532,9 @@ static void pdsc_reset_done(struct pci_dev *pdev)return ; } +mutex_lock (&pdsc->devcmd_lock); err =pdsc_map_bars (pdsc); +mutex_unlock (&pdsc->devcmd_lock);if (err)return ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 683/1102 pds_core: dont release PCI regions for VFs on reset
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nikhil P. Rao <[email protected]>
[ Upstream commit 73608de7e59246b4b533c1ffaee158a7048e186e ]
pdsc_reset_prepare() called pci_release_regions() unconditionally, but only PFs call pci_request_regions() (pdsc_init_pf). On a VF FLR this makes the kernel warn "Trying to free nonexistent resource".
--- drivers/net/ethernet/amd/pds_core/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/ethernet/amd/pds_core/main.c +1 -1
@@ -503,8 +503,8 @@ static void pdsc_reset_prepare(struct pci_dev *pdev)mutex_lock (&pdsc->devcmd_lock);pdsc_unmap_bars (pdsc);mutex_unlock (&pdsc->devcmd_lock); +pci_release_regions (pdev); } -pci_release_regions (pdev);if (pci_is_enabled (pdev))pci_disable_device (pdev); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 684/1102 powerpc/kexec_file: Use inclusive range checks in add_usable_mem()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thorsten Blum <[email protected]>
[ Upstream commit c6755be4838d6ccd641effbcdc3d917b82631ff9 ]
add_usable_mem() adds usable memory ranges for the kdump kernel.
The ranges are inclusive, but the partial overlap check uses exclusive comparisons. This skips ranges with base == loc_end or end == loc_base. Use inclusive comparisons instead.
--- arch/powerpc/kexec/file_load_64.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/powerpc/kexec/file_load_64.c +1 -1
@@ -296,7 +296,7 @@ static int add_usable_mem(struct umem_info *um_info, u64 base, u64 end) loc_end = um_info->ranges[i].end;if (loc_base >= base && loc_end <= end) add = true; -else if (base < loc_end && end > loc_base) { +else if (base <= loc_end && end >= loc_base) {if (loc_base < base) loc_base = base;if (loc_end > end)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 686/1102 net/sched: defer qdisc freeing after failed creation
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 e6662f2100f8d33b0f4d0047c219efd6bba186ea ]
An RTM_NEWQDISC request can make clsact bind a populated shared ingress block during ->init(), publishing an embedded mini_Qdisc to lockless readers. If the same request has an invalid TCA_RATE, estimator setup fails after ->init(); the unwind removes the pointer but synchronously frees its containing qdisc while tc_run() may still hold it.
Retire failed qdiscs through the same RCU helper as normal destruction. Inline the synchronous free into the callback now that no direct callers remain.
--- include/net/sch_generic.h | 2 +- net/sched/sch_api.c | 2 +- net/sched/sch_generic.c | 20 ++++++++++---------- 3 files changed, 12 insertions(+), 12 deletions(-)
include/net/sch_generic.h +1 -1
@@ -755,7 +755,7 @@ void qdisc_offload_query_caps(struct net_device *dev,struct Qdisc *qdisc_alloc (struct netdev_queue *dev_queue,const struct Qdisc_ops *ops,struct netlink_ext_ack *extack); -void qdisc_free (struct Qdisc *qdisc); +void qdisc_free_rcu (struct Qdisc *qdisc);struct Qdisc *qdisc_create_dflt (struct netdev_queue *dev_queue,const struct Qdisc_ops *ops,u32 parentid,struct netlink_ext_ack *extack);
net/sched/sch_api.c +1 -1
@@ -1408,7 +1408,7 @@ static struct Qdisc *qdisc_create(struct net_device *dev, err_out3:lockdep_unregister_key (&sch->root_lock_key);netdev_put (dev, &sch->dev_tracker); -qdisc_free (sch); +qdisc_free_rcu (sch); err_out2:module_put (ops->owner); err_out:
net/sched/sch_generic.c +10 -10
@@ -1050,21 +1050,21 @@ void qdisc_reset(struct Qdisc *qdisc) }EXPORT_SYMBOL (qdisc_reset); -void qdisc_free (struct Qdisc *qdisc) +static void qdisc_free_cb (struct rcu_head *head) { -if (qdisc_is_percpu_stats (qdisc)) { -free_percpu (qdisc->cpu_bstats); -free_percpu (qdisc->cpu_qstats); + struct Qdisc *q = container_of(head, struct Qdisc, rcu); + +if (qdisc_is_percpu_stats (q)) { +free_percpu (q->cpu_bstats); +free_percpu (q->cpu_qstats); } -kfree (qdisc); +kfree (q); } -static void qdisc_free_cb (struct rcu_head *head) +void qdisc_free_rcu (struct Qdisc *qdisc) { - struct Qdisc *q = container_of(head, struct Qdisc, rcu); - -qdisc_free (q); +call_rcu (&qdisc->rcu, qdisc_free_cb); }static void __qdisc_destroy (struct Qdisc *qdisc)
@@ -1091,7 +1091,7 @@ static void __qdisc_destroy(struct Qdisc *qdisc)trace_qdisc_destroy (qdisc); -call_rcu (&qdisc->rcu, qdisc_free_cb); +qdisc_free_rcu (qdisc); }void qdisc_destroy (struct Qdisc *qdisc)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 687/1102 net/mlx5e: Fix setting RS FEC after remapping
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shahar Shitrit <[email protected]>
[ Upstream commit b9d755c5a37519fb1354034db1dfeb30e1ba6856 ]
When a user sets a FEC mode via ethtool, the driver maps the ethtool FEC type to the lowest mlx5 bit of that type. For RS FEC, this is MLX5E_FEC_RS_528_514 (bit 2). The driver then checks whether this bit is supported by at least one link mode by inspecting the fec_override_cap fields via mlx5e_fec_in_caps(), and returns -EOPNOTSUPP if not.
This check is incorrect. RS FEC has three supported hardware variants:RS_528_514 (bit 2), RS_544_514_INTERLEAVED_QUAD (bit 4), and RS_544_514 (bit 7). mlx5e_remap_fec_conf_mode() already remaps bit 2 to the appropriate RS variant per link mode when writing the admin fields, but the early capability check is done against the raw unmapped bit. As a result, a device that supports RS_544_514 or RS_544_514_INTERLEAVED_QUAD but not RS_528_514 will incorrectly reject the user's RS FEC request.
Remove the early support check from mlx5e_set_fec_mode() and fold it into the existing write loop, checking caps against the remapped policy per link mode. Return -EOPNOTSUPP before the final register write if no link mode accepted the policy.
--- drivers/net/ethernet/mellanox/mlx5/core/en/port.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-)
drivers/net/ethernet/mellanox/mlx5/core/en/port.c +9 -6
@@ -501,6 +501,7 @@ int mlx5e_set_fec_mode(struct mlx5_core_dev *dev, u16 fec_policy)u32 in[MLX5_ST_SZ_DW (pplm_reg)] = {};int sz =MLX5_ST_SZ_BYTES (pplm_reg);u16 fec_policy_auto =0 ; +bool fec_set = false;int err;int i;
@@ -513,9 +514,6 @@ int mlx5e_set_fec_mode(struct mlx5_core_dev *dev, u16 fec_policy)if (fec_policy >= (1 <<MLX5E_FEC_LLRS_272_257_1 ) && !fec_50g_per_lane)return -EOPNOTSUPP ; -if (fec_policy && !mlx5e_fec_in_caps (dev, fec_policy)) -return -EOPNOTSUPP ; -MLX5_SET (pplm_reg, in, local_port,1 ); err =mlx5_core_access_reg (dev, in, sz, out, sz,MLX5_REG_PPLM ,0 ,0 );if (err)
@@ -542,12 +540,17 @@ int mlx5e_set_fec_mode(struct mlx5_core_dev *dev, u16 fec_policy)mlx5e_get_fec_cap_field (out, &fec_caps, i);/* policy supported for link speed */ -if (fec_caps & conf_fec) +if (fec_caps & conf_fec) {mlx5e_fec_admin_field (out, &conf_fec,1 , i); -else -/* set FEC to auto*/ + fec_set = true; + }else { +/* set FEC to auto */ mlx5e_fec_admin_field (out, &fec_policy_auto,1 , i); + } } +if (fec_policy && !fec_set) +return -EOPNOTSUPP ; +return mlx5_core_access_reg (dev, out, sz, out, sz,MLX5_REG_PPLM ,0 ,1 ); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 688/1102 net/mlx5e: Fix ETS zero BW reporting when one TC holds 100%
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Carolina Jubran <[email protected]>
[ Upstream commit e7ee89740800a1cf253713e9249c3ee9203ebe91 ]
When ETS TCs with zero bandwidth are configured, the driver programs the firmware using an alternate representation. On get, it needs to recognize that representation so those TCs can be translated back and reported as 0% bandwidth.
The existing detection relied on the programmed bandwidth because it was enough to identify this representation. However, when a single ETS TC owns 100% of the bandwidth, its firmware representation becomes the same as a strict-priority TC, causing zero-bandwidth ETS TCs to be reported with non-zero bandwidth values.
Use the cached TSA instead to distinguish the ETS and strict-priority cases.
--- drivers/net/ethernet/mellanox/mlx5/core/en_dcbnl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/ethernet/mellanox/mlx5/core/en_dcbnl.c +1 -1
@@ -133,7 +133,7 @@ static int mlx5e_dcbnl_ieee_getets(struct net_device *netdev,if (err)return err; -if (ets->tc_tx_bw[i] <MLX5E_MAX_BW_ALLOC && +if (priv->dcbx.tc_tsa[i] ==IEEE_8021QAZ_TSA_ETS && tc_group[i] == (MLX5E_LOWEST_PRIO_GROUP +1 )) is_zero_bw_ets_tc = true;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 689/1102 net/mlx5e: Fix use-after-free race in sample_restore_put()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Carolina Jubran <[email protected]>
[ Upstream commit af3aef0245abbab5e9f6302e7a7d6407187afb71 ]
Concurrent teardown of TC sample rules sharing the same restore context may re-read restore->count after dropping restore_lock. At that point another thread may already have completed cleanup and freed the restore object.
Use the result of the refcount decrement while holding restore_lock to determine whether cleanup is needed.
--- drivers/net/ethernet/mellanox/mlx5/core/en/tc/sample.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
drivers/net/ethernet/mellanox/mlx5/core/en/tc/sample.c +5 -2
@@ -311,12 +311,15 @@ sample_restore_get(struct mlx5e_tc_psample *tc_psample, u32 obj_id,static void sample_restore_put (struct mlx5e_tc_psample *tc_psample,struct mlx5e_sample_restore *restore) { +bool last; +mutex_lock (&tc_psample->restore_lock); -if (--restore->count ==0 ) + last = --restore->count ==0 ; +if (last)hash_del (&restore->hlist);mutex_unlock (&tc_psample->restore_lock); -if (!restore->count) { +if (last) {mlx5_del_flow_rules (restore->rule);mlx5_modify_header_dealloc (tc_psample->esw->dev, restore->modify_hdr);kfree (restore);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 690/1102 net/mlx5: E-Switch: fix use-after-free in mlx5_eswitch_termtbl_put
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yael Chemla <[email protected]>
[ Upstream commit 7ee07f601f8f507c9faf25c68a49396ab8950596 ]
In mlx5_eswitch_termtbl_put(), the zero-ref cleanup check reads tt->ref_count after termtbl_mutex has been released. Two concurrent callers on the same mlx5_termtbl_handle race: one decrements ref_count to zero, removes the hash entry, and calls kfree(tt) while the other has already dropped the mutex and is about to evaluate
if (!tt->ref_count), producing a use-after-free.
Fix this by capturing the result of the decrement into a stack-local last variable before dropping the mutex. The cleanup decision is now made entirely under termtbl_mutex, and tt is not touched after kfree.
--- .../ethernet/mellanox/mlx5/core/eswitch_offloads_termtbl.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
drivers/net/ethernet/mellanox/mlx5/core/eswitch_offloads_termtbl.c +5 -2
@@ -163,12 +163,15 @@ void mlx5_eswitch_termtbl_put(struct mlx5_eswitch *esw, struct mlx5_termtbl_handle *tt) { + bool last; +mutex_lock (&esw->offloads.termtbl_mutex); -if (--tt->ref_count ==0 ) + last = (--tt->ref_count ==0 ); +if (last)hash_del (&tt->termtbl_hlist);mutex_unlock (&esw->offloads.termtbl_mutex); -if (!tt->ref_count) { +if (last) {mlx5_del_flow_rules (tt->rule);mlx5_destroy_flow_table (tt->termtbl);kfree (tt);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 691/1102 net/mlx5: E-Switch, prevent mc_list repopulation during vport disable
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lama Kayal <[email protected]>
[ Upstream commit c0c6f4ba8a37688f7b4d4044898d88f0450d44c2 ]
In mlx5_esw_vport_disable(), move esw_apply_vport_rx_mode() ahead of esw_vport_change_handle_locked() so vport->allmulti_rule is NULL before the change handler observes it.
During FW-fatal recovery the disable runs while dev->state == INTERNAL_ERROR. The promisc query inside esw_update_vport_rx_mode() fails and returns early, leaving vport->allmulti_rule intact, so esw_update_vport_mc_promisc() runs and adds MLX5_ACTION_ADD entries to vport->mc_list whose flow rules are then installed in the FDB by esw_add_mc_addr(). esw_destroy_legacy_table() tears down the FDB with those refs still held, corrupting the sub-tree and leaving dangling flow_rule pointers in vport->mc_list.
Two-stage failure on echo 1 > /sys/bus/pci/devices/<bdf>/reset:
refcount_t: underflow; use-after-free.
tree_put_node+0xef/0x110 [mlx5_core] clean_tree+0x44/0xd0 [mlx5_core] (x5) mlx5_fs_core_cleanup+0x57/0x1c0 [mlx5_core] mlx5_unload+0x65/0xd0 [mlx5_core] ... mlx5_health_try_recover BUG: unable to handle page fault for address: 0000000003000055 down_write+0x1c/0x60 mlx5_del_flow_rules+0x33/0x1f0 [mlx5_core] esw_del_mc_addr+0x7b/0x170 [mlx5_core] esw_apply_vport_addr_list+0x56/0xf0 [mlx5_core] esw_vport_change_handle_locked+0x28b/0x310 [mlx5_core] mlx5_esw_vport_enable+0x270/0x4a0 [mlx5_core] ... mlx5_load ... mlx5_health_try_recover
esw_apply_vport_rx_mode(false, false) clears vport->allmulti_rule via its local state machine even when the FW del fails. With the rule NULL the !IS_ERR_OR_NULL(allmulti_rule) gate in the change handler closes, no rules are installed during disable, and the reload starts with a clean mc_list.
--- drivers/net/ethernet/mellanox/mlx5/core/eswitch.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
drivers/net/ethernet/mellanox/mlx5/core/eswitch.c +7 -1
@@ -972,13 +972,19 @@ void mlx5_esw_vport_disable(struct mlx5_eswitch *esw, struct mlx5_vport *vport) (vport->info.ipsec_crypto_enabled || vport->info.ipsec_packet_enabled)) esw->enabled_ipsec_vf_count--; +/* Clear rx-mode before esw_vport_change_handle_locked(): on +* MLX5_VPORT_PROMISC_CHANGE it calls esw_update_vport_mc_promisc() +* when vport->allmulti_rule is set, repopulating mc_list with FDB +* rules that dangle once the FDB is destroyed. NULL allmulti_rule +* here skips that path. +*/ +esw_apply_vport_rx_mode (esw, vport, false, false);/* We don't assume VFs will cleanup after themselves. * Calling vport change handler while vport is disabled will cleanup * the vport resources. */ esw_vport_change_handle_locked (vport); vport->enabled_events =0 ; -esw_apply_vport_rx_mode (esw, vport, false, false);esw_vport_cleanup (esw, vport); esw->enabled_vports--;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 692/1102 net/sched: fq_pie: clamp quantum in change path
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jamal Hadi Salim <[email protected]>
[ Upstream commit 4864f58c53eb47257d55e01f47d4a9f355f7f970 ]
fq_pie_change() accepts any quantum value from userspace, including 1. With a crafted size table qdisc_pkt_len reaches ~2 GiB, so quantum=1 makes the deficit-refill loop spin ~2^31 times under the qdisc lock (a soft lockup / denial of service).
Add max(256U, ...) matching fq_codel_change().
Conditions to recreate the bug:
CONFIG_NET_SCH_FQ_PIE=y. Requires CAP_NET_ADMIN (namespace-local via unshare -Urn suffices).
tc qdisc add dev dummy0 root fq_pie
tc qdisc change dev dummy0 root fq_pie quantum 1 stab data 32768 size_log 15 cell_log 0
--- net/sched/sch_fq_pie.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
net/sched/sch_fq_pie.c +2 -1
@@ -340,7 +340,8 @@ static int fq_pie_change(struct Qdisc *sch, struct nlattr *opt, nla_get_u32(tb[TCA_FQ_PIE_BETA]));if (tb[TCA_FQ_PIE_QUANTUM ]) -WRITE_ONCE (q->quantum,nla_get_u32 (tb[TCA_FQ_PIE_QUANTUM ])); +WRITE_ONCE (q->quantum, +max (256U ,nla_get_u32 (tb[TCA_FQ_PIE_QUANTUM ])));if (tb[TCA_FQ_PIE_MEMORY_LIMIT ]) WRITE_ONCE(q->memory_limit,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 693/1102 net/sched: sfq: clamp quantum in change path
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jamal Hadi Salim <[email protected]>
[ Upstream commit fb9f88a33c516ea5c0bcd9a22ca288b246b34567 ]
sfq_change() accepts any non-negative quantum (only rejects (int)ctl->quantum < 0). With a crafted size table qdisc_pkt_len reaches ~2 GiB, so quantum=1 makes the deficit-refill loop spin ~2^31 times under the qdisc lock (a soft lockup / denial of service).
Add max(256U, ...) matching fq_codel_change(). Reject quantum > 1<<20 with -EINVAL, matching fq_codel_change() and the init clamp.
Conditions to recreate the bug:
CONFIG_NET_SCH_SFQ=y. Requires CAP_NET_ADMIN (namespace-local via unshare -Urn suffices).
tc qdisc add dev dummy0 root sfq
tc qdisc change dev dummy0 root sfq quantum 1 stab data 32768 size_log 15 cell_log 0
--- net/sched/sch_sfq.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
net/sched/sch_sfq.c +6 -1
@@ -657,6 +657,11 @@ static int sfq_change(struct Qdisc *sch, struct nlattr *opt,return -EINVAL ; } +if (ctl->quantum >1 <<20 ) { +NL_SET_ERR_MSG_MOD (extack,"quantum too large" ); +return -EINVAL ; + } +if (ctl->perturb_period <0 || ctl->perturb_period >INT_MAX /HZ ) {NL_SET_ERR_MSG_MOD (extack,"invalid perturb period" );
@@ -685,7 +690,7 @@ static int sfq_change(struct Qdisc *sch, struct nlattr *opt,/* update and validate configuration */ if (ctl->quantum) - quantum = ctl->quantum; + quantum =max (256U , ctl->quantum);if (ctl->flows) maxflows =min_t (u32, ctl->flows,SFQ_MAX_FLOWS );if (ctl->divisor) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 694/1102 net/sched: hhf: clamp quantum in change and init paths
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jamal Hadi Salim <[email protected]>
[ Upstream commit eb56a495f59baf6cad5ed80e3ffb9078098b1346 ]
hhf_change() accepts any quantum from userspace, including 1. With a crafted size table qdisc_pkt_len reaches ~2 GiB, so quantum=1 makes the deficit-refill loop spin ~2^31 times under the qdisc lock (a soft lockup / denial of service).
Add max(256U, ...) in hhf_change() matching fq_codel_change(). Clamp hhf_init() to [256, 1<<20] matching the siblings, and remove the old fallback that only set quantum=256 on overflow.
Conditions to recreate the bug:
CONFIG_NET_SCH_HHF=y. Requires CAP_NET_ADMIN (namespace-local via unshare -Urn suffices).
tc qdisc add dev dummy0 root hhf
tc qdisc change dev dummy0 root hhf quantum 1 stab data 32768 size_log 15 cell_log 0
--- net/sched/sch_hhf.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-)
net/sched/sch_hhf.c +2 -6
@@ -550,7 +550,7 @@ static int hhf_change(struct Qdisc *sch, struct nlattr *opt,return err;if (tb[TCA_HHF_QUANTUM ]) - new_quantum =nla_get_u32 (tb[TCA_HHF_QUANTUM ]); + new_quantum =max (256U ,nla_get_u32 (tb[TCA_HHF_QUANTUM ]));if (tb[TCA_HHF_NON_HH_WEIGHT ]) new_hhf_non_hh_weight =nla_get_u32 (tb[TCA_HHF_NON_HH_WEIGHT ]);
@@ -610,7 +610,7 @@ static int hhf_init(struct Qdisc *sch, struct nlattr *opt,int i; sch->limit =1000 ; - q->quantum =psched_mtu (qdisc_dev (sch)); + q->quantum =clamp_t (u32,psched_mtu (qdisc_dev (sch)),256 ,1 <<20 );get_random_bytes (&q->perturbation,sizeof (q->perturbation));INIT_LIST_HEAD (&q->new_buckets);INIT_LIST_HEAD (&q->old_buckets);
@@ -621,10 +621,6 @@ static int hhf_init(struct Qdisc *sch, struct nlattr *opt, q->hhf_evict_timeout =HZ ;/* 1 sec */ q->hhf_non_hh_weight =2 ; -if ((int )q->quantum <=0 || - (u64 )q->quantum * q->hhf_non_hh_weight >INT_MAX ) - q->quantum =256 ; -if (opt) {int err =hhf_change (sch, opt, extack);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 695/1102 net/sched: pie: clamp psched_mtu in pie_drop_early
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jamal Hadi Salim <[email protected]>
[ Upstream commit 54370e44c002770ae61fc889f28f699e91616ffc ]
pie_drop_early() calls psched_mtu() with no clamp. With mtu=0x80000000 the bytemode divide silently zeroes the drop probability, disabling AQM. Clamp to [1, 1<<20].
Conditions to recreate the bug:
CONFIG_NET_SCH_PIE=y. Requires CAP_NET_ADMIN (namespace-local via unshare -Urn suffices).
tc qdisc add dev dummy0 root pie
tc qdisc change dev dummy0 root pie stab data 32768 size_log 15 cell_log 0
--- net/sched/sch_pie.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/sched/sch_pie.c +1 -1
@@ -35,7 +35,7 @@ bool pie_drop_early(struct Qdisc *sch, struct pie_params *params, {u64 rnd;u64 local_prob = vars->prob; -u32 mtu =psched_mtu (qdisc_dev (sch)); +u32 mtu =clamp_t (u32,psched_mtu (qdisc_dev (sch)),1 ,1 <<20 );/* If there is still burst allowance left skip random early drop */ if (vars->burst_time >0 )
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 696/1102 net/sched: drr: clamp quantum in change class
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jamal Hadi Salim <[email protected]>
[ Upstream commit 8382abec0f1568d0a5590d75a3df92f23fcf5196 ]
drr_change_class() rejects explicit quantum==0 but falls back to psched_mtu() with no floor. With a crafted size table qdisc_pkt_len reaches ~2 GiB, so quantum=1 (or a zero psched_mtu on a headerless device) makes the deficit-refill loop spin under the qdisc lock.
Add clamp_t(u32, quantum, 256, 1<<20) after the zero reject and on the fallback path. The explicit-zero reject is preserved.
Conditions to recreate the bug:
CONFIG_NET_SCH_DRR=y. Requires CAP_NET_ADMIN (namespace-local via unshare -Urn suffices).
tc qdisc add dev dummy0 root drr
tc class add dev dummy0 parent 1: classid 1:1 drr quantum 1
--- net/sched/sch_drr.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
net/sched/sch_drr.c +2 -1
@@ -82,8 +82,9 @@ static int drr_change_class(struct Qdisc *sch, u32 classid, u32 parentid,NL_SET_ERR_MSG (extack,"Specified DRR quantum cannot be zero" );return -EINVAL ; } + quantum =clamp_t (u32, quantum,256 ,1 <<20 ); }else - quantum =psched_mtu (qdisc_dev (sch)); + quantum =clamp_t (u32, (u32 )psched_mtu (qdisc_dev (sch)),256 ,1 <<20 );if (cl !=NULL ) {if (tca[TCA_RATE ]) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 697/1102 net/sched: ets: clamp quantum in parse and fallback paths
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jamal Hadi Salim <[email protected]>
[ Upstream commit 1c38487f46b243bfeefec0c0c86023a3904f2214 ]
ets_qdisc_change() falls back to psched_mtu() with no floor for bands without an explicit quantum. With a crafted size table qdisc_pkt_len reaches ~2 GiB, so a zero psched_mtu on a headerless device makes the deficit-refill loop spin under the qdisc lock.
Move the floor into ets_quantum_parse() so explicitly configured quanta are also clamped to [256, 1<<20], not just the fallback path.
Conditions to recreate the bug:
CONFIG_NET_SCH_ETS=y. Requires CAP_NET_ADMIN (namespace-local via unshare -Urn suffices).
tc qdisc add dev dummy0 root ets bands 3 strict 2 quanta 1 1
--- net/sched/sch_ets.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-)
net/sched/sch_ets.c +5 -7
@@ -83,11 +83,7 @@ static int ets_quantum_parse(struct Qdisc *sch, const struct nlattr *attr,unsigned int *quantum, struct netlink_ext_ack *extack) { - *quantum =nla_get_u32 (attr); -if (!*quantum) { -NL_SET_ERR_MSG (extack,"ETS quantum cannot be zero" ); -return -EINVAL ; - } + *quantum =clamp_t (u32,nla_get_u32 (attr),256 ,1 <<20 );return 0 ; }
@@ -634,11 +630,13 @@ static int ets_qdisc_change(struct Qdisc *sch, struct nlattr *opt,return err; }/* If there are more bands than strict + quanta provided, the remaining -* ones are ETS with quantum of MTU. Initialize the missing values here. +* ones are ETS with quantum of max(MTU, 256). Initialize the missing +* values here. */ for (i = nstrict; i < nbands; i++) {if (!quanta[i]) - quanta[i] =psched_mtu (qdisc_dev (sch)); + quanta[i] =clamp_t (u32, (u32 )psched_mtu (qdisc_dev (sch)), +256 ,1 <<20 ); }/* Before commit, make sure we can allocate all new qdiscs */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 698/1102 net: macb: rename bp->sgmii_phy field to bp->phy
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Théo Lebrun <[email protected]>
[ Upstream commit 3f7e51cd5fbf4d970b14956ee9464515bb40666f ]
The bp->sgmii_phy field is initialised at probe by init_reset_optional() if bp->phy_interface == PHY_INTERFACE_MODE_SGMII. It gets used by:
- zynqmp_config: "cdns,zynqmp-gem" or "xlnx,zynqmp-gem" compatibles.
- mpfs_config: "microchip,mpfs-macb" compatible.
- versal_config: "xlnx,versal-gem" compatible.
Make name more generic as EyeQ5 requires the PHY in SGMII & RGMII cases.
Drop "for ZynqMP SGMII mode" comment that is already a lie, as it gets used on Microchip platforms as well. And soon it won't be SGMII-only.
Stable-dep-of: 38b6be101006 ("net: macb: fix NULL pointer dereference on unbind with fixed-link")
--- drivers/net/ethernet/cadence/macb.h | 2 +- drivers/net/ethernet/cadence/macb_main.c | 26 ++++++++++++------------ 2 files changed, 14 insertions(+), 14 deletions(-)
drivers/net/ethernet/cadence/macb.h +1 -1
@@ -1316,7 +1316,7 @@ struct macb {struct macb_ptp_info *ptp_info;/* macb-ptp interface */ -struct phy *sgmii_phy;/* for ZynqMP SGMII mode */ +struct phy *phy;#ifdef MACB_EXT_DESC uint8_t hw_dma_cap;
drivers/net/ethernet/cadence/macb_main.c +13 -13
@@ -3107,7 +3107,7 @@ static int macb_open(struct net_device *dev)macb_init_hw (bp); - err =phy_power_on (bp->sgmii_phy); + err =phy_power_on (bp->phy);if (err) goto reset_hw;
@@ -3123,7 +3123,7 @@ static int macb_open(struct net_device *dev)return 0 ; phy_off: -phy_power_off (bp->sgmii_phy); +phy_power_off (bp->phy); reset_hw:macb_reset_hw (bp);
@@ -3154,7 +3154,7 @@ static int macb_close(struct net_device *dev)phylink_stop (bp->phylink);phylink_disconnect_phy (bp->phylink); -phy_power_off (bp->sgmii_phy); +phy_power_off (bp->phy);spin_lock_irqsave (&bp->lock, flags);macb_reset_hw (bp);
@@ -4881,13 +4881,13 @@ static int init_reset_optional(struct platform_device *pdev)if (bp->phy_interface ==PHY_INTERFACE_MODE_SGMII ) {/* Ensure PHY device used in SGMII mode is ready */ - bp->sgmii_phy =devm_phy_optional_get (&pdev->dev,NULL ); + bp->phy =devm_phy_optional_get (&pdev->dev,NULL ); -if (IS_ERR (bp->sgmii_phy)) -return dev_err_probe (&pdev->dev,PTR_ERR (bp->sgmii_phy), +if (IS_ERR (bp->phy)) +return dev_err_probe (&pdev->dev,PTR_ERR (bp->phy),"failed to get SGMII PHY\n" ); - ret =phy_init (bp->sgmii_phy); + ret =phy_init (bp->phy);if (ret)return dev_err_probe (&pdev->dev, ret,"failed to init SGMII PHY\n" );
@@ -4916,7 +4916,7 @@ static int init_reset_optional(struct platform_device *pdev)/* Fully reset controller at hardware level if mapped in device tree */ ret =device_reset_optional (&pdev->dev);if (ret) { -phy_exit (bp->sgmii_phy); +phy_exit (bp->phy);return dev_err_probe (&pdev->dev, ret,"failed to reset controller" ); }
@@ -4924,7 +4924,7 @@ static int init_reset_optional(struct platform_device *pdev) err_out_phy_exit:if (ret) -phy_exit (bp->sgmii_phy); +phy_exit (bp->phy);return ret; }
@@ -5324,7 +5324,7 @@ static int macb_probe(struct platform_device *pdev)mdiobus_free (bp->mii_bus); err_out_phy_exit: -phy_exit (bp->sgmii_phy); +phy_exit (bp->phy); err_out_free_netdev:free_netdev (dev);
@@ -5348,7 +5348,7 @@ static void macb_remove(struct platform_device *pdev)if (dev) { bp =netdev_priv (dev);unregister_netdev (dev); -phy_exit (bp->sgmii_phy); +phy_exit (bp->phy);mdiobus_unregister (bp->mii_bus);mdiobus_free (bp->mii_bus);
@@ -5375,7 +5375,7 @@ static int __maybe_unused macb_suspend(struct device *dev)int err;if (!device_may_wakeup (&bp->dev->dev)) -phy_exit (bp->sgmii_phy); +phy_exit (bp->phy);if (!netif_running (netdev))return 0 ;
@@ -5512,7 +5512,7 @@ static int __maybe_unused macb_resume(struct device *dev)int err;if (!device_may_wakeup (&bp->dev->dev)) -phy_init (bp->sgmii_phy); +phy_init (bp->phy);if (!netif_running (netdev))return 0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 699/1102 net: macb: fix NULL pointer dereference on unbind with fixed-link
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vineeth Karumanchi <[email protected]>
[ Upstream commit 38b6be101006d3e7af972999f45d4f1e8250587a ]
When the device tree describes a fixed-link and has no "mdio" child node, macb_mii_init() returns early without allocating the MDIO bus, leaving bp->mii_bus as NULL.
Two cleanup paths then dereference this NULL bus:
1. On driver unbind, macb_remove() unconditionally calls mdiobus_unregister(bp->mii_bus), which oopses:
Unable to handle kernel NULL pointer dereference at virtual address 00000000000004a8 pc : mdiobus_unregister+0x14/0xa4 lr : macb_remove+0x38/0xa4 Call trace: mdiobus_unregister+0x14/0xa4 (P) macb_remove+0x38/0xa4 platform_remove+0x20/0x30 device_release_driver_internal+0x1c8/0x224 unbind_store+0xb4/0xbc
2. On the probe error path in macb_probe(), reached when macb_mii_init() has succeeded but a subsequent step fails, the err_out_unregister_mdio label runs the same unconditional cleanup.
mdiobus_unregister() and mdiobus_free() do not guard against a NULL bus, so guard the calls in both macb_remove() and the probe error path.
--- drivers/net/ethernet/cadence/macb_main.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-)
drivers/net/ethernet/cadence/macb_main.c +8 -4
@@ -5320,8 +5320,10 @@ static int macb_probe(struct platform_device *pdev)return 0 ; err_out_unregister_mdio: -mdiobus_unregister (bp->mii_bus); -mdiobus_free (bp->mii_bus); +if (bp->mii_bus) { +mdiobus_unregister (bp->mii_bus); +mdiobus_free (bp->mii_bus); + } err_out_phy_exit:phy_exit (bp->phy);
@@ -5349,8 +5351,10 @@ static void macb_remove(struct platform_device *pdev) bp =netdev_priv (dev);unregister_netdev (dev);phy_exit (bp->phy); -mdiobus_unregister (bp->mii_bus); -mdiobus_free (bp->mii_bus); +if (bp->mii_bus) { +mdiobus_unregister (bp->mii_bus); +mdiobus_free (bp->mii_bus); + }device_set_wakeup_enable (&bp->pdev->dev,0 );cancel_work_sync (&bp->hresp_err_bh_work);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 700/1102 bpf: Reject non-scalar bpf_loop iteration counts
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kumar Kartikeya Dwivedi <[email protected]>
[ Upstream commit c3fd8e5fd100f122bad503bdc0e9277219533253 ]
bpf_loop() declares its nr_loops argument as ARG_ANYTHING. Privileged programs may pass pointer values to such arguments, so check_func_arg() lets a pointer-valued R1 reach the helper-specific checks.
Since commit bb124da69c47 ("bpf: keep track of max number of bpf_loop callback iterations"), the verifier marks R1 precise and reads its upper bound to limit callback simulation. Precision backtracking only accepts scalar registers, so passing a pointer instead triggers the "backtracking misuse" verifier warning. Kernels with panic_on_warn enabled subsequently panic.
Introduce ARG_SCALAR for helper arguments that only accept scalar values and use it for bpf_loop() nr_loops. Generic helper argument validation then rejects pointers before loop inlining and precision processing.
--- include/linux/bpf.h | 1 + kernel/bpf/bpf_iter.c | 2 +- kernel/bpf/verifier.c | 1 + 3 files changed, 3 insertions(+), 1 deletion(-)
include/linux/bpf.h +1 -0
@@ -762,6 +762,7 @@ enum bpf_arg_type {ARG_PTR_TO_CTX ,/* pointer to context */ ARG_ANYTHING ,/* any (initialized) argument is ok */ +ARG_SCALAR ,/* scalar argument */ ARG_PTR_TO_SPIN_LOCK ,/* pointer to bpf_spin_lock */ ARG_PTR_TO_SOCK_COMMON ,/* pointer to sock_common */ ARG_PTR_TO_SOCKET, /* pointer to bpf_sock (fullsock) */
kernel/bpf/bpf_iter.c +1 -1
@@ -770,7 +770,7 @@ const struct bpf_func_proto bpf_loop_proto = { .func = bpf_loop, .gpl_only = false, .ret_type = RET_INTEGER, - .arg1_type = ARG_ANYTHING, + .arg1_type = ARG_SCALAR, .arg2_type = ARG_PTR_TO_FUNC, .arg3_type = ARG_PTR_TO_STACK_OR_NULL, .arg4_type = ARG_ANYTHING,
kernel/bpf/verifier.c +1 -0
@@ -8647,6 +8647,7 @@ static const struct bpf_reg_types *compatible_reg_types[__BPF_ARG_TYPE_MAX] = { [ARG_CONST_SIZE] = &scalar_types, [ARG_CONST_SIZE_OR_ZERO] = &scalar_types, [ARG_CONST_ALLOC_SIZE_OR_ZERO] = &scalar_types, + [ARG_SCALAR] = &scalar_types, [ARG_CONST_MAP_PTR] = &const_map_ptr_types, [ARG_PTR_TO_CTX] = &context_types, [ARG_PTR_TO_SOCK_COMMON] = &sock_types,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 701/1102 ALSA: caiaq: Decoupling ep1_in_urb in caiaq dev
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 402a9d6aab7ac787ab075adeb562c3db8b8f564b ]
The epq_in_urb object belonging to the caiaq device is coupled within the struct snd_usb_caiaqdev. After usb_submit_urb(epq_in_urb, GFP_KERNEL) executes successfully, epq_in_urb is successfully added to the urbp_list queue of the dummy HCD driver (userspace specifies dummy_hcd as the HCD layer driver for the caiaq USB device).
When init_card() calls snd_usb_caiaq_send_command() which subsequently fails due to a timeout, and proceeds to call snd_card_free() to release the card, the embedded ep1_in_urb object is also freed. When the dummy HCD driver detects that the URB has been unlinked, it returns the URB (by usb_hcd_giveback_urb()), which triggers [1].
Decouple the ep1_in_urb object from the struct snd_usb_caiaqdev and switch to using a pointer instead. Separately allocate and manage the memory for ep1_in_urb to prevent the release of the snd_card memory object from interfering with it.
midi_out_urb has the same issue as ep1_in_urb and is handled in the same way.
[1]
BUG: KASAN: slab-use-after-free in usb_free_urb+0x24/0x120 drivers/usb/core/urb.c:96 Write of size 4 at addr ffff88803cee1050 by task ktimers/1/29 Call Trace: usb_free_urb+0x24/0x120 drivers/usb/core/urb.c:96 dummy_timer+0xaac/0x4d50 drivers/usb/gadget/udc/dummy_hcd.c:2019 __run_hrtimer kernel/time/hrtimer.c:2067 [inline] __hrtimer_run_queues+0x3eb/0xaf0 kernel/time/hrtimer.c:2124 hrtimer_run_softirq+0x1e1/0x2e0 kernel/time/hrtimer.c:2141 Allocated by task 36: snd_card_new+0x7b/0x110 sound/core/init.c:184 create_card sound/usb/caiaq/device.c:429 [inline] snd_probe+0x236/0x1af0 sound/usb/caiaq/device.c:544 Freed by task 36: snd_card_free_when_closed sound/core/init.c:630 [inline] snd_card_free+0x138/0x1d0 sound/core/init.c:662 snd_probe+0x162b/0x1af0 sound/usb/caiaq/device.c:553
--- sound/usb/caiaq/device.c | 36 ++++++++++++++++++++++++------------ sound/usb/caiaq/device.h | 4 ++-- sound/usb/caiaq/midi.c | 6 +++--- 3 files changed, 29 insertions(+), 17 deletions(-)
sound/usb/caiaq/device.c +24 -12
@@ -192,8 +192,8 @@ static void usb_ep1_command_reply_dispatch (struct urb* urb)break ; } - cdev->ep1_in_urb.actual_length =0 ; - ret =usb_submit_urb (&cdev->ep1_in_urb,GFP_ATOMIC ); + cdev->ep1_in_urb->actual_length =0 ; + ret =usb_submit_urb (cdev->ep1_in_urb,GFP_ATOMIC );if (ret <0 )dev_err (dev,"unable to submit urb. OOM!?\n" ); }
@@ -408,6 +408,10 @@ static void card_free(struct snd_card *card)#endif snd_usb_caiaq_audio_free (cdev);usb_put_dev (cdev->chip.dev); +usb_free_urb (cdev->ep1_in_urb); + cdev->ep1_in_urb =NULL ; +usb_free_urb (cdev->midi_out_urb); + cdev->midi_out_urb =NULL ; } static int create_card(struct usb_device *usb_dev,
@@ -457,22 +461,30 @@ static int init_card(struct snd_usb_caiaqdev *cdev)return -EIO ; } -usb_init_urb (&cdev->ep1_in_urb); -usb_init_urb (&cdev->midi_out_urb); + cdev->ep1_in_urb =usb_alloc_urb (0 ,GFP_KERNEL ); +if (!cdev->ep1_in_urb) +return -ENOMEM ; -usb_fill_bulk_urb (&cdev->ep1_in_urb, usb_dev, + cdev->midi_out_urb =usb_alloc_urb (0 ,GFP_KERNEL ); +if (!cdev->midi_out_urb) { +usb_free_urb (cdev->ep1_in_urb); + cdev->ep1_in_urb =NULL ; +return -ENOMEM ; + } + +usb_fill_bulk_urb (cdev->ep1_in_urb, usb_dev,usb_rcvbulkpipe (usb_dev,0x1 ), cdev->ep1_in_buf,EP1_BUFSIZE , usb_ep1_command_reply_dispatch, cdev); -usb_fill_bulk_urb (&cdev->midi_out_urb, usb_dev, +usb_fill_bulk_urb (cdev->midi_out_urb, usb_dev,usb_sndbulkpipe (usb_dev,0x1 ), cdev->midi_out_buf,EP1_BUFSIZE , snd_usb_caiaq_midi_output_done, cdev);/* sanity checks of EPs before actually submitting */ -if (usb_urb_ep_type_check (&cdev->ep1_in_urb) || -usb_urb_ep_type_check (&cdev->midi_out_urb)) { +if (usb_urb_ep_type_check (cdev->ep1_in_urb) || +usb_urb_ep_type_check (cdev->midi_out_urb)) {dev_err (dev,"invalid EPs\n" );return -EINVAL ; }
@@ -480,7 +492,7 @@ static int init_card(struct snd_usb_caiaqdev *cdev)init_waitqueue_head (&cdev->ep1_wait_queue);init_waitqueue_head (&cdev->prepare_wait_queue); -if (usb_submit_urb (&cdev->ep1_in_urb,GFP_KERNEL ) !=0 ) +if (usb_submit_urb (cdev->ep1_in_urb,GFP_KERNEL ) !=0 )return -EIO ; err =snd_usb_caiaq_send_command (cdev,EP1_CMD_GET_DEVICE_INFO ,NULL ,0 );
@@ -530,7 +542,7 @@ static int init_card(struct snd_usb_caiaqdev *cdev)return 0 ; err_kill_urb: -usb_kill_urb (&cdev->ep1_in_urb); +usb_kill_urb (cdev->ep1_in_urb);return err; }
@@ -576,8 +588,8 @@ static void snd_disconnect(struct usb_interface *intf)#endif snd_usb_caiaq_audio_disconnect (cdev); -usb_kill_urb (&cdev->ep1_in_urb); -usb_kill_urb (&cdev->midi_out_urb); +usb_kill_urb (cdev->ep1_in_urb); +usb_kill_urb (cdev->midi_out_urb);snd_card_free_when_closed (card); }
sound/usb/caiaq/device.h +2 -2
@@ -60,8 +60,8 @@ struct snd_usb_caiaq_cb_info;struct snd_usb_caiaqdev {struct snd_usb_audio chip; -struct urb ep1_in_urb; -struct urb midi_out_urb; +struct urb *ep1_in_urb; +struct urb *midi_out_urb;struct urb **data_urbs_in;struct urb **data_urbs_out;struct snd_usb_caiaq_cb_info *data_cb_info;
sound/usb/caiaq/midi.c +3 -3
@@ -43,7 +43,7 @@ static int snd_usb_caiaq_midi_output_close(struct snd_rawmidi_substream *substre {struct snd_usb_caiaqdev *cdev = substream->rmidi->private_data;if (cdev->midi_out_active) { -usb_kill_urb (&cdev->midi_out_urb); +usb_kill_urb (cdev->midi_out_urb); cdev->midi_out_active =0 ; }return 0 ;
@@ -64,9 +64,9 @@ static void snd_usb_caiaq_midi_send(struct snd_usb_caiaqdev *cdev,return ; cdev->midi_out_buf[2 ] = len; - cdev->midi_out_urb.transfer_buffer_length = len+3 ; + cdev->midi_out_urb->transfer_buffer_length = len+3 ; - ret =usb_submit_urb (&cdev->midi_out_urb,GFP_ATOMIC ); + ret =usb_submit_urb (cdev->midi_out_urb,GFP_ATOMIC );if (ret <0 )dev_err (dev, "snd_usb_caiaq_midi_send(%p): usb_submit_urb() failed,"
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 702/1102 hwmon: (ltc4282) Make sure clk_init_data is fully initialized
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Geert Uytterhoeven <[email protected]>
[ Upstream commit e317326d1755ea054b98e7a4833b929157461c35 ]
The clk_init_data structure contains several mutually-exclusive members for different methods to specify the possible parents of a clock, prompting drivers to initialize only the members they need. However, not initializing all members may cause subtle issues, which are only exposed when CONFIG_INIT_STACK_ALL_PATTERN or CONFIG_INIT_STACK_NONE is enabled.
ltc428_clk_provider_setup() does not fill in any parent clocks, and assumes that init.num_parents is NULL. However, the latter in uninitialized, and thus may cause a crash.
Make sure all members are fully initialized, to fix such bugs, and to avoid future breakage when converting drivers to a different method for specifying the parents.
--- drivers/hwmon/ltc4282.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/hwmon/ltc4282.c +1 -1
@@ -1138,7 +1138,7 @@ static const struct clk_ops ltc4282_ops = {static int ltc428_clk_provider_setup (struct ltc4282_state *st,struct device *dev) { -struct clk_init_data init; +struct clk_init_data init = {};int ret;if (!IS_ENABLED (CONFIG_COMMON_CLK ))
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 703/1102 libnvdimm: Replace namespace_match() with device_find_child_by_name()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zijun Hu <[email protected]>
[ Upstream commit a7512bda7c176553536a5775fa9540223eef3c1f ]
Simplify nd_namespace_store() implementation by
using device_find_child_by_name().
Stable-dep-of: b4fffa75c1d6 ("Documentation/hwmon: Document hwmon_notify_event()")
--- drivers/nvdimm/claim.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-)
drivers/nvdimm/claim.c +1 -8
@@ -67,13 +67,6 @@ bool nd_attach_ndns(struct device *dev, struct nd_namespace_common *attach,return claimed; } -static int namespace_match (struct device *dev,void *data) -{ -char *name = data; - -return strcmp (name,dev_name (dev)) ==0 ; -} -static bool is_idle (struct device *dev,struct nd_namespace_common *ndns) {struct nd_region *nd_region =to_nd_region (dev->parent);
@@ -168,7 +161,7 @@ ssize_t nd_namespace_store(struct device *dev, goto out; } - found =device_find_child (dev->parent, name, namespace_match); + found =device_find_child_by_name (dev->parent, name);if (!found) {dev_dbg (dev,"'%s' not found under %s\n" , name,dev_name (dev->parent));
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 704/1102 hwmon: Introduce 64-bit energy attribute support
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guenter Roeck <[email protected]>
[ Upstream commit 0bcd01f757bc06471c82a137eafee281ef1b6e38 ]
Many chips require 64-bit variables to display the accumulated energy, even more so since the energy units are micro-Joule. Add new sensor type "energy64" to support reporting the chip energy as 64-bit values.
Changing the entire hardware monitoring API is not feasible, and it is only really necessary to support reading 64-bit values for the "energyX_input" attribute. For this reason, keep the API as-is and use type casts on both ends to pass 64-bit pointers when reading the accumulated energy. On the write side (which is only useful for the energyX_enable attribute), keep passing the written value as long.
Stable-dep-of: b4fffa75c1d6 ("Documentation/hwmon: Document hwmon_notify_event()")
--- Documentation/hwmon/hwmon-kernel-api.rst | 3 +++ drivers/hwmon/hwmon.c | 14 ++++++++++---- include/linux/hwmon.h | 1 + include/trace/events/hwmon.h | 10 +++++----- 4 files changed, 19 insertions(+), 9 deletions(-)
Documentation/hwmon/hwmon-kernel-api.rst +3 -0
@@ -158,6 +158,7 @@ It contains following fields: hwmon_curr Current sensor hwmon_power Power sensor hwmon_energy Energy sensor + hwmon_energy64 Energy sensor, reported as 64-bit signed value hwmon_humidity Humidity sensor hwmon_fan Fan speed sensor hwmon_pwm PWM control
@@ -287,6 +288,8 @@ Parameters: The sensor channel number. val: Pointer to attribute value. + For hwmon_energy64, `'val`' is passed as `long *` but needs + a typecast to `s64 *`. Return value: 0 on success, a negative error number otherwise.
drivers/hwmon/hwmon.c +10 -4
@@ -424,18 +424,22 @@ static ssize_t hwmon_attr_show(struct device *dev, struct device_attribute *devattr, char *buf) { struct hwmon_device_attribute *hattr = to_hwmon_attr(devattr); +s64 val64;long val;int ret; ret = hattr->ops->read (dev, hattr->type, hattr->attr, hattr->index, - &val); + (hattr->type == hwmon_energy64) ? (long *)&val64 : &val);if (ret <0 )return ret; +if (hattr->type != hwmon_energy64) + val64 = val; +trace_hwmon_attr_show (hattr->index +hwmon_attr_base (hattr->type), - hattr->name, val); + hattr->name, val64); -return sprintf (buf,"%ld\n" , val); +return sprintf (buf,"%lld\n" , val64); } static ssize_t hwmon_attr_show_string(struct device *dev,
@@ -476,7 +480,7 @@ static ssize_t hwmon_attr_store(struct device *dev,return ret;trace_hwmon_attr_store (hattr->index +hwmon_attr_base (hattr->type), - hattr->name, val); + hattr->name, (s64 )val);return count; }
@@ -732,6 +736,7 @@ static const char * const *__templates[] = { [hwmon_curr] = hwmon_curr_attr_templates, [hwmon_power] = hwmon_power_attr_templates, [hwmon_energy] = hwmon_energy_attr_templates, + [hwmon_energy64] = hwmon_energy_attr_templates, [hwmon_humidity] = hwmon_humidity_attr_templates, [hwmon_fan] = hwmon_fan_attr_templates, [hwmon_pwm] = hwmon_pwm_attr_templates,
@@ -745,6 +750,7 @@ static const int __templates_size[] = { [hwmon_curr] = ARRAY_SIZE(hwmon_curr_attr_templates), [hwmon_power] = ARRAY_SIZE(hwmon_power_attr_templates), [hwmon_energy] = ARRAY_SIZE(hwmon_energy_attr_templates), + [hwmon_energy64] = ARRAY_SIZE(hwmon_energy_attr_templates), [hwmon_humidity] = ARRAY_SIZE(hwmon_humidity_attr_templates), [hwmon_fan] = ARRAY_SIZE(hwmon_fan_attr_templates), [hwmon_pwm] = ARRAY_SIZE(hwmon_pwm_attr_templates),
include/linux/hwmon.h +1 -0
@@ -24,6 +24,7 @@ enum hwmon_sensor_types { hwmon_curr, hwmon_power, hwmon_energy, + hwmon_energy64, hwmon_humidity, hwmon_fan, hwmon_pwm,
include/trace/events/hwmon.h +5 -5
@@ -9,14 +9,14 @@ DECLARE_EVENT_CLASS(hwmon_attr_class, - TP_PROTO(int index, const char *attr_name, long val), + TP_PROTO(int index, const char *attr_name, long long val), TP_ARGS(index, attr_name, val), TP_STRUCT__entry( __field(int, index) __string(attr_name, attr_name) - __field(long, val) + __field(long long, val) ), TP_fast_assign(
@@ -25,20 +25,20 @@ DECLARE_EVENT_CLASS(hwmon_attr_class, __entry->val = val; ), -TP_printk ("index=%d, attr_name=%s, val=%ld" , +TP_printk ("index=%d, attr_name=%s, val=%lld" , __entry->index,__get_str (attr_name), __entry->val) );DEFINE_EVENT (hwmon_attr_class, hwmon_attr_show, - TP_PROTO(int index, const char *attr_name, long val), + TP_PROTO(int index, const char *attr_name, long long val),TP_ARGS (index, attr_name, val) );DEFINE_EVENT (hwmon_attr_class, hwmon_attr_store, - TP_PROTO(int index, const char *attr_name, long val), + TP_PROTO(int index, const char *attr_name, long long val),TP_ARGS (index, attr_name, val) );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 705/1102 hwmon: (ina2xx) Parameterize ina2xx_data in ina226_alert_read()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jared Kangas <[email protected]>
[ Upstream commit 3d44ab826e0244a8b9eaf0f1f604f4cb8b890325 ]
Mirror ina226_alert_limit_read/write and use struct ina2xx_data instead of struct regmap in ina226_alert_read's parameters.
Stable-dep-of: 35760f5efd7b ("hwmon: (ina2xx) Decouple in0 and curr1 alarms")
--- drivers/hwmon/ina2xx.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-)
drivers/hwmon/ina2xx.c +7 -7
@@ -506,12 +506,12 @@ static int ina2xx_chip_read(struct device *dev, u32 attr, long *val)return 0 ; } -static int ina226_alert_read (struct regmap *regmap,u32 mask,long *val) +static int ina226_alert_read (struct ina2xx_data *data,u32 mask,long *val) {unsigned int regval;int ret; - ret =regmap_read_bypassed (regmap,INA226_MASK_ENABLE , ®val); + ret =regmap_read_bypassed (data->regmap,INA226_MASK_ENABLE , ®val);if (ret)return ret;
@@ -546,9 +546,9 @@ static int ina2xx_in_read(struct device *dev, u32 attr, int channel, long *val)return ina226_alert_limit_read (data, over_voltage_mask, voltage_reg, val);case hwmon_in_lcrit_alarm: -return ina226_alert_read (regmap, under_voltage_mask, val); +return ina226_alert_read (data, under_voltage_mask, val);case hwmon_in_crit_alarm: -return ina226_alert_read (regmap, over_voltage_mask, val); +return ina226_alert_read (data, over_voltage_mask, val);default :return -EOPNOTSUPP ; }
@@ -605,7 +605,7 @@ static int ina2xx_power_read(struct device *dev, u32 attr, long *val)return ina226_alert_limit_read (data,INA226_POWER_OVER_LIMIT_MASK ,INA2XX_POWER , val);case hwmon_power_crit_alarm: -return ina226_alert_read (data->regmap,INA226_POWER_OVER_LIMIT_MASK , val); +return ina226_alert_read (data,INA226_POWER_OVER_LIMIT_MASK , val);default :return -EOPNOTSUPP ; }
@@ -647,9 +647,9 @@ static int ina2xx_curr_read(struct device *dev, u32 attr, long *val)return ina226_alert_limit_read (data,INA226_SHUNT_OVER_VOLTAGE_MASK ,INA2XX_CURRENT , val);case hwmon_curr_lcrit_alarm: -return ina226_alert_read (regmap,INA226_SHUNT_UNDER_VOLTAGE_MASK , val); +return ina226_alert_read (data,INA226_SHUNT_UNDER_VOLTAGE_MASK , val);case hwmon_curr_crit_alarm: -return ina226_alert_read (regmap,INA226_SHUNT_OVER_VOLTAGE_MASK , val); +return ina226_alert_read (data,INA226_SHUNT_OVER_VOLTAGE_MASK , val);default :return -EOPNOTSUPP ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 706/1102 ASoC: bcm: bcm63xx: Publish the OF module aliases
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: hpp.iscas <[email protected]>
[ Upstream commit 32689f0fc54fd801f1cd11637666e534984cb04a ]
The BCM63xx I2S platform driver matches brcm,bcm63xx-i2s using snd_soc_bcm_audio_match. With SND_BCM63XX_I2S_WHISTLER=m, the platform bus emits an OF modalias but snd-soc-63xx does not publish that table.
Export the existing OF IDs for module autoloading. The PCM companion and the probe path remain unchanged.
--- sound/soc/bcm/bcm63xx-i2s-whistler.c | 1 + 1 file changed, 1 insertion(+)
sound/soc/bcm/bcm63xx-i2s-whistler.c +1 -0
@@ -285,6 +285,7 @@ static const struct of_device_id snd_soc_bcm_audio_match[] = { {.compatible = "brcm,bcm63xx-i2s"}, { } }; +MODULE_DEVICE_TABLE (of, snd_soc_bcm_audio_match);#endif static struct platform_driver bcm63xx_i2s_driver = {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 707/1102 ASoC: Intel: SST: Publish the PCI module aliases
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: hpp.iscas <[email protected]>
[ Upstream commit d112159df5c6cc5ee6ab91cc32bf6ed29939df38 ]
The legacy SST PCI driver matches Intel Tangier devices using intel_sst_ids, but its only explicit module alias is "sst". That alias does not match PCI modalias events when this driver is built as a module.
Publish its PCI table. The independently configurable SOF driver does not provide aliases for the legacy SST module.
--- sound/soc/intel/atom/sst/sst_pci.c | 1 + 1 file changed, 1 insertion(+)
sound/soc/intel/atom/sst/sst_pci.c +1 -0
@@ -178,6 +178,7 @@ static const struct pci_device_id intel_sst_ids[] = { { PCI_DEVICE_DATA(INTEL, SST_TNG, 0) }, { 0, } }; +MODULE_DEVICE_TABLE (pci, intel_sst_ids);static struct pci_driver sst_driver = { .name = SST_DRV_NAME,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 708/1102 netfilter: nfnetlink_log: cope with concurrent instance destruction
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 387d744fa7e499d2c3748a4e60e02ebb24e7fb16 ]
Instances are refcounted. However, only memory release happens on the 1 -> 0 transition; the unlink from hashes can occur with any refcount.
Uncooperative userspace can force a situation where a queue is pending for destruction from netlink event while a different socket with same portid processes an UNBIND request.
With right timing, this will unhash the instance again:
Oops: general protection fault, [..] Call Trace: <TASK> nfulnl_recv_config+0x31a/0xd50 nfnetlink_rcv_msg+0x7c2/0xeb0
--- net/netfilter/nfnetlink_log.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-)
net/netfilter/nfnetlink_log.c +9 -4
@@ -228,13 +228,18 @@ static void __nfulnl_flush(struct nfulnl_instance *inst);static void __instance_destroy (struct nfulnl_instance *inst) { +spin_lock (&inst->lock); +if (inst->copy_mode ==NFULNL_COPY_DISABLED ) { +/* attempt to UNBIND a queue already pending +* destruction via netlink close event. Ignore. +*/ +spin_unlock (&inst->lock); +return ; + } +/* first pull it out of the global list */ hlist_del_rcu (&inst->hlist); -/* then flush all pending packets from skb */ - -spin_lock (&inst->lock); -/* lockless readers wont be able to use us */ inst->copy_mode =NFULNL_COPY_DISABLED ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 709/1102 netfilter: ip6_tables: set F_PROTO when proto value is nonzero
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 da4afc5a956d407443988e97a4d4ca14c2e999c7 ]
The ip6tables traverser doesn't search the extension header chain unless userspace did set the IP6T_F_PROTO flag.
This also means that userspace that sets the e->ipv6.proto flag can bypass the protocol check for the rule by not setting this flag.
That in turn means that all ip6_tables modules and targets that want to reject rules without '-p' flag MUST also check for that flag.
Not all do, likely because they got copied from iptables which lacks this flag (no extension headers).
Instead of fixing up all the relevant targets, emulate ip6tables behaviour in the kernel (like nft_compat.c) and set the flag if the protocol is set.
--- net/ipv6/netfilter/ip6_tables.c | 5 +++++ 1 file changed, 5 insertions(+)
net/ipv6/netfilter/ip6_tables.c +5 -0
@@ -647,6 +647,11 @@ check_entry_size_and_hooks(struct ip6t_entry *e,/* Clear counters and comefrom */ e->counters = ((struct xt_counters ) {0 ,0 }); e->comefrom =0 ; + +/* set F_PROTO, else ip6_packet_match won't do the right thing. */ +if (e->ipv6.proto) + e->ipv6.flags |=IP6T_F_PROTO ; +return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 710/1102 ASoC: mt6351: Publish the OF module alias
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: hpp.iscas <[email protected]>
[ Upstream commit 9c3882ec10399c14c59b7e4599d33c4395367c37 ]
The MT6351 codec platform driver uses mt6351_of_match to bind devices with compatible mediatek,mt6351-sound. The codec can be a separate module, but the OF table is not exported to module alias metadata.
Publish the existing table without changing codec matching, register access or the machine-driver configuration.
--- sound/soc/codecs/mt6351.c | 1 + 1 file changed, 1 insertion(+)
sound/soc/codecs/mt6351.c +1 -0
@@ -1479,6 +1479,7 @@ static const struct of_device_id mt6351_of_match[] = { {.compatible = "mediatek,mt6351-sound",}, {} }; +MODULE_DEVICE_TABLE (of, mt6351_of_match);static struct platform_driver mt6351_codec_driver = { .driver = {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 711/1102 virtio: fix use-after-free in unregister_virtio_device()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Karl Mehltretter <[email protected]>
[ Upstream commit 3f9a0fceb730f5107d52421ead5568eae25a0049 ]
device_unregister() is device_del() plus put_device(). When the caller holds no extra reference, that drops the last one and runs the release callback, which for several transports frees the memory the embedded struct virtio_device sits in. unregister_virtio_device() then calls virtio_debug_device_exit(), which reads dev->debugfs_dir out of the freed object.
Affected transports are the ones whose release callback frees and whose remove path takes no reference: virtio_mmio, virtio_vdpa, virtio_uml, mlxbf-tmfifo and virtio_ccw. virtio_pci is unaffected because virtio_pci_remove() brackets the call with get_device() and put_device().
Remove the debugfs entries before the device can go away. They are only accessed through the protected debugfs interface, so debugfs_remove_recursive() waits for in-progress file operations before returning. Tearing them down while the device is still alive is therefore safe.
Reproduced on User-Mode Linux with CONFIG_KASAN and CONFIG_VIRTIO_DEBUG by unbinding a virtio-uml device:
BUG: KASAN: slab-use-after-free in virtio_debug_device_exit+0x36/0x4d Read of size 8 at addr 00000000616e0b10 by task init/1 __asan_report_load8_noabort virtio_debug_device_exit+0x36/0x4d unregister_virtio_device+0x48/0x75 virtio_uml_remove platform_remove device_release_driver_internal unbind_store Freed by task 1: kfree virtio_uml_release_dev device_release kobject_put put_device device_unregister
With this applied, the report is gone and unbind is clean.
Message-ID: <[email protected]>
--- drivers/virtio/virtio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/virtio/virtio.c +1 -1
@@ -521,8 +521,8 @@ void unregister_virtio_device(struct virtio_device *dev) {int index = dev->index;/* save for after device release */ -device_unregister (&dev->dev);virtio_debug_device_exit (dev); +device_unregister (&dev->dev);ida_free (&virtio_index_ida, index); }EXPORT_SYMBOL_GPL (unregister_virtio_device);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 712/1102 virtio_console: do not free control-out buffers on remove
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jia Jia <[email protected]>
[ Upstream commit 894f98e73983f37354214a89a3a7fd35bf9e3072 ]
__send_control_msg() publishes &portdev->cpkt as the control-out virtqueue cookie. remove_vqs() walks every virtqueue and passes leftover cookies to free_buf(), which treats them as struct port_buffer and reads sgpages.
If a control message is still on c_ovq when the device is unbound, free_buf() reads past the ports_device object.
KASAN reported slab-out-of-bounds in free_buf():
free_buf
remove_vqs
virtcons_remove
unbind_store
The object was the ports_device allocated in virtcons_probe().
Drain c_ovq without freeing. The packet lives in portdev and is released with it.
Message-ID: <[email protected]>
--- drivers/char/virtio_console.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-)
drivers/char/virtio_console.c +18 -3
@@ -1896,13 +1896,28 @@ static const struct file_operations portdev_fops = {static void remove_vqs (struct ports_device *portdev) {struct virtqueue *vq; +bool multiport =use_multiport (portdev);virtio_device_for_each_vq (portdev->vdev, vq) {struct port_buffer *buf; +unsigned int len; -flush_bufs (vq, true); -while ((buf =virtqueue_detach_unused_buf (vq))) -free_buf (buf, true); +/* +* c_ovq cookies are &portdev->cpkt, not port_buffer. +* Detach them but do not free_buf(). +*/ +if (multiport && vq == portdev->c_ovq) { +spin_lock (&portdev->c_ovq_lock); +while (virtqueue_get_buf (vq, &len)) + ; +while (virtqueue_detach_unused_buf (vq)) + ; +spin_unlock (&portdev->c_ovq_lock); + }else { +flush_bufs (vq, true); +while ((buf =virtqueue_detach_unused_buf (vq))) +free_buf (buf, true); + }cond_resched (); } portdev->vdev->config->del_vqs (portdev->vdev);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 713/1102 vhost/vdpa: reject VRING_NUM larger than device max
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jia Jia <[email protected]>
[ Upstream commit ccb1dc7c527f8c925925cf92afc76ae590dac311 ]
vhost_vring_set_num() accepts any non-zero power-of-two queue size that fits in 16 bits. vhost-vdpa then passes that value to set_vq_num() without comparing it with get_vq_num_max().
A process with access to /dev/vhost-vdpa-* can therefore configure a queue larger than the device advertises. With vdpa_sim, the worker can walk descriptors beyond the mapped descriptor ring. KASAN reports a 16-byte out-of-bounds read, corresponding to one vring_desc, in the vringh IOTLB path:
BUG: KASAN: out-of-bounds in _copy_from_iter Read of size 16 copy_from_iotlb copydesc_iotlb vringh_getdesc_iotlb vdpasim_net_work
Cache get_vq_num_max() immediately after reset. Some backends derive it from writable queue-size state, so querying it after SET_NUM may return the current size instead of the device capability. Invalidate the cached value before reset so a failed reset leaves SET_NUM disabled.
For VHOST_SET_VRING_NUM, copy the complete vring state once and use the same index and size for validation, vq->num, and set_vq_num(). This ensures that validation and use operate on the same copied values.
Message-ID: <[email protected]>
--- drivers/vhost/vdpa.c | 44 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 37 insertions(+), 7 deletions(-)
drivers/vhost/vdpa.c +37 -7
@@ -53,6 +53,7 @@ struct vhost_vdpa {struct cdev cdev;atomic_t opened;u32 nvqs; +u16 vq_num_max;int virtio_id;int minor;struct eventfd_ctx *config_ctx;
@@ -229,7 +230,9 @@ static void vhost_vdpa_unsetup_vq_irq(struct vhost_vdpa *v, u16 qid)static int _compat_vdpa_reset (struct vhost_vdpa *v) {struct vdpa_device *vdpa = v->vdpa; +const struct vdpa_config_ops *ops = vdpa->config;u32 flags =0 ; +int ret; v->suspended = false;
@@ -239,7 +242,14 @@ static int _compat_vdpa_reset(struct vhost_vdpa *v) VDPA_RESET_F_CLEAN_MAP :0 ; } -return vdpa_reset (vdpa, flags); + v->vq_num_max =0 ; + ret =vdpa_reset (vdpa, flags); +if (!ret) { +/* Some backends derive the max from mutable queue state. */ + v->vq_num_max = ops->get_vq_num_max (vdpa); + } + +return ret; }static int vhost_vdpa_reset (struct vhost_vdpa *v)
@@ -641,9 +651,15 @@ static long vhost_vdpa_vring_ioctl(struct vhost_vdpa *v, unsigned int cmd,u32 idx;long r; - r =get_user (idx, (u32 __user *)argp); -if (r <0 ) -return r; +if (cmd ==VHOST_SET_VRING_NUM ) { +if (copy_from_user (&s, argp,sizeof (s))) +return -EFAULT ; + idx = s.index; + }else { + r =get_user (idx, (u32 __user *)argp); +if (r <0 ) +return r; + }if (idx >= v->nvqs)return -ENOBUFS ;
@@ -652,6 +668,23 @@ static long vhost_vdpa_vring_ioctl(struct vhost_vdpa *v, unsigned int cmd, vq = &v->vqs[idx];switch (cmd) { +case VHOST_SET_VRING_NUM : +mutex_lock (&vq->mutex); +if (vq->private_data) { + r = -EBUSY ; + }else if (!s.num || s.num >0xffff || + s.num > v->vq_num_max || + (s.num & (s.num -1 ))) { + r = -EINVAL ; + }else { + vq->num = s.num; + r =0 ; + } +mutex_unlock (&vq->mutex); +if (r) +return r; + ops->set_vq_num (vdpa, idx, s.num); +return 0 ;case VHOST_VDPA_SET_VRING_ENABLE :if (copy_from_user (&s, argp,sizeof (s)))return -EFAULT ;
@@ -765,9 +798,6 @@ static long vhost_vdpa_vring_ioctl(struct vhost_vdpa *v, unsigned int cmd, ops->set_vq_cb (vdpa, idx, &cb);break ; -case VHOST_SET_VRING_NUM : - ops->set_vq_num (vdpa, idx, vq->num); -break ; }return r;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 714/1102 vhost-vdpa: dont install the eventfd_ctx_fdget() error in config_ctx
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yu Zhang <[email protected]>
[ Upstream commit e74a9fa50749b9940b4fb13199652325e08d3c4a ]
vhost_vdpa_set_config_call() swaps the eventfd_ctx_fdget() return value into v->config_ctx before checking it, so on failure the field briefly holds an ERR_PTR:
ctx = fd == VHOST_FILE_UNBIND ? NULL : eventfd_ctx_fdget(fd);
swap(ctx, v->config_ctx);
if (!IS_ERR_OR_NULL(ctx))
eventfd_ctx_put(ctx);
if (IS_ERR(v->config_ctx)) {
long ret = PTR_ERR(v->config_ctx);
v->config_ctx = NULL;
return ret;
}Commit 0bde59c1723a ("vhost-vdpa: set v->config_ctx to NULL if eventfd_ctx_fdget() fails") added that clearing, and spelled out the invariant the rest of the file relies on: "we consider 'v->config_ctx' valid if it is not NULL". The window between the swap and the clearing still breaks it. vhost_vdpa_config_cb() only tests for NULL, so a config interrupt delivered inside the window hands the ERR_PTR to eventfd_signal().
Check the fd before installing it instead. That closes the window and matches how vhost_vring_ioctl() handles the same failure for the vq call fd.
It also stops a rejected fd from tearing down a config interrupt that was
working: until now the swap replaced the live context and put it, so after an EBADF the device silently stopped delivering config interrupts until userspace installed a new fd.
Message-ID: <[email protected]>
--- drivers/vhost/vdpa.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-)
drivers/vhost/vdpa.c +4 -8
@@ -539,18 +539,14 @@ static long vhost_vdpa_set_config_call(struct vhost_vdpa *v, u32 __user *argp)return -EFAULT ; ctx = fd ==VHOST_FILE_UNBIND ?NULL :eventfd_ctx_fdget (fd); +if (IS_ERR (ctx)) +return PTR_ERR (ctx); +swap (ctx, v->config_ctx); -if (!IS_ERR_OR_NULL (ctx)) +if (ctx)eventfd_ctx_put (ctx); -if (IS_ERR (v->config_ctx)) { -long ret =PTR_ERR (v->config_ctx); - - v->config_ctx =NULL ; -return ret; - } - v->vdpa->config->set_config_cb (v->vdpa, &cb);return 0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 715/1102 vhost-vdpa: protect config_ctx from being freed under the config callback
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yu Zhang <[email protected]>
[ Upstream commit 62be4e3e5f5f947fbf765b914cebdc478f715d12 ]
vhost_vdpa_config_cb() loads v->config_ctx and signals it without taking a reference and without holding any lock:
struct eventfd_ctx *config_ctx = v->config_ctx; if (config_ctx) eventfd_signal(config_ctx);
VHOST_VDPA_SET_CONFIG_CALL replaces that field and drops what is normally the last reference to the old context:
swap(ctx, v->config_ctx); if (ctx) eventfd_ctx_put(ctx);
eventfd_ctx_put() drops the last kref and frees the context immediately, with no RCU grace period, so a callback that has already loaded the pointer goes on to dereference freed memory. The two sides share no
lock: the ioctl runs under vhost_dev.mutex, while the parent invokes the callback from its own interrupt or workqueue context.
This is not the reopen refcount underflow fixed by commit f6bbf0010ba0 ("vhost-vdpa: fix use-after-free of v->config_ctx"), which was about vhost_vdpa_config_put() leaving a stale pointer behind. Here the pointer is maintained correctly and it is the read side that is unprotected.
With VDUSE as the parent this is reachable from userspace with access to /dev/vduse (root by default). VDUSE_DEV_INJECT_CONFIG_IRQ queues dev->inject, and vduse_dev_irq_inject() runs the callback under VDUSE's own dev->irq_lock, which vhost does not hold. vduse_dev_reset() does flush_work(&dev->inject), but VHOST_VDPA_SET_CONFIG_CALL never goes through reset, so an inject already in flight is not waited for. A process that injects config interrupts on the VDUSE fd while another thread swaps the call fd on the vhost-vdpa fd hits it in seconds:
BUG: KASAN: slab-use-after-free in native_queued_spin_lock_slowpath Read of size 4 at addr ffff888107d21808 by task kworker/u17:1/2993 Workqueue: vduse-irq vduse_dev_irq_inject Call Trace: native_queued_spin_lock_slowpath+0x97/0x5b0 _raw_spin_lock_irqsave+0xd4/0xe0 eventfd_signal_mask+0x69/0x120 vhost_vdpa_config_cb+0x34/0x50 vduse_dev_irq_inject+0x46/0x60 process_one_work+0x468/0x950 Allocated by task 2992: do_eventfd+0x50/0x200 __x64_sys_eventfd2+0x2e/0x40 Freed by task 2992: eventfd_ctx_put+0xb9/0xc0 vhost_vdpa_unlocked_ioctl+0x116c/0x2190
Add a spinlock covering every access to config_ctx, so the callback either signals a context that is still alive or observes NULL, and the put happens only once no callback can reach the old value.
Clearing the parent's callback before the put would not be enough: of the in-tree set_config_cb() implementations only VDUSE takes a lock, the rest store the pointer unlocked, so that would not order against an in-flight invocation.
Message-ID: <[email protected]>
--- drivers/vhost/vdpa.c | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-)
drivers/vhost/vdpa.c +25 -7
@@ -57,6 +57,8 @@ struct vhost_vdpa {int virtio_id;int minor;struct eventfd_ctx *config_ctx; +/* Serialises vhost_vdpa_config_cb() against config_ctx being replaced. */ +spinlock_t config_lock;int in_batch;struct vdpa_iova_range range;u32 batch_asid;
@@ -188,10 +190,12 @@ static irqreturn_t vhost_vdpa_virtqueue_cb(void *private)static irqreturn_t vhost_vdpa_config_cb (void *private) {struct vhost_vdpa *v = private; -struct eventfd_ctx *config_ctx = v->config_ctx; +unsigned long flags; -if (config_ctx) -eventfd_signal (config_ctx); +spin_lock_irqsave (&v->config_lock, flags); +if (v->config_ctx) +eventfd_signal (v->config_ctx); +spin_unlock_irqrestore (&v->config_lock, flags);return IRQ_HANDLED ; }
@@ -521,15 +525,22 @@ static long vhost_vdpa_get_vring_num(struct vhost_vdpa *v, u16 __user *argp)static void vhost_vdpa_config_put (struct vhost_vdpa *v) { -if (v->config_ctx) { -eventfd_ctx_put (v->config_ctx); - v->config_ctx =NULL ; - } +struct eventfd_ctx *ctx; +unsigned long flags; + +spin_lock_irqsave (&v->config_lock, flags); + ctx = v->config_ctx; + v->config_ctx =NULL ; +spin_unlock_irqrestore (&v->config_lock, flags); + +if (ctx) +eventfd_ctx_put (ctx); }static long vhost_vdpa_set_config_call (struct vhost_vdpa *v,u32 __user *argp) {struct vdpa_callback cb; +unsigned long flags;int fd;struct eventfd_ctx *ctx;
@@ -542,8 +553,14 @@ static long vhost_vdpa_set_config_call(struct vhost_vdpa *v, u32 __user *argp)if (IS_ERR (ctx))return PTR_ERR (ctx); +spin_lock_irqsave (&v->config_lock, flags);swap (ctx, v->config_ctx); +spin_unlock_irqrestore (&v->config_lock, flags); +/* +* The callback can no longer reach the old context, so this is the +* last reference to it. +*/ if (ctx)eventfd_ctx_put (ctx);
@@ -1630,6 +1647,7 @@ static int vhost_vdpa_probe(struct vdpa_device *vdpa) }atomic_set (&v->opened,0 ); +spin_lock_init (&v->config_lock); v->minor = minor; v->vdpa = vdpa; v->nvqs = vdpa->nvqs;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 716/1102 vdpa_sim_blk: reject out-of-range sector starts
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Linfeng Sun <[email protected]>
[ Upstream commit 0a8693f00c408d85f086ad85d29e7030bf1e2055 ]
vdpasim_blk_check_range() logs an invalid start sector but continues validating the request. The subsequent unsigned capacity subtraction can underflow and let an out-of-range buffer offset reach the data path.
The invalid offset is used by three request paths. VIRTIO_BLK_T_OUT copies guest data to blk->buffer + offset through vringh_iov_pull_iotlb(), causing an out-of-bounds write in _copy_from_iter() or memcpy(). VIRTIO_BLK_T_IN copies from blk->buffer + offset to the guest through vringh_iov_push_iotlb(), causing an out-of-bounds read in _copy_to_iter(). VIRTIO_BLK_T_WRITE_ZEROES passes blk->buffer + offset to memset(), causing an out-of-bounds write.
Reject starts at or beyond the capacity before the subtraction. Treat the capacity boundary as invalid because the IN and OUT paths round byte counts down to sectors for validation but later copy the original byte counts. A sub-sector request at the capacity boundary would otherwise still access past the end of the buffer.
I found this bug myself, though the patch was written with AI assistance.
Message-ID: <[email protected]>
--- drivers/vdpa/vdpa_sim/vdpa_sim_blk.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/vdpa/vdpa_sim/vdpa_sim_blk.c +2 -1
@@ -79,10 +79,11 @@ static void vdpasim_blk_buffer_unlock(struct vdpasim_blk *blk)static bool vdpasim_blk_check_range (struct vdpasim *vdpasim,u64 start_sector,u64 num_sectors,u64 max_sectors) { -if (start_sector >VDPASIM_BLK_CAPACITY ) { +if (start_sector >=VDPASIM_BLK_CAPACITY ) {dev_dbg (&vdpasim->vdpa.dev,"starting sector exceeds the capacity - start: 0x%llx capacity: 0x%x\n" , start_sector,VDPASIM_BLK_CAPACITY ); +return false; }if (num_sectors > max_sectors) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 717/1102 vdpa_sim_net: check TX pull result before RX copy
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Linfeng Sun <[email protected]>
[ Upstream commit 0d195797a80b77f2ec56718cd26d3ee65d0093e8 ]
vringh_iov_pull_iotlb() returns a signed byte count. A failed TX pull is currently added to the unsigned byte counter and then passed as a size_t length to receive_filter() and vringh_iov_push_iotlb(). A negative error can therefore become a large length in the RX path.
Handle non-positive pull results before every length use. Count the TX error and complete the consumed TX descriptor with zero bytes.
I found this bug myself, though the patch was written with AI assistance.
Message-ID: <[email protected]>
--- drivers/vdpa/vdpa_sim/vdpa_sim_net.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
drivers/vdpa/vdpa_sim/vdpa_sim_net.c +6 -1
@@ -225,10 +225,15 @@ static void vdpasim_net_work(struct vdpasim *vdpasim)break ; } - ++tx_pkts; read =vringh_iov_pull_iotlb (&txq->vring, &txq->out_iov, net->buffer,PAGE_SIZE ); +if (read <=0 ) { + ++tx_errors; +vdpasim_net_complete (txq,0 ); +continue ; + } + ++tx_pkts; tx_bytes += read;if (!receive_filter (vdpasim, read)) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 718/1102 virtio-pci: return IRQ_HANDLED after non-zero ISR
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Andrew Stellman <[email protected]>
[ Upstream commit 93fa09455fb1a9624b73d42ac1f83771f4818e80 ]
vp_interrupt() reads the ISR before dispatching config-change and vring handling. Reading the ISR also clears it, so once the read returns non-zero the interrupt was from this device and has already been consumed.
Currently vp_interrupt() returns the result of vp_vring_interrupt(). For a config-change interrupt with no vring work, that can return IRQ_NONE even though the ISR was non-zero and the interrupt was handled.
Call vp_vring_interrupt() for any queue work, but once the ISR is non-zero return IRQ_HANDLED.
Tested with QEMU virtio-blk-pci forced to INTx using vectors=0 and pci=nomsi. On an idle device, 200 config-change interrupts were generated using QMP block_resize.
Before this change, irq_handler_exit reported ret=unhandled and /proc/irq/11/spurious increased from 0 to 200 unhandled interrupts. After this change, irq_handler_exit reported ret=handled and the unhandled count remained at 0.
The issue was found during an LLM-assisted Quality Playbook review.
Message-ID: <[email protected]>
--- drivers/virtio/virtio_pci_common.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/virtio/virtio_pci_common.c +3 -1
@@ -120,7 +120,9 @@ static irqreturn_t vp_interrupt(int irq, void *opaque)if (isr &VIRTIO_PCI_ISR_CONFIG )vp_config_changed (irq, opaque); -return vp_vring_interrupt (irq, opaque); +vp_vring_interrupt (irq, opaque); + +return IRQ_HANDLED ; } static int vp_request_msix_vectors(struct virtio_device *vdev, int nvectors,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 719/1102 virtio_input: reset device if input_register_device() fails
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xiong Weimin <[email protected]>
[ Upstream commit 81489b32a21c9360f8750d1fb600155d27452e19 ]
Probe marks the device DRIVER_OK with virtio_device_ready() before calling input_register_device(). If registration fails, the error path cleared vi->ready and called del_vqs() while the device was still live, so the device could keep DMA to queues that were already torn down.
Match remove/freeze: call virtio_reset_device() on that path before tearing down the virtqueues.
Message-ID: <[email protected]>
--- drivers/virtio/virtio_input.c | 1 + 1 file changed, 1 insertion(+)
drivers/virtio/virtio_input.c +1 -0
@@ -328,6 +328,7 @@ static int virtinput_probe(struct virtio_device *vdev)spin_lock_irqsave (&vi->lock, flags); vi->ready = false;spin_unlock_irqrestore (&vi->lock, flags); +virtio_reset_device (vdev); err_mt_init_slots:input_free_device (vi->idev); err_input_alloc:
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 720/1102 virtio_input: stop callbacks before unregistering input device
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Karl Mehltretter <[email protected]>
[ Upstream commit d7808b37da0a619cf1fa541c2384e783fecc2480 ]
virtinput_remove() unregisters the input device before resetting the virtio device. virtinput_recv_events() drops vi->lock around input_event(), so clearing vi->ready does not stop a callback that passed the entry check. It can still use vi->idev, requeue buffers and kick the queue.
Reset first, as virtinput_freeze() already does. With the preceding core change, reset waits for callbacks before input_unregister_device() can free vi->idev. Recheck vi->ready after taking the lock again: keep draining completed events so an input packet is not truncated, but stop requeueing buffers and kicking the queue.
With evdev attached, input_unregister_handle() currently waits for an RCU grace period, which also waits out IRQ callbacks. This masks the lifetime bug on PCI and MMIO, but does not protect sleepable callbacks on other transports.
Message-ID: <[email protected]>
--- drivers/virtio/virtio_input.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
drivers/virtio/virtio_input.c +6 -2
@@ -46,9 +46,12 @@ static void virtinput_recv_events(struct virtqueue *vq)le16_to_cpu (event->code), le32_to_cpu(event->value));spin_lock_irqsave (&vi->lock, flags); +if (!vi->ready) +continue ;virtinput_queue_evtbuf (vi, event); } -virtqueue_kick (vq); +if (vi->ready) +virtqueue_kick (vq); }spin_unlock_irqrestore (&vi->lock, flags); }
@@ -348,8 +351,9 @@ static void virtinput_remove(struct virtio_device *vdev) vi->ready = false;spin_unlock_irqrestore (&vi->lock, flags); -input_unregister_device (vi->idev); +/* Callbacks use vi->idev. */ virtio_reset_device (vdev); +input_unregister_device (vi->idev);while ((buf =virtqueue_detach_unused_buf (vi->sts)) !=NULL )kfree (buf); vdev->config->del_vqs (vdev);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 721/1102 af_unix: Update last skb marker in manage_oob().
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kuniyuki Iwashima <[email protected]>
[ Upstream commit 94fd4debd2e3a69cf93e766c8b328a810c228119 ]
Fahad Alharbi reported that blocking recv(MSG_PEEK) could hog CPU due to OOB skb.
In the following cases, manage_oob() skips OOB skb(s) and returns NULL for the last recv(MSG_PEEK):
socketpair(AF_UNIX, SOCK_STREAM, 0, sk);
1) skb -> OOB skb -> NULL
send(sk[0], "ab", 2, MSG_OOB);
recv(sk[1], buf, 0, MSG_PEEK);
2) skb -> consumed OOB skb -> NULL
send(sk[0], "ab", 2, MSG_OOB);
recv(sk[1], buf, 1, MSG_OOB);
recv(sk[1], buf, 0, MSG_PEEK);
3) consumed OOB skb -> OOB skb -> NULL
send(sk[0], "a", 1, MSG_OOB);
recv(sk[1], buf, 0, MSG_OOB);
send(sk[0], "b", 1, MSG_OOB);
recv(sk[1], buf, 1, MSG_PEEK);Then, @copied is 0 in unix_stream_read_generic() (zero-length buffer, or non-OOB skb is not yet consumed), and unix_stream_data_wait() is called.
However, it returns immediately because @last is not updated in unix_stream_read_generic(), and the thread busy-waits for a new skb.
Let's update @last in manage_oob().
For MSG_PEEK, @last is updated with the skipped OOB, and for the non-peek case, @last matches the returned value (when !copied) because OOB is unlinked.
Note that manage_oob() is inlined and no stack canary is added.
--- net/unix/af_unix.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-)
net/unix/af_unix.c +7 -3
@@ -2681,8 +2681,8 @@ static int unix_stream_recv_urg(struct unix_stream_read_state *state)return 1 ; } -static struct sk_buff *manage_oob (struct sk_buff *skb,struct sock *sk, -int flags,int copied) +static struct sk_buff *manage_oob (struct sk_buff *skb,struct sk_buff **last, +struct sock *sk,int flags,int copied) {struct sk_buff *read_skb =NULL , *unread_skb =NULL ;struct unix_sock *u =unix_sk (sk);
@@ -2696,11 +2696,13 @@ static struct sk_buff *manage_oob(struct sk_buff *skb, struct sock *sk,if (copied && (!u->oob_skb || skb == u->oob_skb)) { skb =NULL ; }else if (flags &MSG_PEEK ) { + *last = skb; skb =skb_peek_next (skb, &sk->sk_receive_queue); }else { read_skb = skb; skb =skb_peek_next (skb, &sk->sk_receive_queue);__skb_unlink (read_skb, &sk->sk_receive_queue); + *last = skb; }if (!skb)
@@ -2719,8 +2721,10 @@ static struct sk_buff *manage_oob(struct sk_buff *skb, struct sock *sk,__skb_unlink (skb, &sk->sk_receive_queue); unread_skb = skb; skb =skb_peek (&sk->sk_receive_queue); + *last = skb; } }else if (!sock_flag (sk,SOCK_URGINLINE )) { + *last = skb; skb =skb_peek_next (skb, &sk->sk_receive_queue); }
@@ -2838,7 +2842,7 @@ static int unix_stream_read_generic(struct unix_stream_read_state *state, again:#if IS_ENABLED (CONFIG_AF_UNIX_OOB )if (skb) { - skb =manage_oob (skb, sk, flags, copied); + skb =manage_oob (skb, &last, sk, flags, copied);if (!skb && copied) {unix_state_unlock (sk);break ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 722/1102 af_unix: Return immediately when manage_oob() returns NULL for 0-length buffer.
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kuniyuki Iwashima <[email protected]>
[ Upstream commit 6e5ee08eb5858d175da6768d75d163817b6a9d4a ]
Fahad Alharbi reported that recv(0, MSG_PEEK) triggers busy-wait in unix_stream_read_generic() if recv() is blocking and the last skb in the queue is MSG_OOB skb.
In such a situation, TCP returns 0 immediately regardless of blocking or non-blocking.
Let's follow the behaviour.
--- net/unix/af_unix.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/unix/af_unix.c +1 -1
@@ -2843,7 +2843,7 @@ static int unix_stream_read_generic(struct unix_stream_read_state *state,#if IS_ENABLED (CONFIG_AF_UNIX_OOB )if (skb) { skb =manage_oob (skb, &last, sk, flags, copied); -if (!skb && copied) { +if (!skb && (copied || !state->size)) {unix_state_unlock (sk);break ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 723/1102 net: ipv6: Fix UDP length overflow with PMTU discover and big MTU
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alice Mikityanska <[email protected]>
[ Upstream commit 0ae10b6be49b425827659b23bcce498f80eb7182 ]
This commit bounds cork->base.fragsize to IP6_MAX_MTU for UDP sockets to avoid a possible overflow of UDP length that triggers a WARN in udp_set_len_short when setsockopt IPV6_MTU_DISCOVER is set to IPV6_PMTUDISC_DO or IPV6_PMTUDISC_PROBE, and a large packet is sent over a netdev with an unusually large MTU.
Steps to reproduce (included in the new selftest):
1. Set device MTU bigger than IP6_MAX_MTU. cork->base.fragsize will be set to that MTU in ip6_setup_cork.
2. Set IPV6_MTU_DISCOVER to IPV6_PMTUDISC_PROBE or IPV6_PMTUDISC_DO. It lets maxnonfragsize be set to device MTU (cork->fragsize) in __ip6_append_data, rather than to IP6_MAX_MTU.
3. Send 65528 bytes of payload (+8 bytes of UDP header, +40 bytes of IPv6 header). Device MTU allows it (it's only one byte bigger than IP6_MAX_MTU, and the device MTU is bigger than that).
4. The UDP length in the built packet is 65536, which overflows the 16-bit length field and triggers the WARN in udp_set_len_short.
To avoid breaking sending UDP jumbograms over raw IPv6 sockets, limit the change to UDP sockets only.
The original overflow bug with IPv6 and IPV6_PMTUDISC_DO seems to predate git history (verified reproduction on 2.6.21), was fixed later, and then reappeared in commit 427faee167bc ("net: ipv6: introduce ip6_dst_mtu_maybe_forward"), which is chosen as the Fixes tag here. The overflow with IPV6_PMTUDISC_PROBE reproduces since its introduction in commit 628a5c561890 ("[INET]: Add IP(V6)_PMTUDISC_RPOBE").
--- net/ipv6/ip6_output.c | 2 ++ 1 file changed, 2 insertions(+)
net/ipv6/ip6_output.c +2 -0
@@ -1408,6 +1408,8 @@ static int ip6_setup_cork(struct sock *sk, struct inet_cork_full *cork,if (frag_size && frag_size < mtu) mtu = frag_size; +if (sk_is_udp (sk)) + mtu =min (mtu,IP6_MAX_MTU ); cork->base.fragsize = mtu; cork->base.gso_size = ipc6->gso_size; cork->base.tx_flags =0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 724/1102 net: ipv6: Clamp to IP6_MAX_MTU in ip6_dst_mtu_maybe_forward
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alice Mikityanska <[email protected]>
[ Upstream commit 199271ebc71c1e0913b2fad988a7bff330a8828a ]
Commit 427faee167bc ("net: ipv6: introduce ip6_dst_mtu_maybe_forward") dropped the IP6_MAX_MTU clamp that used to be present in ip6_mtu(). A similar IPv4 commit ac6627a28dbf ("net: ipv4: Consolidate ipv4_mtu and ip_dst_mtu_maybe_forward") preserves the IP_MAX_MTU clamp.
Restore the upper bound in the IPv6 flow to avoid potential 16-bit overflows in forwarding paths.
--- include/net/ip6_route.h | 2 ++ 1 file changed, 2 insertions(+)
include/net/ip6_route.h +2 -0
@@ -343,6 +343,8 @@ static inline unsigned int ip6_dst_mtu_maybe_forward(const struct dst_entry *dstrcu_read_unlock (); out: + mtu = min_t(unsigned int, mtu, IP6_MAX_MTU); +return mtu -lwtunnel_headroom (dst->lwtstate, mtu); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 725/1102 net: ethernet: cortina: Fix budget accounting
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Linus Walleij <[email protected]>
[ Upstream commit a0de06d0da78a3db53de65dfd7452cc6d111f703 ]
The gmac_rx() function returns the remaining NAPI budget, but its caller treats the return value as the number of packets received. An idle poll therefore reports a full budget and remains scheduled.
Return the number of received packets instead. Preserve the existing free queue refill accounting by adding that count directly; continuing to subtract it from the budget would invert the refill behavior.
--- drivers/net/ethernet/cortina/gemini.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
drivers/net/ethernet/cortina/gemini.c +5 -3
@@ -1450,6 +1450,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget)unsigned int frame_len, frag_len;struct gmac_rxdesc *rx =NULL ;struct gmac_queue_page *gpage; +unsigned int received =0 ;union gmac_rxdesc_0 word0;union gmac_rxdesc_1 word1;union gmac_rxdesc_3 word3;
@@ -1545,7 +1546,8 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget)napi_gro_frags (&port->napi); skb =NULL ; frag_nr =0 ; - --budget; + budget--; + received++; }continue ;
@@ -1565,7 +1567,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) port->rx_skb = skb; port->rx_frag_nr = frag_nr;writew (r, ptr_reg); -return budget; +return received; }static int gmac_napi_poll (struct napi_struct *napi,int budget)
@@ -1586,7 +1588,7 @@ static int gmac_napi_poll(struct napi_struct *napi, int budget) ++port->rx_napi_exits; } - port->freeq_refill += (budget - received); + port->freeq_refill += received;if (port->freeq_refill > freeq_threshold) { port->freeq_refill -= freeq_threshold;geth_fill_freeq (geth, true);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 726/1102 net: ethernet: cortina: Finish RX updates before NAPI completion
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Linus Walleij <[email protected]>
[ Upstream commit baa26841cb9a2cdc7e0e99d6854a4e3359bf7393 ]
napi_complete_done() releases ownership of the NAPI instance, but the Gemini poll keeps the RX statistics writer section open and updates the free queue after calling it. A new poll can therefore start while the old writer is still active.
Finish the statistics and free queue updates before releasing ownership. Only re-enable RX interrupts when napi_complete_done() reports successful completion.
--- drivers/net/ethernet/cortina/gemini.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-)
drivers/net/ethernet/cortina/gemini.c +6 -6
@@ -1581,12 +1581,10 @@ static int gmac_napi_poll(struct napi_struct *napi, int budget)u64_stats_update_begin (&port->rx_stats_syncp); received =gmac_rx (napi->dev, budget); -if (received < budget) { -napi_gro_flush (napi, false); -napi_complete_done (napi, received); -gmac_enable_rx_irq (napi->dev,1 ); +if (received < budget) ++port->rx_napi_exits; - } + +u64_stats_update_end (&port->rx_stats_syncp); port->freeq_refill += received;if (port->freeq_refill > freeq_threshold) {
@@ -1594,7 +1592,9 @@ static int gmac_napi_poll(struct napi_struct *napi, int budget)geth_fill_freeq (geth, true); } -u64_stats_update_end (&port->rx_stats_syncp); +if (received < budget &&napi_complete_done (napi, received)) +gmac_enable_rx_irq (napi->dev,1 ); +return received; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 727/1102 net: ethernet: cortina: Count dropped frames as NAPI work
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Linus Walleij <[email protected]>
[ Upstream commit b856c552f556bc0341c1dbe0bf88e630fd1dc4b7 ]
The RX loop only consumes budget when it successfully delivers a frame. Error paths keep consuming descriptors without reducing the budget, so a stream of bad frames can process the entire receive ring in one poll.
Move the budget accounting to a common end-of-frame path. This counts each completed frame as NAPI work whether it was delivered or dropped, matching the behavior of the vendor driver.
--- drivers/net/ethernet/cortina/gemini.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-)
drivers/net/ethernet/cortina/gemini.c +10 -5
@@ -1501,7 +1501,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) skb =NULL ; frag_nr =0 ; } -continue ; + goto next_desc; } page = gpage->page;
@@ -1523,7 +1523,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) }else if (!skb) {put_page (page); -continue ; + goto next_desc; }if (word3.bits32 &EOF_BIT )
@@ -1546,10 +1546,8 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget)napi_gro_frags (&port->napi); skb =NULL ; frag_nr =0 ; - budget--; - received++; } -continue ; + goto next_desc; err_drop:if (skb) {
@@ -1562,6 +1560,13 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget)put_page (page); port->stats.rx_dropped++; + +next_desc: +/* Final or single-descriptor fragment, advance things */ +if (word3.bits32 &EOF_BIT ) { + budget--; + received++; + } } port->rx_skb = skb;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 728/1102 net: ethernet: cortina: No mapping is a dropped rx
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Linus Walleij <[email protected]>
[ Upstream commit 2cb156213093a62b80cf40b1ec71738e93491971 ]
Increase stats.rx_dropped++ even if this is the first fragment (skb == NULL) so we are doing proper accounting.
Stable-dep-of: 6520198c430c ("net: ethernet: cortina: Count RX drops once per frame")
--- drivers/net/ethernet/cortina/gemini.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/ethernet/cortina/gemini.c +1 -1
@@ -1495,9 +1495,9 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) gpage =gmac_get_queue_page (geth, port, mapping +PAGE_SIZE );if (!gpage) {dev_err (geth->dev,"could not find mapping\n" ); + port->stats.rx_dropped++;if (skb) {napi_free_frags (&port->napi); - port->stats.rx_dropped++; skb =NULL ; frag_nr =0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 729/1102 net: ethernet: cortina: Count RX drops once per frame
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Linus Walleij <[email protected]>
[ Upstream commit 6520198c430c81bcc367f0dd5e32f2fb740b9d51 ]
The absence of a partial skb means either that the driver is not assembling a frame or that the current frame was already dropped. Consequently, repeated descriptor errors can increment rx_dropped more than once, while an orphaned descriptor chain can reach EOF without being counted at all.
Track the dropping state across NAPI polls. Clear it at frame boundaries and route mapping failures and orphaned continuations through the common drop path so each discarded frame is counted exactly once.
--- drivers/net/ethernet/cortina/gemini.c | 41 +++++++++++++++------------ 1 file changed, 23 insertions(+), 18 deletions(-)
drivers/net/ethernet/cortina/gemini.c +23 -18
@@ -123,6 +123,7 @@ struct gemini_ethernet_port {unsigned int rx_coalesce_nsecs;struct sk_buff *rx_skb;unsigned int rx_frag_nr; +bool rx_dropping;unsigned int freeq_refill;struct gmac_txq txq[TX_QUEUE_NUM ];
@@ -1451,6 +1452,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget)struct gmac_rxdesc *rx =NULL ;struct gmac_queue_page *gpage;unsigned int received =0 ; +bool dropping = port->rx_dropping;union gmac_rxdesc_0 word0;union gmac_rxdesc_1 word1;union gmac_rxdesc_3 word3;
@@ -1472,6 +1474,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) w = rw.bits.wptr;while (budget && w != r) { + page =NULL ; rx = port->rxq_ring + r; word0 = rx->word0; word1 = rx->word1;
@@ -1485,6 +1488,16 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) frame_len = word1.bits.byte_count; page_offs = mapping & ~PAGE_MASK ; +if (word3.bits32 &SOF_BIT ) { +if (skb) { +napi_free_frags (&port->napi); + port->stats.rx_dropped++; + skb =NULL ; + frag_nr =0 ; + } + dropping = false; + } +if (!mapping) {netdev_err (netdev,"rxq[%u]: HW BUG: zero DMA desc\n" , r);
@@ -1495,24 +1508,11 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) gpage =gmac_get_queue_page (geth, port, mapping +PAGE_SIZE );if (!gpage) {dev_err (geth->dev,"could not find mapping\n" ); - port->stats.rx_dropped++; -if (skb) { -napi_free_frags (&port->napi); - skb =NULL ; - frag_nr =0 ; - } - goto next_desc; + goto err_drop; } page = gpage->page;if (word3.bits32 &SOF_BIT ) { -if (skb) { -napi_free_frags (&port->napi); - port->stats.rx_dropped++; - skb =NULL ; - frag_nr =0 ; - } - skb =gmac_skb_if_good_frame (port, word0, frame_len);if (!skb) goto err_drop;
@@ -1522,8 +1522,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) frag_nr =0 ; }else if (!skb) { -put_page (page); - goto next_desc; + goto err_drop; }if (word3.bits32 &EOF_BIT )
@@ -1556,21 +1555,26 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) frag_nr =0 ; } -if (mapping) +if (page)put_page (page); - port->stats.rx_dropped++; +if (!dropping) { + port->stats.rx_dropped++; + dropping = true; + } next_desc:/* Final or single-descriptor fragment, advance things */ if (word3.bits32 &EOF_BIT ) { budget--; received++; + dropping = false; } } port->rx_skb = skb; port->rx_frag_nr = frag_nr; + port->rx_dropping = dropping;writew (r, ptr_reg);return received; }
@@ -1901,6 +1905,7 @@ static int gmac_stop(struct net_device *netdev)napi_disable (&port->napi); port->rx_skb =NULL ; port->rx_frag_nr =0 ; + port->rx_dropping = false;gmac_enable_irq (netdev,0 );gmac_cleanup_rxq (netdev);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 730/1102 net: ethernet: cortina: Count RX descriptors for freeq refill
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Linus Walleij <[email protected]>
[ Upstream commit e89e88ad41d9f31c829c2af39c48313e8e48d5b0 ]
The software free queue provides one buffer fragment for every descriptor moved to an RX queue. The refill heuristic instead advances by NAPI work, which counts frames. A fragmented or discarded frame can consume several queue entries while adding only one to the refill count.
Count the RX descriptors as they are consumed and report that separately from NAPI work. Use the descriptor count to drive free queue refills.
--- drivers/net/ethernet/cortina/gemini.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-)
drivers/net/ethernet/cortina/gemini.c +8 -3
@@ -1440,7 +1440,8 @@ static struct sk_buff *gmac_skb_if_good_frame(struct gemini_ethernet_port *port,return skb; } -static unsigned int gmac_rx (struct net_device *netdev,unsigned int budget) +static unsigned int gmac_rx (struct net_device *netdev,unsigned int budget, +unsigned int *freeq_consumed) {struct gemini_ethernet_port *port =netdev_priv (netdev);unsigned short m = (1 << port->rxq_order) -1 ;
@@ -1448,6 +1449,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget)void __iomem *ptr_reg = port->rxq_rwptr;unsigned int frag_nr = port->rx_frag_nr;struct sk_buff *skb = port->rx_skb; +unsigned int consumed =0 ;unsigned int frame_len, frag_len;struct gmac_rxdesc *rx =NULL ;struct gmac_queue_page *gpage;
@@ -1483,6 +1485,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) r++; r &= m; + consumed++; frag_len = word0.bits.buffer_size; frame_len = word1.bits.byte_count;
@@ -1575,6 +1578,7 @@ static unsigned int gmac_rx(struct net_device *netdev, unsigned int budget) port->rx_skb = skb; port->rx_frag_nr = frag_nr; port->rx_dropping = dropping; + *freeq_consumed = consumed;writew (r, ptr_reg);return received; }
@@ -1584,18 +1588,19 @@ static int gmac_napi_poll(struct napi_struct *napi, int budget)struct gemini_ethernet_port *port =netdev_priv (napi->dev);struct gemini_ethernet *geth = port->geth;unsigned int freeq_threshold; +unsigned int freeq_consumed;unsigned int received; freeq_threshold =1 << (geth->freeq_order -1 );u64_stats_update_begin (&port->rx_stats_syncp); - received =gmac_rx (napi->dev, budget); + received =gmac_rx (napi->dev, budget, &freeq_consumed);if (received < budget) ++port->rx_napi_exits;u64_stats_update_end (&port->rx_stats_syncp); - port->freeq_refill += received; + port->freeq_refill += freeq_consumed;if (port->freeq_refill > freeq_threshold) { port->freeq_refill -= freeq_threshold;geth_fill_freeq (geth, true);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 731/1102 drm/logicvc: Drop the select of the nonexistent CONFIG_DRM_KMS_DMA_HELPER
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Karl Mehltretter <[email protected]>
[ Upstream commit f97802dd98b27e45c04293f9926f07642578b23f ]
CONFIG_DRM_KMS_CMA_HELPER was removed by commit 09717af7d13d ("drm:
Remove CONFIG_DRM_KMS_CMA_HELPER option"). When commit 6bcfe8eaeef0 ("drm/fb: rename FB CMA helpers to FB DMA helpers") later renamed the select in this Kconfig to CONFIG_DRM_KMS_DMA_HELPER, no symbol of that name existed, and git log -S finds no Kconfig file that has defined one since. The select is silently ignored. The driver already selects CONFIG_DRM_GEM_DMA_HELPER, which is what it needs.
Remove the dead line.
--- drivers/gpu/drm/logicvc/Kconfig | 1 - 1 file changed, 1 deletion(-)
drivers/gpu/drm/logicvc/Kconfig +0 -1
@@ -3,7 +3,6 @@ config DRM_LOGICVC depends on DRM depends on OF || COMPILE_TEST select DRM_KMS_HELPER - select DRM_KMS_DMA_HELPER select DRM_GEM_DMA_HELPER select REGMAP select REGMAP_MMIO
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 732/1102 ALSA: hda: Introduce auto cleanup macros for PM
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 5d8c9c987fbdd65677315198c2b1f35a440d7cdf ]
The temporary power up/down of the codec via snd_hda_power_up() and _down() (or snd_hda_power_up_pm() and _down_pm()) is seen in various places. This patch introduces simple auto-cleanup macros for those call patterns, so that the drivers don't have to call the corresponding power-down calls explicitly.
Namely,
err = snd_hda_power_up(codec); if (err < 0) return err; .... snd_power_down(codec);
can drop the *_down() call by replacing with
CLASS(snd_hda_power, pm)(codec); if (pm.err < 0) return pm.err;
Stable-dep-of: 728478874312 ("ALSA: hda: Report a change when only the channel status bytes move")
--- include/sound/hda_codec.h | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+)
include/sound/hda_codec.h +30 -0
@@ -499,6 +499,36 @@ static inline bool hda_codec_need_resume(struct hda_codec *codec)return !codec->relaxed_resume && codec->jacktbl.used; } +/* +* PM with auto-cleanup: call like CLASS(snd_hda_power, pm)(codec) +* If the error handling is needed, refer pm.err. +*/ +struct __hda_power_obj { +struct hda_codec *codec; +int err; +}; + +static inline struct __hda_power_obj __snd_hda_power_up (struct hda_codec *codec) +{ +struct __hda_power_obj T = { .codec = codec }; +T .err =snd_hda_power_up (codec); +return T ; +} + +static inline struct __hda_power_obj __snd_hda_power_up_pm (struct hda_codec *codec) +{ +struct __hda_power_obj T = { .codec = codec }; +T .err =snd_hda_power_up_pm (codec); +return T ; +} + +DEFINE_CLASS(snd_hda_power, struct __hda_power_obj, +snd_hda_power_down ((_T).codec),__snd_hda_power_up (codec), + struct hda_codec *codec) +DEFINE_CLASS(snd_hda_power_pm, struct __hda_power_obj, +snd_hda_power_down_pm ((_T).codec),__snd_hda_power_up_pm (codec), + struct hda_codec *codec) +#ifdef CONFIG_SND_HDA_PATCH_LOADER /* * patch firmware
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 733/1102 ALSA: hda/common: Use cleanup macros for PM controls
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 8dad6b3dac2794c52d63b2336138392eddc17936 ]
The new macro CLASS(snd_hda_power_pm) can replace the manual snd_hda_power_up_pm() and _down() calls gracefully.
A part of the code in codec_exec_verb() is factored out to a function, so that the auto-cleanup can be well scoped.
Merely cleanups and no functional changes.
Stable-dep-of: 728478874312 ("ALSA: hda: Report a change when only the channel status bytes move")
--- sound/pci/hda/hda_codec.c | 30 +++++++++++++++++++----------- sound/pci/hda/hda_proc.c | 4 +--- sound/pci/hda/hda_sysfs.c | 11 ++++------- 3 files changed, 24 insertions(+), 21 deletions(-)
sound/pci/hda/hda_codec.c +19 -11
@@ -31,6 +31,23 @@#define codec_has_clkstop (codec) \ ((codec)->core.power_caps & AC_PWRST_CLKSTOP) +static int call_exec_verb (struct hda_bus *bus,struct hda_codec *codec, +unsigned int cmd,unsigned int flags, +unsigned int *res) +{ +int err; + +CLASS (snd_hda_power_pm, pm)(codec); +mutex_lock (&bus->core.cmd_mutex); +if (flags &HDA_RW_NO_RESPONSE_FALLBACK ) + bus->no_response_fallback =1 ; + err =snd_hdac_bus_exec_verb_unlocked (&bus->core, codec->core.addr, + cmd, res); + bus->no_response_fallback =0 ; +mutex_unlock (&bus->core.cmd_mutex); +return err; +} +/* * Send and receive a verb - passed to exec_verb override for hdac_device */
@@ -45,15 +62,7 @@ static int codec_exec_verb(struct hdac_device *dev, unsigned int cmd,return -1 ; again: -snd_hda_power_up_pm (codec); -mutex_lock (&bus->core.cmd_mutex); -if (flags &HDA_RW_NO_RESPONSE_FALLBACK ) - bus->no_response_fallback =1 ; - err =snd_hdac_bus_exec_verb_unlocked (&bus->core, codec->core.addr, - cmd, res); - bus->no_response_fallback =0 ; -mutex_unlock (&bus->core.cmd_mutex); -snd_hda_power_down_pm (codec); + err =call_exec_verb (bus, codec, cmd, flags, res);if (!codec_in_pm (codec) && res && err == -EAGAIN ) {if (bus->response_reset) { codec_dbg(codec,
@@ -643,12 +652,11 @@ static void hda_jackpoll_work(struct work_struct *work)return ;/* the power-up/down sequence triggers the runtime resume */ -snd_hda_power_up (codec); +CLASS (snd_hda_power, pm)(codec);/* update jacks manually if polling is required, too */ snd_hda_jack_set_dirty_all (codec);snd_hda_jack_poll_all (codec);schedule_delayed_work (&codec->jackpoll_work, codec->jackpoll_interval); -snd_hda_power_down (codec); }/* release all pincfg lists */
sound/pci/hda/hda_proc.c +1 -3
@@ -782,7 +782,7 @@ static void print_codec_info(struct snd_info_entry *entry, fg = codec->core.afg;if (!fg)return ; -snd_hda_power_up (codec); +CLASS (snd_hda_power, pm)(codec);snd_iprintf (buffer,"Default PCM:\n" );print_pcm_caps (buffer, codec, fg);snd_iprintf (buffer,"Default Amp-In caps: " );
@@ -795,7 +795,6 @@ static void print_codec_info(struct snd_info_entry *entry, nodes =snd_hda_get_sub_nodes (codec, fg, &nid);if (! nid || nodes <0 ) {snd_iprintf (buffer,"Invalid AFG subtree\n" ); -snd_hda_power_down (codec);return ; }
@@ -932,7 +931,6 @@ static void print_codec_info(struct snd_info_entry *entry,kfree (conn); } -snd_hda_power_down (codec); }/*
sound/pci/hda/hda_sysfs.c +4 -7
@@ -129,21 +129,18 @@ static int reconfig_codec(struct hda_codec *codec) {int err; -snd_hda_power_up (codec); +CLASS (snd_hda_power, pm)(codec);codec_info (codec,"hda-codec: reconfiguring\n" ); err =snd_hda_codec_reset (codec);if (err <0 ) {codec_err (codec,"The codec is being used, can't reconfigure.\n" ); - goto error; +return err; } err =device_reprobe (hda_codec_dev (codec));if (err <0 ) - goto error; - err =snd_card_register (codec->card); - error: -snd_hda_power_down (codec); -return err; +return err; +return snd_card_register (codec->card); }/*
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 734/1102 ALSA: hda/common: Use guard() for mutex locks
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 62dd3851d2450a5fb2259da1f0391b5870e07577 ]
Replace the manual mutex lock/unlock pairs with guard().
Only code refactoring, and no behavior change.
Stable-dep-of: 728478874312 ("ALSA: hda: Report a change when only the channel status bytes move")
--- sound/pci/hda/hda_codec.c | 89 ++++++++++++++-------------------- sound/pci/hda/hda_controller.c | 24 ++++----- sound/pci/hda/hda_sysfs.c | 66 ++++++++++--------------- 3 files changed, 74 insertions(+), 105 deletions(-)
sound/pci/hda/hda_codec.c +37 -52
@@ -38,13 +38,12 @@ static int call_exec_verb(struct hda_bus *bus, struct hda_codec *codec,int err;CLASS (snd_hda_power_pm, pm)(codec); -mutex_lock (&bus->core.cmd_mutex); +guard (mutex)(&bus->core.cmd_mutex);if (flags &HDA_RW_NO_RESPONSE_FALLBACK ) bus->no_response_fallback =1 ; err =snd_hdac_bus_exec_verb_unlocked (&bus->core, codec->core.addr, cmd, res); bus->no_response_fallback =0 ; -mutex_unlock (&bus->core.cmd_mutex);return err; }
@@ -541,11 +540,11 @@ unsigned int snd_hda_codec_get_pincfg(struct hda_codec *codec, hda_nid_t nid)#ifdef CONFIG_SND_HDA_RECONFIG {unsigned int cfg =0 ; -mutex_lock (&codec->user_mutex); - pin =look_up_pincfg (codec, &codec->user_pins, nid); -if (pin) - cfg = pin->cfg; -mutex_unlock (&codec->user_mutex); + scoped_guard(mutex, &codec->user_mutex) { + pin =look_up_pincfg (codec, &codec->user_pins, nid); +if (pin) + cfg = pin->cfg; + }if (cfg)return cfg; }
@@ -2218,13 +2217,12 @@ static int snd_hda_spdif_default_get(struct snd_kcontrol *kcontrol,if (WARN_ON (codec->spdif_out.used <= idx))return -EINVAL ; -mutex_lock (&codec->spdif_mutex); +guard (mutex)(&codec->spdif_mutex); spdif =snd_array_elem (&codec->spdif_out, idx); ucontrol->value.iec958.status[0 ] = spdif->status &0xff ; ucontrol->value.iec958.status[1 ] = (spdif->status >>8 ) &0xff ; ucontrol->value.iec958.status[2 ] = (spdif->status >>16 ) &0xff ; ucontrol->value.iec958.status[3 ] = (spdif->status >>24 ) &0xff ; -mutex_unlock (&codec->spdif_mutex);return 0 ; }
@@ -2327,7 +2325,7 @@ static int snd_hda_spdif_default_put(struct snd_kcontrol *kcontrol,if (WARN_ON (codec->spdif_out.used <= idx))return -EINVAL ; -mutex_lock (&codec->spdif_mutex); +guard (mutex)(&codec->spdif_mutex); spdif =snd_array_elem (&codec->spdif_out, idx); nid = spdif->nid; spdif->status = ucontrol->value.iec958.status[0] |
@@ -2340,7 +2338,6 @@ static int snd_hda_spdif_default_put(struct snd_kcontrol *kcontrol, spdif->ctls = val;if (change && nid != (u16)-1 )set_dig_out_convert (codec, nid, val &0xff , (val >>8 ) &0xff ); -mutex_unlock (&codec->spdif_mutex);return change; }
@@ -2355,10 +2352,9 @@ static int snd_hda_spdif_out_switch_get(struct snd_kcontrol *kcontrol,if (WARN_ON (codec->spdif_out.used <= idx))return -EINVAL ; -mutex_lock (&codec->spdif_mutex); +guard (mutex)(&codec->spdif_mutex); spdif =snd_array_elem (&codec->spdif_out, idx); ucontrol->value.integer.value[0 ] = spdif->ctls &AC_DIG1_ENABLE ; -mutex_unlock (&codec->spdif_mutex);return 0 ; }
@@ -2385,7 +2381,7 @@ static int snd_hda_spdif_out_switch_put(struct snd_kcontrol *kcontrol,if (WARN_ON (codec->spdif_out.used <= idx))return -EINVAL ; -mutex_lock (&codec->spdif_mutex); +guard (mutex)(&codec->spdif_mutex); spdif =snd_array_elem (&codec->spdif_out, idx); nid = spdif->nid; val = spdif->ctls & ~AC_DIG1_ENABLE ;
@@ -2395,7 +2391,6 @@ static int snd_hda_spdif_out_switch_put(struct snd_kcontrol *kcontrol, spdif->ctls = val;if (change && nid != (u16)-1 )set_spdif_ctls (codec, nid, val &0xff ,-1 ); -mutex_unlock (&codec->spdif_mutex);return change; }
@@ -2540,10 +2535,9 @@ void snd_hda_spdif_ctls_unassign(struct hda_codec *codec, int idx)if (WARN_ON (codec->spdif_out.used <= idx))return ; -mutex_lock (&codec->spdif_mutex); +guard (mutex)(&codec->spdif_mutex); spdif =snd_array_elem (&codec->spdif_out, idx); spdif->nid = (u16)-1 ; -mutex_unlock (&codec->spdif_mutex); }EXPORT_SYMBOL_GPL (snd_hda_spdif_ctls_unassign);
@@ -2562,14 +2556,13 @@ void snd_hda_spdif_ctls_assign(struct hda_codec *codec, int idx, hda_nid_t nid)if (WARN_ON (codec->spdif_out.used <= idx))return ; -mutex_lock (&codec->spdif_mutex); +guard (mutex)(&codec->spdif_mutex); spdif =snd_array_elem (&codec->spdif_out, idx);if (spdif->nid != nid) { spdif->nid = nid; val = spdif->ctls;set_spdif_ctls (codec, nid, val &0xff , (val >>8 ) &0xff ); } -mutex_unlock (&codec->spdif_mutex); }EXPORT_SYMBOL_GPL (snd_hda_spdif_ctls_assign);
@@ -2644,14 +2637,13 @@ static int snd_hda_spdif_in_switch_put(struct snd_kcontrol *kcontrol,unsigned int val = !!ucontrol->value.integer.value[0 ];int change; -mutex_lock (&codec->spdif_mutex); +guard (mutex)(&codec->spdif_mutex); change = codec->spdif_in_enable != val;if (change) { codec->spdif_in_enable = val;snd_hdac_regmap_write (&codec->core, nid,AC_VERB_SET_DIGI_CONVERT_1 , val); } -mutex_unlock (&codec->spdif_mutex);return change; }
@@ -3204,7 +3196,8 @@ int snd_hda_codec_prepare(struct hda_codec *codec, struct snd_pcm_substream *substream) {int ret; -mutex_lock (&codec->bus->prepare_mutex); + +guard (mutex)(&codec->bus->prepare_mutex);if (hinfo->ops.prepare) ret = hinfo->ops.prepare (hinfo, codec, stream, format, substream);
@@ -3212,7 +3205,6 @@ int snd_hda_codec_prepare(struct hda_codec *codec, ret = -ENODEV ;if (ret >=0 )purify_inactive_streams (codec); -mutex_unlock (&codec->bus->prepare_mutex);return ret; }EXPORT_SYMBOL_GPL (snd_hda_codec_prepare);
@@ -3229,10 +3221,9 @@ void snd_hda_codec_cleanup(struct hda_codec *codec,struct hda_pcm_stream *hinfo, struct snd_pcm_substream *substream) { - mutex_lock(&codec->bus->prepare_mutex); + guard(mutex)(&codec->bus->prepare_mutex);if (hinfo->ops.cleanup) hinfo->ops.cleanup (hinfo, codec, substream); -mutex_unlock (&codec->bus->prepare_mutex); }EXPORT_SYMBOL_GPL (snd_hda_codec_cleanup);
@@ -3661,12 +3652,11 @@ static void cleanup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid)int snd_hda_multi_out_dig_open (struct hda_codec *codec,struct hda_multi_out *mout) { -mutex_lock (&codec->spdif_mutex); +guard (mutex)(&codec->spdif_mutex);if (mout->dig_out_used ==HDA_DIG_ANALOG_DUP )/* already opened as analog dup; reset it once */ cleanup_dig_out_stream (codec, mout->dig_out_nid); mout->dig_out_used =HDA_DIG_EXCLUSIVE ; -mutex_unlock (&codec->spdif_mutex);return 0 ; }EXPORT_SYMBOL_GPL (snd_hda_multi_out_dig_open);
@@ -3685,9 +3675,8 @@ int snd_hda_multi_out_dig_prepare(struct hda_codec *codec,unsigned int format, struct snd_pcm_substream *substream) { - mutex_lock(&codec->spdif_mutex); + guard(mutex)(&codec->spdif_mutex);setup_dig_out_stream (codec, mout->dig_out_nid, stream_tag, format); -mutex_unlock (&codec->spdif_mutex);return 0 ; }EXPORT_SYMBOL_GPL (snd_hda_multi_out_dig_prepare);
@@ -3700,9 +3689,8 @@ EXPORT_SYMBOL_GPL(snd_hda_multi_out_dig_prepare);int snd_hda_multi_out_dig_cleanup (struct hda_codec *codec,struct hda_multi_out *mout) { -mutex_lock (&codec->spdif_mutex); +guard (mutex)(&codec->spdif_mutex);cleanup_dig_out_stream (codec, mout->dig_out_nid); -mutex_unlock (&codec->spdif_mutex);return 0 ; }EXPORT_SYMBOL_GPL (snd_hda_multi_out_dig_cleanup);
@@ -3715,9 +3703,8 @@ EXPORT_SYMBOL_GPL(snd_hda_multi_out_dig_cleanup);int snd_hda_multi_out_dig_close (struct hda_codec *codec,struct hda_multi_out *mout) { -mutex_lock (&codec->spdif_mutex); +guard (mutex)(&codec->spdif_mutex); mout->dig_out_used =0 ; -mutex_unlock (&codec->spdif_mutex);return 0 ; }EXPORT_SYMBOL_GPL (snd_hda_multi_out_dig_close);
@@ -3757,7 +3744,7 @@ int snd_hda_multi_out_analog_open(struct hda_codec *codec,NULL , &mout->spdif_maxbps); } -mutex_lock (&codec->spdif_mutex); +guard (mutex)(&codec->spdif_mutex);if (mout->share_spdif) {if ((runtime->hw.rates & mout->spdif_rates) && (runtime->hw.formats & mout->spdif_formats)) {
@@ -3770,7 +3757,6 @@ int snd_hda_multi_out_analog_open(struct hda_codec *codec,/* FIXME: need notify? */ } } -mutex_unlock (&codec->spdif_mutex); }return snd_pcm_hw_constraint_step (substream->runtime,0 ,SNDRV_PCM_HW_PARAM_CHANNELS ,2 );
@@ -3799,23 +3785,23 @@ int snd_hda_multi_out_analog_prepare(struct hda_codec *codec,struct hda_spdif_out *spdif;int i; -mutex_lock (&codec->spdif_mutex); - spdif =snd_hda_spdif_out_of_nid (codec, mout->dig_out_nid); -if (mout->dig_out_nid && mout->share_spdif && - mout->dig_out_used !=HDA_DIG_EXCLUSIVE ) { -if (chs ==2 && spdif !=NULL && -snd_hda_is_supported_format (codec, mout->dig_out_nid, - format) && - !(spdif->status &IEC958_AES0_NONAUDIO )) { - mout->dig_out_used =HDA_DIG_ANALOG_DUP ; -setup_dig_out_stream (codec, mout->dig_out_nid, - stream_tag, format); - }else { - mout->dig_out_used =0 ; -cleanup_dig_out_stream (codec, mout->dig_out_nid); + scoped_guard(mutex, &codec->spdif_mutex) { + spdif =snd_hda_spdif_out_of_nid (codec, mout->dig_out_nid); +if (mout->dig_out_nid && mout->share_spdif && + mout->dig_out_used !=HDA_DIG_EXCLUSIVE ) { +if (chs ==2 && spdif !=NULL && +snd_hda_is_supported_format (codec, mout->dig_out_nid, + format) && + !(spdif->status &IEC958_AES0_NONAUDIO )) { + mout->dig_out_used =HDA_DIG_ANALOG_DUP ; +setup_dig_out_stream (codec, mout->dig_out_nid, + stream_tag, format); + }else { + mout->dig_out_used =0 ; +cleanup_dig_out_stream (codec, mout->dig_out_nid); + } } } -mutex_unlock (&codec->spdif_mutex);/* front */ snd_hda_codec_setup_stream(codec, nids[HDA_FRONT], stream_tag,
@@ -3882,12 +3868,11 @@ int snd_hda_multi_out_analog_cleanup(struct hda_codec *codec,if (mout->extra_out_nid[i])snd_hda_codec_cleanup_stream (codec, mout->extra_out_nid[i]); -mutex_lock (&codec->spdif_mutex); +guard (mutex)(&codec->spdif_mutex);if (mout->dig_out_nid && mout->dig_out_used ==HDA_DIG_ANALOG_DUP ) {cleanup_dig_out_stream (codec, mout->dig_out_nid); mout->dig_out_used =0 ; } -mutex_unlock (&codec->spdif_mutex);return 0 ; }EXPORT_SYMBOL_GPL (snd_hda_multi_out_analog_cleanup);
sound/pci/hda/hda_controller.c +12 -12
@@ -93,12 +93,12 @@ static int azx_pcm_close(struct snd_pcm_substream *substream)struct azx_dev *azx_dev =get_azx_dev (substream);trace_azx_pcm_close (chip, azx_dev); -mutex_lock (&chip->open_mutex); -azx_release_device (azx_dev); -if (hinfo->ops.close) - hinfo->ops.close (hinfo, apcm->codec, substream); -snd_hda_power_down (apcm->codec); -mutex_unlock (&chip->open_mutex); + scoped_guard(mutex, &chip->open_mutex) { +azx_release_device (azx_dev); +if (hinfo->ops.close) + hinfo->ops.close (hinfo, apcm->codec, substream); +snd_hda_power_down (apcm->codec); + }snd_hda_codec_pcm_put (apcm->info);return 0 ; }
@@ -1136,12 +1136,12 @@ static int probe_codec(struct azx *chip, int addr)int err;unsigned int res =-1 ; -mutex_lock (&bus->cmd_mutex); - chip->probing =1 ; -azx_send_cmd (bus, cmd); - err =azx_get_response (bus, addr, &res); - chip->probing =0 ; -mutex_unlock (&bus->cmd_mutex); + scoped_guard(mutex, &bus->cmd_mutex) { + chip->probing =1 ; +azx_send_cmd (bus, cmd); + err =azx_get_response (bus, addr, &res); + chip->probing =0 ; + }if (err <0 || res ==-1 )return -EIO ;dev_dbg (chip->card->dev,"codec #%d probed OK\n" , addr);
sound/pci/hda/hda_sysfs.c +25 -41
153 lines not on this page · raw message
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 735/1102 ALSA: hda: Report a change when only the channel status bytes move
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: HyeongJun An <[email protected]>
[ Upstream commit 7284788743121ec8bed556b00f830dc52ad9955d ]
The put() callback of "IEC958 Playback Default" returns whether the converted register value moved. The convert_from_spdif_status() helper reads part of the first two channel status bytes and none of the last two, while the get() callback returns all four. So a write that lands only in the bits it does not read changes what userspace reads back and reports no change. Of the 31 bits above the mode bit, 20 are such bits in consumer mode and 29 in professional mode. The core notifies only on a positive return.
Toggling status[2] bit 0 on an HDA HDMI codec moves the read-back from 04 00 00 00 to 04 00 01 00 with no event. Toggling the non-audio bit in status[0] gives one.
Compare the stored status as well, the way the ac97 code does. The write to the codec stays gated on the converted value.
--- sound/pci/hda/hda_codec.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
sound/pci/hda/hda_codec.c +3 -1
@@ -2320,6 +2320,7 @@ static int snd_hda_spdif_default_put(struct snd_kcontrol *kcontrol,int idx = kcontrol->private_value;struct hda_spdif_out *spdif;hda_nid_t nid; +unsigned int old_status;unsigned short val;int change;
@@ -2328,6 +2329,7 @@ static int snd_hda_spdif_default_put(struct snd_kcontrol *kcontrol,guard (mutex)(&codec->spdif_mutex); spdif =snd_array_elem (&codec->spdif_out, idx); nid = spdif->nid; + old_status = spdif->status; spdif->status = ucontrol->value.iec958.status[0 ] | ((unsigned int )ucontrol->value.iec958.status[1 ] <<8 ) | ((unsigned int)ucontrol->value.iec958.status[2] << 16) |
@@ -2338,7 +2340,7 @@ static int snd_hda_spdif_default_put(struct snd_kcontrol *kcontrol, spdif->ctls = val;if (change && nid != (u16)-1 )set_dig_out_convert (codec, nid, val &0xff , (val >>8 ) &0xff ); -return change; +return change || spdif->status != old_status; }#define snd_hda_spdif_out_switch_info snd_ctl_boolean_mono_info
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 736/1102 idpf: account for VLAN header when parsing RSC packet header
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Joshua Hay <[email protected]>
[ Upstream commit cc6d60ef92278a31ffc2e94966a0921b9646af18 ]
While parsing the header of a Receive Side Coalesced (RSC) packet, check if a VLAN tag is present and adjust the header parsing accordingly. Otherwise, Rx TCP traffic is completely broken for any VLAN interface whose underlying interface has RSC (rx-gro-hw) enabled.
We only need to worry about one VLAN header since Rx packets with multiple VLAN headers are not candidates for RSC.
--- drivers/net/ethernet/intel/idpf/idpf_txrx.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-)
drivers/net/ethernet/intel/idpf/idpf_txrx.c +7 -3
@@ -2708,6 +2708,7 @@ static int idpf_rx_rsc(struct idpf_rx_queue *rxq, struct sk_buff *skb, struct libeth_rx_pt decoded) {u16 rsc_segments, rsc_seg_len; +u16 l3_start =0 ;bool ipv4, ipv6;int len;
@@ -2730,7 +2731,10 @@ static int idpf_rx_rsc(struct idpf_rx_queue *rxq, struct sk_buff *skb,NAPI_GRO_CB (skb)->count = rsc_segments;skb_shinfo (skb)->gso_size = rsc_seg_len; -skb_reset_network_header (skb); +if (unlikely (eth_type_vlan (skb->protocol))) + l3_start =VLAN_HLEN ; + +skb_set_network_header (skb, l3_start);if (ipv4) {struct iphdr *ipv4h =ip_hdr (skb);
@@ -2738,7 +2742,7 @@ static int idpf_rx_rsc(struct idpf_rx_queue *rxq, struct sk_buff *skb,skb_shinfo (skb)->gso_type =SKB_GSO_TCPV4 ;/* Reset and set transport header offset in skb */ -skb_set_transport_header (skb,sizeof (struct iphdr )); +skb_set_transport_header (skb, l3_start +sizeof (struct iphdr )); len = skb->len -skb_transport_offset (skb);/* Compute the TCP pseudo header checksum*/
@@ -2748,7 +2752,7 @@ static int idpf_rx_rsc(struct idpf_rx_queue *rxq, struct sk_buff *skb,struct ipv6hdr *ipv6h =ipv6_hdr (skb);skb_shinfo (skb)->gso_type =SKB_GSO_TCPV6 ; -skb_set_transport_header (skb,sizeof (struct ipv6hdr )); +skb_set_transport_header (skb, l3_start +sizeof (struct ipv6hdr )); len = skb->len -skb_transport_offset (skb);tcp_hdr (skb)->check = ~tcp_v6_check (len, &ipv6h->saddr, &ipv6h->daddr,0 );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 737/1102 ice: add missing xa_destroy for sched_node_ids
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 53432c4c3e869076350aef319534431af8ba99c1 ]
Commit 16dfa49406bc ("ice: Introduce new parameters in ice_sched_node") added a sched_node_ids xarray to the port info structure, but never called xa_destroy on it.
Since xarrays can allocate internal memory, this can result in a memory leak even if every element in the xarray has been removed.
The xarray is currently embedded in the port_info structure. This appears to have been done because its use is within functions that take the port_info as a primary argument.
However, this complicates managing the lifecycle of the field. The port_info structure is allocated in ice_init_hw() using devm, and it is not released until the devm cleanup when the driver is unloaded.
The ice_init_hw() function is called in many places, including devlink reload, and possibly during DDP load after updating the Tx scheduler layout.
Adding a call of xa_destroy to the ice_deinit_hw() causes Sashiko to raise multiple concerns due to potential ordering issues and possible ways that port_info could be a dangling reference.
To handle this, move the sched_node_ids out of port_info and into the hw structure. All users of the array already have a pointer to hw anyways, and there is only one sched_node_ids per adapter. While here, remove the overly verbose comment explaining the nature of the sched_node_ids xarray.
Add the missing xa_destroy to the cleanup path and to ice_deinit_hw(), ensuring that we properly release the xarray memory.
This was caught by Sashiko during development of unrelated code.
--- drivers/net/ethernet/intel/ice/ice_common.c | 9 ++++++--- drivers/net/ethernet/intel/ice/ice_sched.c | 4 ++-- drivers/net/ethernet/intel/ice/ice_type.h | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-)
drivers/net/ethernet/intel/ice/ice_common.c +6 -3
@@ -1095,14 +1095,13 @@ int ice_init_hw(struct ice_hw *hw) hw->evb_veb = true; -/* init xarray for identifying scheduling nodes uniquely */ -xa_init_flags (&hw->port_info->sched_node_ids,XA_FLAGS_ALLOC ); +xa_init_flags (&hw->sched_node_ids,XA_FLAGS_ALLOC );/* Query the allocated resources for Tx scheduler */ status =ice_sched_query_res_alloc (hw);if (status) {ice_debug (hw,ICE_DBG_SCHED ,"Failed to get scheduler allocated resources\n" ); - goto err_unroll_alloc; + goto err_unroll_xarray; }ice_sched_get_psm_clk_freq (hw);
@@ -1179,6 +1178,8 @@ int ice_init_hw(struct ice_hw *hw)ice_cleanup_fltr_mgmt_struct (hw); err_unroll_sched:ice_sched_cleanup_all (hw); +err_unroll_xarray: +xa_destroy (&hw->sched_node_ids); err_unroll_alloc:devm_kfree (ice_hw_to_dev (hw), hw->port_info); err_unroll_cqinit:
@@ -1210,6 +1211,8 @@ void ice_deinit_hw(struct ice_hw *hw)/* Clear VSI contexts if not already cleared */ ice_clear_all_vsi_ctx (hw); + +xa_destroy (&hw->sched_node_ids); }/**
drivers/net/ethernet/intel/ice/ice_sched.c +2 -2
@@ -371,7 +371,7 @@ void ice_free_sched_node(struct ice_port_info *pi, struct ice_sched_node *node)devm_kfree (ice_hw_to_dev (hw), node->children);kfree (node->name); -xa_erase (&pi->sched_node_ids, node->id); +xa_erase (&hw->sched_node_ids, node->id);devm_kfree (ice_hw_to_dev (hw), node); }
@@ -977,7 +977,7 @@ ice_sched_add_elems(struct ice_port_info *pi, struct ice_sched_node *tc_node,if (!new_node->name)return -ENOMEM ; - status =xa_alloc (&pi->sched_node_ids, &new_node->id,NULL ,XA_LIMIT (0 ,UINT_MAX ), + status =xa_alloc (&hw->sched_node_ids, &new_node->id,NULL ,XA_LIMIT (0 ,UINT_MAX ),GFP_KERNEL );if (status) { ice_debug(hw, ICE_DBG_SCHED, "xa_alloc failed for sched node status =%d\n",
drivers/net/ethernet/intel/ice/ice_type.h +1 -1
@@ -754,7 +754,6 @@ struct ice_port_info {/* List contain profile ID(s) and other params per layer */ struct list_head rl_prof_list[ICE_AQC_TOPO_MAX_LEVEL_NUM ];struct ice_qos_cfg qos_cfg; -struct xarray sched_node_ids; u8 is_vf:1; u8 is_custom_tx_enabled:1; };
@@ -916,6 +915,7 @@ struct ice_hw {u8 sw_entry_point_layer;u16 max_children[ICE_AQC_TOPO_MAX_LEVEL_NUM ];struct list_head agg_list;/* lists all aggregator */ +struct xarray sched_node_ids;struct ice_vsi_ctx *vsi_ctx[ICE_MAX_VSI ];u8 evb_veb;/* true for VEB, false for VEPA */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 738/1102 eth: ice: dont dereference pointers from TP_printk()
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 b8bf9bfda5f62e11444e483c2b4aaff90c5cfc6b ]
After forwarding net-next during the v7.3 merge window we started seeing:
TRACE EVENT ERROR: Event ice_tx_dim_work has double dereference in TP_printk: REC->q_vector->tx.tx_ring->q_index
WARNING: kernel/trace/trace_events.c:420 at test_double_dereference.cold+0x39/0x4b
this is due to extra checks added in tracing subsystem in
commit b5cc230af5e5 ("tracing: Warn when an event dereferences a pointer in TP_printk()").
Printing happens long after the event was recorded, by which point the pointers may be invalid (the ring or the dim instance). Copy the eight scalars into the event instead.
--- drivers/net/ethernet/intel/ice/ice_trace.h | 64 ++++++++++++++-------- 1 file changed, 42 insertions(+), 22 deletions(-)
drivers/net/ethernet/intel/ice/ice_trace.h +42 -22
@@ -63,23 +63,33 @@DECLARE_EVENT_CLASS (ice_rx_dim_template, TP_PROTO(struct ice_q_vector *q_vector, struct dim *dim),TP_ARGS (q_vector, dim), - TP_STRUCT__entry(__field(struct ice_q_vector *, q_vector) - __field(struct dim *, dim) + TP_STRUCT__entry(__field(u16, q_index) + __field(u8, state) + __field(u8, profile_ix) + __field(u8, tune_state) + __field(u8, steps_right) + __field(u8, steps_left) + __field(u8, tired)__string (devname, q_vector->rx.rx_ring->netdev->name)), - TP_fast_assign(__entry->q_vector = q_vector; - __entry->dim = dim; + TP_fast_assign(__entry->q_index = q_vector->rx.rx_ring->q_index; + __entry->state = dim->state; + __entry->profile_ix = dim->profile_ix; + __entry->tune_state = dim->tune_state; + __entry->steps_right = dim->steps_right; + __entry->steps_left = dim->steps_left; + __entry->tired = dim->tired; __assign_str(devname);),TP_printk ("netdev: %s Rx-Q: %d dim-state: %d dim-profile: %d dim-tune: %d dim-st-right: %d dim-st-left: %d dim-tired: %d" ,__get_str (devname), - __entry->q_vector->rx.rx_ring->q_index, - __entry->dim->state, - __entry->dim->profile_ix, - __entry->dim->tune_state, - __entry->dim->steps_right, - __entry->dim->steps_left, - __entry->dim->tired) + __entry->q_index, + __entry->state, + __entry->profile_ix, + __entry->tune_state, + __entry->steps_right, + __entry->steps_left, + __entry->tired) ); DEFINE_EVENT(ice_rx_dim_template, ice_rx_dim_work,
@@ -90,23 +100,33 @@ DEFINE_EVENT(ice_rx_dim_template, ice_rx_dim_work,DECLARE_EVENT_CLASS (ice_tx_dim_template, TP_PROTO(struct ice_q_vector *q_vector, struct dim *dim),TP_ARGS (q_vector, dim), - TP_STRUCT__entry(__field(struct ice_q_vector *, q_vector) - __field(struct dim *, dim) + TP_STRUCT__entry(__field(u16, q_index) + __field(u8, state) + __field(u8, profile_ix) + __field(u8, tune_state) + __field(u8, steps_right) + __field(u8, steps_left) + __field(u8, tired)__string (devname, q_vector->tx.tx_ring->netdev->name)), - TP_fast_assign(__entry->q_vector = q_vector; - __entry->dim = dim; + TP_fast_assign(__entry->q_index = q_vector->tx.tx_ring->q_index; + __entry->state = dim->state; + __entry->profile_ix = dim->profile_ix; + __entry->tune_state = dim->tune_state; + __entry->steps_right = dim->steps_right; + __entry->steps_left = dim->steps_left; + __entry->tired = dim->tired; __assign_str(devname);),TP_printk ("netdev: %s Tx-Q: %d dim-state: %d dim-profile: %d dim-tune: %d dim-st-right: %d dim-st-left: %d dim-tired: %d" ,__get_str (devname), - __entry->q_vector->tx.tx_ring->q_index, - __entry->dim->state, - __entry->dim->profile_ix, - __entry->dim->tune_state, - __entry->dim->steps_right, - __entry->dim->steps_left, - __entry->dim->tired) + __entry->q_index, + __entry->state, + __entry->profile_ix, + __entry->tune_state, + __entry->steps_right, + __entry->steps_left, + __entry->tired) ); DEFINE_EVENT(ice_tx_dim_template, ice_tx_dim_work,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 739/1102 Bluetooth: btusb: Fix UAF of btusb_data by rx_work
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Luiz Augusto von Dentz <[email protected]>
[ Upstream commit 1c12c3117639e78940959d956519c758c57d0849 ]
btusb_close() and btusb_flush() cancel data->rx_work with the asynchronous cancel_delayed_work(), so if btusb_rx_work() is already running on another CPU it keeps running after the cancel returns.
btusb_disconnect() calls hci_unregister_dev(), which invokes btusb_close(), and then frees the btusb_data. A still running btusb_rx_work() then dereferences the freed data:
while ((skb = skb_dequeue(&data->acl_q))) data->recv_acl(data->hdev, skb);
Use cancel_delayed_work_sync() instead. In btusb_close() the cancel also has to happen after btusb_stop_traffic(), otherwise an URB completion racing with the cancel can requeue the work right after it has been waited for.
--- drivers/bluetooth/btusb.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-)
drivers/bluetooth/btusb.c +10 -4
@@ -2012,18 +2012,24 @@ static int btusb_close(struct hci_dev *hdev)BT_DBG ("%s" , hdev->name); -cancel_delayed_work (&data->rx_work);cancel_work_sync (&data->work);cancel_work_sync (&data->waker); -skb_queue_purge (&data->acl_q); -clear_bit (BTUSB_ISOC_RUNNING , &data->flags);clear_bit (BTUSB_BULK_RUNNING , &data->flags);clear_bit (BTUSB_INTR_RUNNING , &data->flags);clear_bit (BTUSB_DIAG_RUNNING , &data->flags);btusb_stop_traffic (data); + +/* rx_work must only be canceled once the URBs that can rearm it are +* gone, and it must be canceled synchronously since btusb_disconnect() +* frees the btusb_data it dereferences right after hci_unregister_dev(). +*/ +cancel_delayed_work_sync (&data->rx_work); + +skb_queue_purge (&data->acl_q); +btusb_free_frags (data); err =usb_autopm_get_interface (data->intf);
@@ -2049,7 +2055,7 @@ static int btusb_flush(struct hci_dev *hdev)BT_DBG ("%s" , hdev->name); -cancel_delayed_work (&data->rx_work); +cancel_delayed_work_sync (&data->rx_work);skb_queue_purge (&data->acl_q);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 740/1102 Bluetooth: btintel_pcie: validate packet_len before skb_put_data
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kiran K <[email protected]>
[ Upstream commit 6436e1b5331b1aebf905c13e0880a37032719b75 ]
btintel_pcie_submit_rx_work() reads packet_len from rfh_hdr without checking if it exceeds the RX buffer size. An oversized packet_len can lead to an out-of-bounds read in skb_put_data().
Validate packet_len to ensure it is non-zero and does not exceed BTINTEL_PCIE_BUFFER_SIZE - sizeof(*rfh_hdr), logging an error when invalid.
This issue was reported by Claude Mythos. It can be simulated either by using customized firmware configured to return an invalid packet_len or by modifying rfh_hdr->packet_len in the driver before calling btintel_pcie_submit_rx_work().
--- drivers/bluetooth/btintel_pcie.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/bluetooth/btintel_pcie.c +3 -1
@@ -739,7 +739,9 @@ static int btintel_pcie_submit_rx_work(struct btintel_pcie_data *data, u8 status rfh_hdr = buf; len = rfh_hdr->packet_len; -if (len <=0 ) { +if (len ==0 || len >BTINTEL_PCIE_BUFFER_SIZE -sizeof (*rfh_hdr)) { +bt_dev_err (data->hdev,"Invalid packet_len %d (max %zu)" , len, +BTINTEL_PCIE_BUFFER_SIZE -sizeof (*rfh_hdr)); ret = -EINVAL ; goto resubmit; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 741/1102 Bluetooth: btintel_pcie: fix tx_handle bounds off-by-one
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kiran K <[email protected]>
[ Upstream commit 3dd1b41f96aad08444be1b7626c89de2b9f2abd4 ]
Valid indices into txq->urbd0s/tfds/bufs are 0..txq->count-1, so tfd_index == txq->count is already out of range. Change the guard in btintel_pcie_msix_tx_handle() from '> txq->count' to '>= txq->count'.
This issue was reported by Claude Mythos.
--- drivers/bluetooth/btintel_pcie.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/bluetooth/btintel_pcie.c +1 -1
@@ -519,7 +519,7 @@ static void btintel_pcie_msix_tx_handle(struct btintel_pcie_data *data) urbd0 = &txq->urbd0s[cr_tia]; -if (urbd0->tfd_index > txq->count) +if (urbd0->tfd_index >= txq->count)return ; cr_tia = (cr_tia +1 ) % txq->count;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 742/1102 Bluetooth: btmtk: Declare MT7920 (MT7961 1a) Bluetooth firmware
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ivan Hu <[email protected]>
[ Upstream commit 3d8a8e81ea8ad8813d4c82a12ba53ecb597b217d ]
btmtk_fw_get_filename() constructs the firmware name at runtime, so for the MT7920 variant (dev_id 0x7961 with fw_flavor set) it requests "mediatek/BT_RAM_CODE_MT7961_1a_2_hdr.bin" without ever declaring it via MODULE_FIRMWARE(). Tools that select firmware from module metadata (e.g. "modinfo -F firmware") therefore omit this blob, so request_firmware() fails and Bluetooth does not initialise on MT7920, even though the file is present in linux-firmware.
Declare it with MODULE_FIRMWARE(), as the mt76 driver already does for the corresponding MT7920 wifi firmware.
--- drivers/bluetooth/btmtk.c | 1 + drivers/bluetooth/btmtk.h | 1 + 2 files changed, 2 insertions(+)
drivers/bluetooth/btmtk.c +1 -0
@@ -1564,5 +1564,6 @@ MODULE_FIRMWARE(FIRMWARE_MT7663);MODULE_FIRMWARE (FIRMWARE_MT7668 );MODULE_FIRMWARE (FIRMWARE_MT7922 );MODULE_FIRMWARE (FIRMWARE_MT7961 ); +MODULE_FIRMWARE (FIRMWARE_MT7920 );MODULE_FIRMWARE (FIRMWARE_MT7925 );MODULE_FIRMWARE (FIRMWARE_MT7927 );
drivers/bluetooth/btmtk.h +1 -0
@@ -7,6 +7,7 @@#define FIRMWARE_MT7922 "mediatek/BT_RAM_CODE_MT7922_1_1_hdr.bin"#define FIRMWARE_MT7902 "mediatek/BT_RAM_CODE_MT7902_1_1_hdr.bin"#define FIRMWARE_MT7961 "mediatek/BT_RAM_CODE_MT7961_1_2_hdr.bin" +#define FIRMWARE_MT7920 "mediatek/BT_RAM_CODE_MT7961_1a_2_hdr.bin"#define FIRMWARE_MT7925 "mediatek/mt7925/BT_RAM_CODE_MT7925_1_1_hdr.bin"#define FIRMWARE_MT7927 "mediatek/mt7927/BT_RAM_CODE_MT6639_2_1_hdr.bin"
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 743/1102 Bluetooth: btusb: mediatek: Fix leaked runtime PM reference in reset
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jiajia Liu <[email protected]>
[ Upstream commit e486a891c412d9d82ee865987f4eead6196e1f96 ]
MT7925 on HP Pro Mini 260 sometimes timed out during reloading driver and reset usb device. btusb_suspend is not called again after closing bluetooth interface.
usbcore: registered new interface driver btusb
Bluetooth: hci0: HW/SW Version: 0x00000000, Build Time: 20260605184935
Bluetooth: hci0: Execution of wmt command timed out
Bluetooth: hci0: Failed to send wmt patch dwnld (-110)
Bluetooth: hci0: Failed to set up firmware (-110)
usb 3-10: reset high-speed USB device number 4 using xhci_hcd
Bluetooth: hci0: HW/SW Version: 0x00000000, Build Time: 20260605184935
Bluetooth: hci0: Device setup in 1856545 usecs
Bluetooth: hci0: AOSP extensions version v1.00
Bluetooth: hci0: AOSP quality report is supported
Bluetooth: MGMT ver 1.23
btusb_mtk_reset calls usb_autopm_get_interface to resume the device before driving the hardware reset, but never calls the matching usb_autopm_put_interface. Every hardware reset therefore leaks a PM usage reference of the interface, preventing the device from being runtime suspended again until it is unbound.
Add the BTUSB_RESET flag. It is set before usb_queue_reset_device and is cleared in btusb_disconnect, which drops the reference as well. If the flag is already set when a new reset is requested, drop one reference.
Also clear BTMTK_HW_RESET_ACTIVE if usb_autopm_get_interface fails, otherwise no further reset could ever be attempted.
--- drivers/bluetooth/btusb.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-)
drivers/bluetooth/btusb.c +13 -1
@@ -911,6 +911,7 @@ struct qca_dump_info {#define BTUSB_USE_ALT3_FOR_WBS 15#define BTUSB_ALT6_CONTINUOUS_TX 16#define BTUSB_HW_SSR_ACTIVE 17 +#define BTUSB_RESET 19struct btusb_data {struct hci_dev *hdev;
@@ -2844,8 +2845,11 @@ static int btusb_mtk_reset(struct hci_dev *hdev, void *rst_data) } err =usb_autopm_get_interface (data->intf); -if (err <0 ) +if (err <0 ) { +bt_dev_err (hdev,"Failed usb_autopm_get_interface: %d" , err); +clear_bit (BTMTK_HW_RESET_ACTIVE , &btmtk_data->flags);return err; + }/* Release MediaTek ISO data interface */ btusb_mtk_release_iso_intf (hdev);
@@ -2855,6 +2859,11 @@ static int btusb_mtk_reset(struct hci_dev *hdev, void *rst_data) err =btmtk_usb_subsys_reset (hdev, btmtk_data->dev_id); +if (test_and_set_bit (BTUSB_RESET , &data->flags)) { +bt_dev_err (hdev,"last usb reset failed? Resetting again" ); +usb_autopm_put_interface_no_suspend (data->intf); + } +usb_queue_reset_device (data->intf);clear_bit (BTMTK_HW_RESET_ACTIVE , &btmtk_data->flags);
@@ -4252,6 +4261,9 @@ static void btusb_disconnect(struct usb_interface *intf)if (data->reset_gpio)gpiod_put (data->reset_gpio); +if (test_and_clear_bit (BTUSB_RESET , &data->flags)) +usb_autopm_put_interface_no_suspend (data->intf); +if (intf == data->intf) {if (data->isoc)usb_driver_release_interface (&btusb_driver, data->isoc);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 744/1102 Bluetooth: btusb: Fix leaked runtime PM reference in btusb_reset
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jiajia Liu <[email protected]>
[ Upstream commit c93922dd316b7273a8667d29084632066fa8a2d3 ]
btusb_reset calls usb_autopm_get_interface to resume the device before queuing a reset of it, but never calls the matching usb_autopm_put_interface.
usb_queue_reset_device ends up in usb_reset_device(), and since btusb provides no pre_reset/post_reset callbacks the interface is merely unbound and rebound: the interface device object survives this cycle, and so does its PM usage count, which is not cleared when the driver is unbound.
As a result every reset permanently leaks a PM usage reference, preventing the interface from being runtime suspended again until it is unbound.
Set BTUSB_RESET flag before usb_queue_reset_device so that btusb_disconnect drops the reference. If the flag is already set, drop one reference.
--- drivers/bluetooth/btusb.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/bluetooth/btusb.c +3 -1
@@ -994,13 +994,15 @@ static void btusb_reset(struct hci_dev *hdev) } data =hci_get_drvdata (hdev); -/* This is not an unbalanced PM reference since the device will reset */ err =usb_autopm_get_interface (data->intf);if (err) {bt_dev_err (hdev,"Failed usb_autopm_get_interface: %d" , err);return ; } +if (test_and_set_bit (BTUSB_RESET , &data->flags)) +usb_autopm_put_interface_no_suspend (data->intf); +bt_dev_err (hdev,"Resetting usb device." );usb_queue_reset_device (data->intf); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 745/1102 net: macb: destroy the phylink instance on the probe error path
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nicolai Buchwitz <[email protected]>
[ Upstream commit 7d059f390750152b9bd69df934198651b94fc26d ]
macb_mii_init() creates a phylink instance on both of its success paths, but the probe unwind frees the netdev without destroying it, so a failing macb_alloc_tieoff() or register_netdev() leaks the instance.
Destroy it at err_out_unregister_mdio, which is only reachable once macb_mii_init() has succeeded, so bp->phylink is valid there.
--- drivers/net/ethernet/cadence/macb_main.c | 1 + 1 file changed, 1 insertion(+)
drivers/net/ethernet/cadence/macb_main.c +1 -0
@@ -5324,6 +5324,7 @@ static int macb_probe(struct platform_device *pdev)mdiobus_unregister (bp->mii_bus);mdiobus_free (bp->mii_bus); } +phylink_destroy (bp->phylink); err_out_phy_exit:phy_exit (bp->phy);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 746/1102 mptcp: remove unneeded READ_ONCE() annotation
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 caa4a79f74f32084ce28aee8653bc04df745970d ]
The subflow->fully_established flag is always written under the subflow socket lock. Reading such value under the same lock does not require any ONCE annotation.
--- net/mptcp/options.c | 4 ++-- net/mptcp/protocol.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-)
net/mptcp/options.c +2 -2
@@ -531,7 +531,7 @@ static bool mptcp_established_options_mp(struct sock *sk, struct sk_buff *skb,return false;/* MPC/MPJ needed only on 3rd ack packet, DATA_FIN and TCP shutdown take precedence */ -if (READ_ONCE (subflow->fully_established) || snd_data_fin_enable || +if (subflow->fully_established || snd_data_fin_enable || subflow->snd_isn !=TCP_SKB_CB (skb)->seq || sk->sk_state !=TCP_ESTABLISHED )return false;
@@ -998,7 +998,7 @@ static bool check_fully_established(struct mptcp_sock *msk, struct sock *ssk,/* here we can process OoO, in-window pkts, only in-sequence 4th ack * will make the subflow fully established */ -if (likely (READ_ONCE (subflow->fully_established))) { +if (likely (subflow->fully_established)) {/* on passive sockets, check for 3rd ack retransmission * note that msk is always set by subflow_syn_recv_sock() * for mp_join subflows
net/mptcp/protocol.c +1 -1
@@ -3685,7 +3685,7 @@ static void schedule_3rdack_retransmission(struct sock *ssk)struct tcp_sock *tp =tcp_sk (ssk);unsigned long timeout; -if (READ_ONCE (mptcp_subflow_ctx (ssk)->fully_established)) +if (mptcp_subflow_ctx (ssk)->fully_established)return ;/* reschedule with a timeout above RTT, as we must look only for drop */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 747/1102 watchdog: fix hrtimer start when pretimeout is zero
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Arcari <[email protected]>
[ Upstream commit 0fa37512eb747e4ffdcf367274f9e72845f1bca4 ]
Per the watchdog API, a pretimeout value of 0 disables the feature. However, watchdog_hrtimer_pretimeout_start() fails to verify if the pretimeout is non-zero before arming the timer.
This omission inadvertently starts the software pretimeout timer, which could result in the pretimeout handler executing incorrectly when the watchdog timeout is reached.
Fix this by adding a check for wdd->pretimeout before calling hrtimer_start(), ensuring the disabled state is respected.
--- drivers/watchdog/watchdog_hrtimer_pretimeout.c | 1 + 1 file changed, 1 insertion(+)
drivers/watchdog/watchdog_hrtimer_pretimeout.c +1 -0
@@ -30,6 +30,7 @@ void watchdog_hrtimer_pretimeout_init(struct watchdog_device *wdd)void watchdog_hrtimer_pretimeout_start (struct watchdog_device *wdd) {if (!(wdd->info->options &WDIOF_PRETIMEOUT ) && + wdd->pretimeout && !watchdog_pretimeout_invalid (wdd, wdd->pretimeout)) hrtimer_start(&wdd->wd_data->pretimeout_timer, ktime_set(wdd->timeout - wdd->pretimeout, 0),
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 748/1102 watchdog: msc313e: Avoid division by zero
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tzung-Bi Shih <[email protected]>
[ Upstream commit 3c73a37f5e40972ce26d8eeb98e8b938d719b069 ]
clk_get_rate() could return 0. Avoid a division by zero panic.
--- drivers/watchdog/msc313e_wdt.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
drivers/watchdog/msc313e_wdt.c +5 -1
@@ -98,6 +98,7 @@ static int msc313e_wdt_probe(struct platform_device *pdev) {struct device *dev = &pdev->dev;struct msc313e_wdt_priv *priv; +unsigned long rate; priv =devm_kzalloc (&pdev->dev,sizeof (*priv),GFP_KERNEL );if (!priv)
@@ -117,7 +118,10 @@ static int msc313e_wdt_probe(struct platform_device *pdev) priv->wdev.ops = &msc313e_wdt_ops, priv->wdev.parent = dev; priv->wdev.min_timeout =MSC313E_WDT_MIN_TIMEOUT ; - priv->wdev.max_timeout =U32_MAX /clk_get_rate (priv->clk); + rate =clk_get_rate (priv->clk); +if (!rate) +return -EINVAL ; + priv->wdev.max_timeout =U32_MAX / rate; priv->wdev.timeout =MSC313E_WDT_DEFAULT_TIMEOUT ;/* If the period is non-zero the WDT is running */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 749/1102 watchdog: msc313e: Fix clock leak and spurious timer in settimeout()
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tzung-Bi Shih <[email protected]>
[ Upstream commit 3db30f315935c2fb0d95f46b7a593b5b4d3ec3d0 ]
msc313e_wdt_settimeout() unconditionally calls msc313e_wdt_start() which introduces two severe bugs:
1. If the watchdog is already active, calling start() again will increase the reference count of the clock again. However stop() is only called once, the reference count is unbalance.
2. If the watchdog is stopped, calling settimeout() will start the hardware timer accidentally.
Factor out the register-writing logic into a helper function. Only call it in settimeout() if the watchdog is running. Otherwise, simply update wdev->timeout.
--- drivers/watchdog/msc313e_wdt.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-)
drivers/watchdog/msc313e_wdt.c +16 -6
@@ -32,20 +32,26 @@ struct msc313e_wdt_priv {struct clk *clk; }; +static void msc313e_wdt_set_hw_timeout (struct msc313e_wdt_priv *priv, +unsigned int timeout) +{ +u32 t = timeout *clk_get_rate (priv->clk); + +writew (t &0xffff , priv->base +REG_WDT_MAX_PRD_L ); +writew ((t >>16 ) &0xffff , priv->base +REG_WDT_MAX_PRD_H ); +writew (1 , priv->base +REG_WDT_CLR ); +} +static int msc313e_wdt_start (struct watchdog_device *wdev) {struct msc313e_wdt_priv *priv =watchdog_get_drvdata (wdev); -u32 timeout;int err; err =clk_prepare_enable (priv->clk);if (err)return err; - timeout = wdev->timeout *clk_get_rate (priv->clk); -writew (timeout &0xffff , priv->base +REG_WDT_MAX_PRD_L ); -writew ((timeout >>16 ) &0xffff , priv->base +REG_WDT_MAX_PRD_H ); -writew (1 , priv->base +REG_WDT_CLR ); +msc313e_wdt_set_hw_timeout (priv, wdev->timeout);return 0 ; }
@@ -70,9 +76,13 @@ static int msc313e_wdt_stop(struct watchdog_device *wdev)static int msc313e_wdt_settimeout (struct watchdog_device *wdev,unsigned int new_time) { +struct msc313e_wdt_priv *priv =watchdog_get_drvdata (wdev); + wdev->timeout = new_time; -return msc313e_wdt_start (wdev); +if (watchdog_hw_running (wdev) ||watchdog_active (wdev)) +msc313e_wdt_set_hw_timeout (priv, wdev->timeout); +return 0 ; }static const struct watchdog_info msc313e_wdt_ident = {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 750/1102 watchdog: msc313e: Enable clock before accessing hardware registers
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tzung-Bi Shih <[email protected]>
[ Upstream commit 3db2df24e7f11fb117718f6abe326628d91bc500 ]
msc313e_wdt_probe() reads from hardware registers without ensuring the required clock is enabled. Furthermore, if the bootloader leaves the watchdog running, msc313e_wdt_probe() sets WDOG_HW_RUNNING without increasing the clock's reference count.
While the clock is currently supplied as a fixed clock by the device tree (xtal_div2 in arch/arm/boot/dts/sigmastar/mstar-v7.dtsi) which masks the physical issue, this still violates the API usage.
Call clk_prepare_enable() before reading WDT registers. If the WDT is running, leave the clock enabled so the CCF reference counter is balanced.
--- drivers/watchdog/msc313e_wdt.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-)
drivers/watchdog/msc313e_wdt.c +21 -2
@@ -109,6 +109,7 @@ static int msc313e_wdt_probe(struct platform_device *pdev)struct device *dev = &pdev->dev;struct msc313e_wdt_priv *priv;unsigned long rate; +int ret; priv =devm_kzalloc (&pdev->dev,sizeof (*priv),GFP_KERNEL );if (!priv)
@@ -134,9 +135,21 @@ static int msc313e_wdt_probe(struct platform_device *pdev) priv->wdev.max_timeout =U32_MAX / rate; priv->wdev.timeout =MSC313E_WDT_DEFAULT_TIMEOUT ; + ret =clk_prepare_enable (priv->clk); +if (ret) +return ret; +/* If the period is non-zero the WDT is running */ -if (readw (priv->base +REG_WDT_MAX_PRD_L ) | (readw (priv->base +REG_WDT_MAX_PRD_H ) <<16 )) +if (readw (priv->base +REG_WDT_MAX_PRD_L ) | (readw (priv->base +REG_WDT_MAX_PRD_H ) <<16 )) {set_bit (WDOG_HW_RUNNING , &priv->wdev.status); +/* +* Keep the clock enabled. The watchdog core will skip the next +* start() and a future stop() will balance the CCF reference +* count. +*/ + }else { +clk_disable_unprepare (priv->clk); + }watchdog_set_drvdata (&priv->wdev, priv);platform_set_drvdata (pdev, priv);
@@ -145,7 +158,13 @@ static int msc313e_wdt_probe(struct platform_device *pdev)watchdog_stop_on_reboot (&priv->wdev);watchdog_stop_on_unregister (&priv->wdev); -return devm_watchdog_register_device (dev, &priv->wdev); + ret =devm_watchdog_register_device (dev, &priv->wdev); + +/* If the WDT is running and anything goes wrong, disable the clock. */ +if (ret &&test_bit (WDOG_HW_RUNNING , &priv->wdev.status)) +clk_disable_unprepare (priv->clk); + +return ret; }static int __maybe_unused msc313e_wdt_suspend (struct device *dev)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 751/1102 watchdog: msc313e: Fix spurious reset on suspend
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tzung-Bi Shih <[email protected]>
[ Upstream commit 4f6817c9eff4aa1078e16652d82e4b7ef4ffae3e ]
If the hardware watchdog was started by the bootloader and the device is suspended before userspace opens it, the ping worker (from watchdog core) is frozen and the active hardware timer continues running. This leads to a spurious system reset.
Check both watchdog_active() and watchdog_hw_running() when deciding whether to start or stop the watchdog during suspend and resume.
Additionally, call watchdog_stop_ping_on_suspend() to ensure the ping worker be correctly paused and restarted during suspend and resume.
--- drivers/watchdog/msc313e_wdt.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/watchdog/msc313e_wdt.c +3 -2
@@ -157,6 +157,7 @@ static int msc313e_wdt_probe(struct platform_device *pdev)watchdog_init_timeout (&priv->wdev, timeout, dev);watchdog_stop_on_reboot (&priv->wdev);watchdog_stop_on_unregister (&priv->wdev); +watchdog_stop_ping_on_suspend (&priv->wdev); ret =devm_watchdog_register_device (dev, &priv->wdev);
@@ -171,7 +172,7 @@ static int __maybe_unused msc313e_wdt_suspend(struct device *dev) {struct msc313e_wdt_priv *priv =dev_get_drvdata (dev); -if (watchdog_active (&priv->wdev)) +if (watchdog_active (&priv->wdev) ||watchdog_hw_running (&priv->wdev))msc313e_wdt_stop (&priv->wdev);return 0 ;
@@ -181,7 +182,7 @@ static int __maybe_unused msc313e_wdt_resume(struct device *dev) {struct msc313e_wdt_priv *priv =dev_get_drvdata (dev); -if (watchdog_active (&priv->wdev)) +if (watchdog_active (&priv->wdev) ||watchdog_hw_running (&priv->wdev))msc313e_wdt_start (&priv->wdev);return 0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 752/1102 watchdog: msc313e: Fix undefined behavior
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tzung-Bi Shih <[email protected]>
[ Upstream commit ab390021b2a3bb4cc875f28a6f76d13de90d7457 ]
readw() returns a u16. Left shifting a u16 by 16 bits yields undefined behavior.
Cast to u32 explicitly before the shift.
--- drivers/watchdog/msc313e_wdt.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-)
drivers/watchdog/msc313e_wdt.c +11 -1
@@ -32,6 +32,16 @@ struct msc313e_wdt_priv {struct clk *clk; }; +static u32 msc313e_wdt_get_hw_timeout (struct msc313e_wdt_priv *priv) +{ +u16 low, high; + + low =readw (priv->base +REG_WDT_MAX_PRD_L ); + high =readw (priv->base +REG_WDT_MAX_PRD_H ); + +return ((u32 )high <<16 ) | low; +} +static void msc313e_wdt_set_hw_timeout (struct msc313e_wdt_priv *priv,unsigned int timeout) {
@@ -140,7 +150,7 @@ static int msc313e_wdt_probe(struct platform_device *pdev)return ret;/* If the period is non-zero the WDT is running */ -if (readw (priv->base +REG_WDT_MAX_PRD_L ) | (readw (priv->base +REG_WDT_MAX_PRD_H ) <<16 )) { +if (msc313e_wdt_get_hw_timeout (priv)) {set_bit (WDOG_HW_RUNNING , &priv->wdev.status);/* * Keep the clock enabled. The watchdog core will skip the next
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 753/1102 watchdog: msc313e: Sync timeout value if WDT was running at boot
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tzung-Bi Shih <[email protected]>
[ Upstream commit 01504d14e47b34779911250dd308a03f6ef681c2 ]
If WDT was running at boot, the hardware timeout might be set to values other than the final software timeout.
To be consistent, set the hardware timeout to match the final software timeout (i.e., after watchdog_init_timeout()) if WDT was running.
--- drivers/watchdog/msc313e_wdt.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-)
drivers/watchdog/msc313e_wdt.c +9 -8
@@ -145,12 +145,21 @@ static int msc313e_wdt_probe(struct platform_device *pdev) priv->wdev.max_timeout =U32_MAX / rate; priv->wdev.timeout =MSC313E_WDT_DEFAULT_TIMEOUT ; +watchdog_set_drvdata (&priv->wdev, priv); +platform_set_drvdata (pdev, priv); + +watchdog_init_timeout (&priv->wdev, timeout, dev); +watchdog_stop_on_reboot (&priv->wdev); +watchdog_stop_on_unregister (&priv->wdev); +watchdog_stop_ping_on_suspend (&priv->wdev); + ret =clk_prepare_enable (priv->clk);if (ret)return ret;/* If the period is non-zero the WDT is running */ if (msc313e_wdt_get_hw_timeout (priv)) { +msc313e_wdt_set_hw_timeout (priv, priv->wdev.timeout);set_bit (WDOG_HW_RUNNING , &priv->wdev.status);/* * Keep the clock enabled. The watchdog core will skip the next
@@ -161,14 +170,6 @@ static int msc313e_wdt_probe(struct platform_device *pdev)clk_disable_unprepare (priv->clk); } -watchdog_set_drvdata (&priv->wdev, priv); -platform_set_drvdata (pdev, priv); - -watchdog_init_timeout (&priv->wdev, timeout, dev); -watchdog_stop_on_reboot (&priv->wdev); -watchdog_stop_on_unregister (&priv->wdev); -watchdog_stop_ping_on_suspend (&priv->wdev); - ret =devm_watchdog_register_device (dev, &priv->wdev);/* If the WDT is running and anything goes wrong, disable the clock. */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 754/1102 net: dsa: lantiq_gswip: deduplicate dsa_switch_ops
In reply to Greg Kroah-Hartman6.12-stable review patch. If anyone has any objections, please let me know.
------------------
From: Daniel Golle <[email protected]>
[ Upstream commit fa1439a865830ec3b599114e7cc907f5ad126b07 ]
The two instances of struct dsa_switch_ops differ only by their .phylink_get_caps op. Instead of having two instances of dsa_switch_ops, rather just have a pointer to the phylink_get_caps function in struct gswip_hw_info.
Stable-dep-of: 59fb389ad6bf ("net: dsa: lantiq_gswip: fix GSWIP_MDIO_PHY_FCONTX_EN value")
--- drivers/net/dsa/lantiq_gswip.c | 44 ++++++++++++---------------------- 1 file changed, 15 insertions(+), 29 deletions(-)
drivers/net/dsa/lantiq_gswip.c +15 -29
@@ -254,7 +254,8 @@struct gswip_hw_info {int max_ports;int cpu_port; -const struct dsa_switch_ops *ops; +void (*phylink_get_caps)(struct dsa_switch *ds,int port, +struct phylink_config *config); };struct xway_gphy_match_data {
@@ -1564,6 +1565,14 @@ static void gswip_xrx300_phylink_get_caps(struct dsa_switch *ds, int port,MAC_10 |MAC_100 |MAC_1000 ; } +static void gswip_phylink_get_caps (struct dsa_switch *ds,int port, +struct phylink_config *config) +{ +struct gswip_priv *priv = ds->priv; + + priv->hw_info->phylink_get_caps (ds, port, config); +} +static void gswip_port_set_link (struct gswip_priv *priv,int port,bool link) {u32 mdio_phy;
@@ -1836,7 +1845,7 @@ static const struct phylink_mac_ops gswip_phylink_mac_ops = { .mac_link_up = gswip_phylink_mac_link_up, }; -static const struct dsa_switch_ops gswip_xrx200_switch_ops = { +static const struct dsa_switch_ops gswip_switch_ops = { .get_tag_protocol = gswip_get_tag_protocol, .setup = gswip_setup, .port_setup = gswip_port_setup,
@@ -1854,30 +1863,7 @@ static const struct dsa_switch_ops gswip_xrx200_switch_ops = { .port_fdb_dump = gswip_port_fdb_dump, .port_change_mtu = gswip_port_change_mtu, .port_max_mtu = gswip_port_max_mtu, - .phylink_get_caps = gswip_xrx200_phylink_get_caps, - .get_strings = gswip_get_strings, - .get_ethtool_stats = gswip_get_ethtool_stats, - .get_sset_count = gswip_get_sset_count, -}; - -static const struct dsa_switch_ops gswip_xrx300_switch_ops = { - .get_tag_protocol = gswip_get_tag_protocol, - .setup = gswip_setup, - .port_enable = gswip_port_enable, - .port_disable = gswip_port_disable, - .port_bridge_join = gswip_port_bridge_join, - .port_bridge_leave = gswip_port_bridge_leave, - .port_fast_age = gswip_port_fast_age, - .port_vlan_filtering = gswip_port_vlan_filtering, - .port_vlan_add = gswip_port_vlan_add, - .port_vlan_del = gswip_port_vlan_del, - .port_stp_state_set = gswip_port_stp_state_set, - .port_fdb_add = gswip_port_fdb_add, - .port_fdb_del = gswip_port_fdb_del, - .port_fdb_dump = gswip_port_fdb_dump, - .port_change_mtu = gswip_port_change_mtu, - .port_max_mtu = gswip_port_max_mtu, - .phylink_get_caps = gswip_xrx300_phylink_get_caps, + .phylink_get_caps = gswip_phylink_get_caps, .get_strings = gswip_get_strings, .get_ethtool_stats = gswip_get_ethtool_stats, .get_sset_count = gswip_get_sset_count,
@@ -2140,7 +2126,7 @@ static int gswip_probe(struct platform_device *pdev) priv->ds->dev = dev; priv->ds->num_ports = priv->hw_info->max_ports; priv->ds->priv = priv; - priv->ds->ops = priv->hw_info->ops; + priv->ds->ops = &gswip_switch_ops; priv->ds->phylink_mac_ops = &gswip_phylink_mac_ops; priv->dev = dev;mutex_init (&priv->pce_table_lock);
@@ -2241,13 +2227,13 @@ static void gswip_shutdown(struct platform_device *pdev)static const struct gswip_hw_info gswip_xrx200 = { .max_ports =7 , .cpu_port =6 , - .ops = &gswip_xrx200_switch_ops, + .phylink_get_caps = gswip_xrx200_phylink_get_caps, };static const struct gswip_hw_info gswip_xrx300 = { .max_ports =7 , .cpu_port =6 , - .ops = &gswip_xrx300_switch_ops, + .phylink_get_caps = gswip_xrx300_phylink_get_caps, };static const struct of_device_id gswip_of_match[] = {
Signature · 1 line
2.53.0