7.0.10-rc1 review
Subsystems (6)
Greg Kroah-Hartman
maintainerPATCH 782/1146 tcp: add data-races annotations around tp->reordering, tp->snd_cwnd
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit 829ba1f329cb7cbd56d599a6d225997fba66dc32 ]
tcp_get_timestamping_opt_stats() intentionally runs lockless, we must add READ_ONCE(), WRITE_ONCE() data_race() annotations to keep KCSAN happy.
--- include/net/tcp.h | 2 +- net/ipv4/tcp.c | 8 ++++---- net/ipv4/tcp_input.c | 14 ++++++++------ net/ipv4/tcp_metrics.c | 2 +- 4 files changed, 14 insertions(+), 12 deletions(-)
include/net/tcp.h +1 -1
@@ -1465,7 +1465,7 @@ static inline u32 tcp_snd_cwnd(const struct tcp_sock *tp)static inline void tcp_snd_cwnd_set (struct tcp_sock *tp,u32 val) {WARN_ON_ONCE ((int )val <=0 ); - tp->snd_cwnd = val; +WRITE_ONCE (tp->snd_cwnd, val); }static inline bool tcp_in_slow_start (const struct tcp_sock *tp)
net/ipv4/tcp.c +4 -4
@@ -4479,13 +4479,13 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk, rate64 =tcp_compute_delivery_rate (tp);nla_put_u64_64bit (stats,TCP_NLA_DELIVERY_RATE , rate64,TCP_NLA_PAD ); -nla_put_u32 (stats,TCP_NLA_SND_CWND ,tcp_snd_cwnd (tp)); -nla_put_u32 (stats,TCP_NLA_REORDERING , tp->reordering); -nla_put_u32 (stats,TCP_NLA_MIN_RTT ,tcp_min_rtt (tp)); +nla_put_u32 (stats,TCP_NLA_SND_CWND ,READ_ONCE (tp->snd_cwnd)); +nla_put_u32 (stats,TCP_NLA_REORDERING ,READ_ONCE (tp->reordering)); +nla_put_u32 (stats,TCP_NLA_MIN_RTT ,data_race (tcp_min_rtt (tp)));nla_put_u8 (stats,TCP_NLA_RECUR_RETRANS ,READ_ONCE (inet_csk (sk)->icsk_retransmits)); -nla_put_u8 (stats,TCP_NLA_DELIVERY_RATE_APP_LMT , !!tp->rate_app_limited); +nla_put_u8 (stats,TCP_NLA_DELIVERY_RATE_APP_LMT ,data_race (!!tp->rate_app_limited));nla_put_u32 (stats,TCP_NLA_SND_SSTHRESH , tp->snd_ssthresh);nla_put_u32 (stats,TCP_NLA_DELIVERED , tp->delivered);nla_put_u32 (stats,TCP_NLA_DELIVERED_CE , tp->delivered_ce);
net/ipv4/tcp_input.c +8 -6
@@ -1294,8 +1294,9 @@ static void tcp_check_sack_reordering(struct sock *sk, const u32 low_seq, tp->sacked_out, tp->undo_marker ? tp->undo_retrans : 0);#endif - tp->reordering =min_t (u32, (metric + mss -1 ) / mss, -READ_ONCE (sock_net (sk)->ipv4.sysctl_tcp_max_reordering)); +WRITE_ONCE (tp->reordering, +min_t (u32, (metric + mss -1 ) / mss, +READ_ONCE (sock_net (sk)->ipv4.sysctl_tcp_max_reordering))); }/* This exciting event is worth to be remembered. 8) */
@@ -2440,8 +2441,9 @@ static void tcp_check_reno_reordering(struct sock *sk, const int addend)if (!tcp_limit_reno_sacked (tp))return ; - tp->reordering =min_t (u32, tp->packets_out + addend, -READ_ONCE (sock_net (sk)->ipv4.sysctl_tcp_max_reordering)); +WRITE_ONCE (tp->reordering, +min_t (u32, tp->packets_out + addend, +READ_ONCE (sock_net (sk)->ipv4.sysctl_tcp_max_reordering))); tp->reord_seen++;NET_INC_STATS (sock_net (sk),LINUX_MIB_TCPRENOREORDER ); }
@@ -2580,8 +2582,8 @@ void tcp_enter_loss(struct sock *sk) reordering =READ_ONCE (net->ipv4.sysctl_tcp_reordering);if (icsk->icsk_ca_state <= TCP_CA_Disorder && tp->sacked_out >= reordering) - tp->reordering = min_t(unsigned int, tp->reordering, - reordering); +WRITE_ONCE (tp->reordering, + min_t(unsigned int, tp->reordering, reordering));tcp_set_ca_state (sk, TCP_CA_Loss); tp->high_seq = tp->snd_nxt;
net/ipv4/tcp_metrics.c +1 -1
@@ -496,7 +496,7 @@ void tcp_init_metrics(struct sock *sk) } val =tcp_metric_get (tm,TCP_METRIC_REORDERING );if (val && tp->reordering != val) - tp->reordering = val; +WRITE_ONCE (tp->reordering, val); crtt =tcp_metric_get (tm,TCP_METRIC_RTT );rcu_read_unlock ();
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 783/1146 tcp: annotate data-races around tp->snd_ssthresh
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit fd571afb05ebaeac5d8f09460a0640d4cf6755f8 ]
tcp_get_timestamping_opt_stats() intentionally runs lockless, we must add READ_ONCE() and WRITE_ONCE() annotations to keep KCSAN happy.
--- net/core/filter.c | 2 +- net/ipv4/tcp.c | 4 ++-- net/ipv4/tcp_bbr.c | 6 +++--- net/ipv4/tcp_bic.c | 2 +- net/ipv4/tcp_cdg.c | 4 ++-- net/ipv4/tcp_cubic.c | 6 +++--- net/ipv4/tcp_dctcp.c | 2 +- net/ipv4/tcp_input.c | 8 ++++---- net/ipv4/tcp_metrics.c | 4 ++-- net/ipv4/tcp_nv.c | 4 ++-- net/ipv4/tcp_output.c | 4 ++-- net/ipv4/tcp_vegas.c | 9 +++++---- net/ipv4/tcp_westwood.c | 4 ++-- net/ipv4/tcp_yeah.c | 3 ++- 14 files changed, 32 insertions(+), 30 deletions(-)
net/core/filter.c +1 -1
@@ -5397,7 +5397,7 @@ static int bpf_sol_tcp_setsockopt(struct sock *sk, int optname,if (val <=0 )return -EINVAL ; tp->snd_cwnd_clamp = val; - tp->snd_ssthresh = val; +WRITE_ONCE (tp->snd_ssthresh, val);break ;case TCP_BPF_DELACK_MAX : timeout =usecs_to_jiffies (val);
net/ipv4/tcp.c +2 -2
@@ -3458,7 +3458,7 @@ int tcp_disconnect(struct sock *sk, int flags) icsk->icsk_rto =TCP_TIMEOUT_INIT ;WRITE_ONCE (icsk->icsk_rto_min,TCP_RTO_MIN );WRITE_ONCE (icsk->icsk_delack_max,TCP_DELACK_MAX ); - tp->snd_ssthresh =TCP_INFINITE_SSTHRESH ; +WRITE_ONCE (tp->snd_ssthresh,TCP_INFINITE_SSTHRESH );tcp_snd_cwnd_set (tp,TCP_INIT_CWND ); tp->snd_cwnd_cnt =0 ; tp->is_cwnd_limited =0 ;
@@ -4486,7 +4486,7 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk,nla_put_u8 (stats,TCP_NLA_RECUR_RETRANS ,READ_ONCE (inet_csk (sk)->icsk_retransmits));nla_put_u8 (stats,TCP_NLA_DELIVERY_RATE_APP_LMT ,data_race (!!tp->rate_app_limited)); -nla_put_u32 (stats,TCP_NLA_SND_SSTHRESH , tp->snd_ssthresh); +nla_put_u32 (stats,TCP_NLA_SND_SSTHRESH ,READ_ONCE (tp->snd_ssthresh));nla_put_u32 (stats,TCP_NLA_DELIVERED , tp->delivered);nla_put_u32 (stats,TCP_NLA_DELIVERED_CE , tp->delivered_ce);
net/ipv4/tcp_bbr.c +3 -3
@@ -896,8 +896,8 @@ static void bbr_check_drain(struct sock *sk, const struct rate_sample *rs)if (bbr->mode ==BBR_STARTUP &&bbr_full_bw_reached (sk)) { bbr->mode =BBR_DRAIN ;/* drain queue we created */ -tcp_sk (sk)->snd_ssthresh = -bbr_inflight (sk,bbr_max_bw (sk),BBR_UNIT ); +WRITE_ONCE (tcp_sk (sk)->snd_ssthresh, +bbr_inflight (sk,bbr_max_bw (sk),BBR_UNIT )); }/* fall through to check if in-flight is already small: */ if (bbr->mode ==BBR_DRAIN && bbr_packets_in_net_at_edt(sk, tcp_packets_in_flight(tcp_sk(sk))) <=
@@ -1042,7 +1042,7 @@ __bpf_kfunc static void bbr_init(struct sock *sk)struct bbr *bbr =inet_csk_ca (sk); bbr->prior_cwnd =0 ; - tp->snd_ssthresh =TCP_INFINITE_SSTHRESH ; +WRITE_ONCE (tp->snd_ssthresh,TCP_INFINITE_SSTHRESH ); bbr->rtt_cnt =0 ; bbr->next_rtt_delivered = tp->delivered; bbr->prev_ca_state = TCP_CA_Open;
net/ipv4/tcp_bic.c +1 -1
@@ -74,7 +74,7 @@ static void bictcp_init(struct sock *sk)bictcp_reset (ca);if (initial_ssthresh) -tcp_sk (sk)->snd_ssthresh = initial_ssthresh; +WRITE_ONCE (tcp_sk (sk)->snd_ssthresh, initial_ssthresh); }/*
net/ipv4/tcp_cdg.c +2 -2
@@ -162,7 +162,7 @@ static void tcp_cdg_hystart_update(struct sock *sk)NET_ADD_STATS (sock_net (sk),LINUX_MIB_TCPHYSTARTTRAINCWND ,tcp_snd_cwnd (tp)); - tp->snd_ssthresh =tcp_snd_cwnd (tp); +WRITE_ONCE (tp->snd_ssthresh,tcp_snd_cwnd (tp));return ; } }
@@ -181,7 +181,7 @@ static void tcp_cdg_hystart_update(struct sock *sk)NET_ADD_STATS (sock_net (sk),LINUX_MIB_TCPHYSTARTDELAYCWND ,tcp_snd_cwnd (tp)); - tp->snd_ssthresh =tcp_snd_cwnd (tp); +WRITE_ONCE (tp->snd_ssthresh,tcp_snd_cwnd (tp)); } } }
net/ipv4/tcp_cubic.c +3 -3
@@ -136,7 +136,7 @@ __bpf_kfunc static void cubictcp_init(struct sock *sk)bictcp_hystart_reset (sk);if (!hystart && initial_ssthresh) -tcp_sk (sk)->snd_ssthresh = initial_ssthresh; +WRITE_ONCE (tcp_sk (sk)->snd_ssthresh, initial_ssthresh); } __bpf_kfunc static void cubictcp_cwnd_event(struct sock *sk, enum tcp_ca_event event)
@@ -423,7 +423,7 @@ static void hystart_update(struct sock *sk, u32 delay)NET_ADD_STATS (sock_net (sk),LINUX_MIB_TCPHYSTARTTRAINCWND ,tcp_snd_cwnd (tp)); - tp->snd_ssthresh =tcp_snd_cwnd (tp); +WRITE_ONCE (tp->snd_ssthresh,tcp_snd_cwnd (tp)); } } }
@@ -443,7 +443,7 @@ static void hystart_update(struct sock *sk, u32 delay)NET_ADD_STATS (sock_net (sk),LINUX_MIB_TCPHYSTARTDELAYCWND ,tcp_snd_cwnd (tp)); - tp->snd_ssthresh =tcp_snd_cwnd (tp); +WRITE_ONCE (tp->snd_ssthresh,tcp_snd_cwnd (tp)); } } }
net/ipv4/tcp_dctcp.c +1 -1
@@ -177,7 +177,7 @@ static void dctcp_react_to_loss(struct sock *sk)struct tcp_sock *tp =tcp_sk (sk); ca->loss_cwnd =tcp_snd_cwnd (tp); - tp->snd_ssthresh =max (tcp_snd_cwnd (tp) >>1U ,2U ); +WRITE_ONCE (tp->snd_ssthresh,max (tcp_snd_cwnd (tp) >>1U ,2U )); } __bpf_kfunc static void dctcp_state(struct sock *sk, u8 new_state)
net/ipv4/tcp_input.c +4 -4
@@ -2568,7 +2568,7 @@ void tcp_enter_loss(struct sock *sk) (icsk->icsk_ca_state == TCP_CA_Loss && !icsk->icsk_retransmits)) { tp->prior_ssthresh =tcp_current_ssthresh (sk); tp->prior_cwnd =tcp_snd_cwnd (tp); - tp->snd_ssthresh = icsk->icsk_ca_ops->ssthresh (sk); +WRITE_ONCE (tp->snd_ssthresh, icsk->icsk_ca_ops->ssthresh (sk));tcp_ca_event (sk,CA_EVENT_LOSS );tcp_init_undo (tp); }
@@ -2861,7 +2861,7 @@ static void tcp_undo_cwnd_reduction(struct sock *sk, bool unmark_loss)tcp_snd_cwnd_set (tp, icsk->icsk_ca_ops->undo_cwnd (sk));if (tp->prior_ssthresh > tp->snd_ssthresh) { - tp->snd_ssthresh = tp->prior_ssthresh; +WRITE_ONCE (tp->snd_ssthresh, tp->prior_ssthresh);tcp_ecn_withdraw_cwr (tp); } }
@@ -2979,7 +2979,7 @@ static void tcp_init_cwnd_reduction(struct sock *sk) tp->prior_cwnd =tcp_snd_cwnd (tp); tp->prr_delivered =0 ; tp->prr_out =0 ; - tp->snd_ssthresh =inet_csk (sk)->icsk_ca_ops->ssthresh (sk); +WRITE_ONCE (tp->snd_ssthresh,inet_csk (sk)->icsk_ca_ops->ssthresh (sk));tcp_ecn_queue_cwr (tp); }
@@ -3121,7 +3121,7 @@ static void tcp_non_congestion_loss_retransmit(struct sock *sk)if (icsk->icsk_ca_state != TCP_CA_Loss) { tp->high_seq = tp->snd_nxt; - tp->snd_ssthresh =tcp_current_ssthresh (sk); +WRITE_ONCE (tp->snd_ssthresh,tcp_current_ssthresh (sk)); tp->prior_ssthresh =0 ; tp->undo_marker =0 ;tcp_set_ca_state (sk, TCP_CA_Loss);
net/ipv4/tcp_metrics.c +2 -2
@@ -490,9 +490,9 @@ void tcp_init_metrics(struct sock *sk) val =READ_ONCE (net->ipv4.sysctl_tcp_no_ssthresh_metrics_save) ?0 :tcp_metric_get (tm,TCP_METRIC_SSTHRESH );if (val) { - tp->snd_ssthresh = val; +WRITE_ONCE (tp->snd_ssthresh, val);if (tp->snd_ssthresh > tp->snd_cwnd_clamp) - tp->snd_ssthresh = tp->snd_cwnd_clamp; +WRITE_ONCE (tp->snd_ssthresh, tp->snd_cwnd_clamp); } val =tcp_metric_get (tm,TCP_METRIC_REORDERING );if (val && tp->reordering != val)
net/ipv4/tcp_nv.c +2 -2
@@ -396,8 +396,8 @@ static void tcpnv_acked(struct sock *sk, const struct ack_sample *sample)/* We have enough data to determine we are congested */ ca->nv_allow_cwnd_growth =0 ; - tp->snd_ssthresh = - (nv_ssthresh_factor * max_win) >>3 ; +WRITE_ONCE (tp->snd_ssthresh, + (nv_ssthresh_factor * max_win) >>3 );if (tcp_snd_cwnd (tp) - max_win >2 ) {/* gap > 2, we do exponential cwnd decrease */ int dec;
net/ipv4/tcp_output.c +2 -2
@@ -171,7 +171,7 @@ void tcp_cwnd_restart(struct sock *sk, s32 delta)tcp_ca_event (sk,CA_EVENT_CWND_RESTART ); - tp->snd_ssthresh =tcp_current_ssthresh (sk); +WRITE_ONCE (tp->snd_ssthresh,tcp_current_ssthresh (sk)); restart_cwnd =min (restart_cwnd, cwnd);while ((delta -=inet_csk (sk)->icsk_rto) >0 && cwnd > restart_cwnd)
@@ -2125,7 +2125,7 @@ static void tcp_cwnd_application_limited(struct sock *sk)u32 init_win =tcp_init_cwnd (tp,__sk_dst_get (sk));u32 win_used =max (tp->snd_cwnd_used, init_win);if (win_used <tcp_snd_cwnd (tp)) { - tp->snd_ssthresh =tcp_current_ssthresh (sk); +WRITE_ONCE (tp->snd_ssthresh,tcp_current_ssthresh (sk));tcp_snd_cwnd_set (tp, (tcp_snd_cwnd (tp) + win_used) >>1 ); } tp->snd_cwnd_used =0 ;
net/ipv4/tcp_vegas.c +5 -4
@@ -240,7 +240,8 @@ static void tcp_vegas_cong_avoid(struct sock *sk, u32 ack, u32 acked)*/ tcp_snd_cwnd_set (tp,min (tcp_snd_cwnd (tp), (u32 )target_cwnd +1 )); - tp->snd_ssthresh =tcp_vegas_ssthresh (tp); +WRITE_ONCE (tp->snd_ssthresh, +tcp_vegas_ssthresh (tp)); }else if (tcp_in_slow_start (tp)) {/* Slow start. */
@@ -256,8 +257,8 @@ static void tcp_vegas_cong_avoid(struct sock *sk, u32 ack, u32 acked)* we slow down. */ tcp_snd_cwnd_set (tp,tcp_snd_cwnd (tp) -1 ); - tp->snd_ssthresh - =tcp_vegas_ssthresh (tp); +WRITE_ONCE (tp->snd_ssthresh, +tcp_vegas_ssthresh (tp)); }else if (diff < alpha) {/* We don't have enough extra packets * in the network, so speed up.
@@ -275,7 +276,7 @@ static void tcp_vegas_cong_avoid(struct sock *sk, u32 ack, u32 acked)else if (tcp_snd_cwnd (tp) > tp->snd_cwnd_clamp)tcp_snd_cwnd_set (tp, tp->snd_cwnd_clamp); - tp->snd_ssthresh =tcp_current_ssthresh (sk); +WRITE_ONCE (tp->snd_ssthresh,tcp_current_ssthresh (sk)); }/* Wipe the slate clean for the next RTT. */
net/ipv4/tcp_westwood.c +2 -2
@@ -244,11 +244,11 @@ static void tcp_westwood_event(struct sock *sk, enum tcp_ca_event event)switch (event) {case CA_EVENT_COMPLETE_CWR : - tp->snd_ssthresh =tcp_westwood_bw_rttmin (sk); +WRITE_ONCE (tp->snd_ssthresh,tcp_westwood_bw_rttmin (sk));tcp_snd_cwnd_set (tp, tp->snd_ssthresh);break ;case CA_EVENT_LOSS : - tp->snd_ssthresh =tcp_westwood_bw_rttmin (sk); +WRITE_ONCE (tp->snd_ssthresh,tcp_westwood_bw_rttmin (sk));/* Update RTT_min when next ack arrives */ w->reset_rtt_min =1 ;break ;
net/ipv4/tcp_yeah.c +2 -1
@@ -147,7 +147,8 @@ static void tcp_yeah_cong_avoid(struct sock *sk, u32 ack, u32 acked)tcp_snd_cwnd_set (tp,max (tcp_snd_cwnd (tp), yeah->reno_count)); - tp->snd_ssthresh =tcp_snd_cwnd (tp); +WRITE_ONCE (tp->snd_ssthresh, +tcp_snd_cwnd (tp)); }if (yeah->reno_count <=2 )
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 784/1146 tcp: annotate data-races around tp->delivered and tp->delivered_ce
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit faa886ad3ce5fc8f5156493491fe189b2b726bc9 ]
tcp_get_timestamping_opt_stats() intentionally runs lockless, we must add READ_ONCE() and WRITE_ONCE() annotations to keep KCSAN happy.
--- include/net/tcp_ecn.h | 2 +- net/ipv4/tcp.c | 4 ++-- net/ipv4/tcp_input.c | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-)
include/net/tcp_ecn.h +1 -1
@@ -181,7 +181,7 @@ static inline void tcp_accecn_third_ack(struct sock *sk, tcp_accecn_validate_syn_feedback(sk, ace, sent_ect)) {if ((tcp_accecn_extract_syn_ect (ace) ==INET_ECN_CE ) && !tp->delivered_ce) - tp->delivered_ce++; +WRITE_ONCE (tp->delivered_ce,1 ); }break ; }
net/ipv4/tcp.c +2 -2
@@ -4487,8 +4487,8 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk, READ_ONCE(inet_csk(sk)->icsk_retransmits));nla_put_u8 (stats,TCP_NLA_DELIVERY_RATE_APP_LMT ,data_race (!!tp->rate_app_limited));nla_put_u32 (stats,TCP_NLA_SND_SSTHRESH ,READ_ONCE (tp->snd_ssthresh)); -nla_put_u32 (stats,TCP_NLA_DELIVERED , tp->delivered); -nla_put_u32 (stats,TCP_NLA_DELIVERED_CE , tp->delivered_ce); +nla_put_u32 (stats,TCP_NLA_DELIVERED ,READ_ONCE (tp->delivered)); +nla_put_u32 (stats,TCP_NLA_DELIVERED_CE ,READ_ONCE (tp->delivered_ce));nla_put_u32 (stats,TCP_NLA_SNDQ_SIZE , tp->write_seq - tp->snd_una);nla_put_u8 (stats,TCP_NLA_CA_STATE ,inet_csk (sk)->icsk_ca_state);
net/ipv4/tcp_input.c +4 -4
@@ -476,14 +476,14 @@ static bool tcp_accecn_process_option(struct tcp_sock *tp,static void tcp_count_delivered_ce (struct tcp_sock *tp,u32 ecn_count) { - tp->delivered_ce += ecn_count; +WRITE_ONCE (tp->delivered_ce, tp->delivered_ce + ecn_count); }/* Updates the delivered and delivered_ce counts */ static void tcp_count_delivered (struct tcp_sock *tp,u32 delivered,bool ece_ack) { - tp->delivered += delivered; +WRITE_ONCE (tp->delivered, tp->delivered + delivered);if (tcp_ecn_mode_rfc3168 (tp) && ece_ack)tcp_count_delivered_ce (tp, delivered); }
@@ -6838,7 +6838,7 @@ static bool tcp_rcv_fastopen_synack(struct sock *sk, struct sk_buff *synack,NET_INC_STATS (sock_net (sk),LINUX_MIB_TCPFASTOPENACTIVE );/* SYN-data is counted as two separate packets in tcp_ack() */ if (tp->delivered >1 ) - --tp->delivered; +WRITE_ONCE (tp->delivered, tp->delivered -1 ); }tcp_fastopen_add_skb (sk, synack);
@@ -7269,7 +7269,7 @@ tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb)SKB_DR_SET (reason,NOT_SPECIFIED );switch (sk->sk_state) {case TCP_SYN_RECV : - tp->delivered++;/* SYN-ACK delivery isn't tracked in tcp_ack */ +WRITE_ONCE (tp->delivered, tp->delivered +1 );/* SYN-ACK delivery isn't tracked in tcp_ack */ if (!tp->srtt_us)tcp_synack_rtt_meas (sk, req);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 785/1146 tcp: add data-race annotations for TCP_NLA_SNDQ_SIZE
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit 124199444de467767175a9004e1574dc42523e62 ]
tcp_get_timestamping_opt_stats() intentionally runs lockless, we must add READ_ONCE() and WRITE_ONCE() annotations to keep KCSAN happy.
--- net/ipv4/tcp.c | 4 +++- net/ipv4/tcp_input.c | 4 ++-- net/ipv4/tcp_output.c | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-)
net/ipv4/tcp.c +3 -1
@@ -4490,7 +4490,9 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk,nla_put_u32 (stats,TCP_NLA_DELIVERED ,READ_ONCE (tp->delivered));nla_put_u32 (stats,TCP_NLA_DELIVERED_CE ,READ_ONCE (tp->delivered_ce)); -nla_put_u32 (stats,TCP_NLA_SNDQ_SIZE , tp->write_seq - tp->snd_una); +nla_put_u32 (stats,TCP_NLA_SNDQ_SIZE , +max_t (int,0 , +READ_ONCE (tp->write_seq) -READ_ONCE (tp->snd_una)));nla_put_u8 (stats,TCP_NLA_CA_STATE ,inet_csk (sk)->icsk_ca_state); nla_put_u64_64bit(stats, TCP_NLA_BYTES_SENT, tp->bytes_sent,
net/ipv4/tcp_input.c +2 -2
@@ -3914,7 +3914,7 @@ static void tcp_snd_una_update(struct tcp_sock *tp, u32 ack)sock_owned_by_me ((struct sock *)tp); tp->bytes_acked += delta;tcp_snd_sne_update (tp, ack); - tp->snd_una = ack; +WRITE_ONCE (tp->snd_una, ack); }static void tcp_rcv_sne_update (struct tcp_sock *tp,u32 seq)
@@ -7297,7 +7297,7 @@ tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb)if (sk->sk_socket)sk_wake_async (sk,SOCK_WAKE_IO ,POLL_OUT ); - tp->snd_una =TCP_SKB_CB (skb)->ack_seq; +WRITE_ONCE (tp->snd_una,TCP_SKB_CB (skb)->ack_seq); tp->snd_wnd =ntohs (th->window) << tp->rx_opt.snd_wscale;tcp_init_wl (tp,TCP_SKB_CB (skb)->seq);
net/ipv4/tcp_output.c +1 -1
@@ -4136,7 +4136,7 @@ static void tcp_connect_init(struct sock *sk) tp->snd_wnd =0 ;tcp_init_wl (tp,0 );tcp_write_queue_purge (sk); - tp->snd_una = tp->write_seq; +WRITE_ONCE (tp->snd_una, tp->write_seq); tp->snd_sml = tp->write_seq; tp->snd_up = tp->write_seq;WRITE_ONCE (tp->snd_nxt, tp->write_seq);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 786/1146 tcp: annotate data-races around tp->bytes_sent
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit ee43e957ce2ec77b2ec47fef28f3c0df6ab01a31 ]
tcp_get_timestamping_opt_stats() intentionally runs lockless, we must add READ_ONCE() and WRITE_ONCE() annotations to keep KCSAN happy.
--- net/ipv4/tcp.c | 2 +- net/ipv4/tcp_output.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-)
net/ipv4/tcp.c +1 -1
@@ -4495,7 +4495,7 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk, READ_ONCE(tp->write_seq) - READ_ONCE(tp->snd_una)));nla_put_u8 (stats,TCP_NLA_CA_STATE ,inet_csk (sk)->icsk_ca_state); -nla_put_u64_64bit (stats,TCP_NLA_BYTES_SENT , tp->bytes_sent, +nla_put_u64_64bit (stats,TCP_NLA_BYTES_SENT ,READ_ONCE (tp->bytes_sent),TCP_NLA_PAD );nla_put_u64_64bit (stats,TCP_NLA_BYTES_RETRANS , tp->bytes_retrans,TCP_NLA_PAD );
net/ipv4/tcp_output.c +2 -1
@@ -1670,7 +1670,8 @@ static int __tcp_transmit_skb(struct sock *sk, struct sk_buff *skb,tcp_event_data_sent (tp, sk);WRITE_ONCE (tp->data_segs_out, tp->data_segs_out +tcp_skb_pcount (skb)); - tp->bytes_sent += skb->len - tcp_header_size; +WRITE_ONCE (tp->bytes_sent, + tp->bytes_sent + skb->len - tcp_header_size); }if (after (tcb->end_seq, tp->snd_nxt) || tcb->seq == tcb->end_seq)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 787/1146 tcp: annotate data-races around tp->bytes_retrans
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit 5efc7b9f7cbd43401f1af81d3d7f2be00f93390d ]
tcp_get_timestamping_opt_stats() intentionally runs lockless, we must add READ_ONCE() and WRITE_ONCE() annotations to keep KCSAN happy.
--- net/ipv4/tcp.c | 4 ++-- net/ipv4/tcp_output.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-)
net/ipv4/tcp.c +2 -2
@@ -4497,8 +4497,8 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk,nla_put_u64_64bit (stats,TCP_NLA_BYTES_SENT ,READ_ONCE (tp->bytes_sent),TCP_NLA_PAD ); -nla_put_u64_64bit (stats,TCP_NLA_BYTES_RETRANS , tp->bytes_retrans, -TCP_NLA_PAD ); +nla_put_u64_64bit (stats,TCP_NLA_BYTES_RETRANS , +READ_ONCE (tp->bytes_retrans),TCP_NLA_PAD );nla_put_u32 (stats,TCP_NLA_DSACK_DUPS , tp->dsack_dups);nla_put_u32 (stats,TCP_NLA_REORD_SEEN , tp->reord_seen);nla_put_u32 (stats,TCP_NLA_SRTT , tp->srtt_us >>3 );
net/ipv4/tcp_output.c +1 -1
@@ -3627,7 +3627,7 @@ int __tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb, int segs)if (TCP_SKB_CB (skb)->tcp_flags &TCPHDR_SYN )__NET_INC_STATS (sock_net (sk),LINUX_MIB_TCPSYNRETRANS );WRITE_ONCE (tp->total_retrans, tp->total_retrans + segs); - tp->bytes_retrans += skb->len; +WRITE_ONCE (tp->bytes_retrans, tp->bytes_retrans + skb->len);/* make sure skb->data is aligned on arches that require it * and check if ack-trimming & collapsing extended the headroom
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 788/1146 tcp: annotate data-races around tp->dsack_dups
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit a984705ca88b976bf1087978fd98b7f3993da88c ]
tcp_get_timestamping_opt_stats() intentionally runs lockless, we must add READ_ONCE() and WRITE_ONCE() annotations to keep KCSAN happy.
--- net/ipv4/tcp.c | 2 +- net/ipv4/tcp_input.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-)
net/ipv4/tcp.c +1 -1
@@ -4499,7 +4499,7 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk, TCP_NLA_PAD);nla_put_u64_64bit (stats,TCP_NLA_BYTES_RETRANS ,READ_ONCE (tp->bytes_retrans),TCP_NLA_PAD ); -nla_put_u32 (stats,TCP_NLA_DSACK_DUPS , tp->dsack_dups); +nla_put_u32 (stats,TCP_NLA_DSACK_DUPS ,READ_ONCE (tp->dsack_dups));nla_put_u32 (stats,TCP_NLA_REORD_SEEN , tp->reord_seen);nla_put_u32 (stats,TCP_NLA_SRTT , tp->srtt_us >>3 );nla_put_u16 (stats,TCP_NLA_TIMEOUT_REHASH , tp->timeout_rehash);
net/ipv4/tcp_input.c +1 -1
@@ -1247,7 +1247,7 @@ static u32 tcp_dsack_seen(struct tcp_sock *tp, u32 start_seq,else if (tp->tlp_high_seq && tp->tlp_high_seq == end_seq) state->flag |=FLAG_DSACK_TLP ; - tp->dsack_dups += dup_segs; +WRITE_ONCE (tp->dsack_dups, tp->dsack_dups + dup_segs);/* Skip the DSACK if dup segs weren't retransmitted by sender */ if (tp->dsack_dups > tp->total_retrans)return 0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 789/1146 tcp: annotate data-races around tp->reord_seen
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit 62585690e6b2a112c408fe25f142b246ac833c42 ]
tcp_get_timestamping_opt_stats() intentionally runs lockless, we must add READ_ONCE() and WRITE_ONCE() annotations to keep KCSAN happy.
--- net/ipv4/tcp.c | 2 +- net/ipv4/tcp_input.c | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-)
net/ipv4/tcp.c +1 -1
@@ -4500,7 +4500,7 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk,nla_put_u64_64bit (stats,TCP_NLA_BYTES_RETRANS ,READ_ONCE (tp->bytes_retrans),TCP_NLA_PAD );nla_put_u32 (stats,TCP_NLA_DSACK_DUPS ,READ_ONCE (tp->dsack_dups)); -nla_put_u32 (stats,TCP_NLA_REORD_SEEN , tp->reord_seen); +nla_put_u32 (stats,TCP_NLA_REORD_SEEN ,READ_ONCE (tp->reord_seen));nla_put_u32 (stats,TCP_NLA_SRTT , tp->srtt_us >>3 );nla_put_u16 (stats,TCP_NLA_TIMEOUT_REHASH , tp->timeout_rehash); nla_put_u32(stats, TCP_NLA_BYTES_NOTSENT,
net/ipv4/tcp_input.c +2 -2
@@ -1300,7 +1300,7 @@ static void tcp_check_sack_reordering(struct sock *sk, const u32 low_seq, }/* This exciting event is worth to be remembered. 8) */ - tp->reord_seen++; +WRITE_ONCE (tp->reord_seen, tp->reord_seen +1 );NET_INC_STATS (sock_net (sk), ts ?LINUX_MIB_TCPTSREORDER :LINUX_MIB_TCPSACKREORDER ); }
@@ -2444,7 +2444,7 @@ static void tcp_check_reno_reordering(struct sock *sk, const int addend)WRITE_ONCE (tp->reordering,min_t (u32, tp->packets_out + addend,READ_ONCE (sock_net (sk)->ipv4.sysctl_tcp_max_reordering))); - tp->reord_seen++; +WRITE_ONCE (tp->reord_seen, tp->reord_seen +1 );NET_INC_STATS (sock_net (sk),LINUX_MIB_TCPRENOREORDER ); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 790/1146 tcp: annotate data-races around tp->srtt_us
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit 290b693ce7c9d48588d88b15a782a3efc6fa036b ]
tcp_get_timestamping_opt_stats() intentionally runs lockless, we must add READ_ONCE() and WRITE_ONCE() annotations to keep KCSAN happy.
--- net/ipv4/tcp.c | 5 +++-- net/ipv4/tcp_input.c | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-)
net/ipv4/tcp.c +3 -2
@@ -3656,7 +3656,8 @@ static void tcp_enable_tx_delay(struct sock *sk, int val)if (delta && sk->sk_state ==TCP_ESTABLISHED ) {s64 srtt = (s64 )tp->srtt_us + delta; - tp->srtt_us =clamp_t (s64, srtt,1 , ~0U ); +WRITE_ONCE (tp->srtt_us, +clamp_t (s64, srtt,1 , ~0U ));/* Note: does not deal with non zero icsk_backoff */ tcp_set_rto (sk);
@@ -4501,7 +4502,7 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk, READ_ONCE(tp->bytes_retrans), TCP_NLA_PAD);nla_put_u32 (stats,TCP_NLA_DSACK_DUPS ,READ_ONCE (tp->dsack_dups));nla_put_u32 (stats,TCP_NLA_REORD_SEEN ,READ_ONCE (tp->reord_seen)); -nla_put_u32 (stats,TCP_NLA_SRTT , tp->srtt_us >>3 ); +nla_put_u32 (stats,TCP_NLA_SRTT ,READ_ONCE (tp->srtt_us) >>3 );nla_put_u16 (stats,TCP_NLA_TIMEOUT_REHASH , tp->timeout_rehash);nla_put_u32 (stats,TCP_NLA_BYTES_NOTSENT ,max_t (int,0 , tp->write_seq - tp->snd_nxt));
net/ipv4/tcp_input.c +1 -1
@@ -1133,7 +1133,7 @@ static void tcp_rtt_estimator(struct sock *sk, long mrtt_us)tcp_bpf_rtt (sk, mrtt_us, srtt); } - tp->srtt_us =max (1U , srtt); +WRITE_ONCE (tp->srtt_us,max (1U , srtt)); }void tcp_update_pacing_rate (struct sock *sk)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 791/1146 tcp: annotate data-races around tp->timeout_rehash
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit 71c675358b711bbfd8528949249419dc2dfa4ce1 ]
tcp_get_timestamping_opt_stats() intentionally runs lockless, we must add READ_ONCE() and WRITE_ONCE() annotations to keep KCSAN happy.
--- net/ipv4/tcp.c | 3 ++- net/ipv4/tcp_timer.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-)
net/ipv4/tcp.c +2 -1
@@ -4503,7 +4503,8 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk,nla_put_u32 (stats,TCP_NLA_DSACK_DUPS ,READ_ONCE (tp->dsack_dups));nla_put_u32 (stats,TCP_NLA_REORD_SEEN ,READ_ONCE (tp->reord_seen));nla_put_u32 (stats,TCP_NLA_SRTT ,READ_ONCE (tp->srtt_us) >>3 ); -nla_put_u16 (stats,TCP_NLA_TIMEOUT_REHASH , tp->timeout_rehash); +nla_put_u16 (stats,TCP_NLA_TIMEOUT_REHASH , +READ_ONCE (tp->timeout_rehash));nla_put_u32 (stats,TCP_NLA_BYTES_NOTSENT ,max_t (int,0 , tp->write_seq - tp->snd_nxt)); nla_put_u64_64bit(stats, TCP_NLA_EDT, orig_skb->skb_mstamp_ns,
net/ipv4/tcp_timer.c +1 -1
@@ -297,7 +297,7 @@ static int tcp_write_timeout(struct sock *sk) }if (sk_rethink_txhash (sk)) { - tp->timeout_rehash++; +WRITE_ONCE (tp->timeout_rehash, tp->timeout_rehash +1 );__NET_INC_STATS (sock_net (sk),LINUX_MIB_TCPTIMEOUTREHASH ); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 792/1146 tcp: annotate data-races around (tp->write_seq - tp->snd_nxt)
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit 3a63b3d160560ef51e43fb4c880a5cde8078053c ]
tcp_get_timestamping_opt_stats() intentionally runs lockless, we must add READ_ONCE() annotations to keep KCSAN happy.
WRITE_ONCE() annotations are already present.
--- net/ipv4/tcp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
net/ipv4/tcp.c +2 -1
@@ -4506,7 +4506,8 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk,nla_put_u16 (stats,TCP_NLA_TIMEOUT_REHASH ,READ_ONCE (tp->timeout_rehash));nla_put_u32 (stats,TCP_NLA_BYTES_NOTSENT , -max_t (int,0 , tp->write_seq - tp->snd_nxt)); +max_t (int,0 , +READ_ONCE (tp->write_seq) -READ_ONCE (tp->snd_nxt)));nla_put_u64_64bit (stats,TCP_NLA_EDT , orig_skb->skb_mstamp_ns,TCP_NLA_PAD );if (ack_skb)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 793/1146 tcp: annotate data-races around tp->plb_rehash
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit 9e89b9d03a2d2e30dcca166d5af52f9a8eceab25 ]
tcp_get_timestamping_opt_stats() intentionally runs lockless, we must add READ_ONCE() and WRITE_ONCE() annotations to keep KCSAN happy.
--- net/ipv4/tcp.c | 3 ++- net/ipv4/tcp_plb.c | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-)
net/ipv4/tcp.c +2 -1
@@ -4514,7 +4514,8 @@ struct sk_buff *tcp_get_timestamping_opt_stats(const struct sock *sk,nla_put_u8 (stats,TCP_NLA_TTL ,tcp_skb_ttl_or_hop_limit (ack_skb)); -nla_put_u32 (stats,TCP_NLA_REHASH , tp->plb_rehash + tp->timeout_rehash); +nla_put_u32 (stats,TCP_NLA_REHASH , +READ_ONCE (tp->plb_rehash) +READ_ONCE (tp->timeout_rehash));return stats; }
net/ipv4/tcp_plb.c +1 -1
@@ -79,7 +79,7 @@ void tcp_plb_check_rehash(struct sock *sk, struct tcp_plb_state *plb)sk_rethink_txhash (sk); plb->consec_cong_rounds =0 ; -tcp_sk (sk)->plb_rehash++; +WRITE_ONCE (tcp_sk (sk)->plb_rehash,tcp_sk (sk)->plb_rehash +1 );NET_INC_STATS (sock_net (sk),LINUX_MIB_TCPPLBREHASH ); }EXPORT_SYMBOL_GPL (tcp_plb_check_rehash);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 794/1146 ice: fix adjust timer programming for E830 devices
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Grzegorz Nitka <[email protected]>
[ Upstream commit 885c5e57924dc040b23d0ad0d8388f0e35772159 ]
Fix incorrect 'adjust the timer' programming sequence for E830 devices series. Only shadow registers GLTSYN_SHADJ were programmed in the current implementation. According to the specification [1], write to command GLTSYN_CMD register is also required with CMD field set to "Adjust the Time" value, for the timer adjustment to take the effect.
The flow was broken for the adjustment less than S32_MAX/MIN range (around +/- 2 seconds). For bigger adjustment, non-atomic programming flow is used, involving set timer programming. Non-atomic flow is implemented correctly.
Testing hints:
Run command:
phc_ctl /dev/ptpX get adj 2 get
Expected result:
Returned timestamps differ at least by 2 seconds
[1] Intel® Ethernet Controller E830 Datasheet rev 1.3, chapter 9.7.5.4
https://cdrdv2.intel.com/v1/dl/getContent/787353?explicitVersion=true
--- drivers/net/ethernet/intel/ice/ice_ptp_hw.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/net/ethernet/intel/ice/ice_ptp_hw.c +3 -3
@@ -5381,8 +5381,8 @@ int ice_ptp_write_incval_locked(struct ice_hw *hw, u64 incval)*/ int ice_ptp_adj_clock (struct ice_hw *hw,s32 adj) { +int err =0 ;u8 tmr_idx; -int err; tmr_idx = hw->func_caps.ts_func_info.tmr_index_owned;
@@ -5399,8 +5399,8 @@ int ice_ptp_adj_clock(struct ice_hw *hw, s32 adj) err =ice_ptp_prep_phy_adj_e810 (hw, adj);break ;case ICE_MAC_E830 : -/* E830 sync PHYs automatically after setting GLTSYN_SHADJ */ -return 0 ; +/* E830 sync PHYs automatically after setting cmd register */ +break ;case ICE_MAC_GENERIC : err =ice_ptp_prep_phy_adj_e82x (hw, adj);break ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 795/1146 ice: update PCS latency settings for E825 10G/25Gb modes
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Grzegorz Nitka <[email protected]>
[ Upstream commit 05567e4052732d70c7ff9655217b3d14d25f639a ]
Update MAC Rx/Tx offset registers settings (PHY_MAC_[RX|TX]_OFFSET registers) with the data obtained with the latest research. It applies to PCS latency settings for the following speeds/modes:
* 10Gb NO-FEC
- TX latency changed from 71.25 ns to 73 ns
- RX latency changed from -25.6 ns to -28 ns
* 25Gb NO-FEC
- TX latency changed from 28.17 ns to 33 ns
- RX latency changed from -12.45 ns to -12 ns
* 25Gb RS-FEC
- TX latency changed from 64.5 ns to 69 ns
- RX latency changed from -3.6 ns to -3 ns
The original data came from simulation and pre-production hardware. The new data measures the actual delays and as such is more accurate.
--- drivers/net/ethernet/intel/ice/ice_ptp_consts.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-)
drivers/net/ethernet/intel/ice/ice_ptp_consts.h +6 -6
@@ -78,14 +78,14 @@ struct ice_eth56g_mac_reg_cfg eth56g_mac_cfg[NUM_ICE_ETH56G_LNK_SPD] = { .blktime = 0x666, /* 3.2 */ .tx_offset = { .serdes = 0x234c, /* 17.6484848 */ - .no_fec = 0x8e80, /* 71.25 */ + .no_fec = 0x93d9, /* 73 */ .fc = 0xb4a4, /* 90.32 */ .sfd = 0x4a4, /* 2.32 */ .onestep =0x4ccd /* 38.4 */ }, .rx_offset = { .serdes = 0xffffeb27, /* -10.42424 */ - .no_fec = 0xffffcccd, /* -25.6 */ + .no_fec = 0xffffc7b6, /* -28 */ .fc = 0xfffc557b, /* -469.26 */ .sfd =0x4a4 ,/* 2.32 */ .bs_ds = 0x32 /* 0.0969697 */
@@ -118,17 +118,17 @@ struct ice_eth56g_mac_reg_cfg eth56g_mac_cfg[NUM_ICE_ETH56G_LNK_SPD] = { .mktime = 0x147b, /* 10.24, only if RS-FEC enabled */ .tx_offset = { .serdes = 0xe1e, /* 7.0593939 */ - .no_fec = 0x3857, /* 28.17 */ + .no_fec = 0x4266, /* 33 */ .fc = 0x48c3, /* 36.38 */ - .rs = 0x8100, /* 64.5 */ + .rs = 0x8a00, /* 69 */ .sfd = 0x1dc, /* 0.93 */ .onestep =0x1eb8 /* 15.36 */ }, .rx_offset = { .serdes = 0xfffff7a9, /* -4.1697 */ - .no_fec = 0xffffe71a, /* -12.45 */ + .no_fec = 0xffffe700, /* -12 */ .fc = 0xfffe894d, /* -187.35 */ - .rs = 0xfffff8cd, /* -3.6 */ + .rs = 0xfffff8cc, /* -3 */ .sfd = 0x1dc, /* 0.93 */ .bs_ds =0x14 /* 0.0387879, RS-FEC 0 */ }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 796/1146 ice: fix double-free of tx_buf skb
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michal Schmidt <[email protected]>
[ Upstream commit 1a303baa715e6b78d6a406aaf335f87ff35acfcd ]
If ice_tso() or ice_tx_csum() fail, the error path in ice_xmit_frame_ring() frees the skb, but the 'first' tx_buf still points to it and is marked as valid (ICE_TX_BUF_SKB).
'next_to_use' remains unchanged, so the potential problem will likely fix itself when the next packet is transmitted and the tx_buf gets overwritten. But if there is no next packet and the interface is brought down instead, ice_clean_tx_ring() -> ice_unmap_and_free_tx_buf() will find the tx_buf and free the skb for the second time.
The fix is to reset the tx_buf type to ICE_TX_BUF_EMPTY in the error path, so that ice_unmap_and_free_tx_buf().
Move the initialization of 'first' up, to ensure it's already valid in case we hit the linearization error path.
The bug was spotted by AI while I had it looking for something else. It also proposed an initial version of the patch.
I reproduced the bug and tested the fix by adding code to inject failures, on a build with KASAN.
I looked for similar bugs in related Intel drivers and did not find any.
--- drivers/net/ethernet/intel/ice/ice_txrx.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/net/ethernet/intel/ice/ice_txrx.c +4 -2
@@ -2158,6 +2158,9 @@ ice_xmit_frame_ring(struct sk_buff *skb, struct ice_tx_ring *tx_ring)ice_trace (xmit_frame_ring, tx_ring, skb); +/* record the location of the first descriptor for this packet */ + first = &tx_ring->tx_buf[tx_ring->next_to_use]; + count =ice_xmit_desc_count (skb);if (ice_chk_linearize (skb, count)) {if (__skb_linearize (skb))
@@ -2183,8 +2186,6 @@ ice_xmit_frame_ring(struct sk_buff *skb, struct ice_tx_ring *tx_ring) offload.tx_ring = tx_ring; -/* record the location of the first descriptor for this packet */ - first = &tx_ring->tx_buf[tx_ring->next_to_use]; first->skb = skb; first->type =ICE_TX_BUF_SKB ; first->bytecount = max_t(unsigned int, skb->len, ETH_ZLEN);
@@ -2249,6 +2250,7 @@ ice_xmit_frame_ring(struct sk_buff *skb, struct ice_tx_ring *tx_ring) out_drop:ice_trace (xmit_frame_ring_drop, tx_ring, skb);dev_kfree_skb_any (skb); + first->type =ICE_TX_BUF_EMPTY ;return NETDEV_TX_OK ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 797/1146 ice: fix PHY config on media change with link-down-on-close
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Paul Greenwalt <[email protected]>
[ Upstream commit 55e74f9ea7fea3d3da1cb6d5cacdaf8cf0fe3516 ]
Commit 1a3571b5938c ("ice: restore PHY settings on media insertion") introduced separate flows for setting PHY configuration on media
present: ice_configure_phy() when link-down-on-close is disabled, and ice_force_phys_link_state() when enabled. The latter incorrectly uses the previous configuration even after module change, causing link issues such as wrong speed or no link.
Unify PHY configuration into a single ice_phy_cfg() function with a link_en parameter, ensuring PHY capabilities are always fetched fresh from hardware.
--- drivers/net/ethernet/intel/ice/ice_main.c | 121 +++++----------------- 1 file changed, 27 insertions(+), 94 deletions(-)
drivers/net/ethernet/intel/ice/ice_main.c +27 -94
@@ -1922,82 +1922,6 @@ static void ice_handle_mdd_event(struct ice_pf *pf)ice_print_vfs_mdd_events (pf); } -/** -* ice_force_phys_link_state - Force the physical link state -* @vsi: VSI to force the physical link state to up/down -* @link_up: true/false indicates to set the physical link to up/down -* -* Force the physical link state by getting the current PHY capabilities from -* hardware and setting the PHY config based on the determined capabilities. If -* link changes a link event will be triggered because both the Enable Automatic -* Link Update and LESM Enable bits are set when setting the PHY capabilities. -* -* Returns 0 on success, negative on failure -*/ -static int ice_force_phys_link_state (struct ice_vsi *vsi,bool link_up) -{ -struct ice_aqc_get_phy_caps_data *pcaps; -struct ice_aqc_set_phy_cfg_data *cfg; -struct ice_port_info *pi; -struct device *dev; -int retcode; - -if (!vsi || !vsi->port_info || !vsi->back) -return -EINVAL ; -if (vsi->type !=ICE_VSI_PF ) -return 0 ; - - dev =ice_pf_to_dev (vsi->back); - - pi = vsi->port_info; - - pcaps =kzalloc_obj (*pcaps); -if (!pcaps) -return -ENOMEM ; - - retcode =ice_aq_get_phy_caps (pi, false,ICE_AQC_REPORT_ACTIVE_CFG , pcaps, -NULL ); -if (retcode) { -dev_err (dev,"Failed to get phy capabilities, VSI %d error %d\n" , - vsi->vsi_num, retcode); - retcode = -EIO ; - goto out; - } - -/* No change in link */ -if (link_up == !!(pcaps->caps &ICE_AQC_PHY_EN_LINK ) && - link_up == !!(pi->phy.link_info.link_info &ICE_AQ_LINK_UP )) - goto out; - -/* Use the current user PHY configuration. The current user PHY -* configuration is initialized during probe from PHY capabilities -* software mode, and updated on set PHY configuration. -*/ - cfg =kmemdup (&pi->phy.curr_user_phy_cfg,sizeof (*cfg),GFP_KERNEL ); -if (!cfg) { - retcode = -ENOMEM ; - goto out; - } - - cfg->caps |=ICE_AQ_PHY_ENA_AUTO_LINK_UPDT ; -if (link_up) - cfg->caps |=ICE_AQ_PHY_ENA_LINK ; -else - cfg->caps &= ~ICE_AQ_PHY_ENA_LINK ; - - retcode =ice_aq_set_phy_cfg (&vsi->back->hw, pi, cfg,NULL ); -if (retcode) { -dev_err (dev,"Failed to set phy config, VSI %d error %d\n" , - vsi->vsi_num, retcode); - retcode = -EIO ; - } - -kfree (cfg); -out: -kfree (pcaps); -return retcode; -} -/** * ice_init_nvm_phy_type - Initialize the NVM PHY type * @pi: port info structure
@@ -2066,7 +1990,7 @@ static void ice_init_link_dflt_override(struct ice_port_info *pi)* first time media is available. The ICE_LINK_DEFAULT_OVERRIDE_PENDING state * is used to indicate that the user PHY cfg default override is initialized * and the PHY has not been configured with the default override settings. The -* state is set here, and cleared in ice_configure_phy the first time the PHY is +* state is set here, and cleared in ice_phy_cfg the first time the PHY is * configured. * * This function should be called only if the FW doesn't support default
@@ -2172,14 +2096,18 @@ static int ice_init_phy_user_cfg(struct ice_port_info *pi) }/** -* ice_configure_phy - configure PHY +* ice_phy_cfg - configure PHY * @vsi: VSI of PHY +* @link_en: true/false indicates to set link to enable/disable * * Set the PHY configuration. If the current PHY configuration is the same as -* the curr_user_phy_cfg, then do nothing to avoid link flap. Otherwise -* configure the based get PHY capabilities for topology with media. +* the curr_user_phy_cfg and link_en hasn't changed, then do nothing to avoid +* link flap. Otherwise configure the PHY based get PHY capabilities for +* topology with media and link_en. +* +* Return: 0 on success, negative on failure */ -static int ice_configure_phy (struct ice_vsi *vsi) +static int ice_phy_cfg (struct ice_vsi *vsi,bool link_en) {struct device *dev =ice_pf_to_dev (vsi->back);struct ice_port_info *pi = vsi->port_info;
@@ -2199,9 +2127,6 @@ static int ice_configure_phy(struct ice_vsi *vsi) phy->link_info.topo_media_conflict == ICE_AQ_LINK_TOPO_UNSUPP_MEDIA)return -EPERM ; -if (test_bit (ICE_FLAG_LINK_DOWN_ON_CLOSE_ENA , pf->flags)) -return ice_force_phys_link_state (vsi, true); - pcaps =kzalloc_obj (*pcaps);if (!pcaps)return -ENOMEM ;
@@ -2215,10 +2140,8 @@ static int ice_configure_phy(struct ice_vsi *vsi) goto done; } -/* If PHY enable link is configured and configuration has not changed, -* there's nothing to do -*/ -if (pcaps->caps &ICE_AQC_PHY_EN_LINK && +/* Configuration has not changed. There's nothing to do. */ +if (link_en == !!(pcaps->caps &ICE_AQC_PHY_EN_LINK ) &&ice_phy_caps_equals_cfg (pcaps, &phy->curr_user_phy_cfg)) goto done;
@@ -2282,8 +2205,12 @@ static int ice_configure_phy(struct ice_vsi *vsi)*/ ice_cfg_phy_fc (pi, cfg, phy->curr_user_fc_req); -/* Enable link and link update */ - cfg->caps |=ICE_AQ_PHY_ENA_AUTO_LINK_UPDT |ICE_AQ_PHY_ENA_LINK ; +/* Enable/Disable link and link update */ + cfg->caps |=ICE_AQ_PHY_ENA_AUTO_LINK_UPDT ; +if (link_en) + cfg->caps |=ICE_AQ_PHY_ENA_LINK ; +else + cfg->caps &= ~ICE_AQ_PHY_ENA_LINK ; err =ice_aq_set_phy_cfg (&pf->hw, pi, cfg,NULL );if (err)
@@ -2336,7 +2263,7 @@ static void ice_check_media_subtask(struct ice_pf *pf) test_bit(ICE_FLAG_LINK_DOWN_ON_CLOSE_ENA, vsi->back->flags)) return; - err =ice_configure_phy (vsi); + err =ice_phy_cfg (vsi, true);if (!err)clear_bit (ICE_FLAG_NO_MEDIA , pf->flags);
@@ -4892,9 +4819,15 @@ static int ice_init_link(struct ice_pf *pf)if (!test_bit (ICE_FLAG_LINK_DOWN_ON_CLOSE_ENA , pf->flags)) {struct ice_vsi *vsi =ice_get_main_vsi (pf); +struct ice_link_default_override_tlv *ldo; +bool link_en; + + ldo = &pf->link_dflt_override; + link_en = !(ldo->options & +ICE_LINK_OVERRIDE_AUTO_LINK_DIS );if (vsi) -ice_configure_phy (vsi); +ice_phy_cfg (vsi, link_en); } }else {set_bit (ICE_FLAG_NO_MEDIA , pf->flags);
@@ -9707,7 +9640,7 @@ int ice_open_internal(struct net_device *netdev) } } - err =ice_configure_phy (vsi); + err =ice_phy_cfg (vsi, true);if (err) {netdev_err (netdev,"Failed to set physical link up, error %d\n" , err);
@@ -9748,7 +9681,7 @@ int ice_stop(struct net_device *netdev) }if (test_bit (ICE_FLAG_LINK_DOWN_ON_CLOSE_ENA , vsi->back->flags)) { -int link_err =ice_force_phys_link_state (vsi, false); +int link_err =ice_phy_cfg (vsi, false);if (link_err) {if (link_err == -ENOMEDIUM )
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 798/1146 ice: fix ICE_AQ_LINK_SPEED_M for 200G
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Paul Greenwalt <[email protected]>
[ Upstream commit 4a3a940059e98539de293a6e36e464094c2e875b ]
When setting PHY configuration during driver initialization, 200G link speed is not being advertised even when the PHY is capable. This is because the get PHY capabilities link speed response is being masked by ICE_AQ_LINK_SPEED_M, which does not include the 200G link speed bit.
ICE_AQ_LINK_SPEED_200GB is defined as BIT(11), but the mask 0x7FF only covers bits 0-10. Fix ICE_AQ_LINK_SPEED_M to use GENMASK(11, 0) so that it covers all defined link speed bits including 200G.
--- drivers/net/ethernet/intel/ice/ice_adminq_cmd.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/ethernet/intel/ice/ice_adminq_cmd.h +1 -1
@@ -1252,7 +1252,7 @@ struct ice_aqc_get_link_status_data {#define ICE_AQ_LINK_PWR_QSFP_CLASS_3 2#define ICE_AQ_LINK_PWR_QSFP_CLASS_4 3__le16 link_speed; -#define ICE_AQ_LINK_SPEED_M 0x7FF +#define ICE_AQ_LINK_SPEED_M GENMASK(11, 0)#define ICE_AQ_LINK_SPEED_10MB BIT(0)#define ICE_AQ_LINK_SPEED_100MB BIT(1)#define ICE_AQ_LINK_SPEED_1000MB BIT(2)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 799/1146 ice: fix race condition in TX timestamp ring cleanup
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Keita Morisaki <[email protected]>
[ Upstream commit 7c72ec18c2a4111204c2e915f8e4f6d849ce9398 ]
Fix a race condition between ice_free_tx_tstamp_ring() and ice_tx_map() that can cause a NULL pointer dereference.
ice_free_tx_tstamp_ring currently clears the ICE_TX_FLAGS_TXTIME flag after NULLing the tstamp_ring. This could allow a concurrent ice_tx_map call on another CPU to dereference the tstamp_ring, which could lead to a NULL pointer dereference.
CPU A:ice_free_tx_tstamp_ring() | CPU B:ice_tx_map()
--------------------------------|---------------------------------
tx_ring->tstamp_ring = NULL |
| ice_is_txtime_cfg() -> true
| tstamp_ring = tx_ring->tstamp_ring
| tstamp_ring->count // NULL deref!
flags &= ~ICE_TX_FLAGS_TXTIME |Fix by:
1. Reordering ice_free_tx_tstamp_ring() to clear the flag before NULLing the pointer, with smp_wmb() to ensure proper ordering.
2. Adding smp_rmb() in ice_tx_map() after the flag check to order the flag read before the pointer read, using READ_ONCE() for the pointer, and adding a NULL check as a safety net.
3. Converting tx_ring->flags from u8 to DECLARE_BITMAP() and using atomic bitops (set_bit(), clear_bit(), test_bit()) for all flag operations throughout the driver:
- ICE_TX_RING_FLAGS_XDP
- ICE_TX_RING_FLAGS_VLAN_L2TAG1
- ICE_TX_RING_FLAGS_VLAN_L2TAG2
- ICE_TX_RING_FLAGS_TXTIME
--- drivers/net/ethernet/intel/ice/ice.h | 4 ++-- drivers/net/ethernet/intel/ice/ice_dcb_lib.c | 2 +- drivers/net/ethernet/intel/ice/ice_lib.c | 4 ++-- drivers/net/ethernet/intel/ice/ice_txrx.c | 23 ++++++++++++++------ drivers/net/ethernet/intel/ice/ice_txrx.h | 16 +++++++++----- 5 files changed, 31 insertions(+), 18 deletions(-)
drivers/net/ethernet/intel/ice/ice.h +2 -2
@@ -753,7 +753,7 @@ static inline bool ice_is_xdp_ena_vsi(struct ice_vsi *vsi)static inline void ice_set_ring_xdp (struct ice_tx_ring *ring) { - ring->flags |=ICE_TX_FLAGS_RING_XDP ; +set_bit (ICE_TX_RING_FLAGS_XDP , ring->flags); }/**
@@ -778,7 +778,7 @@ static inline bool ice_is_txtime_ena(const struct ice_tx_ring *ring)*/ static inline bool ice_is_txtime_cfg (const struct ice_tx_ring *ring) { -return !!(ring->flags &ICE_TX_FLAGS_TXTIME ); +return test_bit (ICE_TX_RING_FLAGS_TXTIME , ring->flags); }/**
drivers/net/ethernet/intel/ice/ice_dcb_lib.c +1 -1
@@ -943,7 +943,7 @@ ice_tx_prepare_vlan_flags_dcb(struct ice_tx_ring *tx_ring,/* if this is not already set it means a VLAN 0 + priority needs * to be offloaded */ -if (tx_ring->flags &ICE_TX_FLAGS_RING_VLAN_L2TAG2 ) +if (test_bit (ICE_TX_RING_FLAGS_VLAN_L2TAG2 , tx_ring->flags)) first->tx_flags |=ICE_TX_FLAGS_HW_OUTER_SINGLE_VLAN ;else first->tx_flags |=ICE_TX_FLAGS_HW_VLAN ;
drivers/net/ethernet/intel/ice/ice_lib.c +2 -2
@@ -1412,9 +1412,9 @@ static int ice_vsi_alloc_rings(struct ice_vsi *vsi) ring->count = vsi->num_tx_desc; ring->txq_teid =ICE_INVAL_TEID ;if (dvm_ena) - ring->flags |=ICE_TX_FLAGS_RING_VLAN_L2TAG2 ; +set_bit (ICE_TX_RING_FLAGS_VLAN_L2TAG2 , ring->flags);else - ring->flags |=ICE_TX_FLAGS_RING_VLAN_L2TAG1 ; +set_bit (ICE_TX_RING_FLAGS_VLAN_L2TAG1 , ring->flags);WRITE_ONCE (vsi->tx_rings[i], ring); }
drivers/net/ethernet/intel/ice/ice_txrx.c +16 -7
@@ -190,9 +190,10 @@ void ice_free_tstamp_ring(struct ice_tx_ring *tx_ring)void ice_free_tx_tstamp_ring (struct ice_tx_ring *tx_ring) {ice_free_tstamp_ring (tx_ring); +clear_bit (ICE_TX_RING_FLAGS_TXTIME , tx_ring->flags); +smp_wmb ();/* order flag clear before pointer NULL */ kfree_rcu (tx_ring->tstamp_ring, rcu); - tx_ring->tstamp_ring =NULL ; - tx_ring->flags &= ~ICE_TX_FLAGS_TXTIME ; +WRITE_ONCE (tx_ring->tstamp_ring,NULL ); }/**
@@ -405,7 +406,7 @@ static int ice_alloc_tstamp_ring(struct ice_tx_ring *tx_ring) tx_ring->tstamp_ring = tstamp_ring; tstamp_ring->desc =NULL ; tstamp_ring->count =ice_calc_ts_ring_count (tx_ring); - tx_ring->flags |=ICE_TX_FLAGS_TXTIME ; +set_bit (ICE_TX_RING_FLAGS_TXTIME , tx_ring->flags);return 0 ; }
@@ -1521,13 +1522,20 @@ ice_tx_map(struct ice_tx_ring *tx_ring, struct ice_tx_buf *first,return ;if (ice_is_txtime_cfg (tx_ring)) { -struct ice_tstamp_ring *tstamp_ring = tx_ring->tstamp_ring; -u32 tstamp_count = tstamp_ring->count; -u32 j = tstamp_ring->next_to_use; +struct ice_tstamp_ring *tstamp_ring; +u32 tstamp_count, j;struct ice_ts_desc *ts_desc;struct timespec64 ts;u32 tstamp; +smp_rmb ();/* order flag read before pointer read */ + tstamp_ring =READ_ONCE (tx_ring->tstamp_ring); +if (unlikely (!tstamp_ring)) + goto ring_kick; + + tstamp_count = tstamp_ring->count; + j = tstamp_ring->next_to_use; + ts =ktime_to_timespec64 (first->skb->tstamp); tstamp = ts.tv_nsec >>ICE_TXTIME_CTX_RESOLUTION_128NS ;
@@ -1555,6 +1563,7 @@ ice_tx_map(struct ice_tx_ring *tx_ring, struct ice_tx_buf *first, tstamp_ring->next_to_use = j;writel_relaxed (j, tstamp_ring->tail); }else { +ring_kick:writel_relaxed (i, tx_ring->tail); }return ;
@@ -1814,7 +1823,7 @@ ice_tx_prepare_vlan_flags(struct ice_tx_ring *tx_ring, struct ice_tx_buf *first)*/ if (skb_vlan_tag_present (skb)) { first->vid =skb_vlan_tag_get (skb); -if (tx_ring->flags &ICE_TX_FLAGS_RING_VLAN_L2TAG2 ) +if (test_bit (ICE_TX_RING_FLAGS_VLAN_L2TAG2 , tx_ring->flags)) first->tx_flags |=ICE_TX_FLAGS_HW_OUTER_SINGLE_VLAN ;else first->tx_flags |=ICE_TX_FLAGS_HW_VLAN ;
drivers/net/ethernet/intel/ice/ice_txrx.h +10 -6
@@ -212,6 +212,14 @@ enum ice_rx_dtype { ICE_RX_DTYPE_SPLIT_ALWAYS = 2, }; +enum ice_tx_ring_flags { +ICE_TX_RING_FLAGS_XDP , +ICE_TX_RING_FLAGS_VLAN_L2TAG1 , +ICE_TX_RING_FLAGS_VLAN_L2TAG2 , +ICE_TX_RING_FLAGS_TXTIME , +ICE_TX_RING_FLAGS_NBITS , +}; +struct ice_pkt_ctx {u64 cached_phctime;__be16 vlan_proto;
@@ -352,11 +360,7 @@ struct ice_tx_ring {u16 count;/* Number of descriptors */ u16 q_index;/* Queue number of ring */ -u8 flags; -#define ICE_TX_FLAGS_RING_XDP BIT(0) -#define ICE_TX_FLAGS_RING_VLAN_L2TAG1 BIT(1) -#define ICE_TX_FLAGS_RING_VLAN_L2TAG2 BIT(2) -#define ICE_TX_FLAGS_TXTIME BIT(3) +DECLARE_BITMAP (flags,ICE_TX_RING_FLAGS_NBITS );struct xsk_buff_pool *xsk_pool;
@@ -398,7 +402,7 @@ static inline bool ice_ring_ch_enabled(struct ice_tx_ring *ring)static inline bool ice_ring_is_xdp (struct ice_tx_ring *ring) { -return !!(ring->flags &ICE_TX_FLAGS_RING_XDP ); +return test_bit (ICE_TX_RING_FLAGS_XDP , ring->flags); }enum ice_container_type {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 800/1146 ice: fix potential NULL pointer deref in error path of ice_set_ringparam()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kohei Enju <[email protected]>
[ Upstream commit fa28351f970fa5138c7c5dedfe5dea480a0ee065 ]
ice_set_ringparam nullifies tstamp_ring of temporary tx_rings, without clearing ICE_TX_RING_FLAGS_TXTIME bit.
When ICE_TX_RING_FLAGS_TXTIME is set and the subsequent ice_setup_tx_ring() call fails, a NULL pointer dereference could happen in the unwinding sequence:
ice_clean_tx_ring()
-> ice_is_txtime_cfg() == true (ICE_TX_RING_FLAGS_TXTIME is set) -> ice_free_tx_tstamp_ring()
-> ice_free_tstamp_ring()
-> tstamp_ring->desc (NULL deref)
Clear ICE_TX_RING_FLAGS_TXTIME bit to avoid the potential issue.
Note that this potential issue is found by manual code review. Compile test only since unfortunately I don't have E830 devices.
--- drivers/net/ethernet/intel/ice/ice_ethtool.c | 1 + 1 file changed, 1 insertion(+)
drivers/net/ethernet/intel/ice/ice_ethtool.c +1 -0
@@ -3290,6 +3290,7 @@ ice_set_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring, tx_rings[i].desc =NULL ; tx_rings[i].tx_buf =NULL ; tx_rings[i].tstamp_ring =NULL ; +clear_bit (ICE_TX_RING_FLAGS_TXTIME , tx_rings[i].flags); tx_rings[i].tx_tstamps = &pf->ptp.port.tx; err =ice_setup_tx_ring (&tx_rings[i]);if (err) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 801/1146 i40e: dont advertise IFF_SUPP_NOFCS
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kohei Enju <[email protected]>
[ Upstream commit a24162f18825684ad04e3a5d0531f8a50d679347 ]
i40e advertises IFF_SUPP_NOFCS, allowing users to use the SO_NOFCS socket option. However, this option is silently ignored, as the driver does not check skb->no_fcs, and always enables FCS insertion offload.
Fix this by removing the advertisement of IFF_SUPP_NOFCS.
This behavior can be reproduced with a simple AF_PACKET socket:
import socket
s = socket.socket(socket.AF_PACKET, socket.SOCK_RAW) s.setsockopt(socket.SOL_SOCKET, 43, 1) # SO_NOFCS s.bind(("eth0", 0))
s.send(b'\xff' * 64)
Previously, send() succeeds but the driver ignores SO_NOFCS. With this change, send() fails with -EPROTONOSUPPORT, as expected.
--- drivers/net/ethernet/intel/i40e/i40e_main.c | 1 - 1 file changed, 1 deletion(-)
drivers/net/ethernet/intel/i40e/i40e_main.c +0 -1
@@ -13783,7 +13783,6 @@ static int i40e_config_netdev(struct i40e_vsi *vsi) netdev->neigh_priv_len =sizeof (u32) *4 ; netdev->priv_flags |=IFF_UNICAST_FLT ; - netdev->priv_flags |=IFF_SUPP_NOFCS ;/* Setup netdev TC information */ i40e_vsi_config_netdev_tc (vsi, vsi->tc_config.enabled_tc);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 802/1146 iavf: fix wrong VLAN mask for legacy Rx descriptors L2TAG2
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Petr Oros <[email protected]>
[ Upstream commit 496d9f91062fa07956702e0f234c5203f03a974d ]
The IAVF_RXD_LEGACY_L2TAG2_M mask was incorrectly defined as GENMASK_ULL(63, 32), extracting 32 bits from qw2 instead of the 16-bit VLAN tag. In the legacy Rx descriptor layout, the 2nd L2TAG2 (VLAN tag) occupies bits 63:48 of qw2, not 63:32.
The oversized mask causes FIELD_GET to return a 32-bit value where the actual VLAN tag sits in bits 31:16. When this value is passed to iavf_receive_skb() as a u16 parameter, it gets truncated to the lower 16 bits (which contain the 1st L2TAG2, typically zero). As a result, __vlan_hwaccel_put_tag() is never called and software VLAN interfaces on VFs receive no traffic.
This affects VFs behind ice PF (VIRTCHNL VLAN v2) when the PF advertises VLAN stripping into L2TAG2_2 and legacy descriptors are used.
The flex descriptor path already uses the correct mask (IAVF_RXD_FLEX_L2TAG2_2_M = GENMASK_ULL(63, 48)).
Reproducer:
1. Create 2 VFs on ice PF (echo 2 > sriov_numvfs)
2. Disable spoofchk on both VFs
3. Move each VF into a separate network namespace
4. On each VF: create VLAN interface (e.g. vlan 198), assign IP, bring up
5. Set rx-vlan-offload OFF on both VFs
6. Ping between VLAN interfaces -> expect PASS
(VLAN tag stays in packet data, kernel matches in-band)
7. Set rx-vlan-offload ON on both VFs
8. Ping between VLAN interfaces -> expect FAIL if bug present (HW strips VLAN tag into descriptor L2TAG2 field, wrong mask extracts bits 47:32 instead of 63:48, truncated to u16 -> zero, __vlan_hwaccel_put_tag() never called, packet delivered to parent interface, not VLAN interface)
The reproducer requires legacy Rx descriptors. On modern ice + iavf with full PTP support, flex descriptors are always negotiated and the buggy legacy path is never reached. Flex descriptors require all of:
- CONFIG_PTP_1588_CLOCK enabled
- VIRTCHNL_VF_OFFLOAD_RX_FLEX_DESC granted by PF
- PTP capabilities negotiated (VIRTCHNL_VF_CAP_PTP)
- VIRTCHNL_1588_PTP_CAP_RX_TSTAMP supported
- VIRTCHNL_RXDID_2_FLEX_SQ_NIC present in DDP profile
If any condition is not met, iavf_select_rx_desc_format() falls back to legacy descriptors (RXDID=1) and the wrong L2TAG2 mask is hit.
--- drivers/net/ethernet/intel/iavf/iavf_type.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/ethernet/intel/iavf/iavf_type.h +1 -1
@@ -277,7 +277,7 @@ struct iavf_rx_desc {/* L2 Tag 2 Presence */ #define IAVF_RXD_LEGACY_L2TAG2P_M BIT(0)/* Stripped S-TAG VLAN from the receive packet */ -#define IAVF_RXD_LEGACY_L2TAG2_M GENMASK_ULL(63, 32) +#define IAVF_RXD_LEGACY_L2TAG2_M GENMASK_ULL(63, 48)/* Stripped S-TAG VLAN from the receive packet */ #define IAVF_RXD_FLEX_L2TAG2_2_M GENMASK_ULL(63, 48)/* The packet is a UDP tunneled packet */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 803/1146 e1000e: Unroll PTP in probe error handling
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Matt Vollrath <[email protected]>
[ Upstream commit aa3f7fe409350857c25d050482a2eef2cfd69b58 ]
If probe fails after registering the PTP clock and its delayed work, these resources must be released.
This was not an issue until a 2016 fix moved the e1000e_ptp_init() call before the jump to err_register.
--- drivers/net/ethernet/intel/e1000e/netdev.c | 1 + 1 file changed, 1 insertion(+)
drivers/net/ethernet/intel/e1000e/netdev.c +1 -0
@@ -7706,6 +7706,7 @@ static int e1000_probe(struct pci_dev *pdev, const struct pci_device_id *ent) err_register:if (!(adapter->flags &FLAG_HAS_AMT ))e1000e_release_hw_control (adapter); +e1000e_ptp_remove (adapter); err_eeprom:if (hw->phy.ops.check_reset_block && !hw->phy.ops.check_reset_block (hw))e1000_phy_hw_reset (&adapter->hw);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 804/1146 ipv6: fix possible UAF in icmpv6_rcv()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit f996edd7615e686ada141b7f3395025729ff8ccb ]
Caching saddr and daddr before pskb_pull() is problematic since skb->head can change.
Remove these temporary variables:
- We only access &ipv6_hdr(skb)->saddr and &ipv6_hdr(skb)->daddr when net_dbg_ratelimited() is called in the slow path.
- Avoid potential future misuse after pskb_pull() call.
--- net/ipv6/icmp.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-)
net/ipv6/icmp.c +4 -6
@@ -1104,7 +1104,6 @@ static int icmpv6_rcv(struct sk_buff *skb)struct net *net =dev_net_rcu (skb->dev);struct net_device *dev =icmp6_dev (skb);struct inet6_dev *idev =__in6_dev_get (dev); -const struct in6_addr *saddr, *daddr;struct icmp6hdr *hdr;u8 type;
@@ -1135,12 +1134,10 @@ static int icmpv6_rcv(struct sk_buff *skb)__ICMP6_INC_STATS (dev_net_rcu (dev), idev,ICMP6_MIB_INMSGS ); - saddr = &ipv6_hdr (skb)->saddr; - daddr = &ipv6_hdr (skb)->daddr; -if (skb_checksum_validate (skb,IPPROTO_ICMPV6 , ip6_compute_pseudo)) {net_dbg_ratelimited ("ICMPv6 checksum failed [%pI6c > %pI6c]\n" , - saddr, daddr); + &ipv6_hdr (skb)->saddr, + &ipv6_hdr (skb)->daddr); goto csum_error; }
@@ -1220,7 +1217,8 @@ static int icmpv6_rcv(struct sk_buff *skb)break ;net_dbg_ratelimited ("icmpv6: msg of unknown type [%pI6c > %pI6c]\n" , - saddr, daddr); + &ipv6_hdr (skb)->saddr, + &ipv6_hdr (skb)->daddr);/* * error of unknown type.
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 805/1146 af_unix: Drop all SCM attributes for SOCKMAP.
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kuniyuki Iwashima <[email protected]>
[ Upstream commit 965dc93481d1b80d341bdd16c27b16fe197175ee ]
SOCKMAP can hide inflight fd from AF_UNIX GC.
When a socket in SOCKMAP receives skb with inflight fd, sk_psock_verdict_data_ready() looks up the mapped socket and enqueue skb to its psock->ingress_skb.
Since neither the old nor the new GC can inspect the psock queue, the hidden skb leaks the inflight sockets. Note that this cannot be detected via kmemleak because inflight sockets are linked to a global list.
In addition, SOCKMAP redirect breaks the Tarjan-based GC's assumption that unix_edge.successor is always alive, which is no longer true once skb is redirected, resulting in use-after-free below. [0]
Moreover, SOCKMAP does not call scm_stat_del() properly, so unix_show_fdinfo() could report an incorrect fd count.
sk_msg_recvmsg() does not support any SCM attributes in the first place.
Let's drop all SCM attributes before passing skb to the SOCKMAP layer.
[0]:
BUG: KASAN: slab-use-after-free in unix_del_edges (net/unix/garbage.c:118 net/unix/garbage.c:181 net/unix/garbage.c:251) Read of size 8 at addr ffff888125362670 by task kworker/56:1/496 CPU: 56 UID: 0 PID: 496 Comm: kworker/56:1 Not tainted 7.0.0-rc7-00263-gb9d8b856689d #3 PREEMPT(lazy) Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.17.0-debian-1.17.0-1 04/01/2014 Workqueue: events sk_psock_backlog Call Trace: <TASK> dump_stack_lvl (lib/dump_stack.c:122) print_report (mm/kasan/report.c:379) kasan_report (mm/kasan/report.c:597) unix_del_edges (net/unix/garbage.c:118 net/unix/garbage.c:181 net/unix/garbage.c:251) unix_destroy_fpl (net/unix/garbage.c:317) unix_destruct_scm (./include/net/scm.h:80 ./include/net/scm.h:86 net/unix/af_unix.c:1976) sk_psock_backlog (./include/linux/skbuff.h:?) process_scheduled_works (kernel/workqueue.c:?) worker_thread (kernel/workqueue.c:?) kthread (kernel/kthread.c:438) ret_from_fork (arch/x86/kernel/process.c:164) ret_from_fork_asm (arch/x86/entry/entry_64.S:258) </TASK> Allocated by task 955: kasan_save_track (mm/kasan/common.c:58 mm/kasan/common.c:78) __kasan_slab_alloc (mm/kasan/common.c:369) kmem_cache_alloc_noprof (mm/slub.c:4539) sk_prot_alloc (net/core/sock.c:2240) sk_alloc (net/core/sock.c:2301) unix_create1 (net/unix/af_unix.c:1099) unix_create (net/unix/af_unix.c:1169) __sock_create (net/socket.c:1606) __sys_socketpair (net/socket.c:1811) __x64_sys_socketpair (net/socket.c:1863 net/socket.c:1860 net/socket.c:1860) do_syscall_64 (arch/x86/entry/syscall_64.c:?) entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:130) Freed by task 496: kasan_save_track (mm/kasan/common.c:58 mm/kasan/common.c:78) kasan_save_free_info (mm/kasan/generic.c:587) __kasan_slab_free (mm/kasan/common.c:287) kmem_cache_free (mm/slub.c:6165) __sk_destruct (net/core/sock.c:2282 net/core/sock.c:2384) sk_psock_destroy (./include/net/sock.h:?) process_scheduled_works (kernel/workqueue.c:?) worker_thread (kernel/workqueue.c:?) kthread (kernel/kthread.c:438) ret_from_fork (arch/x86/kernel/process.c:164) ret_from_fork_asm (arch/x86/entry/entry_64.S:258)
--- net/unix/af_unix.c | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-)
net/unix/af_unix.c +27 -8
@@ -1964,16 +1964,19 @@ static void unix_peek_fds(struct scm_cookie *scm, struct sk_buff *skb)static void unix_destruct_scm (struct sk_buff *skb) { -struct scm_cookie scm; +struct scm_cookie scm = {}; + +swap (scm.pid,UNIXCB (skb).pid); -memset (&scm,0 ,sizeof (scm)); - scm.pid =UNIXCB (skb).pid;if (UNIXCB (skb).fp)unix_detach_fds (&scm, skb); -/* Alas, it calls VFS */ -/* So fscking what? fput() had been SMP-safe since the last Summer */ scm_destroy (&scm); +} + +static void unix_wfree (struct sk_buff *skb) +{ +unix_destruct_scm (skb);sock_wfree (skb); }
@@ -1989,7 +1992,7 @@ static int unix_scm_to_skb(struct scm_cookie *scm, struct sk_buff *skb, bool senif (scm->fp && send_fds) err =unix_attach_fds (scm, skb); - skb->destructor = unix_destruct_scm; + skb->destructor = unix_wfree;return err; }
@@ -2066,6 +2069,13 @@ static void scm_stat_del(struct sock *sk, struct sk_buff *skb) } } +static void unix_orphan_scm (struct sock *sk,struct sk_buff *skb) +{ +scm_stat_del (sk, skb); +unix_destruct_scm (skb); + skb->destructor = sock_wfree; +} +/* * Send AF_UNIX data. */
@@ -2679,10 +2689,16 @@ static int unix_read_skb(struct sock *sk, skb_read_actor_t recv_actor)int err;mutex_lock (&u->iolock); + skb =skb_recv_datagram (sk,MSG_DONTWAIT , &err); -mutex_unlock (&u->iolock); -if (!skb) +if (!skb) { +mutex_unlock (&u->iolock);return err; + } + +unix_orphan_scm (sk, skb); + +mutex_unlock (&u->iolock);return recv_actor (sk, skb); }
@@ -2882,6 +2898,9 @@ static int unix_stream_read_skb(struct sock *sk, skb_read_actor_t recv_actor)#endif spin_unlock (&queue->lock); + +unix_orphan_scm (sk, skb); +mutex_unlock (&u->iolock);return recv_actor (sk, skb);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 806/1146 sctp: fix OOB write to userspace in sctp_getsockopt_peer_auth_chunks
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Bommarito <[email protected]>
[ Upstream commit 0cf004ffb61cd32d140531c3a84afe975f9fc7ea ]
sctp_getsockopt_peer_auth_chunks() checks that the caller's optval buffer is large enough for the peer AUTH chunk list with
if (len < num_chunks)
return -EINVAL;
but then writes num_chunks bytes to p->gauth_chunks, which lives at offset offsetof(struct sctp_authchunks, gauth_chunks) == 8 inside optval. The check is missing the sizeof(struct sctp_authchunks) = 8-byte header. When the caller supplies len == num_chunks (for any num_chunks > 0) the test passes but copy_to_user() writes sizeof(struct sctp_authchunks) = 8 bytes past the declared buffer.
The sibling function sctp_getsockopt_local_auth_chunks() at the next line already has the correct check:
if (len < sizeof(struct sctp_authchunks) + num_chunks)
return -EINVAL;
Align the peer variant with its sibling.
Reproducer confirms on v7.0-13-generic: an unprivileged userspace caller that opens a loopback SCTP association with AUTH enabled, queries num_chunks with a short optval, then issues the real getsockopt with len == num_chunks and sentinel bytes painted past the buffer observes those sentinel bytes overwritten with the peer's AUTH chunk type. The bytes written are under the peer's control but land in the caller's own userspace; this is not a kernel memory corruption, but it is a kernel-side contract violation that can silently corrupt adjacent userspace data.
--- net/sctp/socket.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/sctp/socket.c +1 -1
@@ -7042,7 +7042,7 @@ static int sctp_getsockopt_peer_auth_chunks(struct sock *sk, int len,/* See if the user provided enough room for all the data */ num_chunks =ntohs (ch->param_hdr.length) -sizeof (struct sctp_paramhdr ); -if (len < num_chunks) +if (len <sizeof (struct sctp_authchunks ) + num_chunks)return -EINVAL ;if (copy_to_user (to, ch->chunks, num_chunks))
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 807/1146 pppoe: drop PFC frames
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Qingfang Deng <[email protected]>
[ Upstream commit cc1ff87bce1ccd38410ab10960f576dcd17db679 ]
RFC 2516 Section 7 states that Protocol Field Compression (PFC) is NOT RECOMMENDED for PPPoE. In practice, pppd does not support negotiating PFC for PPPoE sessions, and the current PPPoE driver assumes an uncompressed (2-byte) protocol field. However, the generic PPP layer function ppp_input() is not aware of the negotiation result, and still accepts PFC frames.
If a peer with a broken implementation or an attacker sends a frame with a compressed (1-byte) protocol field, the subsequent PPP payload is shifted by one byte. This causes the network header to be 4-byte misaligned, which may trigger unaligned access exceptions on some architectures.
To reduce the attack surface, drop PPPoE PFC frames. Introduce ppp_skb_is_compressed_proto() helper function to be used in both ppp_generic.c and pppoe.c to avoid open-coding.
--- drivers/net/ppp/ppp_generic.c | 2 +- drivers/net/ppp/pppoe.c | 8 +++++++- include/linux/ppp_defs.h | 16 ++++++++++++++++ 3 files changed, 24 insertions(+), 2 deletions(-)
drivers/net/ppp/ppp_generic.c +1 -1
@@ -2260,7 +2260,7 @@ ppp_do_recv(struct ppp *ppp, struct sk_buff *skb, struct channel *pch)*/ static void __ppp_decompress_proto (struct sk_buff *skb) { -if (skb->data[0 ] &0x01 ) +if (ppp_skb_is_compressed_proto (skb)) *(u8 *)skb_push (skb,1 ) =0x00 ; }
drivers/net/ppp/pppoe.c +7 -1
@@ -424,7 +424,7 @@ static int pppoe_rcv(struct sk_buff *skb, struct net_device *dev,if (skb_mac_header_len (skb) <ETH_HLEN ) goto drop; -if (!pskb_may_pull (skb,sizeof (struct pppoe_hdr ))) +if (!pskb_may_pull (skb,PPPOE_SES_HLEN )) goto drop; ph =pppoe_hdr (skb);
@@ -434,6 +434,12 @@ static int pppoe_rcv(struct sk_buff *skb, struct net_device *dev,if (skb->len < len) goto drop; +/* skb->data points to the PPP protocol header after skb_pull_rcsum. +* Drop PFC frames. +*/ +if (ppp_skb_is_compressed_proto (skb)) + goto drop; +if (pskb_trim_rcsum (skb, len)) goto drop;
include/linux/ppp_defs.h +16 -0
@@ -8,6 +8,7 @@#define _PPP_DEFS_H_#include <linux/crc-ccitt.h> +#include <linux/skbuff.h> #include <uapi/linux/ppp_defs.h> #define PPP_FCS (fcs, c) crc_ccitt_byte(fcs, c)
@@ -25,4 +26,19 @@ static inline bool ppp_proto_is_valid(u16 proto) return !!((proto & 0x0101) == 0x0001); } +/** +* ppp_skb_is_compressed_proto - checks if PPP protocol in a skb is compressed +* @skb: skb to check +* +* Check if the PPP protocol field is compressed (the least significant +* bit of the most significant octet is 1). skb->data must point to the PPP +* protocol header. +* +* Return: Whether the PPP protocol field is compressed. +*/ +static inline bool ppp_skb_is_compressed_proto (const struct sk_buff *skb) +{ +return unlikely (skb->data[0 ] &0x01 ); +} +#endif /* _PPP_DEFS_H_ */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 808/1146 net/mlx5: Fix HCA caps leak on notifier init failure
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Prathamesh Deshpande <[email protected]>
[ Upstream commit d03fc81a57956248383efec99967d0ae627390a8 ]
mlx5_mdev_init() allocates HCA caps via mlx5_hca_caps_alloc() before calling mlx5_notifiers_init(). If notifier initialization fails, the error path jumps to err_hca_caps and skips mlx5_hca_caps_free(), leaking allocated caps.
Add a dedicated unwind label for notifier-init failure that frees HCA caps before continuing the existing cleanup sequence.
--- drivers/net/ethernet/mellanox/mlx5/core/main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/net/ethernet/mellanox/mlx5/core/main.c +3 -1
@@ -1907,7 +1907,7 @@ int mlx5_mdev_init(struct mlx5_core_dev *dev, int profile_idx) err =mlx5_notifiers_init (dev);if (err) - goto err_hca_caps; + goto err_notifiers_init;/* The conjunction of sw_vhca_id with sw_owner_id will be a global * unique id per function which uses mlx5_core.
@@ -1923,6 +1923,8 @@ int mlx5_mdev_init(struct mlx5_core_dev *dev, int profile_idx)return 0 ; +err_notifiers_init: +mlx5_hca_caps_free (dev); err_hca_caps:mlx5_adev_cleanup (dev); err_adev_init:
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 809/1146 openvswitch: cap upcall PID array size and pre-size vport replies
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Weiming Shi <[email protected]>
[ Upstream commit 2091c6aa0df6aba47deb5c8ab232b1cb60af3519 ]
The vport netlink reply helpers allocate a fixed-size skb with nlmsg_new(NLMSG_DEFAULT_SIZE, ...) but serialize the full upcall PID array via ovs_vport_get_upcall_portids(). Since ovs_vport_set_upcall_portids() accepts any non-zero multiple of sizeof(u32) with no upper bound, a CAP_NET_ADMIN user can install a PID array large enough to overflow the reply buffer, causing nla_put() to fail with -EMSGSIZE and hitting BUG_ON(err < 0). On systems with unprivileged user namespaces enabled (e.g., Ubuntu default), this is reachable via unshare -Urn since OVS vport mutation operations use GENL_UNS_ADMIN_PERM.
kernel BUG at net/openvswitch/datapath.c:2414!
Oops: invalid opcode: 0000 [#1] SMP KASAN NOPTI CPU: 1 UID: 0 PID: 65 Comm: poc Not tainted 7.0.0-rc7-00195-geb216e422044 #1 RIP: 0010:ovs_vport_cmd_set+0x34c/0x400 Call Trace: <TASK> genl_family_rcv_msg_doit (net/netlink/genetlink.c:1116) genl_rcv_msg (net/netlink/genetlink.c:1194) netlink_rcv_skb (net/netlink/af_netlink.c:2550) genl_rcv (net/netlink/genetlink.c:1219) netlink_unicast (net/netlink/af_netlink.c:1344) netlink_sendmsg (net/netlink/af_netlink.c:1894) __sys_sendto (net/socket.c:2206) __x64_sys_sendto (net/socket.c:2209) do_syscall_64 (arch/x86/entry/syscall_64.c:63) entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:130) </TASK> Kernel panic - not syncing: Fatal exception
Reject attempts to set more PIDs than nr_cpu_ids in ovs_vport_set_upcall_portids(), and pre-compute the worst-case reply size in ovs_vport_cmd_msg_size() based on that bound, similar to the existing ovs_dp_cmd_msg_size(). nr_cpu_ids matches the cap already used by the per-CPU dispatch configuration on the datapath side (ovs_dp_cmd_fill_info() serialises at most nr_cpu_ids PIDs), so the two sides stay consistent.
--- net/openvswitch/datapath.c | 35 +++++++++++++++++++++++++++++++++-- net/openvswitch/vport.c | 3 +++ 2 files changed, 36 insertions(+), 2 deletions(-)
net/openvswitch/datapath.c +33 -2
@@ -2184,9 +2184,40 @@ static int ovs_vport_cmd_fill_info(struct vport *vport, struct sk_buff *skb,return err; } +static size_t ovs_vport_cmd_msg_size (void ) +{ +size_t msgsize =NLMSG_ALIGN (sizeof (struct ovs_header )); + + msgsize +=nla_total_size (sizeof (u32));/* OVS_VPORT_ATTR_PORT_NO */ + msgsize +=nla_total_size (sizeof (u32));/* OVS_VPORT_ATTR_TYPE */ + msgsize +=nla_total_size (IFNAMSIZ );/* OVS_VPORT_ATTR_NAME */ + msgsize +=nla_total_size (sizeof (u32));/* OVS_VPORT_ATTR_IFINDEX */ + msgsize +=nla_total_size (sizeof (s32));/* OVS_VPORT_ATTR_NETNSID */ + +/* OVS_VPORT_ATTR_STATS */ + msgsize +=nla_total_size_64bit (sizeof (struct ovs_vport_stats )); + +/* OVS_VPORT_ATTR_UPCALL_STATS(OVS_VPORT_UPCALL_ATTR_SUCCESS + +* OVS_VPORT_UPCALL_ATTR_FAIL) +*/ + msgsize +=nla_total_size (nla_total_size_64bit (sizeof (u64)) + +nla_total_size_64bit (sizeof (u64))); + +/* OVS_VPORT_ATTR_UPCALL_PID */ + msgsize +=nla_total_size (nr_cpu_ids *sizeof (u32)); + +/* OVS_VPORT_ATTR_OPTIONS(OVS_TUNNEL_ATTR_DST_PORT + +* OVS_TUNNEL_ATTR_EXTENSION(OVS_VXLAN_EXT_GBP)) +*/ + msgsize +=nla_total_size (nla_total_size (sizeof (u16)) + +nla_total_size (nla_total_size (0 ))); + +return msgsize; +} +static struct sk_buff *ovs_vport_cmd_alloc_info (void ) { -return nlmsg_new (NLMSG_DEFAULT_SIZE ,GFP_KERNEL ); +return genlmsg_new (ovs_vport_cmd_msg_size (),GFP_KERNEL ); }/* Called with ovs_mutex, only via ovs_dp_notify_wq(). */
@@ -2196,7 +2227,7 @@ struct sk_buff *ovs_vport_cmd_build_info(struct vport *vport, struct net *net,struct sk_buff *skb;int retval; - skb =nlmsg_new (NLMSG_DEFAULT_SIZE ,GFP_KERNEL ); + skb =ovs_vport_cmd_alloc_info ();if (!skb)return ERR_PTR (-ENOMEM );
net/openvswitch/vport.c +3 -0
@@ -406,6 +406,9 @@ int ovs_vport_set_upcall_portids(struct vport *vport, const struct nlattr *ids)if (!nla_len (ids) ||nla_len (ids) %sizeof (u32))return -EINVAL ; +if (nla_len (ids) /sizeof (u32) > nr_cpu_ids) +return -EINVAL ; + old =ovsl_dereference (vport->upcall_portids); vport_portids = kmalloc(sizeof(*vport_portids) + nla_len(ids),
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 810/1146 net: airoha: Fix possible TX queue stall in airoha_qdma_tx_napi_poll()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lorenzo Bianconi <[email protected]>
[ Upstream commit b94769eb2f30e61e86cd8551c084c34134290d89 ]
Since multiple net_device TX queues can share the same hw QDMA TX queue, there is no guarantee we have inflight packets queued in hw belonging to a net_device TX queue stopped in the xmit path because hw QDMA TX queue can be full. In this corner case the net_device TX queue will never be re-activated. In order to avoid any potential net_device TX queue stall, we need to wake all the net_device TX queues feeding the same hw QDMA TX queue in airoha_qdma_tx_napi_poll routine.
--- drivers/net/ethernet/airoha/airoha_eth.c | 37 ++++++++++++++++++++---- drivers/net/ethernet/airoha/airoha_eth.h | 1 + 2 files changed, 33 insertions(+), 5 deletions(-)
drivers/net/ethernet/airoha/airoha_eth.c +32 -5
@@ -843,6 +843,21 @@ static int airoha_qdma_init_rx(struct airoha_qdma *qdma)return 0 ; } +static void airoha_qdma_wake_netdev_txqs (struct airoha_queue *q) +{ +struct airoha_qdma *qdma = q->qdma; +struct airoha_eth *eth = qdma->eth; +int i; + +for (i =0 ; i <ARRAY_SIZE (eth->ports); i++) { +struct airoha_gdm_port *port = eth->ports[i]; + +if (port && port->qdma == qdma) +netif_tx_wake_all_queues (port->dev); + } + q->txq_stopped = false; +} +static int airoha_qdma_tx_napi_poll (struct napi_struct *napi,int budget) {struct airoha_tx_irq_queue *irq_q;
@@ -919,12 +934,21 @@ static int airoha_qdma_tx_napi_poll(struct napi_struct *napi, int budget) txq =netdev_get_tx_queue (skb->dev, queue);netdev_tx_completed_queue (txq,1 , skb->len); -if (netif_tx_queue_stopped (txq) && - q->ndesc - q->queued >= q->free_thr) -netif_tx_wake_queue (txq); -dev_kfree_skb_any (skb); } + +if (q->txq_stopped && q->ndesc - q->queued >= q->free_thr) { +/* Since multiple net_device TX queues can share the +* same hw QDMA TX queue, there is no guarantee we have +* inflight packets queued in hw belonging to a +* net_device TX queue stopped in the xmit path. +* In order to avoid any potential net_device TX queue +* stall, we need to wake all the net_device TX queues +* feeding the same hw QDMA TX queue. +*/ +airoha_qdma_wake_netdev_txqs (q); + } + unlock:spin_unlock_bh (&q->lock); }
@@ -1970,6 +1994,7 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,if (q->queued + nr_frags >= q->ndesc) {/* not enough space in the queue */ netif_tx_stop_queue (txq); + q->txq_stopped = true;spin_unlock_bh (&q->lock);return NETDEV_TX_BUSY ; }
@@ -2025,8 +2050,10 @@ static netdev_tx_t airoha_dev_xmit(struct sk_buff *skb,TX_RING_CPU_IDX_MASK , FIELD_PREP(TX_RING_CPU_IDX_MASK, index)); -if (q->ndesc - q->queued < q->free_thr) +if (q->ndesc - q->queued < q->free_thr) {netif_tx_stop_queue (txq); + q->txq_stopped = true; + }spin_unlock_bh (&q->lock);
drivers/net/ethernet/airoha/airoha_eth.h +1 -0
@@ -193,6 +193,7 @@ struct airoha_queue {int ndesc;int free_thr;int buf_size; +bool txq_stopped;struct napi_struct napi;struct page_pool *page_pool;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 811/1146 netfilter: nft_osf: restrict it to ipv4
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pablo Neira Ayuso <[email protected]>
[ Upstream commit b336fdbb7103fb1484e1dcb6741151d4b5a41e35 ]
This expression only supports for ipv4, restrict it.
--- net/netfilter/nft_osf.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
net/netfilter/nft_osf.c +5 -1
@@ -28,6 +28,11 @@ static void nft_osf_eval(const struct nft_expr *expr, struct nft_regs *regs,struct nf_osf_data data;struct tcphdr _tcph; +if (nft_pf (pkt) !=NFPROTO_IPV4 ) { + regs->verdict.code =NFT_BREAK ; +return ; + } +if (pkt->tprot !=IPPROTO_TCP ) { regs->verdict.code =NFT_BREAK ;return ;
@@ -114,7 +119,6 @@ static int nft_osf_validate(const struct nft_ctx *ctx,switch (ctx->family) {case NFPROTO_IPV4 : -case NFPROTO_IPV6 :case NFPROTO_INET : hooks = (1 <<NF_INET_LOCAL_IN ) | (1 << NF_INET_PRE_ROUTING) |
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 812/1146 netfilter: nfnetlink_osf: fix divide-by-zero in OSF_WSS_MODULO
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xiang Mei <[email protected]>
[ Upstream commit 2195574dc6d9017d32ac346987e12659f931d932 ]
nf_osf_match_one() computes ctx->window % f->wss.val in the OSF_WSS_MODULO branch with no guard for f->wss.val == 0. A CAP_NET_ADMIN user can add such a fingerprint via nfnetlink; a subsequent matching TCP SYN divides by zero and panics the kernel.
Reject the bogus fingerprint in nfnl_osf_add_callback() above the per-option for-loop. f->wss is per-fingerprint, not per-option, so the check must run regardless of f->opt_num (including 0). Also reject wss.wc >= OSF_WSS_MAX; nf_osf_match_one() already treats that as "should not happen".
Crash:
Oops: divide error: 0000 [#1] SMP KASAN NOPTI RIP: 0010:nf_osf_match_one (net/netfilter/nfnetlink_osf.c:98) Call Trace: <IRQ> nf_osf_match (net/netfilter/nfnetlink_osf.c:220) xt_osf_match_packet (net/netfilter/xt_osf.c:32) ipt_do_table (net/ipv4/netfilter/ip_tables.c:348) nf_hook_slow (net/netfilter/core.c:622) ip_local_deliver (net/ipv4/ip_input.c:265) ip_rcv (include/linux/skbuff.h:1162) __netif_receive_skb_one_core (net/core/dev.c:6181) process_backlog (net/core/dev.c:6642) __napi_poll (net/core/dev.c:7710) net_rx_action (net/core/dev.c:7945) handle_softirqs (kernel/softirq.c:622)
--- net/netfilter/nfnetlink_osf.c | 4 ++++ 1 file changed, 4 insertions(+)
net/netfilter/nfnetlink_osf.c +4 -0
@@ -320,6 +320,10 @@ static int nfnl_osf_add_callback(struct sk_buff *skb,if (f->opt_num >ARRAY_SIZE (f->opt))return -EINVAL ; +if (f->wss.wc >=OSF_WSS_MAX || + (f->wss.wc ==OSF_WSS_MODULO && f->wss.val ==0 )) +return -EINVAL ; +for (i =0 ; i < f->opt_num; i++) {if (!f->opt[i].length || f->opt[i].length >MAX_IPOPTLEN )return -EINVAL ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 813/1146 netfilter: conntrack: remove sprintf usage
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Florian Westphal <[email protected]>
[ Upstream commit 6e7066bdb481a87fe88c4fa563e348c03b2d373d ]
Replace it with scnprintf, the buffer sizes are expected to be large enough to hold the result, no need for snprintf+overflow check.
Increase buffer size in mangle_content_len() while at it.
BUG: KASAN: stack-out-of-bounds in vsnprintf+0xea5/0x1270 Write of size 1 at addr [..] vsnprintf+0xea5/0x1270 sprintf+0xb1/0xe0 mangle_content_len+0x1ac/0x280 nf_nat_sdp_session+0x1cc/0x240 process_sdp+0x8f8/0xb80 process_invite_request+0x108/0x2b0 process_sip_msg+0x5da/0xf50 sip_help_tcp+0x45e/0x780 nf_confirm+0x34d/0x990 [..]
--- net/netfilter/nf_nat_amanda.c | 2 +- net/netfilter/nf_nat_sip.c | 33 ++++++++++++++++++--------------- 2 files changed, 19 insertions(+), 16 deletions(-)
net/netfilter/nf_nat_amanda.c +1 -1
@@ -50,7 +50,7 @@ static unsigned int help(struct sk_buff *skb,return NF_DROP ; } -sprintf (buffer,"%u" , port); +snprintf (buffer,sizeof (buffer),"%u" , port);if (!nf_nat_mangle_udp_packet (skb, exp->master, ctinfo, protoff, matchoff, matchlen, buffer,strlen (buffer))) {
net/netfilter/nf_nat_sip.c +18 -15
@@ -68,25 +68,27 @@ static unsigned int mangle_packet(struct sk_buff *skb, unsigned int protoff, }static int sip_sprintf_addr (const struct nf_conn *ct,char *buffer, +size_t size,const union nf_inet_addr *addr,bool delim) {if (nf_ct_l3num (ct) ==NFPROTO_IPV4 ) -return sprintf (buffer,"%pI4" , &addr->ip); +return scnprintf (buffer, size,"%pI4" , &addr->ip);else {if (delim) -return sprintf (buffer,"[%pI6c]" , &addr->ip6); +return scnprintf (buffer, size,"[%pI6c]" , &addr->ip6);else -return sprintf (buffer,"%pI6c" , &addr->ip6); +return scnprintf (buffer, size,"%pI6c" , &addr->ip6); } }static int sip_sprintf_addr_port (const struct nf_conn *ct,char *buffer, +size_t size,const union nf_inet_addr *addr,u16 port) {if (nf_ct_l3num (ct) ==NFPROTO_IPV4 ) -return sprintf (buffer,"%pI4:%u" , &addr->ip, port); +return scnprintf (buffer, size,"%pI4:%u" , &addr->ip, port);else -return sprintf (buffer,"[%pI6c]:%u" , &addr->ip6, port); +return scnprintf (buffer, size,"[%pI6c]:%u" , &addr->ip6, port); } static int map_addr(struct sk_buff *skb, unsigned int protoff,
@@ -119,7 +121,7 @@ static int map_addr(struct sk_buff *skb, unsigned int protoff,if (nf_inet_addr_cmp (&newaddr, addr) && newport == port)return 1 ; - buflen =sip_sprintf_addr_port (ct, buffer, &newaddr,ntohs (newport)); + buflen =sip_sprintf_addr_port (ct, buffer,sizeof (buffer), &newaddr,ntohs (newport));return mangle_packet (skb, protoff, dataoff, dptr, datalen, matchoff, matchlen, buffer, buflen); }
@@ -212,7 +214,7 @@ static unsigned int nf_nat_sip(struct sk_buff *skb, unsigned int protoff, &addr, true) > 0 && nf_inet_addr_cmp(&addr, &ct->tuplehash[dir].tuple.src.u3) && !nf_inet_addr_cmp(&addr, &ct->tuplehash[!dir].tuple.dst.u3)) { - buflen = sip_sprintf_addr(ct, buffer, + buflen = sip_sprintf_addr(ct, buffer, sizeof(buffer), &ct->tuplehash[!dir].tuple.dst.u3, true); if (!mangle_packet(skb, protoff, dataoff, dptr, datalen,
@@ -229,7 +231,7 @@ static unsigned int nf_nat_sip(struct sk_buff *skb, unsigned int protoff, &addr, false) > 0 && nf_inet_addr_cmp(&addr, &ct->tuplehash[dir].tuple.dst.u3) && !nf_inet_addr_cmp(&addr, &ct->tuplehash[!dir].tuple.src.u3)) { - buflen = sip_sprintf_addr(ct, buffer, + buflen = sip_sprintf_addr(ct, buffer, sizeof(buffer), &ct->tuplehash[!dir].tuple.src.u3, false); if (!mangle_packet(skb, protoff, dataoff, dptr, datalen,
@@ -247,7 +249,7 @@ static unsigned int nf_nat_sip(struct sk_buff *skb, unsigned int protoff, htons(n) == ct->tuplehash[dir].tuple.dst.u.udp.port && htons(n) != ct->tuplehash[!dir].tuple.src.u.udp.port) {__be16 p = ct->tuplehash[!dir].tuple.src.u.udp.port; - buflen =sprintf (buffer,"%u" ,ntohs (p)); + buflen =scnprintf (buffer,sizeof (buffer),"%u" ,ntohs (p));if (!mangle_packet (skb, protoff, dataoff, dptr, datalen, poff, plen, buffer, buflen)) {nf_ct_helper_log (skb, ct,"cannot mangle rport" );
@@ -418,7 +420,8 @@ static unsigned int nf_nat_sip_expect(struct sk_buff *skb, unsigned int protoff,if (!nf_inet_addr_cmp (&exp->tuple.dst.u3, &exp->saved_addr) || exp->tuple.dst.u.udp.port != exp->saved_proto.udp.port) { - buflen =sip_sprintf_addr_port (ct, buffer, &newaddr, port); + buflen =sip_sprintf_addr_port (ct, buffer,sizeof (buffer), + &newaddr, port);if (!mangle_packet (skb, protoff, dataoff, dptr, datalen, matchoff, matchlen, buffer, buflen)) {nf_ct_helper_log (skb, ct,"cannot mangle packet" );
@@ -438,8 +441,8 @@ static int mangle_content_len(struct sk_buff *skb, unsigned int protoff, {enum ip_conntrack_info ctinfo;struct nf_conn *ct =nf_ct_get (skb, &ctinfo); +char buffer[sizeof ("4294967295" )];unsigned int matchoff, matchlen; -char buffer[sizeof ("65536" )];int buflen, c_len;/* Get actual SDP length */
@@ -454,7 +457,7 @@ static int mangle_content_len(struct sk_buff *skb, unsigned int protoff, &matchoff, &matchlen) <= 0)return 0 ; - buflen =sprintf (buffer,"%u" , c_len); + buflen =scnprintf (buffer,sizeof (buffer),"%u" , c_len);return mangle_packet (skb, protoff, dataoff, dptr, datalen, matchoff, matchlen, buffer, buflen); }
@@ -491,7 +494,7 @@ static unsigned int nf_nat_sdp_addr(struct sk_buff *skb, unsigned int protoff,char buffer[INET6_ADDRSTRLEN ];unsigned int buflen; - buflen =sip_sprintf_addr (ct, buffer, addr, false); + buflen =sip_sprintf_addr (ct, buffer,sizeof (buffer), addr, false);if (mangle_sdp_packet (skb, protoff, dataoff, dptr, datalen, sdpoff, type, term, buffer, buflen))return 0 ;
@@ -509,7 +512,7 @@ static unsigned int nf_nat_sdp_port(struct sk_buff *skb, unsigned int protoff,char buffer[sizeof ("nnnnn" )];unsigned int buflen; - buflen =sprintf (buffer,"%u" , port); + buflen =scnprintf (buffer,sizeof (buffer),"%u" , port);if (!mangle_packet (skb, protoff, dataoff, dptr, datalen, matchoff, matchlen, buffer, buflen))return 0 ;
@@ -529,7 +532,7 @@ static unsigned int nf_nat_sdp_session(struct sk_buff *skb, unsigned int protoffunsigned int buflen;/* Mangle session description owner and contact addresses */ - buflen =sip_sprintf_addr (ct, buffer, addr, false); + buflen =sip_sprintf_addr (ct, buffer,sizeof (buffer), addr, false);if (mangle_sdp_packet (skb, protoff, dataoff, dptr, datalen, sdpoff,SDP_HDR_OWNER ,SDP_HDR_MEDIA , buffer, buflen))return 0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 814/1146 netfilter: xtables: restrict several matches to inet family
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pablo Neira Ayuso <[email protected]>
[ Upstream commit b6fe26f86a1649f84e057f3f15605b08eda15497 ]
This is a partial revert of:
commit ab4f21e6fb1c ("netfilter: xtables: use NFPROTO_UNSPEC in more extensions")
to allow ipv4 and ipv6 only.
- xt_mac
- xt_owner
- xt_physdev
These extensions are not used by ebtables in userspace.
Moreover, xt_realm is only for ipv4, since dst->tclassid is ipv4 specific.
--- net/netfilter/xt_mac.c | 34 +++++++++++++++++++++++----------- net/netfilter/xt_owner.c | 37 +++++++++++++++++++++++++------------ net/netfilter/xt_physdev.c | 29 +++++++++++++++++++---------- net/netfilter/xt_realm.c | 2 +- 4 files changed, 68 insertions(+), 34 deletions(-)
net/netfilter/xt_mac.c +23 -11
@@ -38,25 +38,37 @@ static bool mac_mt(const struct sk_buff *skb, struct xt_action_param *par)return ret; } -static struct xt_match mac_mt_reg__read_mostly = { - .name ="mac" , - .revision =0 , - .family =NFPROTO_UNSPEC , - .match = mac_mt, - .matchsize =sizeof (struct xt_mac_info ), - .hooks = (1 <<NF_INET_PRE_ROUTING ) | (1 <<NF_INET_LOCAL_IN ) | - (1 <<NF_INET_FORWARD ), - .me =THIS_MODULE , +static struct xt_match mac_mt_reg[]__read_mostly = { + { + .name ="mac" , + .family =NFPROTO_IPV4 , + .match = mac_mt, + .matchsize =sizeof (struct xt_mac_info ), + .hooks = (1 <<NF_INET_PRE_ROUTING ) | + (1 <<NF_INET_LOCAL_IN ) | + (1 <<NF_INET_FORWARD ), + .me =THIS_MODULE , + }, + { + .name ="mac" , + .family =NFPROTO_IPV6 , + .match = mac_mt, + .matchsize =sizeof (struct xt_mac_info ), + .hooks = (1 <<NF_INET_PRE_ROUTING ) | + (1 <<NF_INET_LOCAL_IN ) | + (1 <<NF_INET_FORWARD ), + .me =THIS_MODULE , + }, };static int __init mac_mt_init (void ) { -return xt_register_match (&mac_mt_reg); +return xt_register_matches (mac_mt_reg,ARRAY_SIZE (mac_mt_reg)); } static void __exit mac_mt_exit(void) { -xt_unregister_match (&mac_mt_reg); +xt_unregister_matches (mac_mt_reg,ARRAY_SIZE (mac_mt_reg)); }module_init (mac_mt_init);
net/netfilter/xt_owner.c +25 -12
@@ -127,26 +127,39 @@ owner_mt(const struct sk_buff *skb, struct xt_action_param *par)return true; } -static struct xt_match owner_mt_reg__read_mostly = { - .name ="owner" , - .revision =1 , - .family =NFPROTO_UNSPEC , - .checkentry = owner_check, - .match = owner_mt, - .matchsize =sizeof (struct xt_owner_match_info ), - .hooks = (1 <<NF_INET_LOCAL_OUT ) | - (1 <<NF_INET_POST_ROUTING ), - .me =THIS_MODULE , +static struct xt_match owner_mt_reg[]__read_mostly = { + { + .name ="owner" , + .revision =1 , + .family =NFPROTO_IPV4 , + .checkentry = owner_check, + .match = owner_mt, + .matchsize =sizeof (struct xt_owner_match_info ), + .hooks = (1 <<NF_INET_LOCAL_OUT ) | + (1 <<NF_INET_POST_ROUTING ), + .me =THIS_MODULE , + }, + { + .name ="owner" , + .revision =1 , + .family =NFPROTO_IPV6 , + .checkentry = owner_check, + .match = owner_mt, + .matchsize =sizeof (struct xt_owner_match_info ), + .hooks = (1 <<NF_INET_LOCAL_OUT ) | + (1 <<NF_INET_POST_ROUTING ), + .me =THIS_MODULE , + } };static int __init owner_mt_init (void ) { -return xt_register_match (&owner_mt_reg); +return xt_register_matches (owner_mt_reg,ARRAY_SIZE (owner_mt_reg)); } static void __exit owner_mt_exit(void) { -xt_unregister_match (&owner_mt_reg); +xt_unregister_matches (owner_mt_reg,ARRAY_SIZE (owner_mt_reg)); }module_init (owner_mt_init);
net/netfilter/xt_physdev.c +19 -10
@@ -115,24 +115,33 @@ static int physdev_mt_check(const struct xt_mtchk_param *par)return 0 ; } -static struct xt_match physdev_mt_reg__read_mostly = { - .name ="physdev" , - .revision =0 , - .family =NFPROTO_UNSPEC , - .checkentry = physdev_mt_check, - .match = physdev_mt, - .matchsize =sizeof (struct xt_physdev_info ), - .me =THIS_MODULE , +static struct xt_match physdev_mt_reg[]__read_mostly = { + { + .name ="physdev" , + .family =NFPROTO_IPV4 , + .checkentry = physdev_mt_check, + .match = physdev_mt, + .matchsize =sizeof (struct xt_physdev_info ), + .me =THIS_MODULE , + }, + { + .name ="physdev" , + .family =NFPROTO_IPV6 , + .checkentry = physdev_mt_check, + .match = physdev_mt, + .matchsize =sizeof (struct xt_physdev_info ), + .me =THIS_MODULE , + }, };static int __init physdev_mt_init (void ) { -return xt_register_match (&physdev_mt_reg); +return xt_register_matches (physdev_mt_reg,ARRAY_SIZE (physdev_mt_reg)); } static void __exit physdev_mt_exit(void) { -xt_unregister_match (&physdev_mt_reg); +xt_unregister_matches (physdev_mt_reg,ARRAY_SIZE (physdev_mt_reg)); }module_init (physdev_mt_init);
net/netfilter/xt_realm.c +1 -1
@@ -33,7 +33,7 @@ static struct xt_match realm_mt_reg __read_mostly = { .matchsize = sizeof(struct xt_realm_info), .hooks = (1 <<NF_INET_POST_ROUTING ) | (1 <<NF_INET_FORWARD ) | (1 << NF_INET_LOCAL_OUT) | (1 << NF_INET_LOCAL_IN), - .family = NFPROTO_UNSPEC, + .family = NFPROTO_IPV4, .me =THIS_MODULE };
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 815/1146 netfilter: nat: use kfree_rcu to release ops
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pablo Neira Ayuso <[email protected]>
[ Upstream commit 6eda0d771f94267f73f57c94630aa47e90957915 ]
Florian Westphal says:
"Historically this is not an issue, even for normal base hooks: the data path doesn't use the original nf_hook_ops that are used to register the callbacks.
However, in v5.14 I added the ability to dump the active netfilter hooks from userspace.
This code will peek back into the nf_hook_ops that are available at the tail of the pointer-array blob used by the datapath.
The nat hooks are special, because they are called indirectly from the central nat dispatcher hook. They are currently invisible to the nfnl hook dump subsystem though.
But once that changes the nat ops structures have to be deferred too."
Update nf_nat_register_fn() to deal with partial exposition of the hooks from error path which can be also an issue for nfnetlink_hook.
--- net/ipv4/netfilter/iptable_nat.c | 4 ++-- net/ipv6/netfilter/ip6table_nat.c | 4 ++-- net/netfilter/nf_nat_core.c | 10 ++++++---- 3 files changed, 10 insertions(+), 8 deletions(-)
net/ipv4/netfilter/iptable_nat.c +2 -2
@@ -79,7 +79,7 @@ static int ipt_nat_register_lookups(struct net *net)while (i)nf_nat_ipv4_unregister_fn (net, &ops[--i]); -kfree (ops); +kfree_rcu (ops, rcu);return ret; } }
@@ -100,7 +100,7 @@ static void ipt_nat_unregister_lookups(struct net *net)for (i =0 ; i <ARRAY_SIZE (nf_nat_ipv4_ops); i++)nf_nat_ipv4_unregister_fn (net, &ops[i]); -kfree (ops); +kfree_rcu (ops, rcu); }static int iptable_nat_table_init (struct net *net)
net/ipv6/netfilter/ip6table_nat.c +2 -2
@@ -81,7 +81,7 @@ static int ip6t_nat_register_lookups(struct net *net)while (i)nf_nat_ipv6_unregister_fn (net, &ops[--i]); -kfree (ops); +kfree_rcu (ops, rcu);return ret; } }
@@ -102,7 +102,7 @@ static void ip6t_nat_unregister_lookups(struct net *net)for (i =0 ; i <ARRAY_SIZE (nf_nat_ipv6_ops); i++)nf_nat_ipv6_unregister_fn (net, &ops[i]); -kfree (ops); +kfree_rcu (ops, rcu); }static int ip6table_nat_table_init (struct net *net)
net/netfilter/nf_nat_core.c +6 -4
@@ -1228,9 +1228,11 @@ int nf_nat_register_fn(struct net *net, u8 pf, const struct nf_hook_ops *ops, ret =nf_register_net_hooks (net, nat_ops, ops_count);if (ret <0 ) {mutex_unlock (&nf_nat_proto_mutex); -for (i =0 ; i < ops_count; i++) -kfree (nat_ops[i].priv); -kfree (nat_ops); +for (i =0 ; i < ops_count; i++) { + priv = nat_ops[i].priv; +kfree_rcu (priv, rcu_head); + } +kfree_rcu (nat_ops, rcu);return ret; }
@@ -1294,7 +1296,7 @@ void nf_nat_unregister_fn(struct net *net, u8 pf, const struct nf_hook_ops *ops, } nat_proto_net->nat_hook_ops =NULL ; -kfree (nat_ops); +kfree_rcu (nat_ops, rcu); } unlock:mutex_unlock (&nf_nat_proto_mutex);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 816/1146 ipvs: fix MTU check for GSO packets in tunnel mode
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yingnan Zhang <[email protected]>
[ Upstream commit 67bf42cae41d847fd6e5749eb68278ca5d748b25 ]
Currently, IPVS skips MTU checks for GSO packets by excluding them with the !skb_is_gso(skb) condition. This creates problems when IPVS tunnel mode encapsulates GSO packets with IPIP headers.
The issue manifests in two ways:
1. MTU violation after encapsulation:
When a GSO packet passes through IPVS tunnel mode, the original MTU check is bypassed. After adding the IPIP tunnel header, the packet size may exceed the outgoing interface MTU, leading to unexpected fragmentation at the IP layer.
2. Fragmentation with problematic IP IDs:
When net.ipv4.vs.pmtu_disc=1 and a GSO packet with multiple segments is fragmented after encapsulation, each segment gets a sequentially incremented IP ID (0, 1, 2, ...). This happens because:
a) The GSO packet bypasses MTU check and gets encapsulated
b) At __ip_finish_output, the oversized GSO packet is split into separate SKBs (one per segment), with IP IDs incrementing
c) Each SKB is then fragmented again based on the actual MTU
This sequential IP ID allocation differs from the expected behavior and can cause issues with fragment reassembly and packet tracking.
Fix this by properly validating GSO packets using skb_gso_validate_network_len(). This function correctly validates whether the GSO segments will fit within the MTU after segmentation. If validation fails, send an ICMP Fragmentation Needed message to enable proper PMTU discovery.
--- net/netfilter/ipvs/ip_vs_xmit.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-)
net/netfilter/ipvs/ip_vs_xmit.c +15 -4
@@ -102,6 +102,18 @@ __ip_vs_dst_check(struct ip_vs_dest *dest)return dest_dst; } +/* Based on ip_exceeds_mtu(). */ +static bool ip_vs_exceeds_mtu (const struct sk_buff *skb,unsigned int mtu) +{ +if (skb->len <= mtu) +return false; + +if (skb_is_gso (skb) &&skb_gso_validate_network_len (skb, mtu)) +return false; + +return true; +} +static inline bool __mtu_check_toobig_v6 (const struct sk_buff *skb,u32 mtu) {
@@ -111,10 +123,9 @@ __mtu_check_toobig_v6(const struct sk_buff *skb, u32 mtu)*/ if (IP6CB (skb)->frag_max_size > mtu)return true;/* largest fragment violate MTU */ - } -else if (skb->len > mtu && !skb_is_gso (skb)) { + }else if (ip_vs_exceeds_mtu (skb, mtu))return true;/* Packet size violate MTU size */ - } +return false; }
@@ -232,7 +243,7 @@ static inline bool ensure_mtu_is_adequate(struct netns_ipvs *ipvs, int skb_af,return true;if (unlikely (ip_hdr (skb)->frag_off &htons (IP_DF ) && - skb->len > mtu && !skb_is_gso (skb) && +ip_vs_exceeds_mtu (skb, mtu) && !ip_vs_iph_icmp (ipvsh))) {icmp_send (skb,ICMP_DEST_UNREACH ,ICMP_FRAG_NEEDED ,htonl (mtu));
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 817/1146 netfilter: nfnetlink_osf: fix out-of-bounds read on option matching
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fernando Fernandez Mancera <[email protected]>
[ Upstream commit f5ca450087c3baf3651055e7a6de92600f827af3 ]
In nf_osf_match(), the nf_osf_hdr_ctx structure is initialized once and passed by reference to nf_osf_match_one() for each fingerprint checked. During TCP option parsing, nf_osf_match_one() advances the shared ctx->optp pointer.
If a fingerprint perfectly matches, the function returns early without restoring ctx->optp to its initial state. If the user has configured NF_OSF_LOGLEVEL_ALL, the loop continues to the next fingerprint. However, because ctx->optp was not restored, the next call to nf_osf_match_one() starts parsing from the end of the options buffer. This causes subsequent matches to read garbage data and fail immediately, making it impossible to log more than one match or logging incorrect matches.
Instead of using a shared ctx->optp pointer, pass the context as a constant pointer and use a local pointer (optp) for TCP option traversal. This makes nf_osf_match_one() strictly stateless from the caller's perspective, ensuring every fingerprint check starts at the correct option offset.
--- net/netfilter/nfnetlink_osf.c | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-)
net/netfilter/nfnetlink_osf.c +8 -11
@@ -64,9 +64,9 @@ struct nf_osf_hdr_ctx {static bool nf_osf_match_one (const struct sk_buff *skb,const struct nf_osf_user_finger *f,int ttl_check, -struct nf_osf_hdr_ctx *ctx) +const struct nf_osf_hdr_ctx *ctx) { -const __u8 *optpinit = ctx->optp; +const __u8 *optp = ctx->optp;unsigned int check_WSS =0 ;int fmatch =FMATCH_WRONG ;int foptsize, optnum;
@@ -95,17 +95,17 @@ static bool nf_osf_match_one(const struct sk_buff *skb, check_WSS = f->wss.wc;for (optnum =0 ; optnum < f->opt_num; ++optnum) { -if (f->opt[optnum].kind == *ctx->optp) { +if (f->opt[optnum].kind == *optp) {__u32 len = f->opt[optnum].length; -const __u8 *optend = ctx->optp + len; +const __u8 *optend = optp + len; fmatch =FMATCH_OK ; -switch (*ctx->optp) { +switch (*optp) {case OSFOPT_MSS : - mss = ctx->optp[3 ]; + mss = optp[3 ]; mss <<=8 ; - mss |= ctx->optp[2 ]; + mss |= optp[2 ]; mss =ntohs ((__force __be16 )mss);break ;
@@ -113,7 +113,7 @@ static bool nf_osf_match_one(const struct sk_buff *skb,break ; } - ctx->optp = optend; + optp = optend; }else fmatch =FMATCH_OPT_WRONG ;
@@ -156,9 +156,6 @@ static bool nf_osf_match_one(const struct sk_buff *skb, } } -if (fmatch !=FMATCH_OK ) - ctx->optp = optpinit; -return fmatch ==FMATCH_OK ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 818/1146 netfilter: nfnetlink_osf: fix potential NULL dereference in ttl check
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fernando Fernandez Mancera <[email protected]>
[ Upstream commit 711987ba281fd806322a7cd244e98e2a81903114 ]
The nf_osf_ttl() function accessed skb->dev to perform a local interface address lookup without verifying that the device pointer was valid.
Additionally, the implementation utilized an in_dev_for_each_ifa_rcu loop to match the packet source address against local interface addresses. It assumed that packets from the same subnet should not see a decrement on the initial TTL. A packet might appear it is from the same subnet but it actually isn't especially in modern environments with containers and virtual switching.
Remove the device dereference and interface loop. Replace the logic with a switch statement that evaluates the TTL according to the ttl_check.
--- net/netfilter/nfnetlink_osf.c | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-)
net/netfilter/nfnetlink_osf.c +7 -15
@@ -31,26 +31,18 @@ EXPORT_SYMBOL_GPL(nf_osf_fingers);static inline int nf_osf_ttl (const struct sk_buff *skb,int ttl_check,unsigned char f_ttl) { -struct in_device *in_dev =__in_dev_get_rcu (skb->dev);const struct iphdr *ip =ip_hdr (skb); -const struct in_ifaddr *ifa; -int ret =0 ; -if (ttl_check ==NF_OSF_TTL_TRUE ) +switch (ttl_check) { +case NF_OSF_TTL_TRUE :return ip->ttl == f_ttl; -if (ttl_check ==NF_OSF_TTL_NOCHECK ) -return 1 ; -else if (ip->ttl <= f_ttl) +break ; +case NF_OSF_TTL_NOCHECK :return 1 ; - -in_dev_for_each_ifa_rcu (ifa, in_dev) { -if (inet_ifa_match (ip->saddr, ifa)) { - ret = (ip->ttl == f_ttl); -break ; - } +case NF_OSF_TTL_LESS : +default : +return ip->ttl <= f_ttl; } - -return ret; }struct nf_osf_hdr_ctx {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 819/1146 slip: reject VJ receive packets on instances with no rstate array
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Weiming Shi <[email protected]>
[ Upstream commit e76607442d5b73e1ba6768f501ef815bb58c2c0e ]
slhc_init() accepts rslots == 0 as a valid configuration, with the documented meaning of 'no receive compression'. In that case the allocation loop in slhc_init() is skipped, so comp->rstate stays NULL and comp->rslot_limit stays 0 (from the kzalloc of struct slcompress).
The receive helpers do not defend against that configuration. slhc_uncompress() dereferences comp->rstate[x] when the VJ header carries an explicit connection ID, and slhc_remember() later assigns cs = &comp->rstate[...] after only comparing the packet's slot number to comp->rslot_limit. Because rslot_limit is 0, slot 0 passes the range check, and the code dereferences a NULL rstate.
The configuration is reachable in-tree through PPP. PPPIOCSMAXCID stores its argument in a signed int, and (val >> 16) uses arithmetic shift. Passing 0xffff0000 therefore sign-extends to -1, so val2 + 1 is 0 and ppp_generic.c ends up calling slhc_init(0, 1). Because /dev/ppp open is gated by ns_capable(CAP_NET_ADMIN), the whole path is reachable from an unprivileged user namespace. Once the malformed VJ state is installed, any inbound VJ-compressed or VJ-uncompressed frame that selects slot 0 crashes the kernel in softirq context:
Oops: general protection fault, probably for non-canonical
address 0xdffffc0000000000: 0000 [#1] SMP KASAN NOPTI
KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007]
RIP: 0010:slhc_uncompress (drivers/net/slip/slhc.c:519)
Call Trace:
<TASK>
ppp_receive_nonmp_frame (drivers/net/ppp/ppp_generic.c:2466)
ppp_input (drivers/net/ppp/ppp_generic.c:2359)
ppp_async_process (drivers/net/ppp/ppp_async.c:492)
tasklet_action_common (kernel/softirq.c:926)
handle_softirqs (kernel/softirq.c:623)
run_ksoftirqd (kernel/softirq.c:1055)
smpboot_thread_fn (kernel/smpboot.c:160)
kthread (kernel/kthread.c:436)
ret_from_fork (arch/x86/kernel/process.c:164)
</TASK>Reject the receive side on such instances instead of touching rstate. slhc_uncompress() falls through to its existing 'bad' label, which bumps sls_i_error and enters the toss state. slhc_remember() mirrors that with an explicit sls_i_error increment followed by slhc_toss(); the sls_i_runt counter is not used here because a missing rstate is an internal configuration state, not a runt packet.
The transmit path is unaffected: the only in-tree caller that picks rslots from userspace (ppp_generic.c) still supplies tslots >= 1, and slip.c always calls slhc_init(16, 16), so comp->tstate remains valid and slhc_compress() continues to work.
--- drivers/net/slip/slhc.c | 6 ++++++ 1 file changed, 6 insertions(+)
drivers/net/slip/slhc.c +6 -0
@@ -506,6 +506,8 @@ slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) comp->sls_i_error++;return 0 ; } +if (!comp->rstate) + goto bad; changes = *cp++;if (changes &NEW_C ){/* Make sure the state index is in range, then grab the state.
@@ -649,6 +651,10 @@ slhc_remember(struct slcompress *comp, unsigned char *icp, int isize)struct cstate *cs;unsigned int ihl; +if (!comp->rstate) { + comp->sls_i_error++; +return slhc_toss (comp); + }/* The packet is shorter than a legal IP header. * Also make sure isize is positive. */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 820/1146 slip: bound decode() reads against the compressed packet length
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Weiming Shi <[email protected]>
[ Upstream commit 4c1367a2d7aad643a6f87c6931b13cc1a25e8ca7 ]
slhc_uncompress() parses a VJ-compressed TCP header by advancing a pointer through the packet via decode() and pull16(). Neither helper bounds-checks against isize, and decode() masks its return with & 0xffff so it can never return the -1 that callers test for -- those error paths are dead code.
A short compressed frame whose change byte requests optional fields lets decode() read past the end of the packet. The over-read bytes are folded into the cached cstate and reflected into subsequent reconstructed packets.
Make decode() and pull16() take the packet end pointer and return -1 when exhausted. Add a bounds check before the TCP-checksum read. The existing == -1 tests now do what they were always meant to.
--- drivers/net/slip/slhc.c | 43 ++++++++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 18 deletions(-)
drivers/net/slip/slhc.c +25 -18
@@ -80,9 +80,9 @@#include <linux/unaligned.h> static unsigned char *encode (unsigned char *cp,unsigned short n); -static long decode (unsigned char **cpp); +static long decode (unsigned char **cpp,const unsigned char *end);static unsigned char *put16 (unsigned char *cp,unsigned short x); -static unsigned short pull16 (unsigned char **cpp); +static long pull16 (unsigned char **cpp,const unsigned char *end);/* Allocate compression data structure * slots must be in range 0 to 255 (zero meaning no compression)
@@ -190,30 +190,34 @@ encode(unsigned char *cp, unsigned short n)return cp; } -/* Pull a 16-bit integer in host order from buffer in network byte order */ -static unsigned short -pull16 (unsigned char **cpp) +/* Pull a 16-bit integer in host order from buffer in network byte order. +* Returns -1 if the buffer is exhausted, otherwise the 16-bit value. +*/ +static long +pull16 (unsigned char **cpp,const unsigned char *end) { -short rval; +long rval; +if (*cpp +2 > end) +return -1 ; rval = *(*cpp)++; rval <<=8 ; rval |= *(*cpp)++;return rval; } -/* Decode a number */ +/* Decode a number. Returns -1 if the buffer is exhausted. */ static long -decode (unsigned char **cpp) +decode (unsigned char **cpp,const unsigned char *end) {int x; +if (*cpp >= end) +return -1 ; x = *(*cpp)++; -if (x ==0 ){ -return pull16 (cpp) &0xffff ;/* pull16 returns -1 on error */ - }else { -return x &0xff ;/* -1 if PULLCHAR returned error */ - } +if (x ==0 ) +return pull16 (cpp, end); +return x &0xff ; }/*
@@ -499,6 +503,7 @@ slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize)struct cstate *cs;int len, hdrlen;unsigned char *cp = icp; +const unsigned char *end = icp + isize;/* We've got a compressed packet; read the change byte */ comp->sls_i_compressed++;
@@ -536,6 +541,8 @@ slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) thp = &cs->cs_tcp; ip = &cs->cs_ip; +if (cp +2 > end) + goto bad; thp->check = *(__sum16 *)cp; cp +=2 ;
@@ -566,26 +573,26 @@ slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize)default :if (changes &NEW_U ){ thp->urg =1 ; -if ((x =decode (&cp)) ==-1 ) { +if ((x =decode (&cp, end)) ==-1 ) { goto bad; } thp->urg_ptr =htons (x); }else thp->urg =0 ;if (changes &NEW_W ){ -if ((x =decode (&cp)) ==-1 ) { +if ((x =decode (&cp, end)) ==-1 ) { goto bad; } thp->window =htons (ntohs (thp->window) + x); }if (changes &NEW_A ){ -if ((x =decode (&cp)) ==-1 ) { +if ((x =decode (&cp, end)) ==-1 ) { goto bad; } thp->ack_seq =htonl (ntohl (thp->ack_seq) + x); }if (changes &NEW_S ){ -if ((x =decode (&cp)) ==-1 ) { +if ((x =decode (&cp, end)) ==-1 ) { goto bad; } thp->seq =htonl (ntohl (thp->seq) + x);
@@ -593,7 +600,7 @@ slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize)break ; }if (changes &NEW_I ){ -if ((x =decode (&cp)) ==-1 ) { +if ((x =decode (&cp, end)) ==-1 ) { goto bad; } ip->id =htons (ntohs (ip->id) + x);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 821/1146 net/sched: sch_dualpi2: drain both C-queue and L-queue in dualpi2_change()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chia-Yu Chang <[email protected]>
[ Upstream commit 478ed6b7d2577439c610f91fa8759a4c878a4264 ]
Fix dualpi2_change() to correctly enforce updated limit and memlimit values after a configuration change of the dualpi2 qdisc.
Before this patch, dualpi2_change() always attempted to dequeue packets via the root qdisc (C-queue) when reducing backlog or memory usage, and unconditionally assumed that a valid skb will be returned. When traffic classification results in packets being queued in the L-queue while the C-queue is empty, this leads to a NULL skb dereference during limit or memlimit enforcement.
This is fixed by first dequeuing from the C-queue path if it is non-empty. Once the C-queue is empty, packets are dequeued directly from the L-queue. Return values from qdisc_dequeue_internal() are checked for both queues. When dequeuing from the L-queue, the parent qdisc qlen and backlog counters are updated explicitly to keep overall qdisc statistics consistent.
--- net/sched/sch_dualpi2.c | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-)
net/sched/sch_dualpi2.c +28 -4
@@ -872,11 +872,35 @@ static int dualpi2_change(struct Qdisc *sch, struct nlattr *opt, old_backlog = sch->qstats.backlog;while (qdisc_qlen (sch) > sch->limit || q->memory_used > q->memory_limit) { -struct sk_buff *skb =qdisc_dequeue_internal (sch, true); +struct sk_buff *skb =NULL ; - q->memory_used -= skb->truesize; -qdisc_qstats_backlog_dec (sch, skb); -rtnl_qdisc_drop (skb, sch); +if (qdisc_qlen (sch) >qdisc_qlen (q->l_queue)) { + skb =qdisc_dequeue_internal (sch, true); +if (unlikely (!skb)) { +WARN_ON_ONCE (1 ); +break ; + } + q->memory_used -= skb->truesize; +rtnl_qdisc_drop (skb, sch); + }else if (qdisc_qlen (q->l_queue)) { + skb =qdisc_dequeue_internal (q->l_queue, true); +if (unlikely (!skb)) { +WARN_ON_ONCE (1 ); +break ; + } +/* L-queue packets are counted in both sch and +* l_queue on enqueue; qdisc_dequeue_internal() +* handled l_queue, so we further account for sch. +*/ + --sch->q.qlen; +qdisc_qstats_backlog_dec (sch, skb); + q->memory_used -= skb->truesize; +rtnl_qdisc_drop (skb, q->l_queue); +qdisc_qstats_drop (sch); + }else { +WARN_ON_ONCE (1 ); +break ; + } }qdisc_tree_reduce_backlog (sch, old_qlen -qdisc_qlen (sch), old_backlog - sch->qstats.backlog);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 822/1146 arm64: dts: amlogic: meson-axg: Add missing cache information to cpu0
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Anand Moon <[email protected]>
[ Upstream commit 918273be0885362a9a00615b46e03f15f8b55667 ]
Add missing L1 data and instruction cache parameters to the CPU node 0 for the Cortex-A53 caches on the Meson AXG SoC.
--- arch/arm64/boot/dts/amlogic/meson-axg.dtsi | 6 ++++++ 1 file changed, 6 insertions(+)
arch/arm64/boot/dts/amlogic/meson-axg.dtsi +6 -0
@@ -72,6 +72,12 @@ cpu0: cpu@0 { compatible = "arm,cortex-a53"; reg = <0x0 0x0>; enable-method = "psci"; + d-cache-line-size = <32>; + d-cache-size = <0x8000>; + d-cache-sets = <32>; + i-cache-line-size = <32>; + i-cache-size = <0x8000>; + i-cache-sets = <32>; next-level-cache = <&l2>; clocks = <&scpi_dvfs 0>; dynamic-power-coefficient = <140>;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 823/1146 arm64: dts: meson-gxl-p230: fix ethernet PHY interrupt number
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jun Yan <[email protected]>
[ Upstream commit 174a0ef3b33434f475c87e66f37980e39b73805a ]
Correct the interrupt number assigned to the Realtek PHY in the p230
following the same logic as commit 3106507e1004 ("ARM64: dts: meson-gxm:
fix q200 interrupt number"),as reported in [PATCH 0/2] Ethernet PHY interrupt improvements [1].
[1] https://lore.kernel.org/all/[email protected]/
--- arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
arch/arm64/boot/dts/amlogic/meson-gxl-s905d-p230.dts +2 -1
@@ -84,7 +84,8 @@ external_phy: ethernet-phy@0 { reset-gpios = <&gpio GPIOZ_14 GPIO_ACTIVE_LOW>; interrupt-parent = <&gpio_intc>; - interrupts = <29 IRQ_TYPE_LEVEL_LOW>; + /* MAC_INTR on GPIOZ_15 */ + interrupts = <25 IRQ_TYPE_LEVEL_LOW>; eee-broken-1000t; }; };
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 824/1146 vfio/pci: Clean up DMABUFs before disabling function
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Matt Evans <[email protected]>
[ Upstream commit d97708701434ce72968e771976aaf9d3438fcafd ]
On device shutdown, make vfio_pci_core_close_device() call vfio_pci_dma_buf_cleanup() before the function is disabled via vfio_pci_core_disable(). This ensures that all access via DMABUFs is revoked before the function's BARs become inaccessible.
This fixes an issue where, if the function is disabled first, a tiny window exists in which the function's MSE is cleared and yet BARs could still be accessed via the DMABUF. The resources would also be freed and up for grabs by a different driver.
--- drivers/vfio/pci/vfio_pci_core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/vfio/pci/vfio_pci_core.c +2 -2
@@ -734,10 +734,10 @@ void vfio_pci_core_close_device(struct vfio_device *core_vdev)#if IS_ENABLED (CONFIG_EEH )eeh_dev_release (vdev->pdev);#endif -vfio_pci_core_disable (vdev); -vfio_pci_dma_buf_cleanup (vdev); +vfio_pci_core_disable (vdev); +mutex_lock (&vdev->igate);vfio_pci_eventfd_replace_locked (vdev, &vdev->err_trigger,NULL );vfio_pci_eventfd_replace_locked (vdev, &vdev->req_trigger,NULL );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 825/1146 pwm: atmel-tcb: Cache clock rates and mark chip as atomic
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sangyun Kim <[email protected]>
[ Upstream commit 68637b68afcc3cb4d56aca14a3a1d1b47b879369 ]
atmel_tcb_pwm_apply() holds tcbpwmc->lock as a spinlock via guard(spinlock)() and then calls atmel_tcb_pwm_config(), which calls clk_get_rate() twice. clk_get_rate() acquires clk_prepare_lock (a mutex), so this is a sleep-in-atomic-context violation.
On CONFIG_DEBUG_ATOMIC_SLEEP kernels every pwm_apply_state() that enables or reconfigures the PWM triggers a "BUG: sleeping function called from invalid context" warning.
Acquire exclusive control over the clock rates with clk_rate_exclusive_get() at probe time and cache the rates in struct atmel_tcb_pwm_chip, then read the cached rates from atmel_tcb_pwm_config(). This keeps the spinlock-based mutual exclusion introduced in commit 37f7707077f5 ("pwm: atmel-tcb: Fix race condition and convert to guards") and removes the sleeping calls from the atomic section.
With no sleeping calls left in .apply() and the regmap-mmio bus already running with fast_io=true, also mark the chip as atomic so consumers can use pwm_apply_atomic() from atomic context.
--- drivers/pwm/pwm-atmel-tcb.c | 38 +++++++++++++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 4 deletions(-)
drivers/pwm/pwm-atmel-tcb.c +34 -4
@@ -50,6 +50,8 @@ struct atmel_tcb_pwm_chip {spinlock_t lock;u8 channel;u8 width; +unsigned long rate; +unsigned long slow_rate;struct regmap *regmap;struct clk *clk;struct clk *gclk;
@@ -266,7 +268,7 @@ static int atmel_tcb_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,int slowclk =0 ;unsigned period;unsigned duty; -unsigned rate =clk_get_rate (tcbpwmc->clk); +unsigned long rate = tcbpwmc->rate;unsigned long long min;unsigned long long max;
@@ -294,7 +296,7 @@ static int atmel_tcb_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,*/ if (i ==ARRAY_SIZE (atmel_tcb_divisors)) { i = slowclk; - rate =clk_get_rate (tcbpwmc->slow_clk); + rate = tcbpwmc->slow_rate; min =div_u64 (NSEC_PER_SEC , rate); max = min << tcbpwmc->width;
@@ -431,24 +433,49 @@ static int atmel_tcb_pwm_probe(struct platform_device *pdev) } chip->ops = &atmel_tcb_pwm_ops; + chip->atomic = true; tcbpwmc->channel = channel; tcbpwmc->width = config->counter_width; - err =clk_prepare_enable (tcbpwmc->slow_clk); + err =clk_prepare_enable (tcbpwmc->clk);if (err) goto err_gclk; + err =clk_prepare_enable (tcbpwmc->slow_clk); +if (err) + goto err_disable_clk;; + + err =clk_rate_exclusive_get (tcbpwmc->clk); +if (err) + goto err_disable_slow_clk; + + err =clk_rate_exclusive_get (tcbpwmc->slow_clk); +if (err) + goto err_clk_unlock; + + tcbpwmc->rate =clk_get_rate (tcbpwmc->clk); + tcbpwmc->slow_rate =clk_get_rate (tcbpwmc->slow_clk); +spin_lock_init (&tcbpwmc->lock); err =pwmchip_add (chip);if (err <0 ) - goto err_disable_clk; + goto err_slow_clk_unlock;platform_set_drvdata (pdev, chip);return 0 ; +err_slow_clk_unlock: +clk_rate_exclusive_put (tcbpwmc->slow_clk); + +err_clk_unlock: +clk_rate_exclusive_put (tcbpwmc->clk); + err_disable_clk: +clk_disable_unprepare (tcbpwmc->clk); + +err_disable_slow_clk:clk_disable_unprepare (tcbpwmc->slow_clk); err_gclk:
@@ -470,6 +497,9 @@ static void atmel_tcb_pwm_remove(struct platform_device *pdev)pwmchip_remove (chip); +clk_rate_exclusive_put (tcbpwmc->slow_clk); +clk_rate_exclusive_put (tcbpwmc->clk); +clk_disable_unprepare (tcbpwmc->clk);clk_disable_unprepare (tcbpwmc->slow_clk);clk_put (tcbpwmc->gclk);clk_put (tcbpwmc->clk);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 826/1146 ksmbd: destroy tree_conn_ida in ksmbd_session_destroy()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: DaeMyung Kang <[email protected]>
[ Upstream commit c049ee14eb4343b69b6f7755563f961f5e153423 ]
When per-session tree_conn_ida was converted from a dynamically allocated ksmbd_ida to an embedded struct ida, ksmbd_ida_free() was removed from ksmbd_session_destroy() but no matching ida_destroy() was added. The session is therefore freed with the IDA's backing xarray still intact.
The kernel IDA API expects ida_init() and ida_destroy() to be paired over an object's lifetime, so add the missing cleanup before the enclosing session is freed.
Also move ida_init() to right after the session is allocated so that it is always paired with the destroy call even on the early error paths of __session_create() (ksmbd_init_file_table() or __init_smb2_session() failures), both of which jump to the error label and invoke ksmbd_session_destroy() on a partially initialised session.
No leak has been observed in testing; this is a pairing fix to match the IDA lifetime rules, not a response to a reproduced regression.
--- fs/smb/server/mgmt/user_session.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
fs/smb/server/mgmt/user_session.c +3 -2
@@ -391,6 +391,7 @@ void ksmbd_session_destroy(struct ksmbd_session *sess)free_channel_list (sess);kfree (sess->Preauth_HashValue);ksmbd_release_id (&session_ida, sess->id); +ida_destroy (&sess->tree_conn_ida);kfree (sess); }
@@ -665,6 +666,8 @@ static struct ksmbd_session *__session_create(int protocol)if (!sess)return NULL ; +ida_init (&sess->tree_conn_ida); +if (ksmbd_init_file_table (&sess->file_table)) goto error;
@@ -684,8 +687,6 @@ static struct ksmbd_session *__session_create(int protocol)if (ret) goto error; -ida_init (&sess->tree_conn_ida); -down_write (&sessions_table_lock);hash_add (sessions_table, &sess->hlist, sess->id);up_write (&sessions_table_lock);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 827/1146 ksmbd: destroy async_ida in ksmbd_conn_free()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: DaeMyung Kang <[email protected]>
[ Upstream commit b32c8db48212a34998c36d0bbc05b29d5c407ef5 ]
When per-connection async_ida was converted from a dynamically allocated ksmbd_ida to an embedded struct ida, ksmbd_ida_free() was removed from the connection teardown path but no matching ida_destroy() was added. The connection is therefore freed with the IDA's backing xarray still intact.
The kernel IDA API expects ida_init() and ida_destroy() to be paired over an object's lifetime, so add the missing cleanup before the connection is freed.
No leak has been observed in testing; this is a pairing fix to match the IDA lifetime rules, not a response to a reproduced regression.
--- fs/smb/server/connection.c | 9 +++++++++ 1 file changed, 9 insertions(+)
fs/smb/server/connection.c +9 -0
@@ -98,6 +98,15 @@ void ksmbd_conn_free(struct ksmbd_conn *conn)kfree (conn->preauth_info);kfree (conn->mechToken);if (atomic_dec_and_test (&conn->refcnt)) { +/* +* async_ida is embedded in struct ksmbd_conn, so pair +* ida_destroy() with the final kfree() rather than with +* the unconditional field teardown above. This keeps +* the IDA valid for the entire lifetime of the struct, +* even while other refcount holders (oplock / vfs +* durable handles) still reference the connection. +*/ +ida_destroy (&conn->async_ida); conn->transport->ops->free_transport (conn->transport);kfree (conn); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 828/1146 ksmbd: fix durable fd leak on ClientGUID mismatch in durable v2 open
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: DaeMyung Kang <[email protected]>
[ Upstream commit 804054d19886ac6628883d82410f6ee42a818664 ]
ksmbd_lookup_fd_cguid() returns a ksmbd_file with its refcount incremented via ksmbd_fp_get(). parse_durable_handle_context() in the DURABLE_REQ_V2 case properly releases this reference on every path inside the ClientGUID-match branch, either by calling ksmbd_put_durable_fd() or by transferring ownership to dh_info->fp for a successful reconnect. However, when an entry exists in the global file table with the same CreateGuid but a different ClientGUID, the code simply falls through to the new-open path without dropping the reference obtained from ksmbd_lookup_fd_cguid().
Per MS-SMB2 section 3.3.5.9.10 ("Handling the SMB2_CREATE_DURABLE_HANDLE_REQUEST_V2 Create Context"), the server MUST locate an Open whose Open.CreateGuid matches the request's CreateGuid AND whose Open.ClientGuid matches the ClientGuid of the connection that received the request. If no such Open is found, the server MUST continue with the normal open execution phase. A CreateGuid hit with a ClientGUID mismatch is therefore the "Open not found" case: proceeding with a new open is correct, but the reference obtained purely as a side effect of the lookup must not be leaked.
Repeated requests that hit this mismatch pin global_ft entries, prevent __ksmbd_close_fd() from ever running for the corresponding files, and defeat the durable scavenger, leading to long-lived resource leaks.
Release the reference in the mismatch path and clear dh_info->fp so subsequent logic does not mistake a non-matching lookup result for a reconnect target.
--- fs/smb/server/smb2pdu.c | 2 ++ 1 file changed, 2 insertions(+)
fs/smb/server/smb2pdu.c +2 -0
@@ -2845,6 +2845,8 @@ static int parse_durable_handle_context(struct ksmbd_work *work, dh_info->reconnected = true; goto out; } +ksmbd_put_durable_fd (dh_info->fp); + dh_info->fp =NULL ; } if ((lc && (lc->req_state & SMB2_LEASE_HANDLE_CACHING_LE)) ||
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 829/1146 ksmbd: scope conn->binding slowpath to bound sessions only
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hyunwoo Kim <[email protected]>
[ Upstream commit b0da97c034b6107d14e537e212d4ce8b22109a58 ]
When the binding SESSION_SETUP sets conn->binding = true, the flag stays set after the call so that the global session lookup in ksmbd_session_lookup_all() can find the session, which was not added to conn->sessions. Because the flag is connection-wide, the global lookup path will also resolve any other session by id if asked.
Tighten the global lookup so that the returned session must have this connection registered in its channel xarray (sess->ksmbd_chann_list). The channel entry is installed by the existing binding_session path in ntlm_authenticate()/krb5_authenticate() when a SESSION_SETUP completes successfully, so this condition is a strict equivalent of "this connection has been accepted as a channel of this session". Connections that have not bound to a given session cannot reach it via the global table.
The existing conn->binding gate for entering the slowpath is preserved so that non-binding connections keep the fast-path-only behavior, and the session->state check is unchanged.
--- fs/smb/server/mgmt/user_session.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
fs/smb/server/mgmt/user_session.c +6 -1
@@ -548,8 +548,13 @@ struct ksmbd_session *ksmbd_session_lookup_all(struct ksmbd_conn *conn,struct ksmbd_session *sess; sess =ksmbd_session_lookup (conn, id); -if (!sess && conn->binding) +if (!sess && conn->binding) { sess =ksmbd_session_lookup_slowpath (id); +if (sess && !xa_load (&sess->ksmbd_chann_list, (long )conn)) { +ksmbd_user_session_put (sess); + sess =NULL ; + } + }if (sess && sess->state !=SMB2_SESSION_VALID ) {ksmbd_user_session_put (sess); sess =NULL ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 830/1146 net: validate skb->napi_id in RX tracepoints
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kohei Enju <[email protected]>
[ Upstream commit 3bfcf396081ace536733b454ff128d53116581e5 ]
Since commit 2bd82484bb4c ("xps: fix xps for stacked devices"), skb->napi_id shares storage with sender_cpu. RX tracepoints using net_dev_rx_verbose_template read skb->napi_id directly and can therefore report sender_cpu values as if they were NAPI IDs.
For example, on the loopback path this can report 1 as napi_id, where 1 comes from raw_smp_processor_id() + 1 in the XPS path:
# bpftrace -e 'tracepoint:net:netif_rx_entry{ print(args->napi_id); }'
# taskset -c 0 ping -c 1 ::1Report only valid NAPI IDs in these tracepoints and use 0 otherwise.
--- include/trace/events/net.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
include/trace/events/net.h +3 -1
@@ -10,6 +10,7 @@#include <linux/if_vlan.h> #include <linux/ip.h> #include <linux/tracepoint.h> +#include <net/busy_poll.h> TRACE_EVENT(net_dev_start_xmit,
@@ -208,7 +209,8 @@ DECLARE_EVENT_CLASS(net_dev_rx_verbose_template,TP_fast_assign ( __assign_str(name);#ifdef CONFIG_NET_RX_BUSY_POLL - __entry->napi_id = skb->napi_id; + __entry->napi_id =napi_id_valid (skb->napi_id) ? + skb->napi_id :0 ;#else __entry->napi_id =0 ;#endif
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 831/1146 bnge: fix initial HWRM sequence
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vikas Gupta <[email protected]>
[ Upstream commit 70d7c905a07ae8415b955569620bf2bf77423553 ]
Firmware may not advertize correct resources if backing store is not enabled before resource information is queried.
Fix the initial sequence of HWRMs so that driver gets capabilities and resource information correctly.
--- .../net/ethernet/broadcom/bnge/bnge_core.c | 30 ++++++++++++++----- 1 file changed, 22 insertions(+), 8 deletions(-)
drivers/net/ethernet/broadcom/bnge/bnge_core.c +22 -8
@@ -73,6 +73,13 @@ static int bnge_func_qcaps(struct bnge_dev *bd)return rc; } +return 0 ; +} + +static int bnge_func_qrcaps_qcfg (struct bnge_dev *bd) +{ +int rc; + rc =bnge_hwrm_func_resc_qcaps (bd);if (rc) {dev_err (bd->dev,"query resc caps failure rc: %d\n" , rc);
@@ -132,23 +139,28 @@ static int bnge_fw_register_dev(struct bnge_dev *bd)bnge_hwrm_fw_set_time (bd); - rc =bnge_hwrm_func_drv_rgtr (bd); +/* Get the resources and configuration from firmware */ + rc =bnge_func_qcaps (bd);if (rc) { -dev_err (bd->dev,"Failed to rgtr with firmware rc: %d\n" , rc); +dev_err (bd->dev,"Failed querying caps rc: %d\n" , rc);return rc; } rc =bnge_alloc_ctx_mem (bd);if (rc) {dev_err (bd->dev,"Failed to allocate ctx mem rc: %d\n" , rc); - goto err_func_unrgtr; + goto err_free_ctx_mem; } -/* Get the resources and configuration from firmware */ - rc =bnge_func_qcaps (bd); + rc =bnge_hwrm_func_drv_rgtr (bd);if (rc) { -dev_err (bd->dev,"Failed initial configuration rc: %d\n" , rc); - rc = -ENODEV ; +dev_err (bd->dev,"Failed to rgtr with firmware rc: %d\n" , rc); + goto err_free_ctx_mem; + } + + rc =bnge_func_qrcaps_qcfg (bd); +if (rc) { +dev_err (bd->dev,"Failed querying resources rc: %d\n" , rc); goto err_func_unrgtr; }
@@ -157,7 +169,9 @@ static int bnge_fw_register_dev(struct bnge_dev *bd)return 0 ; err_func_unrgtr: -bnge_fw_unregister_dev (bd); +bnge_hwrm_func_drv_unrgtr (bd); +err_free_ctx_mem: +bnge_free_ctx_mem (bd);return rc; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 832/1146 bnge: remove unsupported backing store type
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vikas Gupta <[email protected]>
[ Upstream commit c6b34add67a5402f53359580956b5c318965a893 ]
The backing store type, BNGE_CTX_MRAV, is not applicable in Thor Ultra devices. Remove it from the backing store configuration, as the firmware will not populate entities in this backing store type, due to which the driver load fails.
--- drivers/net/ethernet/broadcom/bnge/bnge_rmem.c | 16 ---------------- 1 file changed, 16 deletions(-)
drivers/net/ethernet/broadcom/bnge/bnge_rmem.c +0 -16
@@ -324,7 +324,6 @@ int bnge_alloc_ctx_mem(struct bnge_dev *bd)u32 l2_qps, qp1_qps, max_qps;u32 ena, entries_sp, entries;u32 srqs, max_srqs, min; -u32 num_mr, num_ah;u32 extra_srqs =0 ;u32 extra_qps =0 ;u32 fast_qpmd_qps;
@@ -390,21 +389,6 @@ int bnge_alloc_ctx_mem(struct bnge_dev *bd)if (!bnge_is_roce_en (bd)) goto skip_rdma; - ctxm = &ctx->ctx_arr[BNGE_CTX_MRAV ]; -/* 128K extra is needed to accommodate static AH context -* allocation by f/w. -*/ - num_mr =min_t (u32, ctxm->max_entries /2 ,1024 *256 ); - num_ah =min_t (u32, num_mr,1024 *128 ); - ctxm->split_entry_cnt =BNGE_CTX_MRAV_AV_SPLIT_ENTRY +1 ; -if (!ctxm->mrav_av_entries || ctxm->mrav_av_entries > num_ah) - ctxm->mrav_av_entries = num_ah; - - rc =bnge_setup_ctxm_pg_tbls (bd, ctxm, num_mr + num_ah,2 ); -if (rc) -return rc; - ena |=FUNC_BACKING_STORE_CFG_REQ_ENABLES_MRAV ; - ctxm = &ctx->ctx_arr[BNGE_CTX_TIM ]; rc =bnge_setup_ctxm_pg_tbls (bd, ctxm, l2_qps + qp1_qps + extra_qps,1 );if (rc)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 833/1146 sctp: fix sockets_allocated imbalance after sk_clone()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xin Long <[email protected]>
[ Upstream commit 7c9b012d6367a335f1e91da28401a7c612305a46 ]
sk_clone() increments sockets_allocated and sets the socket refcount to 2. SCTP performs additional accounting in sctp_clone_sock(), so the clone-time increment must be undone to avoid double counting.
Note we cannot simply remove the SCTP-side increment, because the SCTP destroy path in sctp_destroy_sock() only decrements sockets_allocated when sp->ep is set, which may not be true for all failure paths in sctp_clone_sock().
--- net/sctp/socket.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
net/sctp/socket.c +2 -1
@@ -4864,8 +4864,9 @@ static struct sock *sctp_clone_sock(struct sock *sk,if (!newsk)return ERR_PTR (err); -/* sk_clone() sets refcnt to 2 */ +/* sk_clone() sets refcnt to 2 and increments sockets_allocated */ sock_put (newsk); +sk_sockets_allocated_dec (newsk); newinet =inet_sk (newsk); newsp =sctp_sk (newsk);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 834/1146 net/rds: zero per-item info buffer before handing it to visitors
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Bommarito <[email protected]>
[ Upstream commit c88eb7e8d8397a8c1db59c425332c5a30b2a1682 ]
rds_for_each_conn_info() and rds_walk_conn_path_info() both hand a caller-allocated on-stack u64 buffer to a per-connection visitor and then copy the full item_len bytes back to user space via rds_info_copy() regardless of how much of the buffer the visitor actually wrote.
rds_ib_conn_info_visitor() and rds6_ib_conn_info_visitor() only write a subset of their output struct when the underlying rds_connection is not in state RDS_CONN_UP (src/dst addr, tos, sl and the two GIDs via explicit memsets). Several u32 fields (max_send_wr, max_recv_wr, max_send_sge, rdma_mr_max, rdma_mr_size, cache_allocs) and the 2-byte alignment hole between sl and cache_allocs remain as whatever stack contents preceded the visitor call and are then memcpy_to_user()'d out to user space.
struct rds_info_rdma_connection and struct rds6_info_rdma_connection are the only rds_info_* structs in include/uapi/linux/rds.h that are not marked __attribute__((packed)), so they have a real alignment hole. The other info visitors (rds_conn_info_visitor, rds6_conn_info_visitor, rds_tcp_tc_info, ...) write all fields of their packed output struct today and are not known to be vulnerable, but a future visitor that adds a conditional write-path would have the same bug.
Reproduction on a kernel built without CONFIG_INIT_STACK_ALL_ZERO=y:
a local unprivileged user opens AF_RDS, sets SO_RDS_TRANSPORT=IB, binds to a local address on an RDMA-capable netdev (rxe soft-RoCE on any netdev is sufficient), sendto()'s any peer on the same subnet (fails cleanly but installs an rds_connection in the global hash in RDS_CONN_CONNECTING), then calls getsockopt(SOL_RDS, RDS_INFO_IB_CONNECTIONS). The returned 68-byte item contains 26 bytes of stack garbage including kernel text/data pointers:
0..7 0a 63 00 01 0a 63 00 02 src=10.99.0.1 dst=10.99.0.2
8..39 00 ... gids (memset-zeroed)
40..47 e0 92 a3 81 ff ff ff ff kernel pointer (max_send_wr)
48..55 7f 37 b5 81 ff ff ff ff kernel pointer (rdma_mr_max)
56..59 01 00 08 00 rdma_mr_size (garbage)
60..61 00 00 tos, sl
62..63 00 00 alignment padding
64..67 18 00 00 00 cache_allocs (garbage)Fix by zeroing the per-item buffer in both rds_for_each_conn_info() and rds_walk_conn_path_info() before invoking the visitor. This covers the IPv4/IPv6 IB visitors and hardens all current and future visitors against the same class of bug.
No functional change for visitors that fully populate their output.
Changes in v2:
- retarget at the net tree (subject prefix "[PATCH net v2]", net/rds: prefix in the title)
- pick up Reviewed-by tags from Sharath Srinivasan and Allison Henderson
--- net/rds/connection.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+)
net/rds/connection.c +14 -0
@@ -701,6 +701,13 @@ void rds_for_each_conn_info(struct socket *sock, unsigned int len, i++, head++) {hlist_for_each_entry_rcu (conn, head, c_hash_node) { +/* Zero the per-item buffer before handing it to the +* visitor so any field the visitor does not write - +* including implicit alignment padding - cannot leak +* stack contents to user space via rds_info_copy(). +*/ +memset (buffer,0 , item_len); +/* XXX no c_lock usage.. */ if (!visitor (conn, buffer))continue ;
@@ -750,6 +757,13 @@ static void rds_walk_conn_path_info(struct socket *sock, unsigned int len,*/ cp = conn->c_path; +/* Zero the per-item buffer for the same reason as +* rds_for_each_conn_info(): any byte the visitor +* does not write (including alignment padding) must +* not leak stack contents via rds_info_copy(). +*/ +memset (buffer,0 , item_len); +/* XXX no cp_lock usage.. */ if (!visitor (cp, buffer))continue ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 835/1146 ice: fix timestamp interrupt configuration for E825C
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Grzegorz Nitka <[email protected]>
[ Upstream commit c0a575a801a2040eb1e0db54b488f8c548c8458a ]
The E825C ice_phy_cfg_intr_eth56g() function is responsible for programming the PHY interrupt for a given port. This function writes to the PHY_REG_TS_INT_CONFIG register of the port. The register is responsible for configuring whether the port interrupt logic is enabled, as well as programming the threshold of waiting timestamps that will trigger an interrupt from this port.
This threshold value must not be programmed to zero while the interrupt is enabled. Doing so puts the port in a misconfigured state where the PHY timestamp interrupt for the quad of connected ports will become stuck.
This occurs, because a threshold of zero results in the timestamp interrupt status for the port becoming stuck high. The four ports in the connected quad have their timestamp status indicators muxed together. A new interrupt cannot be generated until the timestamp status indicators return low for all four ports.
Normally, the timestamp status for a port will clear once there are fewer timestamps in that ports timestamp memory bank than the threshold. A threshold of zero makes this impossible, so the timestamp status for the port does not clear.
The ice driver never intentionally programs the threshold to zero, indeed the driver always programs it to a value of 1, intending to get an interrupt immediately as soon as even a single packet is waiting for a timestamp.
However, there is a subtle flaw in the programming logic in the ice_phy_cfg_intr_eth56g() function. Due to the way that the hardware handles enabling the PHY interrupt. If the threshold value is modified at the same time as the interrupt is enabled, the HW PHY state machine might enable the interrupt before the new threshold value is actually updated. This leaves a potential race condition caused by the hardware logic where a PHY timestamp interrupt might be triggered before the non-zero threshold is written, resulting in the PHY timestamp logic becoming stuck.
Once the PHY timestamp status is stuck high, it will remain stuck even after attempting to reprogram the PHY block by changing its threshold or disabling the interrupt. Even a typical PF or CORE reset will not reset the particular block of the PHY that becomes stuck. Even a warm power cycle is not guaranteed to cause the PHY block to reset, and a cold power cycle is required.
Prevent this by always writing the PHY_REG_TS_INT_CONFIG in two stages. First write the threshold value with the interrupt disabled, and only write the enable bit after the threshold has been programmed. When disabling the interrupt, leave the threshold unchanged. Additionally, re-read the register after writing it to guarantee that the write to the PHY has been flushed upon exit of the function.
While we're modifying this function implementation, explicitly reject programming a threshold of 0 when enabling the interrupt. No caller does this today, but the consequences of doing so are significant. An explicit rejection in the code makes this clear.
--- drivers/net/ethernet/intel/ice/ice_ptp_hw.c | 36 ++++++++++++++++++--- 1 file changed, 32 insertions(+), 4 deletions(-)
drivers/net/ethernet/intel/ice/ice_ptp_hw.c +32 -4
@@ -1847,6 +1847,8 @@ static int ice_phy_cfg_mac_eth56g(struct ice_hw *hw, u8 port)* @ena: enable or disable interrupt * @threshold: interrupt threshold * +* The threshold cannot be 0 while the interrupt is enabled. +* * Configure TX timestamp interrupt for the specified port * * Return:
@@ -1858,19 +1860,45 @@ int ice_phy_cfg_intr_eth56g(struct ice_hw *hw, u8 port, bool ena, u8 threshold)int err;u32 val; +if (ena && !threshold) +return -EINVAL ; + err =ice_read_ptp_reg_eth56g (hw, port,PHY_REG_TS_INT_CONFIG , &val);if (err)return err; + val &= ~PHY_TS_INT_CONFIG_ENA_M ;if (ena) { - val |=PHY_TS_INT_CONFIG_ENA_M ; val &= ~PHY_TS_INT_CONFIG_THRESHOLD_M ; val |=FIELD_PREP (PHY_TS_INT_CONFIG_THRESHOLD_M , threshold); - }else { - val &= ~PHY_TS_INT_CONFIG_ENA_M ; + err =ice_write_ptp_reg_eth56g (hw, port,PHY_REG_TS_INT_CONFIG , + val); +if (err) { +ice_debug (hw,ICE_DBG_PTP , +"Failed to update 'threshold' PHY_REG_TS_INT_CONFIG port=%u ena=%u threshold=%u\n" , + port, !!ena, threshold); +return err; + } + val |=PHY_TS_INT_CONFIG_ENA_M ; } -return ice_write_ptp_reg_eth56g (hw, port,PHY_REG_TS_INT_CONFIG , val); + err =ice_write_ptp_reg_eth56g (hw, port,PHY_REG_TS_INT_CONFIG , val); +if (err) { +ice_debug (hw,ICE_DBG_PTP , +"Failed to update 'ena' PHY_REG_TS_INT_CONFIG port=%u ena=%u threshold=%u\n" , + port, !!ena, threshold); +return err; + } + + err =ice_read_ptp_reg_eth56g (hw, port,PHY_REG_TS_INT_CONFIG , &val); +if (err) { +ice_debug (hw,ICE_DBG_PTP , +"Failed to read PHY_REG_TS_INT_CONFIG port=%u ena=%u threshold=%u\n" , + port, !!ena, threshold); +return err; + } + +return 0 ; }/**
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 836/1146 ice: perform PHY soft reset for E825C ports at initialization
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Grzegorz Nitka <[email protected]>
[ Upstream commit 3ec46e157c7fa420c77dfc23f7030e61f2f3fd55 ]
In some cases the PHY timestamp block of the E825C can become stuck. This is known to occur if the software writes 0 to the Tx timestamp threshold, and with older versions of the ice driver the threshold configuration is buggy and can race in such that hardware briefly operates with a zero threshold enabled. There are no other known ways to trigger this behavior, but once it occurs, the hardware is not recovered by normal reset, a driver reload, or even a warm power cycle of the system. A cold power cycle is sufficient to recover hardware, but this is extremely invasive and can result in significant downtime on customer deployments.
The PHY for each port has a timestamping block which has its own reset functionality accessible by programming the PHY_REG_GLOBAL register. Writing to the PHY_REG_GLOBAL_SOFT_RESET_BIT triggers the hardware to perform a complete reset of the timestamping block of the PHY. This includes clearing the timestamp status for the port, clearing all outstanding timestamps in the memory bank, and resetting the PHY timer.
The new ice_ptp_phy_soft_reset_eth56g() function toggles the PHY_REG_GLOBAL soft reset bit with the required delays, ensuring the PHY is properly reinitialized without requiring a full device reset. The sequence clears the reset bit, asserts it, then clears it again, with short waits between transitions to allow hardware stabilization.
Call this function in the new ice_ptp_init_phc_e825c(), implementing the E825C device specific variant of the ice_ptp_init_phc(). Note that if ice_ptp_init_phc() fails, PTP functionality may be disabled, but the driver will still load to allow basic functionality to continue.
This causes the clock owning PF driver to perform a PHY soft reset for every port during initialization. This ensures the driver begins life in a known functional state regardless of how it was previously programmed.
This ensures that we properly reconfigure the hardware after a device reset or when loading the driver, even if it was previously misconfigured with an out-of-date or modified driver.
--- drivers/net/ethernet/intel/ice/ice_ptp_hw.c | 90 ++++++++++++++++++++- drivers/net/ethernet/intel/ice/ice_ptp_hw.h | 4 + 2 files changed, 93 insertions(+), 1 deletion(-)
drivers/net/ethernet/intel/ice/ice_ptp_hw.c +89 -1
@@ -377,6 +377,31 @@ static void ice_ptp_cfg_sync_delay(const struct ice_hw *hw, u32 delay)* The following functions operate on devices with the ETH 56G PHY. */ +/** +* ice_ptp_init_phc_e825c - Perform E825C specific PHC initialization +* @hw: pointer to HW struct +* +* Perform E825C-specific PTP hardware clock initialization steps. +* +* Return: 0 on success, or a negative error value on failure. +*/ +static int ice_ptp_init_phc_e825c (struct ice_hw *hw) +{ +int err; + +/* Soft reset all ports, to ensure everything is at a clean state */ +for (int port =0 ; port < hw->ptp.num_lports; port++) { + err =ice_ptp_phy_soft_reset_eth56g (hw, port); +if (err) { +ice_debug (hw,ICE_DBG_PTP ,"Failed to soft reset port %d, err %d\n" , + port, err); +return err; + } + } + +return 0 ; +} +/** * ice_ptp_get_dest_dev_e825 - get destination PHY for given port number * @hw: pointer to the HW struct
@@ -2179,6 +2204,69 @@ int ice_ptp_read_tx_hwtstamp_status_eth56g(struct ice_hw *hw, u32 *ts_status)return 0 ; } +/** +* ice_ptp_phy_soft_reset_eth56g - Perform a PHY soft reset on ETH56G +* @hw: pointer to the HW structure +* @port: PHY port number +* +* Trigger a soft reset of the ETH56G PHY by toggling the soft reset +* bit in the PHY global register. The reset sequence consists of: +* 1. Clearing the soft reset bit +* 2. Asserting the soft reset bit +* 3. Clearing the soft reset bit again +* +* Short delays are inserted between each step to allow the hardware +* to settle. This provides a controlled way to reinitialize the PHY +* without requiring a full device reset. +* +* Return: 0 on success, or a negative error code on failure when +* reading or writing the PHY register. +*/ +int ice_ptp_phy_soft_reset_eth56g (struct ice_hw *hw,u8 port) +{ +u32 global_val; +int err; + + err =ice_read_ptp_reg_eth56g (hw, port,PHY_REG_GLOBAL , &global_val); +if (err) { +ice_debug (hw,ICE_DBG_PTP ,"Failed to read PHY_REG_GLOBAL for port %d, err %d\n" , + port, err); +return err; + } + + global_val &= ~PHY_REG_GLOBAL_SOFT_RESET_M ; +ice_debug (hw,ICE_DBG_PTP ,"Clearing soft reset bit for port %d, val: 0x%x\n" , + port, global_val); + err =ice_write_ptp_reg_eth56g (hw, port,PHY_REG_GLOBAL , global_val); +if (err) { +ice_debug (hw,ICE_DBG_PTP ,"Failed to write PHY_REG_GLOBAL for port %d, err %d\n" , + port, err); +return err; + } + +usleep_range (5000 ,6000 ); + + global_val |=PHY_REG_GLOBAL_SOFT_RESET_M ; +ice_debug (hw,ICE_DBG_PTP ,"Set soft reset bit for port %d, val: 0x%x\n" , + port, global_val); + err =ice_write_ptp_reg_eth56g (hw, port,PHY_REG_GLOBAL , global_val); +if (err) { +ice_debug (hw,ICE_DBG_PTP ,"Failed to write PHY_REG_GLOBAL for port %d, err %d\n" , + port, err); +return err; + } +usleep_range (5000 ,6000 ); + + global_val &= ~PHY_REG_GLOBAL_SOFT_RESET_M ; +ice_debug (hw,ICE_DBG_PTP ,"Clear soft reset bit for port %d, val: 0x%x\n" , + port, global_val); + err =ice_write_ptp_reg_eth56g (hw, port,PHY_REG_GLOBAL , global_val); +if (err) +ice_debug (hw,ICE_DBG_PTP ,"Failed to write PHY_REG_GLOBAL for port %d, err %d\n" , + port, err); +return err; +} +/** * ice_get_phy_tx_tstamp_ready_eth56g - Read the Tx memory status register * @hw: pointer to the HW struct
@@ -5592,7 +5680,7 @@ int ice_ptp_init_phc(struct ice_hw *hw)case ICE_MAC_GENERIC :return ice_ptp_init_phc_e82x (hw);case ICE_MAC_GENERIC_3K_E825 : -return 0 ; +return ice_ptp_init_phc_e825c (hw);default :return -EOPNOTSUPP ; }
drivers/net/ethernet/intel/ice/ice_ptp_hw.h +4 -0
@@ -374,6 +374,7 @@ int ice_stop_phy_timer_eth56g(struct ice_hw *hw, u8 port, bool soft_reset);int ice_start_phy_timer_eth56g (struct ice_hw *hw,u8 port);int ice_phy_cfg_intr_eth56g (struct ice_hw *hw,u8 port,bool ena,u8 threshold);int ice_phy_cfg_ptp_1step_eth56g (struct ice_hw *hw,u8 port); +int ice_ptp_phy_soft_reset_eth56g (struct ice_hw *hw,u8 port);#define ICE_ETH56G_NOMINAL_INCVAL 0x140000000ULL#define ICE_ETH56G_NOMINAL_PCS_REF_TUS 0x100000000ULL
@@ -676,6 +677,9 @@ static inline u64 ice_get_base_incval(struct ice_hw *hw)#define ICE_P0_GNSS_PRSNT_N BIT(4)/* ETH56G PHY register addresses */ +#define PHY_REG_GLOBAL 0x0 +#define PHY_REG_GLOBAL_SOFT_RESET_M BIT(11) +/* Timestamp PHY incval registers */ #define PHY_REG_TIMETUS_L 0x8#define PHY_REG_TIMETUS_U 0xC
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 837/1146 ice: fix ready bitmap check for non-E822 devices
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jacob Keller <[email protected]>
[ Upstream commit 359dc1d41358c88955eeff1b75aee55da7a415d3 ]
The E800 hardware (apart from E810) has a ready bitmap for the PHY indicating which timestamp slots currently have an outstanding timestamp waiting to be read by software.
This bitmap is checked in multiple places using the ice_get_phy_tx_tstamp_ready():
* ice_ptp_process_tx_tstamp() calls it to determine which timestamps to attempt reading from the PHY
* ice_ptp_tx_tstamps_pending() calls it in a loop at the end of the miscellaneous IRQ to check if new timestamps came in while the interrupt handler was executing.
* ice_ptp_maybe_trigger_tx_interrupt() calls it in the auxiliary work task to trigger a software interrupt in the event that the hardware logic gets stuck.
For E82X devices, multiple PHYs share the same block, and the parameter passed to the ready bitmap is a block number associated with the given port. For E825-C devices, the PHYs have their own independent blocks and do not share, so the parameter passed needs to be the port number. For E810 devices, the ice_get_phy_tx_tstamp_ready() always returns all 1s regardless of what port, since this hardware does not have a ready bitmap. Finally, for E830 devices, each PF has its own ready bitmap accessible via register, and the block parameter is unused.
The first call correctly uses the Tx timestamp tracker block parameter to check the appropriate timestamp block. This works because the tracker is setup correctly for each timestamp device type.
The second two callers behave incorrectly for all device types other than the older E822 devices. They both iterate in a loop using ICE_GET_QUAD_NUM() which is a macro only used by E822 devices. This logic is incorrect for devices other than the E822 devices.
For E810 the calls would always return true, causing E810 devices to always attempt to trigger a software interrupt even when they have no reason to. For E830, this results in duplicate work as the ready bitmap is checked once per number of quads. Finally, for E825-C, this results in the pending checks failing to detect timestamps on ports other than the first two.
Fix this by introducing a new hardware API function to ice_ptp_hw.c, ice_check_phy_tx_tstamp_ready(). This function will check if any timestamps are available and returns a positive value if any timestamps are pending. For E810, the function always returns false, so that the re-trigger checks never happen. For E830, check the ready bitmap just once. For E82x hardware, check each quad. Finally, for E825-C, check every port.
The interface function returns an integer to enable reporting of error code if the driver is unable read the ready bitmap. This enables callers to handle this case properly. The previous implementation assumed that timestamps are available if they failed to read the bitmap. This is problematic as it could lead to continuous software IRQ triggering if the PHY timestamp registers somehow become inaccessible.
This change is especially important for E825-C devices, as the missing checks could leave a window open where a new timestamp could arrive while the existing timestamps aren't completed. As a result, the hardware threshold logic would not trigger a new interrupt. Without the check, the timestamp is left unhandled, and new timestamps will not cause an interrupt again until the timestamp is handled. Since both the interrupt check and the backup check in the auxiliary task do not function properly, the device may have Tx timestamps permanently stuck failing on a given port.
The faulty checks originate from commit d938a8cca88a ("ice: Auxbus devices & driver for E822 TS") and commit 712e876371f8 ("ice: periodically kick Tx timestamp interrupt"), however at the time of the original coding, both functions only operated on E822 hardware. This is no longer the case, and hasn't been since the introduction of the ETH56G PHY model in commit 7cab44f1c35f ("ice: Introduce ETH56G PHY model for E825C products")
--- drivers/net/ethernet/intel/ice/ice_ptp.c | 44 +++----- drivers/net/ethernet/intel/ice/ice_ptp_hw.c | 117 ++++++++++++++++++++ drivers/net/ethernet/intel/ice/ice_ptp_hw.h | 1 + 3 files changed, 136 insertions(+), 26 deletions(-)
drivers/net/ethernet/intel/ice/ice_ptp.c +18 -26
@@ -2710,7 +2710,7 @@ static bool ice_any_port_has_timestamps(struct ice_pf *pf)bool ice_ptp_tx_tstamps_pending (struct ice_pf *pf) {struct ice_hw *hw = &pf->hw; -unsigned int i; +int ret;/* Check software indicator */ switch (pf->ptp.tx_interrupt_mode) {
@@ -2731,16 +2731,19 @@ bool ice_ptp_tx_tstamps_pending(struct ice_pf *pf) }/* Check hardware indicator */ -for (i =0 ; i <ICE_GET_QUAD_NUM (hw->ptp.num_lports); i++) { -u64 tstamp_ready =0 ; -int err; - - err =ice_get_phy_tx_tstamp_ready (&pf->hw, i, &tstamp_ready); -if (err || tstamp_ready) -return true; + ret =ice_check_phy_tx_tstamp_ready (hw); +if (ret <0 ) { +dev_dbg (ice_pf_to_dev (pf),"Unable to read PHY Tx timestamp ready bitmap, err %d\n" , + ret); +/* Stop triggering IRQs if we're unable to read PHY */ +return false; } -return false; +/* ice_check_phy_tx_tstamp_ready() returns 1 if there are timestamps +* available, 0 if there are no waiting timestamps, and a negative +* value if there was an error (which we checked for above). +*/ +return ret >0 ; }/**
@@ -2824,8 +2827,7 @@ static void ice_ptp_maybe_trigger_tx_interrupt(struct ice_pf *pf) {struct device *dev =ice_pf_to_dev (pf);struct ice_hw *hw = &pf->hw; -bool trigger_oicr = false; -unsigned int i; +int ret;if (!pf->ptp.port.tx.has_ready_bitmap)return ;
@@ -2833,21 +2835,11 @@ static void ice_ptp_maybe_trigger_tx_interrupt(struct ice_pf *pf)if (!ice_pf_src_tmr_owned (pf))return ; -for (i =0 ; i <ICE_GET_QUAD_NUM (hw->ptp.num_lports); i++) { -u64 tstamp_ready; -int err; - - err =ice_get_phy_tx_tstamp_ready (&pf->hw, i, &tstamp_ready); -if (!err && tstamp_ready) { - trigger_oicr = true; -break ; - } - } - -if (trigger_oicr) { -/* Trigger a software interrupt, to ensure this data -* gets processed. -*/ + ret =ice_check_phy_tx_tstamp_ready (hw); +if (ret <0 ) { +dev_dbg (dev,"PTP periodic task unable to read PHY timestamp ready bitmap, err %d\n" , + ret); + }else if (ret) {dev_dbg (dev,"PTP periodic task detected waiting timestamps. Triggering Tx timestamp interrupt now.\n" );wr32 (hw,PFINT_OICR ,PFINT_OICR_TSYN_TX_M );
drivers/net/ethernet/intel/ice/ice_ptp_hw.c +117 -0
147 lines not on this page · raw message
drivers/net/ethernet/intel/ice/ice_ptp_hw.h +1 -0
@@ -300,6 +300,7 @@ void ice_ptp_reset_ts_memory(struct ice_hw *hw);int ice_ptp_init_phc (struct ice_hw *hw);void ice_ptp_init_hw (struct ice_hw *hw);int ice_get_phy_tx_tstamp_ready (struct ice_hw *hw,u8 block,u64 *tstamp_ready); +int ice_check_phy_tx_tstamp_ready (struct ice_hw *hw);int ice_ptp_one_port_cmd (struct ice_hw *hw,u8 configured_port,enum ice_ptp_tmr_cmd configured_cmd);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 838/1146 ice: fix ice_ptp_read_tx_hwtstamp_status_eth56g
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jacob Keller <[email protected]>
[ Upstream commit 1f75dbc53f68f0fb2acd99f92315e426a3d0b446 ]
The ice_ptp_read_tx_hwtstamp_status_eth56g function calls ice_read_phy_eth56g with a PHY index. However the function actually expects a port index. This causes the function to read the wrong PHY_PTP_INT_STATUS registers, and effectively makes the status wrong for the second set of ports from 4 to 7.
The ice_read_phy_eth56g function uses the provided port index to determine which PHY device to read. We could refactor the entire chain to take a PHY index, but this would impact many code sites. Instead, multiply the PHY index by the number of ports, so that we read from the first port of each PHY.
--- drivers/net/ethernet/intel/ice/ice_ptp_hw.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
drivers/net/ethernet/intel/ice/ice_ptp_hw.c +8 -2
@@ -2219,13 +2219,19 @@ int ice_ptp_read_tx_hwtstamp_status_eth56g(struct ice_hw *hw, u32 *ts_status) *ts_status =0 ;for (phy =0 ; phy < params->num_phys; phy++) { +u8 port;int err; - err =ice_read_phy_eth56g (hw, phy,PHY_PTP_INT_STATUS , &status); +/* ice_read_phy_eth56g expects a port index, so use the first +* port of the PHY +*/ + port = phy * hw->ptp.ports_per_phy; + + err =ice_read_phy_eth56g (hw, port,PHY_PTP_INT_STATUS , &status);if (err)return err; - *ts_status |= (status & mask) << (phy * hw->ptp.ports_per_phy); + *ts_status |= (status & mask) << port; }ice_debug (hw,ICE_DBG_PTP ,"PHY interrupt err: %x\n" , *ts_status);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 839/1146 net_sched: sch_hhf: annotate data-races in hhf_dump_stats()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit a6edf2cd4156b71e07258876b7626692e158f7e8 ]
hhf_dump_stats() only runs with RTNL held, reading fields that can be changed in qdisc fast path.
Add READ_ONCE()/WRITE_ONCE() annotations.
--- net/sched/sch_hhf.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-)
net/sched/sch_hhf.c +10 -9
@@ -198,7 +198,8 @@ static struct hh_flow_state *seek_list(const u32 hash,return NULL ;list_del (&flow->flowchain);kfree (flow); - q->hh_flows_current_cnt--; +WRITE_ONCE (q->hh_flows_current_cnt, + q->hh_flows_current_cnt -1 ); }else if (flow->hash_id == hash) {return flow; }
@@ -226,7 +227,7 @@ static struct hh_flow_state *alloc_new_hh(struct list_head *head, }if (q->hh_flows_current_cnt >= q->hh_flows_limit) { - q->hh_flows_overlimit++; +WRITE_ONCE (q->hh_flows_overlimit, q->hh_flows_overlimit +1 );return NULL ; }/* Create new entry. */
@@ -234,7 +235,7 @@ static struct hh_flow_state *alloc_new_hh(struct list_head *head,if (!flow)return NULL ; - q->hh_flows_current_cnt++; +WRITE_ONCE (q->hh_flows_current_cnt, q->hh_flows_current_cnt +1 );INIT_LIST_HEAD (&flow->flowchain);list_add_tail (&flow->flowchain, head);
@@ -309,7 +310,7 @@ static enum wdrr_bucket_idx hhf_classify(struct sk_buff *skb, struct Qdisc *sch)return WDRR_BUCKET_FOR_NON_HH ; flow->hash_id = hash; flow->hit_timestamp = now; - q->hh_flows_total_cnt++; +WRITE_ONCE (q->hh_flows_total_cnt, q->hh_flows_total_cnt +1 );/* By returning without updating counters in q->hhf_arrays, * we implicitly implement "shielding" (see Optimization O1).
@@ -403,7 +404,7 @@ static int hhf_enqueue(struct sk_buff *skb, struct Qdisc *sch,return NET_XMIT_SUCCESS ; prev_backlog = sch->qstats.backlog; - q->drop_overlimit++; +WRITE_ONCE (q->drop_overlimit, q->drop_overlimit +1 );/* Return Congestion Notification only if we dropped a packet from this * bucket. */
@@ -686,10 +687,10 @@ static int hhf_dump_stats(struct Qdisc *sch, struct gnet_dump *d) {struct hhf_sched_data *q =qdisc_priv (sch);struct tc_hhf_xstats st = { - .drop_overlimit = q->drop_overlimit, - .hh_overlimit = q->hh_flows_overlimit, - .hh_tot_count = q->hh_flows_total_cnt, - .hh_cur_count = q->hh_flows_current_cnt, + .drop_overlimit =READ_ONCE (q->drop_overlimit), + .hh_overlimit =READ_ONCE (q->hh_flows_overlimit), + .hh_tot_count =READ_ONCE (q->hh_flows_total_cnt), + .hh_cur_count =READ_ONCE (q->hh_flows_current_cnt), };return gnet_stats_copy_app (d, &st,sizeof (st));
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 840/1146 net/sched: sch_pie: annotate data-races in pie_dump_stats()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit 5154561d9b119f781249f8e845fecf059b38b483 ]
pie_dump_stats() only runs with RTNL held, reading fields that can be changed in qdisc fast path.
Add READ_ONCE()/WRITE_ONCE() annotations.
Alternative would be to acquire the qdisc spinlock, but our long-term goal is to make qdisc dump operations lockless as much as we can.
tc_pie_xstats fields don't need to be latched atomically, otherwise this bug would have been caught earlier.
--- include/net/pie.h | 2 +- net/sched/sch_pie.c | 38 +++++++++++++++++++------------------- 2 files changed, 20 insertions(+), 20 deletions(-)
include/net/pie.h +1 -1
@@ -104,7 +104,7 @@ static inline void pie_vars_init(struct pie_vars *vars) vars->dq_tstamp =DTIME_INVALID ; vars->accu_prob =0 ; vars->dq_count =DQCOUNT_INVALID ; - vars->avg_dq_rate =0 ; +WRITE_ONCE (vars->avg_dq_rate,0 ); }static inline struct pie_skb_cb *get_pie_cb (const struct sk_buff *skb)
net/sched/sch_pie.c +19 -19
@@ -90,7 +90,7 @@ static int pie_qdisc_enqueue(struct sk_buff *skb, struct Qdisc *sch,bool enqueue = false;if (unlikely (qdisc_qlen (sch) >= sch->limit)) { - q->stats.overlimit++; +WRITE_ONCE (q->stats.overlimit, q->stats.overlimit +1 ); goto out; }
@@ -104,7 +104,7 @@ static int pie_qdisc_enqueue(struct sk_buff *skb, struct Qdisc *sch,/* If packet is ecn capable, mark it if drop probability * is lower than 10%, else drop it. */ - q->stats.ecn_mark++; +WRITE_ONCE (q->stats.ecn_mark, q->stats.ecn_mark +1 ); enqueue = true; }
@@ -114,15 +114,15 @@ static int pie_qdisc_enqueue(struct sk_buff *skb, struct Qdisc *sch,if (!q->params.dq_rate_estimator)pie_set_enqueue_time (skb); - q->stats.packets_in++; +WRITE_ONCE (q->stats.packets_in, q->stats.packets_in +1 );if (qdisc_qlen (sch) > q->stats.maxq) - q->stats.maxq =qdisc_qlen (sch); +WRITE_ONCE (q->stats.maxq,qdisc_qlen (sch));return qdisc_enqueue_tail (skb, sch); } out: - q->stats.dropped++; +WRITE_ONCE (q->stats.dropped, q->stats.dropped +1 ); q->vars.accu_prob =0 ;return qdisc_drop_reason (skb, sch, to_free, reason); }
@@ -267,11 +267,11 @@ void pie_process_dequeue(struct sk_buff *skb, struct pie_params *params, count = count / dtime;if (vars->avg_dq_rate ==0 ) - vars->avg_dq_rate = count; +WRITE_ONCE (vars->avg_dq_rate, count);else - vars->avg_dq_rate = +WRITE_ONCE (vars->avg_dq_rate, (vars->avg_dq_rate - - (vars->avg_dq_rate >>3 )) + (count >>3 ); + (vars->avg_dq_rate >>3 )) + (count >>3 ));/* If the queue has receded below the threshold, we hold * on to the last drain rate calculated, else we reset
@@ -381,7 +381,7 @@ void pie_calculate_probability(struct pie_params *params, struct pie_vars *vars,if (delta >0 ) {/* prevent overflow */ if (vars->prob < oldprob) { - vars->prob =MAX_PROB ; +WRITE_ONCE (vars->prob,MAX_PROB );/* Prevent normalization error. If probability is at * maximum value already, we normalize it here, and * skip the check to do a non-linear drop in the next
@@ -392,7 +392,7 @@ void pie_calculate_probability(struct pie_params *params, struct pie_vars *vars, }else {/* prevent underflow */ if (vars->prob > oldprob) - vars->prob =0 ; +WRITE_ONCE (vars->prob,0 ); }/* Non-linear drop in probability: Reduce drop probability quickly if
@@ -403,7 +403,7 @@ void pie_calculate_probability(struct pie_params *params, struct pie_vars *vars,/* Reduce drop probability to 98.4% */ vars->prob -= vars->prob /64 ; - vars->qdelay = qdelay; +WRITE_ONCE (vars->qdelay, qdelay); vars->backlog_old = backlog;/* We restart the measurement cycle if the following conditions are met
@@ -502,21 +502,21 @@ static int pie_dump_stats(struct Qdisc *sch, struct gnet_dump *d)struct pie_sched_data *q =qdisc_priv (sch);struct tc_pie_xstats st = { .prob = q->vars.prob <<BITS_PER_BYTE , - .delay = ((u32 )PSCHED_TICKS2NS (q->vars.qdelay)) / + .delay = ((u32 )PSCHED_TICKS2NS (READ_ONCE (q->vars.qdelay))) /NSEC_PER_USEC , - .packets_in = q->stats.packets_in, - .overlimit = q->stats.overlimit, - .maxq = q->stats.maxq, - .dropped = q->stats.dropped, - .ecn_mark = q->stats.ecn_mark, + .packets_in =READ_ONCE (q->stats.packets_in), + .overlimit =READ_ONCE (q->stats.overlimit), + .maxq =READ_ONCE (q->stats.maxq), + .dropped =READ_ONCE (q->stats.dropped), + .ecn_mark =READ_ONCE (q->stats.ecn_mark), };/* avg_dq_rate is only valid if dq_rate_estimator is enabled */ st.dq_rate_estimating = q->params.dq_rate_estimator;/* unscale and return dq_rate in bytes per sec */ -if (q->params.dq_rate_estimator) - st.avg_dq_rate = q->vars.avg_dq_rate * +if (st.dq_rate_estimating) + st.avg_dq_rate =READ_ONCE (q->vars.avg_dq_rate) * (PSCHED_TICKS_PER_SEC ) >>PIE_SCALE ;return gnet_stats_copy_app (d, &st,sizeof (st));
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 841/1146 net/sched: sch_fq_codel: remove data-races from fq_codel_dump_stats()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit bbfaa73ea6871db03dc05d7f05f00557a8981f25 ]
fq_codel_dump_stats() acquires the qdisc spinlock a bit too late.
Move this acquisition before we fill st.qdisc_stats with live data.
--- net/sched/sch_fq_codel.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
net/sched/sch_fq_codel.c +2 -1
@@ -585,6 +585,8 @@ static int fq_codel_dump_stats(struct Qdisc *sch, struct gnet_dump *d) };struct list_head *pos; +sch_tree_lock (sch); + st.qdisc_stats.maxpacket = q->cstats.maxpacket; st.qdisc_stats.drop_overlimit = q->drop_overlimit; st.qdisc_stats.ecn_mark = q->cstats.ecn_mark;
@@ -593,7 +595,6 @@ static int fq_codel_dump_stats(struct Qdisc *sch, struct gnet_dump *d) st.qdisc_stats.memory_usage = q->memory_usage; st.qdisc_stats.drop_overmemory = q->drop_overmemory; -sch_tree_lock (sch);list_for_each (pos, &q->new_flows) st.qdisc_stats.new_flows_len++;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 842/1146 net/sched: sch_red: annotate data-races in red_dump_stats()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit a8f5192809caf636d05ba47c144f282cfd0e3839 ]
red_dump_stats() only runs with RTNL held, reading fields that can be changed in qdisc fast path.
Add READ_ONCE()/WRITE_ONCE() annotations.
Alternative would be to acquire the qdisc spinlock, but our long-term goal is to make qdisc dump operations lockless as much as we can.
tc_red_xstats fields don't need to be latched atomically, otherwise this bug would have been caught earlier.
--- net/sched/sch_red.c | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-)
net/sched/sch_red.c +21 -10
@@ -90,17 +90,20 @@ static int red_enqueue(struct sk_buff *skb, struct Qdisc *sch,case RED_PROB_MARK :qdisc_qstats_overlimit (sch);if (!red_use_ecn (q)) { - q->stats.prob_drop++; +WRITE_ONCE (q->stats.prob_drop, + q->stats.prob_drop +1 ); goto congestion_drop; }if (INET_ECN_set_ce (skb)) { - q->stats.prob_mark++; +WRITE_ONCE (q->stats.prob_mark, + q->stats.prob_mark +1 ); skb =tcf_qevent_handle (&q->qe_mark, sch, skb, to_free, &ret);if (!skb)return NET_XMIT_CN | ret; }else if (!red_use_nodrop (q)) { - q->stats.prob_drop++; +WRITE_ONCE (q->stats.prob_drop, + q->stats.prob_drop +1 ); goto congestion_drop; }
@@ -111,17 +114,20 @@ static int red_enqueue(struct sk_buff *skb, struct Qdisc *sch, reason =SKB_DROP_REASON_QDISC_OVERLIMIT ;qdisc_qstats_overlimit (sch);if (red_use_harddrop (q) || !red_use_ecn (q)) { - q->stats.forced_drop++; +WRITE_ONCE (q->stats.forced_drop, + q->stats.forced_drop +1 ); goto congestion_drop; }if (INET_ECN_set_ce (skb)) { - q->stats.forced_mark++; +WRITE_ONCE (q->stats.forced_mark, + q->stats.forced_mark +1 ); skb =tcf_qevent_handle (&q->qe_mark, sch, skb, to_free, &ret);if (!skb)return NET_XMIT_CN | ret; }else if (!red_use_nodrop (q)) { - q->stats.forced_drop++; +WRITE_ONCE (q->stats.forced_drop, + q->stats.forced_drop +1 ); goto congestion_drop; }
@@ -135,7 +141,8 @@ static int red_enqueue(struct sk_buff *skb, struct Qdisc *sch, sch->qstats.backlog += len; sch->q.qlen++; }else if (net_xmit_drop_count (ret)) { - q->stats.pdrop++; +WRITE_ONCE (q->stats.pdrop, + q->stats.pdrop +1 );qdisc_qstats_drop (sch); }return ret;
@@ -463,9 +470,13 @@ static int red_dump_stats(struct Qdisc *sch, struct gnet_dump *d) dev->netdev_ops->ndo_setup_tc (dev,TC_SETUP_QDISC_RED , &hw_stats_request); } - st.early = q->stats.prob_drop + q->stats.forced_drop; - st.pdrop = q->stats.pdrop; - st.marked = q->stats.prob_mark + q->stats.forced_mark; + st.early =READ_ONCE (q->stats.prob_drop) + +READ_ONCE (q->stats.forced_drop); + + st.pdrop =READ_ONCE (q->stats.pdrop); + + st.marked =READ_ONCE (q->stats.prob_mark) + +READ_ONCE (q->stats.forced_mark);return gnet_stats_copy_app (d, &st,sizeof (st)); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 843/1146 net/sched: sch_sfb: annotate data-races in sfb_dump_stats()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit 1ada03fdef82d3d7d2edb9dcd3acc91917675e48 ]
sfb_dump_stats() only runs with RTNL held, reading fields that can be changed in qdisc fast path.
Add READ_ONCE()/WRITE_ONCE() annotations.
Alternative would be to acquire the qdisc spinlock, but our long-term goal is to make qdisc dump operations lockless as much as we can.
tc_sfb_xstats fields don't need to be latched atomically, otherwise this bug would have been caught earlier.
--- net/sched/sch_sfb.c | 54 +++++++++++++++++++++++++++------------------ 1 file changed, 32 insertions(+), 22 deletions(-)
net/sched/sch_sfb.c +32 -22
@@ -130,7 +130,7 @@ static void increment_one_qlen(u32 sfbhash, u32 slot, struct sfb_sched_data *q) sfbhash >>=SFB_BUCKET_SHIFT ;if (b[hash].qlen <0xFFFF ) - b[hash].qlen++; +WRITE_ONCE (b[hash].qlen, b[hash].qlen +1 ); b +=SFB_NUMBUCKETS ;/* next level */ } }
@@ -159,7 +159,7 @@ static void decrement_one_qlen(u32 sfbhash, u32 slot, sfbhash >>=SFB_BUCKET_SHIFT ;if (b[hash].qlen >0 ) - b[hash].qlen--; +WRITE_ONCE (b[hash].qlen, b[hash].qlen -1 ); b +=SFB_NUMBUCKETS ;/* next level */ } }
@@ -179,12 +179,12 @@ static void decrement_qlen(const struct sk_buff *skb, struct sfb_sched_data *q)static void decrement_prob (struct sfb_bucket *b,struct sfb_sched_data *q) { - b->p_mark =prob_minus (b->p_mark, q->decrement); +WRITE_ONCE (b->p_mark,prob_minus (b->p_mark, q->decrement)); }static void increment_prob (struct sfb_bucket *b,struct sfb_sched_data *q) { - b->p_mark =prob_plus (b->p_mark, q->increment); +WRITE_ONCE (b->p_mark,prob_plus (b->p_mark, q->increment)); }static void sfb_zero_all_buckets (struct sfb_sched_data *q)
@@ -202,11 +202,14 @@ static u32 sfb_compute_qlen(u32 *prob_r, u32 *avgpm_r, const struct sfb_sched_daconst struct sfb_bucket *b = &q->bins[q->slot].bins[0 ][0 ];for (i =0 ; i <SFB_LEVELS *SFB_NUMBUCKETS ; i++) { -if (qlen < b->qlen) - qlen = b->qlen; - totalpm += b->p_mark; -if (prob < b->p_mark) - prob = b->p_mark; +u32 b_qlen =READ_ONCE (b->qlen); +u32 b_mark =READ_ONCE (b->p_mark); + +if (qlen < b_qlen) + qlen = b_qlen; + totalpm += b_mark; +if (prob < b_mark) + prob = b_mark; b++; } *prob_r = prob;
@@ -295,7 +298,8 @@ static int sfb_enqueue(struct sk_buff *skb, struct Qdisc *sch,if (unlikely (sch->q.qlen >= q->limit)) {qdisc_qstats_overlimit (sch); - q->stats.queuedrop++; +WRITE_ONCE (q->stats.queuedrop, + q->stats.queuedrop +1 ); goto drop; }
@@ -348,7 +352,8 @@ static int sfb_enqueue(struct sk_buff *skb, struct Qdisc *sch,if (unlikely (minqlen >= q->max)) {qdisc_qstats_overlimit (sch); - q->stats.bucketdrop++; +WRITE_ONCE (q->stats.bucketdrop, + q->stats.bucketdrop +1 ); goto drop; }
@@ -374,7 +379,8 @@ static int sfb_enqueue(struct sk_buff *skb, struct Qdisc *sch, }if (sfb_rate_limit (skb, q)) {qdisc_qstats_overlimit (sch); - q->stats.penaltydrop++; +WRITE_ONCE (q->stats.penaltydrop, + q->stats.penaltydrop +1 ); goto drop; } goto enqueue;
@@ -390,14 +396,17 @@ static int sfb_enqueue(struct sk_buff *skb, struct Qdisc *sch,* In either case, we want to start dropping packets. */ if (r < (p_min -SFB_MAX_PROB /2 ) *2 ) { - q->stats.earlydrop++; +WRITE_ONCE (q->stats.earlydrop, + q->stats.earlydrop +1 ); goto drop; } }if (INET_ECN_set_ce (skb)) { - q->stats.marked++; +WRITE_ONCE (q->stats.marked, + q->stats.marked +1 ); }else { - q->stats.earlydrop++; +WRITE_ONCE (q->stats.earlydrop, + q->stats.earlydrop +1 ); goto drop; } }
@@ -410,7 +419,8 @@ static int sfb_enqueue(struct sk_buff *skb, struct Qdisc *sch, sch->q.qlen++;increment_qlen (&cb, q); }else if (net_xmit_drop_count (ret)) { - q->stats.childdrop++; +WRITE_ONCE (q->stats.childdrop, + q->stats.childdrop +1 );qdisc_qstats_drop (sch); }return ret;
@@ -599,12 +609,12 @@ static int sfb_dump_stats(struct Qdisc *sch, struct gnet_dump *d) {struct sfb_sched_data *q =qdisc_priv (sch);struct tc_sfb_xstats st = { - .earlydrop = q->stats.earlydrop, - .penaltydrop = q->stats.penaltydrop, - .bucketdrop = q->stats.bucketdrop, - .queuedrop = q->stats.queuedrop, - .childdrop = q->stats.childdrop, - .marked = q->stats.marked, + .earlydrop =READ_ONCE (q->stats.earlydrop), + .penaltydrop =READ_ONCE (q->stats.penaltydrop), + .bucketdrop =READ_ONCE (q->stats.bucketdrop), + .queuedrop =READ_ONCE (q->stats.queuedrop), + .childdrop =READ_ONCE (q->stats.childdrop), + .marked =READ_ONCE (q->stats.marked), }; st.maxqlen =sfb_compute_qlen (&st.maxprob, &st.avgprob, q);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 844/1146 net: airoha: Move ndesc initialization at end of airoha_qdma_init_tx()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lorenzo Bianconi <[email protected]>
[ Upstream commit f329924bb49458c65297f1361f545816a5b90998 ]
If queue entry list allocation fails in airoha_qdma_init_tx_queue routine, airoha_qdma_cleanup_tx_queue() will trigger a NULL pointer dereference accessing the queue entry array. The issue is due to the early ndesc initialization in airoha_qdma_init_tx_queue(). Fix the issue moving ndesc initialization at end of airoha_qdma_init_tx routine.
--- drivers/net/ethernet/airoha/airoha_eth.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/net/ethernet/airoha/airoha_eth.c +4 -4
@@ -978,27 +978,27 @@ static int airoha_qdma_init_tx_queue(struct airoha_queue *q,dma_addr_t dma_addr;spin_lock_init (&q->lock); - q->ndesc = size; q->qdma = qdma; q->free_thr =1 +MAX_SKB_FRAGS ;INIT_LIST_HEAD (&q->tx_list); - q->entry =devm_kzalloc (eth->dev, q->ndesc *sizeof (*q->entry), + q->entry =devm_kzalloc (eth->dev, size *sizeof (*q->entry),GFP_KERNEL );if (!q->entry)return -ENOMEM ; - q->desc =dmam_alloc_coherent (eth->dev, q->ndesc *sizeof (*q->desc), + q->desc =dmam_alloc_coherent (eth->dev, size *sizeof (*q->desc), &dma_addr,GFP_KERNEL );if (!q->desc)return -ENOMEM ; -for (i =0 ; i < q->ndesc; i++) { +for (i =0 ; i < size; i++) {u32 val =FIELD_PREP (QDMA_DESC_DONE_MASK ,1 );list_add_tail (&q->entry[i].list, &q->tx_list);WRITE_ONCE (q->desc[i].ctrl,cpu_to_le32 (val)); } + q->ndesc = size;/* xmit ring drop default setting */ airoha_qdma_set(qdma, REG_TX_RING_BLOCKING(qid),
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 845/1146 net: airoha: Add missing bits in airoha_qdma_cleanup_tx_queue()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lorenzo Bianconi <[email protected]>
[ Upstream commit 3309965fe44c00fd65af7cef5016e9e782c021a7 ]
Similar to airoha_qdma_cleanup_rx_queue(), reset DMA TX descriptors in airoha_qdma_cleanup_tx_queue routine. Moreover, reset TX_DMA_IDX to TX_CPU_IDX to notify the NIC the QDMA TX ring is empty.
--- drivers/net/ethernet/airoha/airoha_eth.c | 32 ++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-)
drivers/net/ethernet/airoha/airoha_eth.c +30 -2
@@ -1063,12 +1063,15 @@ static int airoha_qdma_init_tx(struct airoha_qdma *qdma)static void airoha_qdma_cleanup_tx_queue (struct airoha_queue *q) { -struct airoha_eth *eth = q->qdma->eth; -int i; +struct airoha_qdma *qdma = q->qdma; +struct airoha_eth *eth = qdma->eth; +int i, qid = q - &qdma->q_tx[0 ]; +u16 index =0 ;spin_lock_bh (&q->lock);for (i =0 ; i < q->ndesc; i++) {struct airoha_queue_entry *e = &q->entry[i]; +struct airoha_qdma_desc *desc = &q->desc[i];if (!e->dma_addr)continue ;
@@ -1079,8 +1082,33 @@ static void airoha_qdma_cleanup_tx_queue(struct airoha_queue *q) e->dma_addr =0 ; e->skb =NULL ;list_add_tail (&e->list, &q->tx_list); + +/* Reset DMA descriptor */ +WRITE_ONCE (desc->ctrl,0 ); +WRITE_ONCE (desc->addr,0 ); +WRITE_ONCE (desc->data,0 ); +WRITE_ONCE (desc->msg0,0 ); +WRITE_ONCE (desc->msg1,0 ); +WRITE_ONCE (desc->msg2,0 ); + q->queued--; } + +if (!list_empty (&q->tx_list)) { +struct airoha_queue_entry *e; + + e = list_first_entry(&q->tx_list, struct airoha_queue_entry, + list); + index = e - q->entry; + } +/* Set TX_DMA_IDX to TX_CPU_IDX to notify the hw the QDMA TX ring is +* empty. +*/ +airoha_qdma_rmw (qdma,REG_TX_CPU_IDX (qid),TX_RING_CPU_IDX_MASK , +FIELD_PREP (TX_RING_CPU_IDX_MASK , index)); +airoha_qdma_rmw (qdma,REG_TX_DMA_IDX (qid),TX_RING_DMA_IDX_MASK , +FIELD_PREP (TX_RING_DMA_IDX_MASK , index)); +spin_unlock_bh (&q->lock); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 846/1146 net: dsa: realtek: rtl8365mb: fix mode mask calculation
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mieczyslaw Nalewaj <[email protected]>
[ Upstream commit 0c078021d3861966614d5e594ee03587f0c9e74d ]
The RTL8365MB_DIGITAL_INTERFACE_SELECT_MODE_MASK macro was shifting the 4-bit mask (0xF) by only (_extint % 2) bits instead of (_extint % 2) * 4. This caused the mask to overlap with the adjacent nibble when configuring odd-numbered external interfaces, selecting the wrong bits entirely.
Align the shift calculation with the existing ...MODE_OFFSET macro.
--- drivers/net/dsa/realtek/rtl8365mb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/dsa/realtek/rtl8365mb.c +1 -1
@@ -216,7 +216,7 @@ (_extint) == 2 ? RTL8365MB_DIGITAL_INTERFACE_SELECT_REG1 : \ 0x0)#define RTL8365MB_DIGITAL_INTERFACE_SELECT_MODE_MASK (_extint) \ - (0xF << (((_extint) % 2))) + (0xF << (((_extint) % 2) * 4))#define RTL8365MB_DIGITAL_INTERFACE_SELECT_MODE_OFFSET (_extint) \ (((_extint) % 2) * 4)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 847/1146 net: airoha: Move ndesc initialization at end of airoha_qdma_init_rx_queue()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lorenzo Bianconi <[email protected]>
[ Upstream commit 379050947a1828826ad7ea50c95245a56929b35a ]
If queue entry or DMA descriptor list allocation fails in airoha_qdma_init_rx_queue routine, airoha_qdma_cleanup() will trigger a NULL pointer dereference running netif_napi_del() for RX queue NAPIs since netif_napi_add() has never been executed to this particular RX NAPI. The issue is due to the early ndesc initialization in airoha_qdma_init_rx_queue() since airoha_qdma_cleanup() relies on ndesc value to check if the queue is properly initialized. Fix the issue moving ndesc initialization at end of airoha_qdma_init_tx routine. Move page_pool allocation after descriptor list allocation in order to avoid memory leaks if desc allocation fails.
--- drivers/net/ethernet/airoha/airoha_eth.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-)
drivers/net/ethernet/airoha/airoha_eth.c +7 -7
@@ -745,14 +745,18 @@ static int airoha_qdma_init_rx_queue(struct airoha_queue *q,dma_addr_t dma_addr; q->buf_size =PAGE_SIZE /2 ; - q->ndesc = ndesc; q->qdma = qdma; - q->entry =devm_kzalloc (eth->dev, q->ndesc *sizeof (*q->entry), + q->entry =devm_kzalloc (eth->dev, ndesc *sizeof (*q->entry),GFP_KERNEL );if (!q->entry)return -ENOMEM ; + q->desc =dmam_alloc_coherent (eth->dev, ndesc *sizeof (*q->desc), + &dma_addr,GFP_KERNEL ); +if (!q->desc) +return -ENOMEM ; + q->page_pool =page_pool_create (&pp_params);if (IS_ERR (q->page_pool)) {int err =PTR_ERR (q->page_pool);
@@ -761,11 +765,7 @@ static int airoha_qdma_init_rx_queue(struct airoha_queue *q,return err; } - q->desc =dmam_alloc_coherent (eth->dev, q->ndesc *sizeof (*q->desc), - &dma_addr,GFP_KERNEL ); -if (!q->desc) -return -ENOMEM ; - + q->ndesc = ndesc;netif_napi_add (eth->napi_dev, &q->napi, airoha_qdma_rx_napi_poll);airoha_qdma_wr (qdma,REG_RX_RING_BASE (qid), dma_addr);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 848/1146 net: airoha: Rework the code flow in airoha_remove() and in airoha_probe() error path
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lorenzo Bianconi <[email protected]>
[ Upstream commit b1c803d5c8167026791abfaed96fd3e6a1fcd750 ]
As suggested by Simon in [0], rework the code flow in airoha_remove() and in the airoha_probe() error path in order to rely on a more common approach un-registering configured net-devices first and destroying the hw resources at the end of the code.
Introduce airoha_qdma_cleanup routine to release QDMA resources.
[0] https://lore.kernel.org/netdev/20251214-airoha-fix-dev-registration-v1-1-860e027ad4c6@kernel.org/
Stable-dep-of: 4b91cb65789b ("net: airoha: Add size check for TX NAPIs in airoha_qdma_cleanup()")
--- drivers/net/ethernet/airoha/airoha_eth.c | 76 ++++++++++++++---------- 1 file changed, 44 insertions(+), 32 deletions(-)
drivers/net/ethernet/airoha/airoha_eth.c +44 -32
@@ -1434,6 +1434,33 @@ static int airoha_qdma_init(struct platform_device *pdev,return airoha_qdma_hw_init (qdma); } +static void airoha_qdma_cleanup (struct airoha_qdma *qdma) +{ +int i; + +for (i =0 ; i <ARRAY_SIZE (qdma->q_rx); i++) { +if (!qdma->q_rx[i].ndesc) +continue ; + +netif_napi_del (&qdma->q_rx[i].napi); +airoha_qdma_cleanup_rx_queue (&qdma->q_rx[i]); +if (qdma->q_rx[i].page_pool) { +page_pool_destroy (qdma->q_rx[i].page_pool); + qdma->q_rx[i].page_pool =NULL ; + } + } + +for (i =0 ; i <ARRAY_SIZE (qdma->q_tx_irq); i++) +netif_napi_del (&qdma->q_tx_irq[i].napi); + +for (i =0 ; i <ARRAY_SIZE (qdma->q_tx); i++) { +if (!qdma->q_tx[i].ndesc) +continue ; + +airoha_qdma_cleanup_tx_queue (&qdma->q_tx[i]); + } +} +static int airoha_hw_init (struct platform_device *pdev,struct airoha_eth *eth) {
@@ -1461,41 +1488,30 @@ static int airoha_hw_init(struct platform_device *pdev,for (i =0 ; i <ARRAY_SIZE (eth->qdma); i++) { err =airoha_qdma_init (pdev, eth, ð->qdma[i]);if (err) -return err; + goto error; } err =airoha_ppe_init (eth);if (err) -return err; + goto error;set_bit (DEV_STATE_INITIALIZED , ð->state);return 0 ; +error: +for (i =0 ; i <ARRAY_SIZE (eth->qdma); i++) +airoha_qdma_cleanup (ð->qdma[i]); + +return err; } -static void airoha_hw_cleanup (struct airoha_qdma *qdma) +static void airoha_hw_cleanup (struct airoha_eth *eth) {int i; -for (i =0 ; i <ARRAY_SIZE (qdma->q_rx); i++) { -if (!qdma->q_rx[i].ndesc) -continue ; - -netif_napi_del (&qdma->q_rx[i].napi); -airoha_qdma_cleanup_rx_queue (&qdma->q_rx[i]); -if (qdma->q_rx[i].page_pool) -page_pool_destroy (qdma->q_rx[i].page_pool); - } - -for (i =0 ; i <ARRAY_SIZE (qdma->q_tx_irq); i++) -netif_napi_del (&qdma->q_tx_irq[i].napi); - -for (i =0 ; i <ARRAY_SIZE (qdma->q_tx); i++) { -if (!qdma->q_tx[i].ndesc) -continue ; - -airoha_qdma_cleanup_tx_queue (&qdma->q_tx[i]); - } +for (i =0 ; i <ARRAY_SIZE (eth->qdma); i++) +airoha_qdma_cleanup (ð->qdma[i]); +airoha_ppe_deinit (eth); }static void airoha_qdma_start_napi (struct airoha_qdma *qdma)
@@ -3088,7 +3104,7 @@ static int airoha_probe(struct platform_device *pdev) err =airoha_hw_init (pdev, eth);if (err) - goto error_hw_cleanup; + goto error_netdev_free;for (i =0 ; i <ARRAY_SIZE (eth->qdma); i++)airoha_qdma_start_napi (ð->qdma[i]);
@@ -3117,10 +3133,6 @@ static int airoha_probe(struct platform_device *pdev) error_napi_stop:for (i =0 ; i <ARRAY_SIZE (eth->qdma); i++)airoha_qdma_stop_napi (ð->qdma[i]); -airoha_ppe_deinit (eth); -error_hw_cleanup: -for (i =0 ; i <ARRAY_SIZE (eth->qdma); i++) -airoha_hw_cleanup (ð->qdma[i]);for (i =0 ; i <ARRAY_SIZE (eth->ports); i++) {struct airoha_gdm_port *port = eth->ports[i];
@@ -3132,6 +3144,8 @@ static int airoha_probe(struct platform_device *pdev)unregister_netdev (port->dev);airoha_metadata_dst_free (port); } +airoha_hw_cleanup (eth); +error_netdev_free:free_netdev (eth->napi_dev);platform_set_drvdata (pdev,NULL );
@@ -3143,10 +3157,8 @@ static void airoha_remove(struct platform_device *pdev)struct airoha_eth *eth =platform_get_drvdata (pdev);int i; -for (i =0 ; i <ARRAY_SIZE (eth->qdma); i++) { +for (i =0 ; i <ARRAY_SIZE (eth->qdma); i++)airoha_qdma_stop_napi (ð->qdma[i]); -airoha_hw_cleanup (ð->qdma[i]); - }for (i =0 ; i <ARRAY_SIZE (eth->ports); i++) {struct airoha_gdm_port *port = eth->ports[i];
@@ -3157,9 +3169,9 @@ static void airoha_remove(struct platform_device *pdev)unregister_netdev (port->dev);airoha_metadata_dst_free (port); } -free_netdev (eth->napi_dev); +airoha_hw_cleanup (eth); -airoha_ppe_deinit (eth); +free_netdev (eth->napi_dev);platform_set_drvdata (pdev,NULL ); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 849/1146 net: airoha: Add size check for TX NAPIs in airoha_qdma_cleanup()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lorenzo Bianconi <[email protected]>
[ Upstream commit 4b91cb65789b794bfc8d50554b8994f8e0f16309 ]
If airoha_qdma_init routine fails before airoha_qdma_tx_irq_init() runs successfully for all TX NAPIs, airoha_qdma_cleanup() will unconditionally runs netif_napi_del() on TX NAPIs, triggering a NULL pointer dereference. Fix the issue relying on q_tx_irq size value to check if the TX NAPIs is properly initialized in airoha_qdma_cleanup(). Moreover, run netif_napi_add_tx() just if irq_q queue is properly allocated.
--- drivers/net/ethernet/airoha/airoha_eth.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-)
drivers/net/ethernet/airoha/airoha_eth.c +8 -3
@@ -1020,8 +1020,6 @@ static int airoha_qdma_tx_irq_init(struct airoha_tx_irq_queue *irq_q,struct airoha_eth *eth = qdma->eth;dma_addr_t dma_addr; -netif_napi_add_tx (eth->napi_dev, &irq_q->napi, - airoha_qdma_tx_napi_poll); irq_q->q =dmam_alloc_coherent (eth->dev, size *sizeof (u32), &dma_addr,GFP_KERNEL );if (!irq_q->q)
@@ -1031,6 +1029,9 @@ static int airoha_qdma_tx_irq_init(struct airoha_tx_irq_queue *irq_q, irq_q->size = size; irq_q->qdma = qdma; +netif_napi_add_tx (eth->napi_dev, &irq_q->napi, + airoha_qdma_tx_napi_poll); +airoha_qdma_wr (qdma,REG_TX_IRQ_BASE (id), dma_addr);airoha_qdma_rmw (qdma,REG_TX_IRQ_CFG (id),TX_IRQ_DEPTH_MASK ,FIELD_PREP (TX_IRQ_DEPTH_MASK , size));
@@ -1450,8 +1451,12 @@ static void airoha_qdma_cleanup(struct airoha_qdma *qdma) } } -for (i =0 ; i <ARRAY_SIZE (qdma->q_tx_irq); i++) +for (i =0 ; i <ARRAY_SIZE (qdma->q_tx_irq); i++) { +if (!qdma->q_tx_irq[i].size) +continue ; +netif_napi_del (&qdma->q_tx_irq[i].napi); + }for (i =0 ; i <ARRAY_SIZE (qdma->q_tx); i++) {if (!qdma->q_tx[i].ndesc)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 850/1146 net: mana: Init link_change_work before potential error paths in probe
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Erni Sri Satya Vennela <[email protected]>
[ Upstream commit cb4a90744bcd1adf12f0d0c7c4f0dd2647444ec5 ]
Move INIT_WORK(link_change_work) to right after the mana_context allocation, before any error path that could reach mana_remove().
Previously, if mana_create_eq() or mana_query_device_cfg() failed, mana_probe() would jump to the error path which calls mana_remove(). mana_remove() unconditionally calls disable_work_sync(link_change_work), but the work struct had not been initialized yet. This can trigger CONFIG_DEBUG_OBJECTS_WORK enabled.
--- drivers/net/ethernet/microsoft/mana/mana_en.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/net/ethernet/microsoft/mana/mana_en.c +2 -2
@@ -3594,6 +3594,8 @@ int mana_probe(struct gdma_dev *gd, bool resuming) ac->gdma_dev = gd; gd->driver_data = ac; + +INIT_WORK (&ac->link_change_work, mana_link_state_handle); } err =mana_create_eq (ac);
@@ -3611,8 +3613,6 @@ int mana_probe(struct gdma_dev *gd, bool resuming)if (!resuming) { ac->num_ports = num_ports; - -INIT_WORK (&ac->link_change_work, mana_link_state_handle); }else {if (ac->num_ports != num_ports) { dev_err(dev, "The number of vPorts changed: %d->%d\n",
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 851/1146 net: mana: Init gf_stats_work before potential error paths in probe
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Erni Sri Satya Vennela <[email protected]>
[ Upstream commit 6e8bc03349fe4f09567fa76235abf52bdaf83082 ]
Move INIT_DELAYED_WORK(gf_stats_work) to before mana_create_eq(), while keeping schedule_delayed_work() at its original location.
Previously, if any function between mana_create_eq() and the INIT_DELAYED_WORK call failed, mana_probe() would call mana_remove() which unconditionally calls cancel_delayed_work_sync(gf_stats_work) in __flush_work() or debug object warnings with CONFIG_DEBUG_OBJECTS_WORK enabled.
--- drivers/net/ethernet/microsoft/mana/mana_en.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/net/ethernet/microsoft/mana/mana_en.c +2 -1
@@ -3598,6 +3598,8 @@ int mana_probe(struct gdma_dev *gd, bool resuming)INIT_WORK (&ac->link_change_work, mana_link_state_handle); } +INIT_DELAYED_WORK (&ac->gf_stats_work, mana_gf_stats_work_handler); + err =mana_create_eq (ac);if (err) {dev_err (dev,"Failed to create EQs: %d\n" , err);
@@ -3672,7 +3674,6 @@ int mana_probe(struct gdma_dev *gd, bool resuming) err =add_adev (gd,"eth" ); -INIT_DELAYED_WORK (&ac->gf_stats_work, mana_gf_stats_work_handler);schedule_delayed_work (&ac->gf_stats_work,MANA_GF_STATS_PERIOD ); out:
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 852/1146 net: mana: Guard mana_remove against double invocation
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Erni Sri Satya Vennela <[email protected]>
[ Upstream commit 50271d7ec95144d26808025b508f463780517d3c ]
If PM resume fails (e.g., mana_attach() returns an error), mana_probe() calls mana_remove(), which tears down the device and sets gd->gdma_context = NULL and gd->driver_data = NULL.
However, a failed resume callback does not automatically unbind the driver. When the device is eventually unbound, mana_remove() is invoked a second time. Without a NULL check, it dereferences gc->dev with gc == NULL, causing a kernel panic.
Add an early return if gdma_context or driver_data is NULL so the second invocation is harmless. Move the dev = gc->dev assignment after the guard so it cannot dereference NULL.
--- drivers/net/ethernet/microsoft/mana/mana_en.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
drivers/net/ethernet/microsoft/mana/mana_en.c +6 -1
@@ -3694,11 +3694,16 @@ void mana_remove(struct gdma_dev *gd, bool suspending)struct gdma_context *gc = gd->gdma_context;struct mana_context *ac = gd->driver_data;struct mana_port_context *apc; -struct device *dev = gc->dev; +struct device *dev;struct net_device *ndev;int err;int i; +if (!gc || !ac) +return ; + + dev = gc->dev; +disable_work_sync (&ac->link_change_work);cancel_delayed_work_sync (&ac->gf_stats_work);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 853/1146 net: mana: Dont overwrite port probe error with add_adev result
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Erni Sri Satya Vennela <[email protected]>
[ Upstream commit a7fdaf069bd031fcc234581fa6a580be11bf2175 ]
In mana_probe(), if mana_probe_port() fails for any port, the error is stored in 'err' and the loop breaks. However, the subsequent unconditional 'err = add_adev(gd, "eth")' overwrites this error. If add_adev() succeeds, mana_probe() returns success despite ports being left in a partially initialized state (ac->ports[i] == NULL).
Only call add_adev() when there is no prior error, so the probe correctly fails and triggers mana_remove() cleanup.
--- drivers/net/ethernet/microsoft/mana/mana_en.c | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-)
drivers/net/ethernet/microsoft/mana/mana_en.c +8 -9
@@ -3643,10 +3643,9 @@ int mana_probe(struct gdma_dev *gd, bool resuming)if (!resuming) {for (i =0 ; i < ac->num_ports; i++) { err =mana_probe_port (ac, i, &ac->ports[i]); -/* we log the port for which the probe failed and stop -* probes for subsequent ports. -* Note that we keep running ports, for which the probes -* were successful, unless add_adev fails too +/* Log the port for which the probe failed, stop probing +* subsequent ports, and skip add_adev. +* mana_remove() will clean up already-probed ports. */ if (err) {dev_err (dev,"Probe Failed for port %d\n" , i);
@@ -3660,10 +3659,9 @@ int mana_probe(struct gdma_dev *gd, bool resuming)enable_work (&apc->queue_reset_work); err =mana_attach (ac->ports[i]);rtnl_unlock (); -/* we log the port for which the attach failed and stop -* attach for subsequent ports -* Note that we keep running ports, for which the attach -* were successful, unless add_adev fails too +/* Log the port for which the attach failed, stop +* attaching subsequent ports, and skip add_adev. +* mana_remove() will clean up already-attached ports. */ if (err) {dev_err (dev,"Attach Failed for port %d\n" , i);
@@ -3672,7 +3670,8 @@ int mana_probe(struct gdma_dev *gd, bool resuming) } } - err =add_adev (gd,"eth" ); +if (!err) + err =add_adev (gd,"eth" );schedule_delayed_work (&ac->gf_stats_work,MANA_GF_STATS_PERIOD );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 854/1146 net: mana: Fix EQ leak in mana_remove on NULL port
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Erni Sri Satya Vennela <[email protected]>
[ Upstream commit 65267c9c4f28199985505977bc2c628c82fc50ef ]
In mana_remove(), when a NULL port is encountered in the port iteration loop, 'goto out' skips the mana_destroy_eq(ac) call, leaking the event queues allocated earlier by mana_create_eq().
This can happen when mana_probe_port() fails for port 0, leaving ac->ports[0] as NULL. On driver unload or error cleanup, mana_remove() hits the NULL entry and jumps past mana_destroy_eq().
Change 'goto out' to 'break' so the for-loop exits normally and mana_destroy_eq() is always reached. Remove the now-unreferenced out:
label.
--- drivers/net/ethernet/microsoft/mana/mana_en.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/net/ethernet/microsoft/mana/mana_en.c +2 -2
@@ -3715,7 +3715,7 @@ void mana_remove(struct gdma_dev *gd, bool suspending)if (!ndev) {if (i ==0 )dev_err (dev,"No net device to remove\n" ); - goto out; +break ; } apc =netdev_priv (ndev);
@@ -3746,7 +3746,7 @@ void mana_remove(struct gdma_dev *gd, bool suspending) }mana_destroy_eq (ac); -out: +if (ac->per_port_queue_reset_wq) {destroy_workqueue (ac->per_port_queue_reset_wq); ac->per_port_queue_reset_wq =NULL ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 855/1146 vsock/virtio: fix MSG_ZEROCOPY pinned-pages accounting
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stefano Garzarella <[email protected]>
[ Upstream commit 1cb36e252211506f51095fe7ced8286cc77b4c80 ]
virtio_transport_init_zcopy_skb() uses iter->count as the size argument for msg_zerocopy_realloc(), which in turn passes it to mm_account_pinned_pages() for RLIMIT_MEMLOCK accounting. However, this function is called after virtio_transport_fill_skb() has already consumed the iterator via __zerocopy_sg_from_iter(), so on the last skb, iter->count will be 0, skipping the RLIMIT_MEMLOCK enforcement.
Pass pkt_len (the total bytes being sent) as an explicit parameter to virtio_transport_init_zcopy_skb() instead of reading the already-consumed iter->count.
This matches TCP and UDP, which both call msg_zerocopy_realloc() with the original message size.
--- net/vmw_vsock/virtio_transport_common.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-)
net/vmw_vsock/virtio_transport_common.c +8 -3
@@ -75,6 +75,7 @@ static bool virtio_transport_can_zcopy(const struct virtio_transport *t_ops,static int virtio_transport_init_zcopy_skb (struct vsock_sock *vsk,struct sk_buff *skb,struct msghdr *msg, +size_t pkt_len,bool zerocopy) {struct ubuf_info *uarg;
@@ -83,12 +84,10 @@ static int virtio_transport_init_zcopy_skb(struct vsock_sock *vsk, uarg = msg->msg_ubuf;net_zcopy_get (uarg); }else { -struct iov_iter *iter = &msg->msg_iter;struct ubuf_info_msgzc *uarg_zc; uarg =msg_zerocopy_realloc (sk_vsock (vsk), - iter->count, -NULL , false); + pkt_len,NULL , false);if (!uarg)return -1 ;
@@ -385,11 +384,17 @@ static int virtio_transport_send_pkt_info(struct vsock_sock *vsk,* each iteration. If this is last skb for this buffer * and MSG_ZEROCOPY mode is in use - we must allocate * completion for the current syscall. +* +* Pass pkt_len because msg iter is already consumed +* by virtio_transport_fill_skb(), so iter->count +* can not be used for RLIMIT_MEMLOCK pinned-pages +* accounting done by msg_zerocopy_realloc(). */ if (info->msg && info->msg->msg_flags &MSG_ZEROCOPY && skb_len == rest_len && info->op ==VIRTIO_VSOCK_OP_RW ) {if (virtio_transport_init_zcopy_skb (vsk, skb, info->msg, + pkt_len, can_zcopy)) {kfree_skb (skb); ret = -ENOMEM ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 856/1146 virtio_net: sync rss_trailer.max_tx_vq on queue_pairs change via VQ_PAIRS_SET
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Brett Creeley <[email protected]>
[ Upstream commit 3bc06da858ef17cfe94b49efc0d9713727012835 ]
When netif_is_rxfh_configured() is true (i.e., the user has explicitly configured the RSS indirection table), virtnet_set_queues() skips the RSS update path and falls through to the VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET command to change the number of queue pairs. However, it does not update vi->rss_trailer.max_tx_vq to reflect the new queue_pairs value.
This causes a mismatch between vi->curr_queue_pairs and vi->rss_trailer.max_tx_vq. Any subsequent RSS reconfiguration (e.g., via ethtool -X) calls virtnet_commit_rss_command(), which sends the stale max_tx_vq to the device, silently reverting the queue count.
Reproduction:
1. User configured RSS
ethtool -X eth0 equal 8
2. VQ_PAIRS_SET path; max_tx_vq stays 16
ethtool -L eth0 combined 12
3. RSS commit uses max_tx_vq=16 instead of 12
ethtool -X eth0 equal 4
Fix this by updating vi->rss_trailer.max_tx_vq after a successful VQ_PAIRS_SET command when RSS is enabled, keeping it in sync with curr_queue_pairs.
--- drivers/net/virtio_net.c | 6 ++++++ 1 file changed, 6 insertions(+)
drivers/net/virtio_net.c +6 -0
@@ -3748,6 +3748,12 @@ static int virtnet_set_queues(struct virtnet_info *vi, u16 queue_pairs) queue_pairs);return -EINVAL ; } + +/* Keep max_tx_vq in sync so that a later RSS command does not +* revert queue_pairs to a stale value. +*/ +if (vi->has_rss) + vi->rss_trailer.max_tx_vq =cpu_to_le16 (queue_pairs); succ: vi->curr_queue_pairs = queue_pairs;if (dev->flags &IFF_UP ) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 857/1146 nfp: fix swapped arguments in nfp_encode_basic_qdr() calls
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alexey Kodanev <[email protected]>
[ Upstream commit 4078c5611d7585548b249377ebd60c272e410490 ]
There is a mismatch between the passed arguments and the actual nfp_encode_basic_qdr() function parameter names:
static int nfp_encode_basic_qdr(u64 addr, int dest_island, int cpp_tgt,
int mode, bool addr40, int isld1, int isld0)
{
...But "dest_island" and "cpp_tgt" are swapped at every call-site. For example:
return nfp_encode_basic_qdr(*addr, cpp_tgt, dest_island,
mode, addr40, isld1, isld0);
As a result, nfp_encode_basic_qdr() receives "dest_island" as CPP target type, which is always NFP_CPP_TARGET_QDR(2) for these calls, and "cpp_tgt" as the destination island ID, which can accidentally match or be outside the valid NFP_CPP_TARGET_* types (e.g. '-1' for any destination).
Since code already worked for years, also add extra pr_warn() to error paths in nfp_encode_basic_qdr() to help identify any potential address verification failures.
Detected using the static analysis tool - Svace.
--- .../ethernet/netronome/nfp/nfpcore/nfp_target.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-)
drivers/net/ethernet/netronome/nfp/nfpcore/nfp_target.c +11 -6
@@ -435,12 +435,17 @@ static int nfp_encode_basic_qdr(u64 addr, int dest_island, int cpp_tgt,/* Full Island ID and channel bits overlap? */ ret =nfp_decode_basic (addr, &v, cpp_tgt, mode, addr40, isld1, isld0); -if (ret) +if (ret) { +pr_warn ("%s: decode dest_island failed: %d\n" , __func__, ret);return ret; + }/* The current address won't go where expected? */ -if (dest_island !=-1 && dest_island != v) +if (dest_island !=-1 && dest_island != v) { +pr_warn ("%s: dest_island mismatch: current (%d) != decoded (%d)\n" , + __func__, dest_island, v);return -EINVAL ; + }/* If dest_island was -1, we don't care where it goes. */ return 0 ;
@@ -493,7 +498,7 @@ static int nfp_encode_basic(u64 *addr, int dest_island, int cpp_tgt,* the address but we can verify if the existing * contents will point to a valid island. */ -return nfp_encode_basic_qdr (*addr, cpp_tgt, dest_island, +return nfp_encode_basic_qdr (*addr, dest_island, cpp_tgt, mode, addr40, isld1, isld0); iid_lsb = addr40 ?34 :26 ;
@@ -504,7 +509,7 @@ static int nfp_encode_basic(u64 *addr, int dest_island, int cpp_tgt,return 0 ;case 1 :if (cpp_tgt ==NFP_CPP_TARGET_QDR && !addr40) -return nfp_encode_basic_qdr (*addr, cpp_tgt, dest_island, +return nfp_encode_basic_qdr (*addr, dest_island, cpp_tgt, mode, addr40, isld1, isld0); idx_lsb = addr40 ?39 :31 ;
@@ -530,7 +535,7 @@ static int nfp_encode_basic(u64 *addr, int dest_island, int cpp_tgt,* be set before hand and with them select an island. * So we need to confirm that it's at least plausible. */ -return nfp_encode_basic_qdr (*addr, cpp_tgt, dest_island, +return nfp_encode_basic_qdr (*addr, dest_island, cpp_tgt, mode, addr40, isld1, isld0);/* Make sure we compare against isldN values
@@ -551,7 +556,7 @@ static int nfp_encode_basic(u64 *addr, int dest_island, int cpp_tgt,* iid<1> = addr<30> = channel<0> * channel<1> = addr<31> = Index */ -return nfp_encode_basic_qdr (*addr, cpp_tgt, dest_island, +return nfp_encode_basic_qdr (*addr, dest_island, cpp_tgt, mode, addr40, isld1, isld0); isld[0 ] &= ~3 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 858/1146 tcp: send a challenge ACK on SEG.ACK > SND.NXT
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jiayuan Chen <[email protected]>
[ Upstream commit 42726ec644cbdde0035c3e0417fee8ed9547e120 ]
RFC 5961 Section 5.2 validates an incoming segment's ACK value against the range [SND.UNA - MAX.SND.WND, SND.NXT] and states:
"All incoming segments whose ACK value doesn't satisfy the above
condition MUST be discarded and an ACK sent back."
Commit 354e4aa391ed ("tcp: RFC 5961 5.2 Blind Data Injection Attack Mitigation") opted Linux into this mitigation and implements the challenge ACK on the lower side (SEG.ACK < SND.UNA - MAX.SND.WND), but the symmetric upper side (SEG.ACK > SND.NXT) still takes the pre-RFC-5961 path and silently returns SKB_DROP_REASON_TCP_ACK_UNSENT_DATA, even though RFC 793 Section 3.9 (now RFC 9293 Section 3.10.7.4) has always required:
"If the ACK acknowledges something not yet sent (SEG.ACK > SND.NXT)
then send an ACK, drop the segment, and return."
Complete the mitigation by sending a challenge ACK on that branch, reusing the existing tcp_send_challenge_ack() path which already enforces the per-socket RFC 5961 Section 7 rate limit via __tcp_oow_rate_limited(). FLAG_NO_CHALLENGE_ACK is honoured for symmetry with the lower-edge case.
Update the existing tcp_ts_recent_invalid_ack.pkt selftest, which drives this exact path, to consume the new challenge ACK.
--- net/ipv4/tcp_input.c | 10 +++++++--- .../net/packetdrill/tcp_ts_recent_invalid_ack.pkt | 4 +++- 2 files changed, 10 insertions(+), 4 deletions(-)
net/ipv4/tcp_input.c +7 -3
@@ -4288,11 +4288,15 @@ static int tcp_ack(struct sock *sk, const struct sk_buff *skb, int flag) goto old_ack; } -/* If the ack includes data we haven't sent yet, discard -* this segment (RFC793 Section 3.9). +/* If the ack includes data we haven't sent yet, drop the +* segment. RFC 793 Section 3.9 and RFC 5961 Section 5.2 +* require us to send an ACK back in that case. */ -if (after (ack, tp->snd_nxt)) +if (after (ack, tp->snd_nxt)) { +if (!(flag &FLAG_NO_CHALLENGE_ACK )) +tcp_send_challenge_ack (sk, false);return -SKB_DROP_REASON_TCP_ACK_UNSENT_DATA ; + }if (after (ack, prior_snd_una)) { flag |=FLAG_SND_UNA_ADVANCED ;
tools/testing/selftests/net/packetdrill/tcp_ts_recent_invalid_ack.pkt +3 -1
@@ -19,7 +19,9 @@ // bad packet with high tsval (its ACK sequence is above our sndnxt) +0 < F. 1:1(0) ack 9999 win 20000 <nop,nop,TS val 200000 ecr 100> - +// Challenge ACK for SEG.ACK > SND.NXT (RFC 5961 5.2 / RFC 793 3.9). +// ecr=200 (not 200000) proves ts_recent was not updated from the bad packet. + +0 > . 1:1(0) ack 1 <nop,nop,TS val 200 ecr 200> +0 < . 1:1001(1000) ack 1 win 20000 <nop,nop,TS val 201 ecr 100> +0 > . 1:1(0) ack 1001 <nop,nop,TS val 200 ecr 201>
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 859/1146 tipc: fix double-free in tipc_buf_append()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lee Jones <[email protected]>
[ Upstream commit d293ca716e7d5dffdaecaf6b9b2f857a33dc3d3a ]
tipc_msg_validate() can potentially reallocate the skb it is validating, freeing the old one. In tipc_buf_append(), it was being called with a pointer to a local variable which was a copy of the caller's skb pointer.
If the skb was reallocated and validation subsequently failed, the error handling path would free the original skb pointer, which had already been freed, leading to double-free.
Fix this by checking if head now points to a newly allocated reassembled skb. If it does, reassign *headbuf for later freeing operations.
--- net/tipc/msg.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-)
net/tipc/msg.c +13 -1
@@ -177,8 +177,20 @@ int tipc_buf_append(struct sk_buff **headbuf, struct sk_buff **buf)if (fragid ==LAST_FRAGMENT ) {TIPC_SKB_CB (head)->validated =0 ; -if (unlikely (!tipc_msg_validate (&head))) + +/* If the reassembled skb has been freed in +* tipc_msg_validate() because of an invalid truesize, +* then head will point to a newly allocated reassembled +* skb, while *headbuf points to freed reassembled skb. +* In such cases, correct *headbuf for freeing the newly +* allocated reassembled skb later. +*/ +if (unlikely (!tipc_msg_validate (&head))) { +if (head != *headbuf) + *headbuf = head; goto err; + } + *buf = head;TIPC_SKB_CB (head)->tail =NULL ; *headbuf =NULL ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 860/1146 vhost_net: fix sleeping with preempt-disabled in vhost_net_busy_poll()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kohei Enju <[email protected]>
[ Upstream commit e08a9fac5cf8c3fecf4755e7e3ac059f78b8f83d ]
syzbot reported "sleeping function called from invalid context" in vhost_net_busy_poll().
Commit 030881372460 ("vhost_net: basic polling support") introduced a busy-poll loop and preempt_{disable,enable}() around it, where each iteration calls a sleepable function inside the loop.
The purpose of disabling preemption was to keep local_clock()-based timeout accounting on a single CPU, rather than as a requirement of busy-poll itself:
https://lore.kernel.org/[email protected]
Quoted 1 line
From this perspective,
migrate_disable()is sufficient here, so replace
preempt_disable() with migrate_disable(), avoiding sleepable accesses from a preempt-disabled context.
--- drivers/vhost/net.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/vhost/net.c +2 -2
@@ -560,7 +560,7 @@ static void vhost_net_busy_poll(struct vhost_net *net, busyloop_timeout = poll_rx ? rvq->busyloop_timeout: tvq->busyloop_timeout; -preempt_disable (); +migrate_disable (); endtime =busy_clock () + busyloop_timeout;while (vhost_can_busy_poll (endtime)) {
@@ -577,7 +577,7 @@ static void vhost_net_busy_poll(struct vhost_net *net,cpu_relax (); } -preempt_enable (); +migrate_enable ();if (poll_rx ||sock_has_rx_data (sock))vhost_net_busy_poll_try_queue (net, vq);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 861/1146 nstree: fix func. parameter kernel-doc warnings
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Randy Dunlap <[email protected]>
[ Upstream commit 43eb354ecb471426e97b0ce6a0c922ec20f82027 ]
Use the correct parameter name ("__ns") for function parameter kernel-doc to avoid 3 warnings:
Warning: include/linux/nstree.h:68 function parameter '__ns' not described in 'ns_tree_add_raw'
Warning: include/linux/nstree.h:77 function parameter '__ns' not described in 'ns_tree_add'
Warning: include/linux/nstree.h:88 function parameter '__ns' not described in 'ns_tree_remove'
--- include/linux/nstree.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
include/linux/nstree.h +3 -3
@@ -61,7 +61,7 @@ static inline void __ns_tree_add(struct ns_common *ns, struct ns_tree_root *ns_t/** * ns_tree_add_raw - Add a namespace to a namespace -* @ns: Namespace to add +* @__ns: Namespace to add * * This function adds a namespace to the appropriate namespace tree * without assigning a id.
@@ -70,7 +70,7 @@ static inline void __ns_tree_add(struct ns_common *ns, struct ns_tree_root *ns_t/** * ns_tree_add - Add a namespace to a namespace tree -* @ns: Namespace to add +* @__ns: Namespace to add * * This function assigns a new id to the namespace and adds it to the * appropriate namespace tree and list.
@@ -81,7 +81,7 @@ static inline void __ns_tree_add(struct ns_common *ns, struct ns_tree_root *ns_t/** * ns_tree_remove - Remove a namespace from a namespace tree -* @ns: Namespace to remove +* @__ns: Namespace to remove * * This function removes a namespace from the appropriate namespace * tree and list.
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 862/1146 eventpoll: use hlist_is_singular_node() in __ep_remove()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian Brauner <[email protected]>
[ Upstream commit 3d9fd0abc94d8cd430cc7cd7d37ce5e5aae2cd2b ]
Replace the open-coded "epi is the only entry in file->f_ep" check with hlist_is_singular_node(). Same semantics, and the helper avoids the head-cacheline access in the common false case.
Stable-dep-of: a6dc643c6931 ("eventpoll: fix ep_remove struct eventpoll / struct file UAF")
--- fs/eventpoll.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/eventpoll.c +1 -1
@@ -856,7 +856,7 @@ static bool __ep_remove(struct eventpoll *ep, struct epitem *epi, bool force) to_free =NULL ; head = file->f_ep; -if (head->first == &epi->fllink && !epi->fllink.next) { +if (hlist_is_singular_node (&epi->fllink, head)) {/* See eventpoll_release() for details. */ WRITE_ONCE (file->f_ep,NULL );if (!is_file_epoll (file)) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 863/1146 eventpoll: split __ep_remove()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian Brauner <[email protected]>
[ Upstream commit 0f7bdfd413000985de09fc39eb9efa1e091a3ce0 ]
Split __ep_remove() to delineate file removal from epoll item removal.
Stable-dep-of: a6dc643c6931 ("eventpoll: fix ep_remove struct eventpoll / struct file UAF")
--- fs/eventpoll.c | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-)
fs/eventpoll.c +23 -4
@@ -826,6 +826,9 @@ static void ep_free(struct eventpoll *ep)kfree_rcu (ep, rcu); } +static void __ep_remove_file (struct eventpoll *ep,struct epitem *epi,struct file *file); +static bool __ep_remove_epi (struct eventpoll *ep,struct epitem *epi); +/* * Removes a "struct epitem" from the eventpoll RB tree and deallocates * all the associated resources. Must be called with "mtx" held.
@@ -837,8 +840,6 @@ static void ep_free(struct eventpoll *ep)static bool __ep_remove (struct eventpoll *ep,struct epitem *epi,bool force) {struct file *file = epi->ffd.file; -struct epitems_head *to_free; -struct hlist_head *head;lockdep_assert_irqs_enabled ();
@@ -854,8 +855,21 @@ static bool __ep_remove(struct eventpoll *ep, struct epitem *epi, bool force)return false; } - to_free =NULL ; - head = file->f_ep; +__ep_remove_file (ep, epi, file); +return __ep_remove_epi (ep, epi); +} + +/* +* Called with &file->f_lock held, +* returns with it released +*/ +static void __ep_remove_file (struct eventpoll *ep,struct epitem *epi,struct file *file) +{ +struct epitems_head *to_free =NULL ; +struct hlist_head *head = file->f_ep; + +lockdep_assert_held (&ep->mtx); +if (hlist_is_singular_node (&epi->fllink, head)) {/* See eventpoll_release() for details. */ WRITE_ONCE (file->f_ep,NULL );
@@ -869,6 +883,11 @@ static bool __ep_remove(struct eventpoll *ep, struct epitem *epi, bool force)hlist_del_rcu (&epi->fllink);spin_unlock (&file->f_lock);free_ephead (to_free); +} + +static bool __ep_remove_epi (struct eventpoll *ep,struct epitem *epi) +{ +lockdep_assert_held (&ep->mtx);rb_erase_cached (&epi->rbn, &ep->rbr);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 864/1146 eventpoll: kill __ep_remove()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian Brauner <[email protected]>
[ Upstream commit e9e5cd40d7c403e19f21d0f7b8b8ba3a76b58330 ]
Remove the boolean conditional in __ep_remove() and restructure the code so the check for racing with eventpoll_release_file() are only done in the ep_remove_safe() path where they belong.
Stable-dep-of: a6dc643c6931 ("eventpoll: fix ep_remove struct eventpoll / struct file UAF")
--- fs/eventpoll.c | 67 ++++++++++++++++++++++---------------------------- 1 file changed, 30 insertions(+), 37 deletions(-)
fs/eventpoll.c +30 -37
@@ -826,49 +826,18 @@ static void ep_free(struct eventpoll *ep)kfree_rcu (ep, rcu); } -static void __ep_remove_file (struct eventpoll *ep,struct epitem *epi,struct file *file); -static bool __ep_remove_epi (struct eventpoll *ep,struct epitem *epi); - -/* -* Removes a "struct epitem" from the eventpoll RB tree and deallocates -* all the associated resources. Must be called with "mtx" held. -* If the dying flag is set, do the removal only if force is true. -* This prevents ep_clear_and_put() from dropping all the ep references -* while running concurrently with eventpoll_release_file(). -* Returns true if the eventpoll can be disposed. -*/ -static bool __ep_remove (struct eventpoll *ep,struct epitem *epi,bool force) -{ -struct file *file = epi->ffd.file; - -lockdep_assert_irqs_enabled (); - -/* -* Removes poll wait queue hooks. -*/ -ep_unregister_pollwait (ep, epi); - -/* Remove the current item from the list of epoll hooks */ -spin_lock (&file->f_lock); -if (epi->dying && !force) { -spin_unlock (&file->f_lock); -return false; - } - -__ep_remove_file (ep, epi, file); -return __ep_remove_epi (ep, epi); -} -/* * Called with &file->f_lock held, * returns with it released */ -static void __ep_remove_file (struct eventpoll *ep,struct epitem *epi,struct file *file) +static void __ep_remove_file (struct eventpoll *ep,struct epitem *epi, +struct file *file) {struct epitems_head *to_free =NULL ;struct hlist_head *head = file->f_ep;lockdep_assert_held (&ep->mtx); +lockdep_assert_held (&file->f_lock);if (hlist_is_singular_node (&epi->fllink, head)) {/* See eventpoll_release() for details. */
@@ -915,7 +884,25 @@ static bool __ep_remove_epi(struct eventpoll *ep, struct epitem *epi)*/ static void ep_remove_safe (struct eventpoll *ep,struct epitem *epi) { -if (__ep_remove (ep, epi, false)) +struct file *file = epi->ffd.file; + +lockdep_assert_irqs_enabled (); +lockdep_assert_held (&ep->mtx); + +ep_unregister_pollwait (ep, epi); + +/* sync with eventpoll_release_file() */ +if (unlikely (READ_ONCE (epi->dying))) +return ; + +spin_lock (&file->f_lock); +if (epi->dying) { +spin_unlock (&file->f_lock); +return ; + } +__ep_remove_file (ep, epi, file); + +if (__ep_remove_epi (ep, epi))WARN_ON_ONCE (ep_refcount_dec_and_test (ep)); }
@@ -1147,7 +1134,7 @@ void eventpoll_release_file(struct file *file)spin_lock (&file->f_lock);if (file->f_ep && file->f_ep->first) { epi = hlist_entry(file->f_ep->first, struct epitem, fllink); - epi->dying = true; +WRITE_ONCE (epi->dying, true);spin_unlock (&file->f_lock);/*
@@ -1156,7 +1143,13 @@ void eventpoll_release_file(struct file *file)*/ ep = epi->ep;mutex_lock (&ep->mtx); - dispose =__ep_remove (ep, epi, true); + +ep_unregister_pollwait (ep, epi); + +spin_lock (&file->f_lock); +__ep_remove_file (ep, epi, file); + dispose =__ep_remove_epi (ep, epi); +mutex_unlock (&ep->mtx);if (dispose &&ep_refcount_dec_and_test (ep))
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 865/1146 eventpoll: drop vestigial __ prefix from ep_remove_{file,epi}()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian Brauner <[email protected]>
[ Upstream commit 0feaf644f7180c4a91b6b405a881afbfd958f1cf ]
With __ep_remove() gone, the double-underscore on __ep_remove_file() and __ep_remove_epi() no longer contrasts with a __-less parent and just reads as noise. Rename both to ep_remove_file() and ep_remove_epi(). No functional change.
Stable-dep-of: a6dc643c6931 ("eventpoll: fix ep_remove struct eventpoll / struct file UAF")
--- fs/eventpoll.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-)
fs/eventpoll.c +6 -6
@@ -830,7 +830,7 @@ static void ep_free(struct eventpoll *ep)* Called with &file->f_lock held, * returns with it released */ -static void __ep_remove_file (struct eventpoll *ep,struct epitem *epi, +static void ep_remove_file (struct eventpoll *ep,struct epitem *epi,struct file *file) {struct epitems_head *to_free =NULL ;
@@ -854,7 +854,7 @@ static void __ep_remove_file(struct eventpoll *ep, struct epitem *epi,free_ephead (to_free); } -static bool __ep_remove_epi (struct eventpoll *ep,struct epitem *epi) +static bool ep_remove_epi (struct eventpoll *ep,struct epitem *epi) {lockdep_assert_held (&ep->mtx);
@@ -900,9 +900,9 @@ static void ep_remove_safe(struct eventpoll *ep, struct epitem *epi)spin_unlock (&file->f_lock);return ; } -__ep_remove_file (ep, epi, file); +ep_remove_file (ep, epi, file); -if (__ep_remove_epi (ep, epi)) +if (ep_remove_epi (ep, epi))WARN_ON_ONCE (ep_refcount_dec_and_test (ep)); }
@@ -1147,8 +1147,8 @@ void eventpoll_release_file(struct file *file)ep_unregister_pollwait (ep, epi);spin_lock (&file->f_lock); -__ep_remove_file (ep, epi, file); - dispose =__ep_remove_epi (ep, epi); +ep_remove_file (ep, epi, file); + dispose =ep_remove_epi (ep, epi);mutex_unlock (&ep->mtx);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 866/1146 eventpoll: move epi_fget() up
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian Brauner <[email protected]>
[ Upstream commit 86e87059e6d1fd5115a31949726450ed03c1073b ]
We'll need it when removing files so move it up. No functional change.
Stable-dep-of: a6dc643c6931 ("eventpoll: fix ep_remove struct eventpoll / struct file UAF")
--- fs/eventpoll.c | 56 +++++++++++++++++++++++++------------------------- 1 file changed, 28 insertions(+), 28 deletions(-)
fs/eventpoll.c +28 -28
@@ -826,6 +826,34 @@ static void ep_free(struct eventpoll *ep)kfree_rcu (ep, rcu); } +/* +* The ffd.file pointer may be in the process of being torn down due to +* being closed, but we may not have finished eventpoll_release() yet. +* +* Normally, even with the atomic_long_inc_not_zero, the file may have +* been free'd and then gotten re-allocated to something else (since +* files are not RCU-delayed, they are SLAB_TYPESAFE_BY_RCU). +* +* But for epoll, users hold the ep->mtx mutex, and as such any file in +* the process of being free'd will block in eventpoll_release_file() +* and thus the underlying file allocation will not be free'd, and the +* file re-use cannot happen. +* +* For the same reason we can avoid a rcu_read_lock() around the +* operation - 'ffd.file' cannot go away even if the refcount has +* reached zero (but we must still not call out to ->poll() functions +* etc). +*/ +static struct file *epi_fget (const struct epitem *epi) +{ +struct file *file; + + file = epi->ffd.file; +if (!file_ref_get (&file->f_ref)) + file =NULL ; +return file; +} +/* * Called with &file->f_lock held, * returns with it released
@@ -1018,34 +1046,6 @@ static __poll_t __ep_eventpoll_poll(struct file *file, poll_table *wait, int depreturn res; } -/* -* The ffd.file pointer may be in the process of being torn down due to -* being closed, but we may not have finished eventpoll_release() yet. -* -* Normally, even with the atomic_long_inc_not_zero, the file may have -* been free'd and then gotten re-allocated to something else (since -* files are not RCU-delayed, they are SLAB_TYPESAFE_BY_RCU). -* -* But for epoll, users hold the ep->mtx mutex, and as such any file in -* the process of being free'd will block in eventpoll_release_file() -* and thus the underlying file allocation will not be free'd, and the -* file re-use cannot happen. -* -* For the same reason we can avoid a rcu_read_lock() around the -* operation - 'ffd.file' cannot go away even if the refcount has -* reached zero (but we must still not call out to ->poll() functions -* etc). -*/ -static struct file *epi_fget (const struct epitem *epi) -{ -struct file *file; - - file = epi->ffd.file; -if (!file_ref_get (&file->f_ref)) - file =NULL ; -return file; -} -/* * Differs from ep_eventpoll_poll() in that internal callers already have * the ep->mtx so we need to start from depth=1, such that mutex_lock_nested()
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 867/1146 eventpoll: fix ep_remove struct eventpoll / struct file UAF
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian Brauner <[email protected]>
[ Upstream commit a6dc643c69311677c574a0f17a3f4d66a5f3744b ]
ep_remove() (via ep_remove_file()) cleared file->f_ep under file->f_lock but then kept using @file inside the critical section (is_file_epoll(), hlist_del_rcu() through the head, spin_unlock). A concurrent __fput() taking the eventpoll_release() fastpath in that window observed the transient NULL, skipped eventpoll_release_file() and ran to f_op->release / file_free().
For the epoll-watches-epoll case, f_op->release is ep_eventpoll_release() -> ep_clear_and_put() -> ep_free(), which kfree()s the watched struct eventpoll. Its embedded ->refs hlist_head is exactly where epi->fllink.pprev points, so the subsequent hlist_del_rcu()'s "*pprev = next" scribbles into freed kmalloc-192 memory.
In addition, struct file is SLAB_TYPESAFE_BY_RCU, so the slot backing @file could be recycled by alloc_empty_file() -- reinitializing f_lock and f_ep -- while ep_remove() is still nominally inside that lock. The upshot is an attacker-controllable kmem_cache_free() against the wrong slab cache.
Pin @file via epi_fget() at the top of ep_remove() and gate the critical section on the pin succeeding. With the pin held @file cannot reach refcount zero, which holds __fput() off and transitively keeps the watched struct eventpoll alive across the hlist_del_rcu() and the f_lock use, closing both UAFs.
If the pin fails @file has already reached refcount zero and its __fput() is in flight. Because we bailed before clearing f_ep, that path takes the eventpoll_release() slow path into eventpoll_release_file() and blocks on ep->mtx until the waiter side's ep_clear_and_put() drops it. The bailed epi's share of ep->refcount stays intact, so the trailing ep_refcount_dec_and_test() in ep_clear_and_put() cannot free the eventpoll out from under eventpoll_release_file(); the orphaned epi is then cleaned up there.
A successful pin also proves we are not racing eventpoll_release_file() on this epi, so drop the now-redundant re-check of epi->dying under f_lock. The cheap lockless READ_ONCE(epi->dying) fast-path bailout stays.
--- fs/eventpoll.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-)
fs/eventpoll.c +10 -6
@@ -912,22 +912,26 @@ static bool ep_remove_epi(struct eventpoll *ep, struct epitem *epi)*/ static void ep_remove_safe (struct eventpoll *ep,struct epitem *epi) { -struct file *file = epi->ffd.file; + struct file *file __free(fput) = NULL;lockdep_assert_irqs_enabled ();lockdep_assert_held (&ep->mtx);ep_unregister_pollwait (ep, epi); -/* sync with eventpoll_release_file() */ +/* cheap sync with eventpoll_release_file() */ if (unlikely (READ_ONCE (epi->dying)))return ; -spin_lock (&file->f_lock); -if (epi->dying) { -spin_unlock (&file->f_lock); +/* +* If we manage to grab a reference it means we're not in +* eventpoll_release_file() and aren't going to be. +*/ + file =epi_fget (epi); +if (!file)return ; - } + +spin_lock (&file->f_lock);ep_remove_file (ep, epi, file);if (ep_remove_epi (ep, epi))
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 868/1146 fs/adfs: validate nzones in adfs_validate_bblk()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bae Yeonju <[email protected]>
[ Upstream commit dd9d3e16c2d5fa166e13dce07413be51f42c8f5d ]
Reject ADFS disc records with a zero zone count during boot block validation, before the disc record is used.
When nzones is 0, adfs_read_map() passes it to kmalloc_array(0, ...) which returns ZERO_SIZE_PTR, and adfs_map_layout() then writes to dm[-1], causing an out-of-bounds write before the allocated buffer.
adfs_validate_dr0() already rejects nzones != 1 for old-format images. Add the equivalent check to adfs_validate_bblk() for new-format images so that a crafted image with nzones == 0 is rejected at probe time.
Found by syzkaller.
--- fs/adfs/super.c | 3 +++ 1 file changed, 3 insertions(+)
fs/adfs/super.c +3 -0
@@ -317,6 +317,9 @@ static int adfs_validate_bblk(struct super_block *sb, struct buffer_head *bh,if (adfs_checkdiscrecord (dr))return -EILSEQ ; +if ((dr->nzones | dr->nzones_high <<8 ) ==0 ) +return -EILSEQ ; + *drp = dr;return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 869/1146 rtc: abx80x: Disable alarm feature if no interrupt attached
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Anthony Pighin (Nokia) <[email protected]>
[ Upstream commit 0fedce7244e4b85c049ce579c87e298a1b0b811d ]
Commit 795cda8338ea ("rtc: interface: Fix long-standing race when setting alarm") exposed an issue where the rtc-abx80x driver does not clear the alarm feature bit, but instead relies on the set_alarm operation to return invalid.
For example, when a RTC_UIE_ON ioctl is handled, it should abort at the feature validation. Instead, it proceeds to the rtc_timer_enqueue(), which used to return an error from the set_alarm call. However, following the race condition handling, which likely should not be discarding predecing errors, a success condition is returned to the ioctl() caller. This results in (for example):
hwclock: select() to /dev/rtc0 to wait for clock tick timed out
Notwithstanding the validity of the race condition handling, if an interrupt wasn't specified, or could not be attached, the driver should clear the alarm feature bit.
--- drivers/rtc/rtc-abx80x.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/rtc/rtc-abx80x.c +2 -0
@@ -933,6 +933,8 @@ static int abx80x_probe(struct i2c_client *client) client->irq =0 ; } } +if (client->irq <=0 ) +clear_bit (RTC_FEATURE_ALARM , priv->rtc->features); err =rtc_add_group (priv->rtc, &rtc_calib_attr_group);if (err) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 870/1146 kbuild: builddeb - avoid recompiles for non-cross-compiles
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mathias Krause <[email protected]>
[ Upstream commit 2452dcf4d740effff5aa71b7f6529ee8c04fd8f6 ]
Commit e2c318225ac1 ("kbuild: deb-pkg: add pkg.linux-upstream.nokernelheaders build profile") changed how install-extmod-build gets called, making it always rebuild the host programs below scripts/ if HOSTCC wasn't specified with its full triplet on the make command line. That is, apparently, needed to fix up commit f1d87664b82a ("kbuild: cross-compile linux-headers package when possible") for cross-compiles. However, in the much more common case of non-cross-compile builds this will lead to unnecessary rebuilding of host tools including gcc plugins. This, in turn, will lead to a full kernel rebuild on the next 'make bindeb-pkg' which is unfortunate.
Avoid that by only triggering the rebuild of host tools for actual cross-compile builds.
--- scripts/package/builddeb | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
scripts/package/builddeb +7 -1
@@ -139,7 +139,13 @@ install_kernel_headers () { pdir=debian/$1 version=${1#linux-headers-} - CC="${DEB_HOST_GNU_TYPE}-gcc" "${srctree}/scripts/package/install-extmod-build" "${pdir}/usr/src/linux-headers-${version}" + # Override $CC only for cross-compiles, to not unnecessarily rebuild + # scripts/ including plugins, which may lead to a full kernel rebuild. + if [ -n "${CROSS_COMPILE}" ]; then + CC="${DEB_HOST_GNU_TYPE}-gcc" "${srctree}/scripts/package/install-extmod-build" "${pdir}/usr/src/linux-headers-${version}" + else + "${srctree}/scripts/package/install-extmod-build" "${pdir}/usr/src/linux-headers-${version}" + fi mkdir -p $pdir/lib/modules/$version/ ln -s /usr/src/linux-headers-$version $pdir/lib/modules/$version/build
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 871/1146 tools/power turbostat: Fix AMD RAPL regression on big systems
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Len Brown <[email protected]>
[ Upstream commit 3ae6bafa104d93ddc525b8de547bf66b43fcaf10 ]
turbostat.c:8688: rapl_perf_init: Assertion `next_domain < num_domains' failed.
The initial fix for this regression was incomplete, as it did not handle multi-package systems with sparse core ids.
--- tools/power/x86/turbostat/turbostat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
tools/power/x86/turbostat/turbostat.c +1 -1
@@ -5155,7 +5155,7 @@ static inline int get_rapl_num_domains(void)if (!platform->has_per_core_rapl)return topo.num_packages; -return topo.num_cores; +return GLOBAL_CORE_ID (topo.max_core_id, topo.num_packages) +1 ; }static inline int get_rapl_domain_id (int cpu)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 872/1146 fbdev: offb: fix PCI device reference leak on probe failure
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yuho Choi <[email protected]>
[ Upstream commit 869b93ba04088713596e68453c1146f52f713290 ]
offb_init_nodriver() gets a referenced PCI device with pci_get_device(). If pci_enable_device() fails, the function returns without dropping that reference.
Release the PCI device reference before returning from the pci_enable_device() failure path.
--- drivers/video/fbdev/offb.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
drivers/video/fbdev/offb.c +6 -1
@@ -640,8 +640,13 @@ static void offb_init_nodriver(struct platform_device *parent, struct device_nod vid =be32_to_cpup (vidp); did =be32_to_cpup (didp); pdev =pci_get_device (vid, did,NULL ); -if (!pdev ||pci_enable_device (pdev)) +if (!pdev)return ; + +if (pci_enable_device (pdev)) { +pci_dev_put (pdev); +return ; + } }#endif /* kludge for valkyrie */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 873/1146 tools/power turbostat: Fix unrecognized option -P
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Arcari <[email protected]>
[ Upstream commit ce012c966b518c53475ba9a4e979242d7322d819 ]
The '-P' short option (shorthand for --no-perf) is not present in the optstring of the second call to getopt_long_only(). This results in the "unrecognized option" error when the tool reaches the main parsing loop.
Add 'P' to the second getopt_long_only() call to ensure it is consistently recognized.
--- tools/power/x86/turbostat/turbostat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
tools/power/x86/turbostat/turbostat.c +1 -1
@@ -11449,7 +11449,7 @@ void cmdline(int argc, char **argv) } optind =0 ; -while ((opt =getopt_long_only (argc, argv,"+C:c:Dde:hi:Jn:N:o:qMST:v" , long_options, &option_index)) !=-1 ) { +while ((opt =getopt_long_only (argc, argv,"+C:c:Dde:hi:Jn:N:o:qMPST:v" , long_options, &option_index)) !=-1 ) {switch (opt) {case 'a' :parse_add_command (optarg);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 874/1146 tools/power turbostat: Fix --cpu-set 0 regression on HT systems
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Len Brown <[email protected]>
[ Upstream commit 2c52f942fcf21c8e09c7dac669fca591cec2692b ]
"turbostat --cpu-set 0" appears to hang if cpu0 has an HT sibling.
This is because the initialization code recognizes that it does not have to open perf files for the HT sibling, but the HT support in the collection code sees the HT sibling and tries to read from an uninitialized file descriptor, 0 (standard input).
Access HT siblings only when they are in the allowed set.
--- tools/power/x86/turbostat/turbostat.c | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-)
tools/power/x86/turbostat/turbostat.c +17 -5
@@ -2427,11 +2427,17 @@ char *sys_lpi_file_debugfs = "/sys/kernel/debug/pmc_core/slp_s0_residency_usec";int cpu_is_not_present (int cpu) { +if (cpu <0 ) +return 1 ; +return !CPU_ISSET_S (cpu, cpu_present_setsize, cpu_present_set); }int cpu_is_not_allowed (int cpu) { +if (cpu <0 ) +return 1 ; +return !CPU_ISSET_S (cpu, cpu_allowed_setsize, cpu_allowed_set); }
@@ -2473,9 +2479,12 @@ int for_all_cpus(int (func) (struct thread_data *, struct core_data *, struct pkint i;for (i =MAX_HT_ID ; i >0 ; --i) {/* ht_id 0 is self */ -if (cpus[cpu].ht_sibling_cpu_id[i] <=0 ) +int sibling_cpu_id = cpus[cpu].ht_sibling_cpu_id[i]; + +if (cpu_is_not_allowed (sibling_cpu_id))continue ; - t = &thread_base[cpus[cpu].ht_sibling_cpu_id[i]]; + + t = &thread_base[sibling_cpu_id]; retval |=func (t, c, p); }
@@ -6252,10 +6261,13 @@ int for_all_cpus_2(int (func) (struct thread_data *, struct core_data *,int i;for (i =MAX_HT_ID ; i >0 ; --i) {/* ht_id 0 is self */ -if (cpus[cpu].ht_sibling_cpu_id[i] <=0 ) +int sibling_cpu_id = cpus[cpu].ht_sibling_cpu_id[i]; + +if (cpu_is_not_allowed (sibling_cpu_id))continue ; - t = &thread_base[cpus[cpu].ht_sibling_cpu_id[i]]; - t2 = &thread_base2[cpus[cpu].ht_sibling_cpu_id[i]]; + + t = &thread_base[sibling_cpu_id]; + t2 = &thread_base2[sibling_cpu_id]; retval |=func (t, c, p, t2, c2, p2); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 875/1146 tools/power turbostat: Fix --cpu-set 1 regression on HT systems
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Len Brown <[email protected]>
[ Upstream commit 08e11edd0e63b72651ed5eb9142430d1ca764923 ]
When the "--cpu-set" option limits turbostat to run on a higher numbered HT sibling, it exits upon dividing by zero.
This is because the HT support handles higher numbered siblings at the same time as lower numbered siblings. But when that lower number sibling is dis-allowed, the higher numbered sibling is never processed. The result is a time delta of 0, which results in a divide by 0 for any of the "per-second" metrics.
Enhance the HT enumeration code to record all siblings (up to SMT4). Consult this complete HT sibling list to determine when to process an HT sibling, and when to skip it.
--- tools/power/x86/turbostat/turbostat.c | 70 +++++++++++++++++++++------ 1 file changed, 55 insertions(+), 15 deletions(-)
tools/power/x86/turbostat/turbostat.c +55 -15
@@ -2449,6 +2449,22 @@ int cpu_is_not_allowed(int cpu)#define PER_THREAD_PARAMS struct thread_data *t, struct core_data *c, struct pkg_data *p +int has_allowed_lower_ht_sibling (int cpu) +{ +int i; + +for (i =0 ; i <= cpus[cpu].ht_id; ++i) { +int sibling_cpu_id = cpus[cpu].ht_sibling_cpu_id[i]; + +if (sibling_cpu_id == cpu) +return 0 ; + +if (!cpu_is_not_allowed (sibling_cpu_id)) +return 1 ; + } +return 0 ; +} +int for_all_cpus (int (func ) (struct thread_data *,struct core_data *,struct pkg_data *),struct thread_data *thread_base,struct core_data *core_base,struct pkg_data *pkg_base) {
@@ -2466,7 +2482,7 @@ int for_all_cpus(int (func) (struct thread_data *, struct core_data *, struct pkif (cpu_is_not_allowed (cpu))continue ; -if (cpus[cpu].ht_id >0 )/* skip HT sibling */ +if (has_allowed_lower_ht_sibling (cpu))/* skip HT sibling */ continue ; t = &thread_base[cpu];
@@ -2475,12 +2491,18 @@ int for_all_cpus(int (func) (struct thread_data *, struct core_data *, struct pk retval |=func (t, c, p); -/* Handle HT sibling now */ +/* Handle other HT siblings now */ int i; -for (i =MAX_HT_ID ; i >0 ; --i) {/* ht_id 0 is self */ +for (i =0 ; i <=MAX_HT_ID ; ++i) {int sibling_cpu_id = cpus[cpu].ht_sibling_cpu_id[i]; +if (sibling_cpu_id <0 ) +break ; + +if (sibling_cpu_id == cpu) +continue ; +if (cpu_is_not_allowed (sibling_cpu_id))continue ;
@@ -6178,11 +6200,11 @@ int set_thread_siblings(struct cpu_topology *thiscpu)int cpu = thiscpu->cpu_id;int offset = topo.max_cpu_num +1 ;size_t size; -int thread_id =0 ; +int ht_id =0 ; thiscpu->put_ids =CPU_ALLOC ((topo.max_cpu_num +1 ));if (thiscpu->ht_id <0 ) - thiscpu->ht_id = thread_id++; + thiscpu->ht_id =0 ;/* first CPU in core */ if (!thiscpu->put_ids)return -1 ;
@@ -6206,13 +6228,9 @@ int set_thread_siblings(struct cpu_topology *thiscpu) sib_core =get_core_id (so);if (sib_core == thiscpu->core_id) {CPU_SET_S (so, size, thiscpu->put_ids); -if ((so != cpu) && (cpus[so].ht_id <0 )) { - cpus[so].ht_id = thread_id; - cpus[cpu].ht_sibling_cpu_id[thread_id] = so; -if (debug) -fprintf (stderr,"%s: cpu%d.ht_sibling_cpu_id[%d] = %d\n" , __func__, cpu, thread_id, so); - thread_id +=1 ; - } + cpus[so].ht_id = ht_id; + cpus[cpu].ht_sibling_cpu_id[ht_id] = so; + ht_id +=1 ; } } }
@@ -6245,7 +6263,7 @@ int for_all_cpus_2(int (func) (struct thread_data *, struct core_data *,if (cpu_is_not_allowed (cpu))continue ; -if (cpus[cpu].ht_id >0 )/* skip HT sibling */ +if (has_allowed_lower_ht_sibling (cpu))/* skip HT sibling */ continue ; t = &thread_base[cpu];
@@ -6260,9 +6278,15 @@ int for_all_cpus_2(int (func) (struct thread_data *, struct core_data *,/* Handle HT sibling now */ int i; -for (i =MAX_HT_ID ; i >0 ; --i) {/* ht_id 0 is self */ +for (i =0 ; i <=MAX_HT_ID ; ++i) {int sibling_cpu_id = cpus[cpu].ht_sibling_cpu_id[i]; +if (sibling_cpu_id <0 ) +break ; + +if (sibling_cpu_id == cpu) +continue ; +if (cpu_is_not_allowed (sibling_cpu_id))continue ;
@@ -9517,6 +9541,8 @@ void topology_probe(bool startup) cpu_present_setsize =CPU_ALLOC_SIZE ((topo.max_cpu_num +1 ));CPU_ZERO_S (cpu_present_setsize, cpu_present_set);for_all_proc_cpus (mark_cpu_present); +if (debug) +print_cpu_set ("present set" , cpu_present_set);/* * Allocate and initialize cpu_possible_set
@@ -9527,6 +9553,8 @@ void topology_probe(bool startup) cpu_possible_setsize =CPU_ALLOC_SIZE ((topo.max_cpu_num +1 ));CPU_ZERO_S (cpu_possible_setsize, cpu_possible_set);initialize_cpu_set_from_sysfs (cpu_possible_set,"/sys/devices/system/cpu" ,"possible" ); +if (debug) +print_cpu_set ("possible set" , cpu_possible_set);/* * Allocate and initialize cpu_effective_set
@@ -9537,6 +9565,8 @@ void topology_probe(bool startup) cpu_effective_setsize =CPU_ALLOC_SIZE ((topo.max_cpu_num +1 ));CPU_ZERO_S (cpu_effective_setsize, cpu_effective_set);update_effective_set (startup); +if (debug) +print_cpu_set ("effective set" , cpu_effective_set);/* * Allocate and initialize cpu_allowed_set
@@ -9580,6 +9610,8 @@ void topology_probe(bool startup)CPU_SET_S (i, cpu_allowed_setsize, cpu_allowed_set); } +if (debug) +print_cpu_set ("allowed set" , cpu_allowed_set);if (!CPU_COUNT_S (cpu_allowed_setsize, cpu_allowed_set))err (-ENODEV ,"No valid cpus found" );
@@ -9683,12 +9715,18 @@ void topology_probe(bool startup)return ;for (i =0 ; i <= topo.max_cpu_num; ++i) { +int ht_id; +if (cpu_is_not_present (i))continue ;fprintf (outf, -"cpu %d pkg %d die %d l3 %d node %d lnode %d core %d thread %d\n" , +"cpu %d pkg %d die %d l3 %d node %d lnode %d core %d ht_id %d" , i, cpus[i].package_id, cpus[i].die_id, cpus[i].l3_id, cpus[i].physical_node_id, cpus[i].logical_node_id, cpus[i].core_id, cpus[i].ht_id); +fprintf (outf," siblings" ); +for (ht_id =0 ; ht_id <=MAX_HT_ID ; ++ht_id) +fprintf (outf," %d" , cpus[i].ht_sibling_cpu_id[ht_id]); +fprintf (outf,"\n" ); } }
@@ -9829,6 +9867,8 @@ void topology_update(void) topo.allowed_cores =0 ; topo.allowed_packages =0 ;for_all_cpus (update_topo,ODD_COUNTERS ); +if (debug) +fprintf (stderr,"allowed_cpus %d allowed_cores %d allowed_packages %d\n" , topo.allowed_cpus, topo.allowed_cores, topo.allowed_packages); }void setup_all_buffers (bool startup)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 876/1146 kbuild: Never respect CONFIG_WERROR / W=e to fixdep
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thomas Weißschuh <[email protected]>
[ Upstream commit 75f7c47ccd78c947cf1b6ddb18ea453ff0555716 ]
The fixdep hostprog may be built multiple times during a single build. Once during the configuration phase and later during the regular phase. As only the regular build phase respects CONFIG_WERROR / W=e, the compiler flags might change between the phases, leading to rebuilds.
Example, the rebuilds will happen twice on each invocation of the build:
$ make allyesconfig prepare
make[1]: Entering directory '/tmp/deleteme'
HOSTCC scripts/basic/fixdep
#
# No change to .config
#
HOSTCC scripts/basic/fixdep
DESCEND objtool
INSTALL libsubcmd_headers
make[1]: Leaving directory '/tmp/deleteme'Fix the compilation flags used for scripts/basic/ before scripts/Makefile.warn is evaluated to stop CONFIG_WERROR / W=e influencing the fixdep build to avoid the spurious rebuilds.
--- Makefile | 2 ++ 1 file changed, 2 insertions(+)
Makefile +2 -0
@@ -658,6 +658,8 @@ export RCS_FIND_IGNORE := \( -name SCCS -o -name BitKeeper -o -name .svn -o \ # Basic helpers built in scripts/basic/ PHONY += scripts_basic +scripts_basic: KBUILD_HOSTCFLAGS := $(KBUILD_HOSTCFLAGS) +scripts_basic: KBUILD_HOSTLDFLAGS := $(KBUILD_HOSTLDFLAGS) scripts_basic: $(Q)$(MAKE) $(build)=scripts/basic
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 877/1146 mailbox: mtk-vcp-mailbox: Fix the return value in mtk_vcp_mbox_xlate()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Felix Gu <[email protected]>
[ Upstream commit 1e0ec9719f58d53da61adf830e81f4af892e4582 ]
The return value of mtk_vcp_mbox_xlate() is checked by IS_ERR(), so return NULL is incorrect and could lead to a NULL pointer dereference.
--- drivers/mailbox/mtk-vcp-mailbox.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/mailbox/mtk-vcp-mailbox.c +1 -1
@@ -50,7 +50,7 @@ static struct mbox_chan *mtk_vcp_mbox_xlate(struct mbox_controller *mbox, const struct of_phandle_args *sp) {if (sp->args_count) -return NULL ; +return ERR_PTR (-EINVAL );return &mbox->chans[0 ]; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 878/1146 mailbox: mtk-cmdq: Fix CURR and END addr for task insert case
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jason-JH Lin <[email protected]>
[ Upstream commit d2591db9c8ef19fbb4d24ed15e0c6edfa6bc7917 ]
Fix CURR and END address calculation for inserting a cmdq task into the task list by using cmdq_reg_shift_addr() for proper address converting. This ensures both CURR and END addresses are set correctly when enabling the thread.
--- drivers/mailbox/mtk-cmdq-mailbox.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/mailbox/mtk-cmdq-mailbox.c +4 -4
@@ -493,14 +493,14 @@ static int cmdq_mbox_send_data(struct mbox_chan *chan, void *data)if (curr_pa == end_pa -CMDQ_INST_SIZE || curr_pa == end_pa) {/* set to this task directly */ -writel (task->pa_base >> cmdq->pdata->shift, - thread->base +CMDQ_THR_CURR_ADDR ); + gce_addr =cmdq_convert_gce_addr (task->pa_base, cmdq->pdata); +writel (gce_addr, thread->base +CMDQ_THR_CURR_ADDR ); }else {cmdq_task_insert_into_thread (task);smp_mb ();/* modify jump before enable thread */ } -writel ((task->pa_base + pkt->cmd_buf_size) >> cmdq->pdata->shift, - thread->base +CMDQ_THR_END_ADDR ); + gce_addr =cmdq_convert_gce_addr (task->pa_base + pkt->cmd_buf_size, cmdq->pdata); +writel (gce_addr, thread->base +CMDQ_THR_END_ADDR );cmdq_thread_resume (thread); }list_move_tail (&task->list_entry, &thread->task_busy_list);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 879/1146 mailbox: mailbox-test: free channels on probe error
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wolfram Sang <[email protected]>
[ Upstream commit c02053a9055d5fdfd32432287cca8958db1d5bc5 ]
On probe error, free the previously obtained channels. This not only prevents a leak, but also UAF scenarios because the client structure will be removed nonetheless because it was allocated with devm.
--- drivers/mailbox/mailbox-test.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-)
drivers/mailbox/mailbox-test.c +12 -3
@@ -404,18 +404,27 @@ static int mbox_test_probe(struct platform_device *pdev)if (tdev->rx_channel) { tdev->rx_buffer =devm_kzalloc (&pdev->dev,MBOX_MAX_MSG_LEN ,GFP_KERNEL ); -if (!tdev->rx_buffer) -return -ENOMEM ; +if (!tdev->rx_buffer) { + ret = -ENOMEM ; + goto err_free_chans; + } } ret =mbox_test_add_debugfs (pdev, tdev);if (ret) -return ret; + goto err_free_chans;init_waitqueue_head (&tdev->waitq);dev_info (&pdev->dev,"Successfully registered\n" );return 0 ; + +err_free_chans: +if (tdev->tx_channel) +mbox_free_channel (tdev->tx_channel); +if (tdev->rx_channel) +mbox_free_channel (tdev->rx_channel); +return ret; }static void mbox_test_remove (struct platform_device *pdev)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 880/1146 sched/psi: fix race between file release and pressure write
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Edward Adam Davis <[email protected]>
[ Upstream commit a5b98009f16d8a5fb4a8ff9a193f5735515c38fa ]
A potential race condition exists between pressure write and cgroup file release regarding the priv member of struct kernfs_open_file, which triggers the uaf reported in [1].
Consider the following scenario involving execution on two separate CPUs:
CPU0 CPU1
==== ====
vfs_rmdir() kernfs_iop_rmdir() cgroup_rmdir() cgroup_kn_lock_live() cgroup_destroy_locked() cgroup_addrm_files() cgroup_rm_file() kernfs_remove_by_name() kernfs_remove_by_name_ns() vfs_write() __kernfs_remove() new_sync_write() kernfs_drain() kernfs_fop_write_iter() kernfs_drain_open_files() cgroup_file_write() kernfs_release_file() pressure_write() cgroup_file_release() ctx = of->priv; kfree(ctx);
of->priv = NULL; cgroup_kn_unlock()
cgroup_kn_lock_live()
cgroup_get(cgrp)
cgroup_kn_unlock()
if (ctx->psi.trigger) // here, trigger uaf for ctx, that is of->priv
The cgroup_rmdir() is protected by the cgroup_mutex, it also safeguards the memory deallocation of of->priv performed within cgroup_file_release(). However, the operations involving of->priv executed within pressure_write() are not entirely covered by the protection of cgroup_mutex. Consequently, if the code in pressure_write(), specifically the section handling the ctx variable executes after cgroup_file_release() has completed, a uaf vulnerability involving of->priv is triggered.
Therefore, the issue can be resolved by extending the scope of the cgroup_mutex lock within pressure_write() to encompass all code paths involving of->priv, thereby properly synchronizing the race condition occurring between cgroup_file_release() and pressure_write().
And, if an live kn lock can be successfully acquired while executing the pressure write operation, it indicates that the cgroup deletion process has not yet reached its final stage; consequently, the priv pointer within open_file cannot be NULL. Therefore, the operation to retrieve the ctx value must be moved to a point *after* the live kn lock has been successfully acquired.
In another situation, specifically after entering cgroup_kn_lock_live() but before acquiring cgroup_mutex, there exists a different class of race condition:
CPU0: write memory.pressure CPU1: write cgroup.pressure=0
=========================== =============================
kernfs_fop_write_iter()
kernfs_get_active_of(of)
pressure_write()
cgroup_kn_lock_live(memory.pressure)
cgroup_tryget(cgrp)
kernfs_break_active_protection(kn)
... blocks on cgroup_mutex
cgroup_pressure_write() cgroup_kn_lock_live(cgroup.pressure) cgroup_file_show(memory.pressure, false)
kernfs_show(false)
kernfs_drain_open_files()
cgroup_file_release(of)
kfree(ctx)
of->priv = NULL
cgroup_kn_unlock()
... acquires cgroup_mutex
ctx = of->priv; // may now be NULL
if (ctx->psi.trigger) // NULL dereference
Consequently, there is a possibility that of->priv is NULL, the pressure write needs to check for this.
Now that the scope of the cgroup_mutex has been expanded, the original explicit cgroup_get/put operations are no longer necessary, this is because acquiring/releasing the live kn lock inherently executes a cgroup get/put operation.
[1]
BUG: KASAN: slab-use-after-free in pressure_write+0xa4/0x210 kernel/cgroup/cgroup.c:4011 Call Trace: pressure_write+0xa4/0x210 kernel/cgroup/cgroup.c:4011 cgroup_file_write+0x36f/0x790 kernel/cgroup/cgroup.c:4311 kernfs_fop_write_iter+0x3b0/0x540 fs/kernfs/file.c:352 Allocated by task 9352: cgroup_file_open+0x90/0x3a0 kernel/cgroup/cgroup.c:4256 kernfs_fop_open+0x9eb/0xcb0 fs/kernfs/file.c:724 do_dentry_open+0x83d/0x13e0 fs/open.c:949 Freed by task 9353: cgroup_file_release+0xd6/0x100 kernel/cgroup/cgroup.c:4283 kernfs_release_file fs/kernfs/file.c:764 [inline] kernfs_drain_open_files+0x392/0x720 fs/kernfs/file.c:834 kernfs_drain+0x470/0x600 fs/kernfs/dir.c:525
--- kernel/cgroup/cgroup.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-)
kernel/cgroup/cgroup.c +16 -8
@@ -4018,33 +4018,41 @@ static int cgroup_cpu_pressure_show(struct seq_file *seq, void *v)static ssize_t pressure_write (struct kernfs_open_file *of,char *buf,size_t nbytes,enum psi_res res) { -struct cgroup_file_ctx *ctx = of->priv; +struct cgroup_file_ctx *ctx;struct psi_trigger *new;struct cgroup *cgrp;struct psi_group *psi; +ssize_t ret =0 ; cgrp =cgroup_kn_lock_live (of->kn, false);if (!cgrp)return -ENODEV ; -cgroup_get (cgrp); -cgroup_kn_unlock (of->kn); + ctx = of->priv; +if (!ctx) { + ret = -ENODEV ; + goto out_unlock; + }/* Allow only one trigger per file descriptor */ if (ctx->psi.trigger) { -cgroup_put (cgrp); -return -EBUSY ; + ret = -EBUSY ; + goto out_unlock; } psi =cgroup_psi (cgrp); new =psi_trigger_create (psi, buf, res, of->file, of);if (IS_ERR (new)) { -cgroup_put (cgrp); -return PTR_ERR (new); + ret =PTR_ERR (new); + goto out_unlock; }smp_store_release (&ctx->psi.trigger, new); -cgroup_put (cgrp); + +out_unlock: +cgroup_kn_unlock (of->kn); +if (ret) +return ret;return nbytes; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 881/1146 cgroup/rdma: fix integer overflow in rdmacg_try_charge()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: cuitao <[email protected]>
[ Upstream commit c802f460dd485c1332b5a35e7adcfb2bc22536a2 ]
The expression rpool->resources[index].usage + 1 is computed in int arithmetic before being assigned to s64 variable new. When usage equals INT_MAX (the default "max" value), the addition overflows to INT_MIN. This negative value then passes the new > max check incorrectly, allowing a charge that should be rejected and corrupting usage to negative.
Fix by casting usage to s64 before the addition so the arithmetic is done in 64-bit.
--- kernel/cgroup/rdma.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/cgroup/rdma.c +1 -1
@@ -283,7 +283,7 @@ int rdmacg_try_charge(struct rdma_cgroup **rdmacg, ret =PTR_ERR (rpool); goto err; }else { - new = rpool->resources[index].usage +1 ; + new = (s64 )rpool->resources[index].usage +1 ;if (new > rpool->resources[index].max) { ret = -EAGAIN ; goto err;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 882/1146 cgroup/cpuset: record DL BW alloc CPU for attach rollback
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guopeng Zhang <[email protected]>
[ Upstream commit 41d701ddc36d5301b44ea79529f3cf03c541c1e1 ]
cpuset_can_attach() allocates DL bandwidth only when migrating deadline tasks to a disjoint CPU mask, but cpuset_cancel_attach() rolls back based only on nr_migrate_dl_tasks. This makes the DL bandwidth alloc/free paths asymmetric: rollback can call dl_bw_free() even when no dl_bw_alloc() was done.
Rollback also needs to undo the reservation against the same CPU/root domain that was charged. Record the CPU used by dl_bw_alloc() and use that state in cpuset_cancel_attach(). If no allocation happened, dl_bw_cpu stays at -1 and rollback skips dl_bw_free(). If allocation did happen, bandwidth is returned to the same CPU/root domain.
Successful attach paths are unchanged. This only fixes failed attach rollback accounting.
--- kernel/cgroup/cpuset-internal.h | 5 +++++ kernel/cgroup/cpuset.c | 13 +++++++++---- 2 files changed, 14 insertions(+), 4 deletions(-)
kernel/cgroup/cpuset-internal.h +5 -0
@@ -168,6 +168,11 @@ struct cpuset {int nr_deadline_tasks;int nr_migrate_dl_tasks;u64 sum_migrate_dl_bw; +/* +* CPU used for temporary DL bandwidth allocation during attach; +* -1 if no DL bandwidth was allocated in the current attach. +*/ +int dl_bw_cpu;/* Invalid partition error code, not lock protected */ enum prs_errcode prs_err;
kernel/cgroup/cpuset.c +9 -4
@@ -288,6 +288,7 @@ struct cpuset top_cpuset = { .flags = BIT(CS_CPU_EXCLUSIVE) | BIT(CS_MEM_EXCLUSIVE) | BIT(CS_SCHED_LOAD_BALANCE), .partition_root_state = PRS_ROOT, + .dl_bw_cpu = -1, };/**
@@ -579,6 +580,8 @@ static struct cpuset *dup_or_alloc_cpuset(struct cpuset *cs)if (!trial)return NULL ; + trial->dl_bw_cpu =-1 ; +/* Setup cpumask pointer array */ cpumask_var_t *pmask[4 ] = { &trial->cpus_allowed,
@@ -2980,6 +2983,7 @@ static void reset_migrate_dl_data(struct cpuset *cs) { cs->nr_migrate_dl_tasks =0 ; cs->sum_migrate_dl_bw =0 ; + cs->dl_bw_cpu =-1 ; }/* Called by cgroups to determine if a cpuset is usable; cpuset_mutex held */
@@ -3056,6 +3060,8 @@ static int cpuset_can_attach(struct cgroup_taskset *tset)reset_migrate_dl_data (cs); goto out_unlock; } + + cs->dl_bw_cpu = cpu; } out_success:
@@ -3080,12 +3086,11 @@ static void cpuset_cancel_attach(struct cgroup_taskset *tset)mutex_lock (&cpuset_mutex);dec_attach_in_progress_locked (cs); -if (cs->nr_migrate_dl_tasks) { -int cpu =cpumask_any (cs->effective_cpus); +if (cs->dl_bw_cpu >=0 ) +dl_bw_free (cs->dl_bw_cpu, cs->sum_migrate_dl_bw); -dl_bw_free (cpu, cs->sum_migrate_dl_bw); +if (cs->nr_migrate_dl_tasks)reset_migrate_dl_data (cs); - }mutex_unlock (&cpuset_mutex); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 883/1146 mailbox: add sanity check for channel array
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wolfram Sang <[email protected]>
[ Upstream commit c1aad75595fb67edc7fda8af249d3b886efa1be9 ]
Fail gracefully if there is no channel array attached to the mailbox controller. Otherwise the later dereference will cause an OOPS which might not be seen because mailbox controllers might instantiate very early. Remove the comment explaining the obvious while here.
--- drivers/mailbox/mailbox.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
drivers/mailbox/mailbox.c +1 -2
@@ -505,8 +505,7 @@ int mbox_controller_register(struct mbox_controller *mbox) {int i, txdone; -/* Sanity check */ -if (!mbox || !mbox->dev || !mbox->ops || !mbox->num_chans) +if (!mbox || !mbox->dev || !mbox->ops || !mbox->chans || !mbox->num_chans)return -EINVAL ;if (mbox->txdone_irq)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 884/1146 mailbox: mailbox-test: handle channel errors consistently
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wolfram Sang <[email protected]>
[ Upstream commit dd9aa1f269000d679f4ec12b32abacfc8d921413 ]
mbox_test_request_channel() returns either an ERR_PTR or NULL. The callers, however, mostly checked for non-NULL which allows for bogus code paths when an ERR_PTR is treated like a valid channel. A later commit tried to fix it in one place but missed the other ones. Because the ERR_PTR is only used for -ENOMEM once and is converted to -EPROBE_DEFER anyhow, convert the callee to only return NULL which simplifies handling a lot and makes it less error prone.
--- drivers/mailbox/mailbox-test.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/mailbox/mailbox-test.c +2 -2
@@ -336,7 +336,7 @@ mbox_test_request_channel(struct platform_device *pdev, const char *name) client =devm_kzalloc (&pdev->dev,sizeof (*client),GFP_KERNEL );if (!client) -return ERR_PTR (-ENOMEM ); +return NULL ; client->dev = &pdev->dev; client->rx_callback = mbox_test_receive_message;
@@ -388,7 +388,7 @@ static int mbox_test_probe(struct platform_device *pdev) tdev->tx_channel =mbox_test_request_channel (pdev,"tx" ); tdev->rx_channel =mbox_test_request_channel (pdev,"rx" ); -if (IS_ERR_OR_NULL (tdev->tx_channel) &&IS_ERR_OR_NULL (tdev->rx_channel)) +if (!tdev->tx_channel && !tdev->rx_channel)return -EPROBE_DEFER ;/* If Rx is not specified but has Rx MMIO, then Rx = Tx */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 885/1146 mailbox: mailbox-test: dont free the reused channel
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wolfram Sang <[email protected]>
[ Upstream commit 88ebadbf0deefdaccdab868b44ff70a0a257f473 ]
The RX channel can be aliased to the TX channel if it has a different MMIO. This special case needs to be handled when freeing the channels otherwise a double-free occurs.
--- drivers/mailbox/mailbox-test.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/mailbox/mailbox-test.c +2 -2
@@ -422,7 +422,7 @@ static int mbox_test_probe(struct platform_device *pdev) err_free_chans:if (tdev->tx_channel)mbox_free_channel (tdev->tx_channel); -if (tdev->rx_channel) +if (tdev->rx_channel && tdev->rx_channel != tdev->tx_channel)mbox_free_channel (tdev->rx_channel);return ret; }
@@ -435,7 +435,7 @@ static void mbox_test_remove(struct platform_device *pdev)if (tdev->tx_channel)mbox_free_channel (tdev->tx_channel); -if (tdev->rx_channel) +if (tdev->rx_channel && tdev->rx_channel != tdev->tx_channel)mbox_free_channel (tdev->rx_channel); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 886/1146 mailbox: mailbox-test: initialize struct earlier
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wolfram Sang <[email protected]>
[ Upstream commit bbcf9af68bfedb3d9cc3c7eae62f5c844d8b78b9 ]
The waitqueue must be initialized before the debugfs files are created because from that time, requests from userspace can already be made. Similarily, drvdata and spinlock needs to be initialized before we request the channel, otherwise dangling irqs might run into problems like a NULL pointer exception.
--- drivers/mailbox/mailbox-test.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-)
drivers/mailbox/mailbox-test.c +6 -7
@@ -366,6 +366,12 @@ static int mbox_test_probe(struct platform_device *pdev)if (!tdev)return -ENOMEM ; + tdev->dev = &pdev->dev; +spin_lock_init (&tdev->lock); +mutex_init (&tdev->mutex); +init_waitqueue_head (&tdev->waitq); +platform_set_drvdata (pdev, tdev); +/* It's okay for MMIO to be NULL */ tdev->tx_mmio =devm_platform_get_and_ioremap_resource (pdev,0 , &res);if (PTR_ERR (tdev->tx_mmio) == -EBUSY ) {
@@ -395,12 +401,6 @@ static int mbox_test_probe(struct platform_device *pdev)if (!tdev->rx_channel && (tdev->rx_mmio != tdev->tx_mmio)) tdev->rx_channel = tdev->tx_channel; - tdev->dev = &pdev->dev; -platform_set_drvdata (pdev, tdev); - -spin_lock_init (&tdev->lock); -mutex_init (&tdev->mutex); -if (tdev->rx_channel) { tdev->rx_buffer =devm_kzalloc (&pdev->dev,MBOX_MAX_MSG_LEN ,GFP_KERNEL );
@@ -414,7 +414,6 @@ static int mbox_test_probe(struct platform_device *pdev)if (ret) goto err_free_chans; -init_waitqueue_head (&tdev->waitq);dev_info (&pdev->dev,"Successfully registered\n" );return 0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 887/1146 mailbox: mailbox-test: make data_ready a per-instance variable
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wolfram Sang <[email protected]>
[ Upstream commit 6e937f4e769e60947909e3525965f0137b9039e8 ]
While not the default case, multiple tests can be run simultaneously. Then, data_ready being a global variable will be overwritten and the per-instance lock will not help. Turn the global variable into a per-instance one to avoid this problem.
--- drivers/mailbox/mailbox-test.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-)
drivers/mailbox/mailbox-test.c +4 -5
@@ -28,8 +28,6 @@#define MBOX_HEXDUMP_MAX_LEN (MBOX_HEXDUMP_LINE_LEN * \ (MBOX_MAX_MSG_LEN / MBOX_BYTES_PER_LINE)) -static bool mbox_data_ready; -struct mbox_test_device {struct device *dev;void __iomem *tx_mmio;
@@ -42,6 +40,7 @@ struct mbox_test_device {spinlock_t lock;struct mutex mutex;wait_queue_head_t waitq; +bool data_ready;struct fasync_struct *async_queue;struct dentry *root_debugfs_dir; };
@@ -162,7 +161,7 @@ static bool mbox_test_message_data_ready(struct mbox_test_device *tdev)unsigned long flags;spin_lock_irqsave (&tdev->lock, flags); - data_ready = mbox_data_ready; + data_ready = tdev->data_ready;spin_unlock_irqrestore (&tdev->lock, flags);return data_ready;
@@ -227,7 +226,7 @@ static ssize_t mbox_test_message_read(struct file *filp, char __user *userbuf, *(touser + l) ='\0' ;memset (tdev->rx_buffer,0 ,MBOX_MAX_MSG_LEN ); - mbox_data_ready = false; + tdev->data_ready = false;spin_unlock_irqrestore (&tdev->lock, flags);
@@ -297,7 +296,7 @@ static void mbox_test_receive_message(struct mbox_client *client, void *message) message, MBOX_MAX_MSG_LEN);memcpy (tdev->rx_buffer, message,MBOX_MAX_MSG_LEN ); } - mbox_data_ready = true; + tdev->data_ready = true;spin_unlock_irqrestore (&tdev->lock, flags);wake_up_interruptible (&tdev->waitq);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 888/1146 fsnotify: fix inode reference leak in fsnotify_recalc_mask()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Amir Goldstein <[email protected]>
[ Upstream commit 4aca914ac152f5d055ddcb36704d1e539ac08977 ]
fsnotify_recalc_mask() fails to handle the return value of __fsnotify_recalc_mask(), which may return an inode pointer that needs to be released via fsnotify_drop_object() when the connector's HAS_IREF flag transitions from set to cleared.
This manifests as a hung task with the following call trace:
INFO: task umount:1234 blocked for more than 120 seconds. Call Trace: __schedule schedule fsnotify_sb_delete generic_shutdown_super kill_anon_super cleanup_mnt task_work_run do_exit do_group_exit
The race window that triggers the iref leak:
Thread A (adding mark) Thread B (removing mark)
────────────────────── ────────────────────────
fsnotify_add_mark_locked():
fsnotify_add_mark_list():
spin_lock(conn->lock)
add mark_B(evictable) to list
spin_unlock(conn->lock)
return
/* ---- gap: no lock held ---- */
fsnotify_detach_mark(mark_A):
spin_lock(mark_A->lock)
clear ATTACHED flag on mark_A
spin_unlock(mark_A->lock)
fsnotify_put_mark(mark_A)
fsnotify_recalc_mask():
spin_lock(conn->lock)
__fsnotify_recalc_mask():
/* mark_A skipped: ATTACHED cleared */
/* only mark_B(evictable) remains */
want_iref = false
has_iref = true /* not yet cleared */
-> HAS_IREF transitions true -> false
-> returns inode pointer
spin_unlock(conn->lock)
/* BUG: return value discarded!
* iput() and fsnotify_put_sb_watched_objects()
* are never called */Fix this by deferring the transition true -> false of HAS_IREF flag from fsnotify_recalc_mask() (Thread A) to fsnotify_put_mark() (thread B).
--- fs/notify/mark.c | 39 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-)
fs/notify/mark.c +36 -3
@@ -238,7 +238,12 @@ static struct inode *fsnotify_update_iref(struct fsnotify_mark_connector *conn,return inode; } -static void *__fsnotify_recalc_mask (struct fsnotify_mark_connector *conn) +/* +* Calculate mask of events for a list of marks. +* +* Return true if any of the attached marks want to hold an inode reference. +*/ +static bool __fsnotify_recalc_mask (struct fsnotify_mark_connector *conn) {u32 new_mask =0 ;bool want_iref = false;
@@ -262,6 +267,34 @@ static void *__fsnotify_recalc_mask(struct fsnotify_mark_connector *conn)*/ WRITE_ONCE (*fsnotify_conn_mask_p (conn), new_mask); +return want_iref; +} + +/* +* Calculate mask of events for a list of marks after attach/modify mark +* and get an inode reference for the connector if needed. +* +* A concurrent add of evictable mark and detach of non-evictable mark can +* lead to __fsnotify_recalc_mask() returning false want_iref, but in this +* case we defer clearing iref to fsnotify_recalc_mask_clear_iref() called +* from fsnotify_put_mark(). +*/ +static void fsnotify_recalc_mask_set_iref (struct fsnotify_mark_connector *conn) +{ +bool has_iref = conn->flags &FSNOTIFY_CONN_FLAG_HAS_IREF ; +bool want_iref =__fsnotify_recalc_mask (conn) || has_iref; + + (void )fsnotify_update_iref (conn, want_iref); +} + +/* +* Calculate mask of events for a list of marks after detach mark +* and return the inode object if its reference is no longer needed. +*/ +static void *fsnotify_recalc_mask_clear_iref (struct fsnotify_mark_connector *conn) +{ +bool want_iref =__fsnotify_recalc_mask (conn); +return fsnotify_update_iref (conn, want_iref); }
@@ -298,7 +331,7 @@ void fsnotify_recalc_mask(struct fsnotify_mark_connector *conn)spin_lock (&conn->lock); update_children = !fsnotify_conn_watches_children (conn); -__fsnotify_recalc_mask (conn); +fsnotify_recalc_mask_set_iref (conn); update_children &=fsnotify_conn_watches_children (conn);spin_unlock (&conn->lock);/*
@@ -419,7 +452,7 @@ void fsnotify_put_mark(struct fsnotify_mark *mark)/* Update watched objects after detaching mark */ if (sb)fsnotify_update_sb_watchers (sb, conn); - objp =__fsnotify_recalc_mask (conn); + objp =fsnotify_recalc_mask_clear_iref (conn); type = conn->type; }WRITE_ONCE (mark->connector,NULL );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 889/1146 btrfs: fix bytes_may_use leak in move_existing_remap()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mark Harmstone <[email protected]>
[ Upstream commit 68a135013bf73dfd6a277f76fc4e088b0f3dfa79 ]
If the call to btrfs_reserve_extent() in move_existing_remap() returns a smaller extent than we asked for, currently we're not undoing the bytes_may_use change that we made. Fix this by calling btrfs_space_info_update_bytes_may_use() again for the difference.
--- fs/btrfs/relocation.c | 6 ++++++ 1 file changed, 6 insertions(+)
fs/btrfs/relocation.c +6 -0
@@ -4182,6 +4182,12 @@ static int move_existing_remap(struct btrfs_fs_info *fs_info,return ret; } +if (ins.offset < length) { +spin_lock (&sinfo->lock); +btrfs_space_info_update_bytes_may_use (sinfo, ins.offset - length); +spin_unlock (&sinfo->lock); + } + dest_addr = ins.objectid; dest_length = ins.offset;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 890/1146 btrfs: fix bytes_may_use leak in do_remap_reloc_trans()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mark Harmstone <[email protected]>
[ Upstream commit 9b8824533d75fb199a3fb0f6147ffcca64b5caf8 ]
If the call to btrfs_reserve_extent() in do_remap_reloc_trans() returns a smaller extent than we asked for, currently we're not undoing the bytes_may_use change that we made. Fix this by calling btrfs_space_info_update_bytes_may_use() again for the difference.
--- fs/btrfs/relocation.c | 6 ++++++ 1 file changed, 6 insertions(+)
fs/btrfs/relocation.c +6 -0
@@ -5014,6 +5014,12 @@ static int do_remap_reloc_trans(struct btrfs_fs_info *fs_info,return ret; } +if (ins.offset < remap_length) { +spin_lock (&sinfo->lock); +btrfs_space_info_update_bytes_may_use (sinfo, ins.offset - remap_length); +spin_unlock (&sinfo->lock); + } + made_reservation = true; new_addr = ins.objectid;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 891/1146 btrfs: dont clobber errors in add_remap_tree_entries()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mark Harmstone <[email protected]>
[ Upstream commit 44366af74061793ee5ceef455a4f0e465892d0de ]
In add_remap_tree_entries(), we only process a certain number of entries at a time, meaning we may need to loop.
But because we weren't checking the return value of btrfs_insert_empty_items() within the loop, this meant that if the last iteration of the loop succeeded but a previous iteration failed, we were erroneously returning 0.
Fix this by breaking the loop early if btrfs_insert_empty_items() fails.
--- fs/btrfs/relocation.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/btrfs/relocation.c +1 -1
@@ -3884,7 +3884,7 @@ static int add_remap_tree_entries(struct btrfs_trans_handle *trans, struct btrfs ret =btrfs_insert_empty_items (trans, fs_info->remap_root, path, &batch);btrfs_release_path (path); -if (num_entries <= max_items) +if (ret || num_entries <= max_items)break ; num_entries -= max_items;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 892/1146 btrfs: fix double-decrement of bytes_may_use in submit_one_async_extent()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mark Harmstone <[email protected]>
[ Upstream commit 82323b1a7088b7a5c3e528a5d634bff447fa286f ]
submit_one_async_extent() calls btrfs_reserve_extent(), which decrements bytes_may_use. If the call btrfs_create_io_em() fails, we jump to out_free_reserve, which calls extent_clear_unlock_delalloc().
Because we're specifying EXTENT_DO_ACCOUNTING, i.e. EXTENT_CLEAR_META_RESV | EXTENT_CLEAR_DATA_RESV, this decreases bytes_may_use again. This can lead to problems later on, as an initial write can fail only for the writeback to silently ENOSPC.
Fix this by replacing EXTENT_DO_ACCOUNTING with EXTENT_CLEAR_META_RESV. This parallels a4fe134fc1d8eb ("btrfs: fix a double release on reserved extents in cow_one_range()"), which is the same fix in cow_one_range().
--- fs/btrfs/inode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/btrfs/inode.c +1 -1
@@ -1245,7 +1245,7 @@ static void submit_one_async_extent(struct async_chunk *async_chunk,NULL , &cached,EXTENT_LOCKED |EXTENT_DELALLOC |EXTENT_DELALLOC_NEW | -EXTENT_DEFRAG |EXTENT_DO_ACCOUNTING , +EXTENT_DEFRAG |EXTENT_CLEAR_META_RESV ,PAGE_UNLOCK |PAGE_START_WRITEBACK | PAGE_END_WRITEBACK);if (async_extent->cb)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 893/1146 tracing: branch: Fix inverted check on stat tracer registration
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Breno Leitao <[email protected]>
[ Upstream commit 3b75dd76e64a04771861bb5647951c264919e563 ]
init_annotated_branch_stats() and all_annotated_branch_stats() check the return value of register_stat_tracer() with "if (!ret)", but register_stat_tracer() returns 0 on success and a negative errno on failure. The inverted check causes the warning to be printed on every successful registration, e.g.:
Warning: could not register annotated branches stats
while leaving real failures silent. The initcall also returned a hard-coded 1 instead of the actual error.
Invert the check and propagate ret so that the warning fires on real errors and the initcall reports the correct status.
--- kernel/trace/trace_branch.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
kernel/trace/trace_branch.c +4 -4
@@ -373,10 +373,10 @@ __init static int init_annotated_branch_stats(void)int ret; ret =register_stat_tracer (&annotated_branch_stats); -if (!ret) { +if (ret) {printk (KERN_WARNING "Warning: could not register " "annotated branches stats\n" ); -return 1 ; +return ret; }return 0 ; }
@@ -438,10 +438,10 @@ __init static int all_annotated_branch_stats(void)int ret; ret =register_stat_tracer (&all_branch_stats); -if (!ret) { +if (ret) {printk (KERN_WARNING "Warning: could not register " "all branches stats\n" ); -return 1 ; +return ret; }return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 894/1146 nvmet-tcp: propagate nvmet_tcp_build_pdu_iovec() errors to its callers
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Maurizio Lombardi <[email protected]>
[ Upstream commit ea8e356acb165cb1fd75537a52e1f66e5e76c538 ]
Currently, when nvmet_tcp_build_pdu_iovec() detects an out-of-bounds PDU length or offset, it triggers nvmet_tcp_fatal_error(cmd->queue) and returns early. However, because the function returns void, the callers are entirely unaware that a fatal error has occurred and that the cmd->recv_msg.msg_iter was left uninitialized.
Callers such as nvmet_tcp_handle_h2c_data_pdu() proceed to blindly overwrite the queue state with queue->rcv_state = NVMET_TCP_RECV_DATA Consequently, the socket receiving loop may attempt to read incoming network data into the uninitialized iterator.
Fix this by shifting the error handling responsibility to the callers.
--- drivers/nvme/target/tcp.c | 51 ++++++++++++++++++++++----------------- 1 file changed, 29 insertions(+), 22 deletions(-)
drivers/nvme/target/tcp.c +29 -22
@@ -351,7 +351,7 @@ static void nvmet_tcp_free_cmd_buffers(struct nvmet_tcp_cmd *cmd)static void nvmet_tcp_fatal_error (struct nvmet_tcp_queue *queue); -static void nvmet_tcp_build_pdu_iovec (struct nvmet_tcp_cmd *cmd) +static int nvmet_tcp_build_pdu_iovec (struct nvmet_tcp_cmd *cmd) {struct bio_vec *iov = cmd->iov;struct scatterlist *sg;
@@ -364,22 +364,19 @@ static void nvmet_tcp_build_pdu_iovec(struct nvmet_tcp_cmd *cmd) offset = cmd->rbytes_done; cmd->sg_idx = offset /PAGE_SIZE ; sg_offset = offset %PAGE_SIZE ; -if (!cmd->req.sg_cnt || cmd->sg_idx >= cmd->req.sg_cnt) { -nvmet_tcp_fatal_error (cmd->queue); -return ; - } +if (!cmd->req.sg_cnt || cmd->sg_idx >= cmd->req.sg_cnt) +return -EPROTO ; + sg = &cmd->req.sg[cmd->sg_idx]; sg_remaining = cmd->req.sg_cnt - cmd->sg_idx;while (length) { -if (!sg_remaining) { -nvmet_tcp_fatal_error (cmd->queue); -return ; - } -if (!sg->length || sg->length <= sg_offset) { -nvmet_tcp_fatal_error (cmd->queue); -return ; - } +if (!sg_remaining) +return -EPROTO ; + +if (!sg->length || sg->length <= sg_offset) +return -EPROTO ; +u32 iov_len =min_t (u32, length, sg->length - sg_offset); bvec_set_page(iov, sg_page(sg), iov_len,
@@ -394,6 +391,7 @@ static void nvmet_tcp_build_pdu_iovec(struct nvmet_tcp_cmd *cmd)iov_iter_bvec (&cmd->recv_msg.msg_iter,ITER_DEST , cmd->iov, nr_pages, cmd->pdu_len); +return 0 ; }static void nvmet_tcp_fatal_error (struct nvmet_tcp_queue *queue)
@@ -957,7 +955,7 @@ static int nvmet_tcp_handle_icreq(struct nvmet_tcp_queue *queue)return 0 ; } -static void nvmet_tcp_handle_req_failure (struct nvmet_tcp_queue *queue, +static int nvmet_tcp_handle_req_failure (struct nvmet_tcp_queue *queue,struct nvmet_tcp_cmd *cmd,struct nvmet_req *req) {size_t data_len =le32_to_cpu (req->cmd->common.dptr.sgl.length);
@@ -973,19 +971,23 @@ static void nvmet_tcp_handle_req_failure(struct nvmet_tcp_queue *queue,if (!nvme_is_write (cmd->req.cmd) || !data_len || data_len > cmd->req.port->inline_data_size) {nvmet_prepare_receive_pdu (queue); -return ; +return 0 ; } ret =nvmet_tcp_map_data (cmd);if (unlikely (ret)) {pr_err ("queue %d: failed to map data\n" , queue->idx);nvmet_tcp_fatal_error (queue); -return ; +return -EPROTO ; } queue->rcv_state =NVMET_TCP_RECV_DATA ; -nvmet_tcp_build_pdu_iovec (cmd); cmd->flags |=NVMET_TCP_F_INIT_FAILED ; + ret =nvmet_tcp_build_pdu_iovec (cmd); +if (unlikely (ret)) +pr_err ("queue %d: failed to build PDU iovec\n" , queue->idx); + +return ret; }static int nvmet_tcp_handle_h2c_data_pdu (struct nvmet_tcp_queue *queue)
@@ -1037,7 +1039,10 @@ static int nvmet_tcp_handle_h2c_data_pdu(struct nvmet_tcp_queue *queue) goto err_proto; } cmd->pdu_recv =0 ; -nvmet_tcp_build_pdu_iovec (cmd); +if (unlikely (nvmet_tcp_build_pdu_iovec (cmd))) { +pr_err ("queue %d: failed to build PDU iovec\n" , queue->idx); + goto err_proto; + } queue->cmd = cmd; queue->rcv_state =NVMET_TCP_RECV_DATA ;
@@ -1100,8 +1105,7 @@ static int nvmet_tcp_done_recv_pdu(struct nvmet_tcp_queue *queue)le32_to_cpu (req->cmd->common.dptr.sgl.length), le16_to_cpu(req->cqe->status)); -nvmet_tcp_handle_req_failure (queue, queue->cmd, req); -return 0 ; +return nvmet_tcp_handle_req_failure (queue, queue->cmd, req); } ret =nvmet_tcp_map_data (queue->cmd);
@@ -1118,8 +1122,11 @@ static int nvmet_tcp_done_recv_pdu(struct nvmet_tcp_queue *queue)if (nvmet_tcp_need_data_in (queue->cmd)) {if (nvmet_tcp_has_inline_data (queue->cmd)) { queue->rcv_state =NVMET_TCP_RECV_DATA ; -nvmet_tcp_build_pdu_iovec (queue->cmd); -return 0 ; + ret =nvmet_tcp_build_pdu_iovec (queue->cmd); +if (unlikely (ret)) +pr_err ("queue %d: failed to build PDU iovec\n" , + queue->idx); +return ret; }/* send back R2T */ nvmet_tcp_queue_response (&queue->cmd->req);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 895/1146 netfilter: arp_tables: fix IEEE1394 ARP payload parsing
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pablo Neira Ayuso <[email protected]>
[ Upstream commit 1e8e3f449b1e73b73a843257635b9c50f0cc0f0a ]
Weiming Shi says:
"arp_packet_match() unconditionally parses the ARP payload assuming two hardware addresses are present (source and target). However, IPv4-over-IEEE1394 ARP (RFC 2734) omits the target hardware address field, and arp_hdr_len() already accounts for this by returning a shorter length for ARPHRD_IEEE1394 devices.
As a result, on IEEE1394 interfaces arp_packet_match() advances past a nonexistent target hardware address and reads the wrong bytes for both the target device address comparison and the target IP address. This causes arptables rules to match against garbage data, leading to incorrect filtering decisions: packets that should be accepted may be dropped and vice versa.
The ARP stack in net/ipv4/arp.c (arp_create and arp_process) already handles this correctly by skipping the target hardware address for ARPHRD_IEEE1394. Apply the same pattern to arp_packet_match()."
Mangle the original patch to always return 0 (no match) in case user matches on the target hardware address which is never present in IEEE1394.
Note that this returns 0 (no match) for either normal and inverse match because matching in the target hardware address in ARPHRD_IEEE1394 has never been supported by arptables. This is intentional, matching on the target hardware address should never evaluate true for ARPHRD_IEEE1394.
Moreover, adjust arpt_mangle to drop the packet too as AI suggests:
In arpt_mangle, the logic assumes a standard ARP layout. Because IEEE1394 (FireWire) omits the target hardware address, the linear pointer arithmetic miscalculates the offset for the target IP address. This causes mangling operations to write to the wrong location, leading to packet corruption. To ensure safety, this patch drops packets (NF_DROP) when mangling is requested for these fields on IEEE1394 devices, as the current implementation cannot correctly map the FireWire ARP payload.
This omits both mangling target hardware and IP address. Even if IP address mangling should be possible in IEEE1394, this would require to adjust arpt_mangle offset calculation, which has never been supported.
Based on patch from Weiming Shi <[email protected]>.
--- net/ipv4/netfilter/arp_tables.c | 18 +++++++++++++++--- net/ipv4/netfilter/arpt_mangle.c | 8 ++++++++ 2 files changed, 23 insertions(+), 3 deletions(-)
net/ipv4/netfilter/arp_tables.c +15 -3
@@ -110,13 +110,25 @@ static inline int arp_packet_match(const struct arphdr *arphdr, arpptr += dev->addr_len;memcpy (&src_ipaddr, arpptr,sizeof (u32)); arpptr +=sizeof (u32); - tgt_devaddr = arpptr; - arpptr += dev->addr_len; + +if (IS_ENABLED (CONFIG_FIREWIRE_NET ) && dev->type ==ARPHRD_IEEE1394 ) { +if (unlikely (memchr_inv (arpinfo->tgt_devaddr.mask,0 , +sizeof (arpinfo->tgt_devaddr.mask)))) +return 0 ; + + tgt_devaddr =NULL ; + }else { + tgt_devaddr = arpptr; + arpptr += dev->addr_len; + }memcpy (&tgt_ipaddr, arpptr,sizeof (u32));if (NF_INVF (arpinfo,ARPT_INV_SRCDEVADDR ,arp_devaddr_compare (&arpinfo->src_devaddr, src_devaddr, - dev->addr_len)) || + dev->addr_len))) +return 0 ; + +if (tgt_devaddr &&NF_INVF (arpinfo,ARPT_INV_TGTDEVADDR ,arp_devaddr_compare (&arpinfo->tgt_devaddr, tgt_devaddr, dev->addr_len)))
net/ipv4/netfilter/arpt_mangle.c +8 -0
@@ -40,6 +40,10 @@ target(struct sk_buff *skb, const struct xt_action_param *par) } arpptr += pln;if (mangle->flags &ARPT_MANGLE_TDEV ) { +if (unlikely (IS_ENABLED (CONFIG_FIREWIRE_NET ) && + skb->dev->type ==ARPHRD_IEEE1394 )) +return NF_DROP ; +if (ARPT_DEV_ADDR_LEN_MAX < hln || (arpptr + hln >skb_tail_pointer (skb)))return NF_DROP ;
@@ -47,6 +51,10 @@ target(struct sk_buff *skb, const struct xt_action_param *par) } arpptr += hln;if (mangle->flags &ARPT_MANGLE_TIP ) { +if (unlikely (IS_ENABLED (CONFIG_FIREWIRE_NET ) && + skb->dev->type ==ARPHRD_IEEE1394 )) +return NF_DROP ; +if (ARPT_MANGLE_ADDR_LEN_MAX < pln || (arpptr + pln >skb_tail_pointer (skb)))return NF_DROP ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 896/1146 netfilter: nf_tables: use list_del_rcu for netlink hooks
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Florian Westphal <[email protected]>
[ Upstream commit f3224ee463f8f6f6ced7dcdf6081add4f8128527 ]
nft_netdev_unregister_hooks and __nft_unregister_flowtable_net_hooks need to use list_del_rcu(), this list can be walked by concurrent dumpers.
Add a new helper and use it consistently.
--- net/netfilter/nf_tables_api.c | 44 ++++++++++++++--------------------- 1 file changed, 18 insertions(+), 26 deletions(-)
net/netfilter/nf_tables_api.c +18 -26
@@ -374,6 +374,12 @@ static void nft_netdev_hook_free_rcu(struct nft_hook *hook)call_rcu (&hook->rcu, __nft_netdev_hook_free_rcu); } +static void nft_netdev_hook_unlink_free_rcu (struct nft_hook *hook) +{ +list_del_rcu (&hook->list); +nft_netdev_hook_free_rcu (hook); +} +static void nft_netdev_unregister_hooks (struct net *net,struct list_head *hook_list,bool release_netdev)
@@ -384,10 +390,8 @@ static void nft_netdev_unregister_hooks(struct net *net,list_for_each_entry_safe (hook, next, hook_list, list) {list_for_each_entry (ops, &hook->ops_list, list)nf_unregister_net_hook (net, ops); -if (release_netdev) { -list_del (&hook->list); -nft_netdev_hook_free_rcu (hook); - } +if (release_netdev) +nft_netdev_hook_unlink_free_rcu (hook); } }
@@ -2323,10 +2327,8 @@ void nf_tables_chain_destroy(struct nft_chain *chain)if (nft_base_chain_netdev (table->family, basechain->ops.hooknum)) {list_for_each_entry_safe (hook, next, - &basechain->hook_list, list) { -list_del_rcu (&hook->list); -nft_netdev_hook_free_rcu (hook); - } + &basechain->hook_list, list) +nft_netdev_hook_unlink_free_rcu (hook); }module_put (basechain->type->owner);if (rcu_access_pointer (basechain->stats)) {
@@ -3026,6 +3028,7 @@ static int nf_tables_updchain(struct nft_ctx *ctx, u8 genmask, u8 policy,list_for_each_entry (ops, &h->ops_list, list)nf_unregister_net_hook (ctx->net, ops); } +/* hook.list is on stack, no need for list_del_rcu() */ list_del (&h->list);nft_netdev_hook_free_rcu (h); }
@@ -8903,10 +8906,8 @@ static void __nft_unregister_flowtable_net_hooks(struct net *net,list_for_each_entry_safe (hook, next, hook_list, list) {list_for_each_entry (ops, &hook->ops_list, list)nft_unregister_flowtable_ops (net, flowtable, ops); -if (release_netdev) { -list_del (&hook->list); -nft_netdev_hook_free_rcu (hook); - } +if (release_netdev) +nft_netdev_hook_unlink_free_rcu (hook); } }
@@ -8977,8 +8978,7 @@ static int nft_register_flowtable_net_hooks(struct net *net,nft_unregister_flowtable_ops (net, flowtable, ops); } -list_del_rcu (&hook->list); -nft_netdev_hook_free_rcu (hook); +nft_netdev_hook_unlink_free_rcu (hook); }return err;
@@ -8988,10 +8988,8 @@ static void nft_hooks_destroy(struct list_head *hook_list) {struct nft_hook *hook, *next; -list_for_each_entry_safe (hook, next, hook_list, list) { -list_del_rcu (&hook->list); -nft_netdev_hook_free_rcu (hook); - } +list_for_each_entry_safe (hook, next, hook_list, list) +nft_netdev_hook_unlink_free_rcu (hook); } static int nft_flowtable_update(struct nft_ctx *ctx, const struct nlmsghdr *nlh,
@@ -9079,8 +9077,7 @@ static int nft_flowtable_update(struct nft_ctx *ctx, const struct nlmsghdr *nlh,nft_unregister_flowtable_ops (ctx->net, flowtable, ops); } -list_del_rcu (&hook->list); -nft_netdev_hook_free_rcu (hook); +nft_netdev_hook_unlink_free_rcu (hook); }return err;
@@ -9586,13 +9583,8 @@ static void nf_tables_flowtable_notify(struct nft_ctx *ctx,static void nf_tables_flowtable_destroy (struct nft_flowtable *flowtable) { -struct nft_hook *hook, *next; - flowtable->data.type->free (&flowtable->data); -list_for_each_entry_safe (hook, next, &flowtable->hook_list, list) { -list_del_rcu (&hook->list); -nft_netdev_hook_free_rcu (hook); - } +nft_hooks_destroy (&flowtable->hook_list);kfree (flowtable->name);module_put (flowtable->data.type->owner);kfree (flowtable);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 897/1146 rculist: add list_splice_rcu() for private lists
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pablo Neira Ayuso <[email protected]>
[ Upstream commit f902877b635551513729bdf9a8d1422c4aab7741 ]
This patch adds a helper function, list_splice_rcu(), to safely splice a private (non-RCU-protected) list into an RCU-protected list.
The function ensures that only the pointer visible to RCU readers (prev->next) is updated using rcu_assign_pointer(), while the rest of the list manipulations are performed with regular assignments, as the source list is private and not visible to concurrent RCU readers.
This is useful for moving elements from a private list into a global RCU-protected list, ensuring safe publication for RCU readers. Subsystems with some sort of batching mechanism from userspace can benefit from this new function.
The function __list_splice_rcu() has been added for clarity and to follow the same pattern as in the existing list_splice*() interfaces, where there is a check to ensure that the list to splice is not empty. Note that __list_splice_rcu() has no documentation for this reason.
Stable-dep-of: a6134e62dba2 ("netfilter: nf_tables: join hook list via splice_list_rcu() in commit phase")
--- include/linux/rculist.h | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+)
include/linux/rculist.h +29 -0
@@ -261,6 +261,35 @@ static inline void list_replace_rcu(struct list_head *old, old->prev =LIST_POISON2 ; } +static inline void __list_splice_rcu (struct list_head *list, +struct list_head *prev, +struct list_head *next) +{ +struct list_head *first = list->next; +struct list_head *last = list->prev; + + last->next = next; + first->prev = prev; + next->prev = last; +rcu_assign_pointer (list_next_rcu (prev), first); +} + +/** +* list_splice_rcu - splice a non-RCU list into an RCU-protected list, +* designed for stacks. +* @list: the non RCU-protected list to splice +* @head: the place in the existing RCU-protected list to splice +* +* The list pointed to by @head can be RCU-read traversed concurrently with +* this function. +*/ +static inline void list_splice_rcu (struct list_head *list, +struct list_head *head) +{ +if (!list_empty (list)) +__list_splice_rcu (list, head, head->next); +} +/** * __list_splice_init_rcu - join an RCU-protected list into an existing list. * @list: the RCU-protected list to splice
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 898/1146 netfilter: nf_tables: join hook list via splice_list_rcu() in commit phase
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pablo Neira Ayuso <[email protected]>
[ Upstream commit a6134e62dba2ea4f760b29d5226907f447c92400 ]
Publish new hooks in the list into the basechain/flowtable using splice_list_rcu() to ensure netlink dump list traversal via rcu is safe while concurrent ruleset update is going on.
--- net/netfilter/nf_tables_api.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
net/netfilter/nf_tables_api.c +4 -4
@@ -10904,8 +10904,8 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)nft_chain_commit_update (nft_trans_container_chain (trans));nf_tables_chain_notify (&ctx,NFT_MSG_NEWCHAIN , &nft_trans_chain_hooks (trans)); -list_splice (&nft_trans_chain_hooks (trans), - &nft_trans_basechain (trans)->hook_list); +list_splice_rcu (&nft_trans_chain_hooks (trans), + &nft_trans_basechain (trans)->hook_list);/* trans destroyed after rcu grace period */ }else {nft_chain_commit_drop_policy (nft_trans_container_chain (trans));
@@ -11034,8 +11034,8 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)nft_trans_flowtable (trans), &nft_trans_flowtable_hooks (trans), NFT_MSG_NEWFLOWTABLE); -list_splice (&nft_trans_flowtable_hooks (trans), - &nft_trans_flowtable (trans)->hook_list); +list_splice_rcu (&nft_trans_flowtable_hooks (trans), + &nft_trans_flowtable (trans)->hook_list); }else {nft_clear (net,nft_trans_flowtable (trans)); nf_tables_flowtable_notify(&ctx,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 899/1146 netfilter: nf_tables: add hook transactions for device deletions
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pablo Neira Ayuso <[email protected]>
[ Upstream commit 10f79dbd7719d1da9f5884d13060322d8729f091 ]
Restore the flag that indicates that the hook is going away, ie. NFT_HOOK_REMOVE, but add a new transaction object to track deletion of hooks without altering the basechain/flowtable hook_list during the preparation phase.
The existing approach that moves the hook from the basechain/flowtable hook_list to transaction hook_list breaks netlink dump path readers of this RCU-protected list.
It should be possible use an array for nft_trans_hook to store the deleted hooks to compact the representation but I am not expecting many hook object, specially now that wildcard support for devices is in place.
Note that the nft_trans_chain_hooks() list contains a list of struct nft_trans_hook objects for DELCHAIN and DELFLOWTABLE commands, while this list stores struct nft_hook objects for NEWCHAIN and NEWFLOWTABLE. Note that new commands can be updated to use nft_trans_hook for consistency.
This patch also adapts the event notification path to deal with the list of hook transactions.
--- include/net/netfilter/nf_tables.h | 13 ++ net/netfilter/nf_tables_api.c | 264 +++++++++++++++++++++++------- 2 files changed, 217 insertions(+), 60 deletions(-)
include/net/netfilter/nf_tables.h +13 -0
@@ -1216,12 +1216,15 @@ struct nft_stats {struct u64_stats_sync syncp; }; +#define NFT_HOOK_REMOVE (1 << 0) +struct nft_hook {struct list_head list;struct list_head ops_list;struct rcu_head rcu;char ifname[IFNAMSIZ ];u8 ifnamelen; +u8 flags; }; struct nf_hook_ops *nft_hook_find_ops(const struct nft_hook *hook,
@@ -1676,6 +1679,16 @@ struct nft_trans { u8 put_net:1; }; +/** +* struct nft_trans_hook - nf_tables hook update in transaction +* @list: used internally +* @hook: struct nft_hook with the device hook +*/ +struct nft_trans_hook { +struct list_head list; +struct nft_hook *hook; +}; +/** * struct nft_trans_binding - nf_tables object with binding support in transaction * @nft_trans: base structure, MUST be first member
net/netfilter/nf_tables_api.c +204 -60
494 lines not on this page · raw message
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 900/1146 nvme-pci: fix missed admin queue sq doorbell write
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Keith Busch <[email protected]>
[ Upstream commit 1cc4cdae2a3b7730d462d69e30f213fd2efe7807 ]
We can batch admin commands submitted through io_uring_cmd passthrough, which means bd->last may be false and skips the doorbell write to aggregate multiple commands per write. If a subsequent command can't be dispatched for whatever reason, we have to provide the blk-mq ops' commit_rqs callback in order to ensure we properly update the doorbell.
--- drivers/nvme/host/pci.c | 1 + 1 file changed, 1 insertion(+)
drivers/nvme/host/pci.c +1 -0
@@ -2241,6 +2241,7 @@ static int nvme_create_queue(struct nvme_queue *nvmeq, int qid, bool polled)static const struct blk_mq_ops nvme_mq_admin_ops = { .queue_rq = nvme_queue_rq, .complete = nvme_pci_complete_rq, + .commit_rqs = nvme_commit_rqs, .init_hctx = nvme_admin_init_hctx, .init_request = nvme_pci_init_request, .timeout = nvme_timeout,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 901/1146 drm/amdgpu: avoid double drm_exec_fini() in userq validate
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hongyan Xu <[email protected]>
[ Upstream commit 508babf310365f1107a2e8831c267c292a286818 ]
When new_addition is true, amdgpu_userq_vm_validate() calls drm_exec_fini(&exec) before iterating over the collected HMM ranges and calling amdgpu_ttm_tt_get_user_pages().
If amdgpu_ttm_tt_get_user_pages() fails in that path, the code jumps to unlock_all and calls drm_exec_fini(&exec) a second time on the same exec object. drm_exec_fini() is not idempotent: it frees exec->objects and may also drop exec->contended and finalize the ww acquire context.
Route that error path directly to the range cleanup once exec has already been finalized.
Issue found using a prototype static analysis tool and confirmed by code review.
--- drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_userq.c +2 -1
@@ -1231,7 +1231,7 @@ amdgpu_userq_vm_validate(struct amdgpu_userq_mgr *uq_mgr) bo = range->bo; ret =amdgpu_ttm_tt_get_user_pages (bo, range);if (ret) - goto unlock_all; + goto free_ranges; } invalidated = true;
@@ -1258,6 +1258,7 @@ amdgpu_userq_vm_validate(struct amdgpu_userq_mgr *uq_mgr) unlock_all:drm_exec_fini (&exec); +free_ranges:xa_for_each (&xa, tmp_key, range) {if (!range)continue ;
Signature · 1 line
2.53.0