6.6.145-rc1 review
Subsystems (7)
Greg Kroah-Hartman
maintainerPATCH 549/1266 Bluetooth: hci_qca: fix NULL pointer dereference in qca_dmp_hdr() for non-serdev device
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zijun Hu <[email protected]>
[ Upstream commit 6b8cbcf08de0db62254d1981f83db0f94681ccd9 ]
hu->serdev is NULL for hci_uart attached via non-serdev paths, but qca_dmp_hdr() unconditionally dereferences hu->serdev->dev.driver->name, causing a NULL pointer dereference.
Fix by guarding the dereference with a NULL check and falling back to "hci_ldisc_qca" for the non-serdev case.
--- drivers/bluetooth/hci_qca.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/bluetooth/hci_qca.c +1 -1
@@ -1008,7 +1008,7 @@ static void qca_dmp_hdr(struct hci_dev *hdev, struct sk_buff *skb)skb_put_data (skb, buf,strlen (buf));snprintf (buf,sizeof (buf),"Driver: %s\n" , - hu->serdev->dev.driver->name); + hu->serdev ? hu->serdev->dev.driver->name :"hci_ldisc_qca" );skb_put_data (skb, buf,strlen (buf)); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 550/1266 Bluetooth: hci: validate codec capability element length
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Samuel Moelius <[email protected]>
[ Upstream commit c38fbcdc407925c7088f7e5f11c1fff73d2d35a2 ]
Read Local Codec Capabilities returns a sequence of capability elements. Each element starts with a one-byte length followed by that many payload bytes.
hci_read_codec_capabilities() checks that the skb contains the length byte, but then validates only caps->len against the remaining skb length. A malformed controller response with one remaining byte and caps->len set to one passes that check even though the element needs two bytes. The parser then records a two-byte capability and copies one byte beyond the advertised response payload into the codec list.
Validate the full element size, including the length byte, before adding it to the accumulated capability length. This preserves all well-formed capability elements and drops only truncated controller responses.
--- net/bluetooth/hci_codec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/bluetooth/hci_codec.c +1 -1
@@ -100,7 +100,7 @@ static void hci_read_codec_capabilities(struct hci_dev *hdev, __u8 transport, caps = (void *)skb->data;if (skb->len <sizeof (*caps)) goto error; -if (skb->len < caps->len) +if (skb->len <sizeof (caps->len) + caps->len) goto error; len +=sizeof (caps->len) + caps->len;skb_pull (skb,sizeof (caps->len) + caps->len);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 551/1266 Bluetooth: vhci: validate devcoredump state before side effects
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Samuel Moelius <[email protected]>
[ Upstream commit 88c2404a3c59c3126453919388dbd5ed98ed01bd ]
The VHCI force_devcoredump debugfs hook accepts a small test record from userspace. It validates the requested terminal state only after registering, initializing and appending a Bluetooth devcoredump.
As a result, an invalid state returns -EINVAL but still leaves queued devcoredump work behind. With a non-zero timeout field, the rejected write can still emit a devcoredump after the timeout expires.
Reject unsupported states before allocating the skb or changing the HCI devcoredump state machine.
--- drivers/bluetooth/hci_vhci.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
drivers/bluetooth/hci_vhci.c +10 -0
@@ -337,7 +337,17 @@ static ssize_t force_devcd_write(struct file *file, const char __user *user_buf,if (copy_from_user (&dump_data, user_buf, count))return -EFAULT ; +switch (dump_data.state) { +case HCI_DEVCOREDUMP_DONE : +case HCI_DEVCOREDUMP_ABORT : +case HCI_DEVCOREDUMP_TIMEOUT : +break ; +default : +return -EINVAL ; + } + data_size = count - offsetof(struct devcoredump_test_data , data); + skb =alloc_skb (data_size,GFP_ATOMIC );if (!skb)return -ENOMEM ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 552/1266 fs: efs: remove unneeded debug prints
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Maxwell Doose <[email protected]>
[ Upstream commit 89009392c80da5da00876c8334ff20028e6e3eb6 ]
The current code uses debug prints conditionally compiled with #ifdef DEBUG. However, that code, when compiled, causes compiler errors due to incompatible formatters and undefined variables, notably:
fs/efs/file.c: In function `efs_get_block':fs/efs/file.c:26:35: error: block' undeclared (first use in this function); did you mean iblock'?
26 | __func__, block, inode->i_blocks, inode->i_size);
| ^~~~~
and:
fs/efs/file.c: In function `efs_bmap':./include/linux/kern_levels.h:5:25: error: format %ld' expects argument of type long int', but argument 4 has type blkcnt_t' {aka long long unsigned int'} [-Werror=format=]
5 | #define KERN_SOH "\001" /* ASCII Start Of Header */
| ^~~~~~which also extends to the other formatters. As this part of the code has been dead for just about 14 years now, it has not been modernized to stay compatible with the most recent gcc compilers. Fix these issues by removing the debug prints.
--- fs/efs/file.c | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-)
fs/efs/file.c +3 -18
@@ -18,16 +18,9 @@ int efs_get_block(struct inode *inode, sector_t iblock,if (create)return error; -if (iblock >= inode->i_blocks) { -#ifdef DEBUG -/* -* i have no idea why this happens as often as it does -*/ -pr_warn ("%s(): block %d >= %ld (filesize %ld)\n" , - __func__, block, inode->i_blocks, inode->i_size); -#endif +if (iblock >= inode->i_blocks)return 0 ; - } + phys =efs_map_block (inode, iblock);if (phys)map_bh (bh_result, inode->i_sb, phys);
@@ -42,16 +35,8 @@ int efs_bmap(struct inode *inode, efs_block_t block) { }/* are we about to read past the end of a file ? */ -if (!(block < inode->i_blocks)) { -#ifdef DEBUG -/* -* i have no idea why this happens as often as it does -*/ -pr_warn ("%s(): block %d >= %ld (filesize %ld)\n" , - __func__, block, inode->i_blocks, inode->i_size); -#endif +if (!(block < inode->i_blocks))return 0 ; - }return efs_map_block (inode, block); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 553/1266 RDMA/mlx5: Remove raw RSS QP restrack tracking
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Patrisious Haddad <[email protected]>
[ Upstream commit 666031fed8f0fdfc29b20d125a628c1b0a04cdaf ]
Raw RSS QP restrack tracking wasn't working to begin with as it was only tracking the first raw RSS QP which was added, since at creation the raw RSS QP number is reserved so the QP number for this qp type was always zero.
The following raw RSS QP additions were always failing silently.
Since the fix isn't trivial and there were no users that required or complained about this issue we are dropping this for now instead of fixing.
--- drivers/infiniband/hw/mlx5/qp.c | 1 + 1 file changed, 1 insertion(+)
drivers/infiniband/hw/mlx5/qp.c +1 -0
@@ -3090,6 +3090,7 @@ static int create_qp(struct mlx5_ib_dev *dev, struct ib_pd *pd,int err;if (params->is_rss_raw) { +rdma_restrack_no_track (&qp->ibqp.res); err =create_rss_raw_qp_tir (dev, pd, qp, params); goto out; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 554/1266 RDMA/mlx5: Fix undefined shift of user RQ WQE size
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Maher Sanalla <[email protected]>
[ Upstream commit d881d60223aac8fdc12b227d89c76e131e92a9cd ]
set_rq_size() computes the RQ WQE size as "1 << rq_wqe_shift" based on the user-provided rq_wqe_shift, which is only checked to be greater than 32, so shifts of 32 are still accepted. A shift of 31 also overflows a signed integer, leading to undefined behavior.
Use check_shl_overflow() to compute the RQ WQE size and reject any invalid values.
--- drivers/infiniband/hw/mlx5/qp.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-)
drivers/infiniband/hw/mlx5/qp.c +4 -7
@@ -451,16 +451,13 @@ static int set_rq_size(struct mlx5_ib_dev *dev, struct ib_qp_cap *cap,if (ucmd) { qp->rq.wqe_cnt = ucmd->rq_wqe_count; -if (ucmd->rq_wqe_shift >BITS_PER_BYTE *sizeof (ucmd->rq_wqe_shift)) -return -EINVAL ; qp->rq.wqe_shift = ucmd->rq_wqe_shift; -if ((1 << qp->rq.wqe_shift) / -sizeof (struct mlx5_wqe_data_seg ) < - wq_sig) +if (check_shl_overflow (1 , qp->rq.wqe_shift, &wqe_size)) +return -EINVAL ; +if (wqe_size /sizeof (struct mlx5_wqe_data_seg ) < wq_sig)return -EINVAL ; qp->rq.max_gs = - (1 << qp->rq.wqe_shift) / -sizeof (struct mlx5_wqe_data_seg ) - + wqe_size /sizeof (struct mlx5_wqe_data_seg ) - wq_sig; qp->rq.max_post = qp->rq.wqe_cnt; }else {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 555/1266 RDMA/mlx5: Release the HW‑provided UAR index rather than the SW one
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Leon Romanovsky <[email protected]>
[ Upstream commit 449ae7927152e46acbe5f19f97eafdae6d3a96b1 ]
Free the UAR index returned by the hardware.
--- drivers/infiniband/hw/mlx5/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/infiniband/hw/mlx5/main.c +1 -1
@@ -2282,7 +2282,7 @@ static int uar_mmap(struct mlx5_ib_dev *dev, enum mlx5_ib_mmap_cmd cmd,if (!dyn_uar)return err; -mlx5_cmd_uar_dealloc (dev->mdev, idx, context->devx_uid); +mlx5_cmd_uar_dealloc (dev->mdev, uar_index, context->devx_uid); free_bfreg:mlx5_ib_free_bfreg (dev, bfregi, bfreg_dyn_idx);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 556/1266 ASoC: codecs: hdac_hdmi: Validate written enum value
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: HyeongJun An <[email protected]>
[ Upstream commit 0b08baeccdcf52fad328ad645f5b4fbee04eea34 ]
hdac_hdmi_set_pin_port_mux() uses the written enum value to index the texts array before calling snd_soc_dapm_put_enum_double(), which validates that the value is within the enum item range.
An out-of-range value can therefore make the driver read past the texts array before the helper rejects the write. Move the lookup after the helper has accepted the value.
--- sound/soc/codecs/hdac_hdmi.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
sound/soc/codecs/hdac_hdmi.c +3 -1
@@ -906,12 +906,14 @@ static int hdac_hdmi_set_pin_port_mux(struct snd_kcontrol *kcontrol,struct hdac_device *hdev =dev_to_hdac_dev (dapm->dev);struct hdac_hdmi_priv *hdmi =hdev_to_hdmi_priv (hdev);struct hdac_hdmi_pcm *pcm; -const char *cvt_name = e->texts[ucontrol->value.enumerated.item[0 ]]; +const char *cvt_name; ret =snd_soc_dapm_put_enum_double (kcontrol, ucontrol);if (ret <0 )return ret; + cvt_name = e->texts[ucontrol->value.enumerated.item[0 ]]; +if (port ==NULL )return -EINVAL ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 557/1266 ASoC: fsl: fsl_audmix: Validate written enum values
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: HyeongJun An <[email protected]>
[ Upstream commit 3cd17e4e2871114d5579fa7bc8da66faf7fc1930 ]
fsl_audmix_put_mix_clk_src() and fsl_audmix_put_out_src() convert the user-provided enum item with snd_soc_enum_item_to_val() before checking whether the item is within the enum's item count.
The generic snd_soc_put_enum_double() helper performs that validation, but these callbacks use the converted value first: the clock-source path tests it with BIT(), and the output-source path indexes the prms transition table with it.
Reject out-of-range enum items before converting them.
--- sound/soc/fsl/fsl_audmix.c | 6 ++++++ 1 file changed, 6 insertions(+)
sound/soc/fsl/fsl_audmix.c +6 -0
@@ -117,6 +117,9 @@ static int fsl_audmix_put_mix_clk_src(struct snd_kcontrol *kcontrol,unsigned int *item = ucontrol->value.enumerated.item;unsigned int reg_val, val, mix_clk; +if (item[0 ] >= e->items) +return -EINVAL ; +/* Get current state */ reg_val =snd_soc_component_read (comp,FSL_AUDMIX_CTR ); mix_clk = ((reg_val & FSL_AUDMIX_CTR_MIXCLK_MASK)
@@ -157,6 +160,9 @@ static int fsl_audmix_put_out_src(struct snd_kcontrol *kcontrol,unsigned int reg_val, val, mask =0 , ctr =0 ;int ret; +if (item[0 ] >= e->items) +return -EINVAL ; +/* Get current state */ reg_val =snd_soc_component_read (comp,FSL_AUDMIX_CTR );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 558/1266 ASoC: tegra: tegra210_ahub: Validate written enum value
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: HyeongJun An <[email protected]>
[ Upstream commit 1d8aabb413b5638670dfd1162169edc0ba276a2e ]
tegra_ahub_put_value_enum() reads e->values[item[0]] before checking whether item[0] is within the enum item range. The existing check therefore happens too late to prevent an out-of-range read of the values array.
Move the check before the array access.
--- sound/soc/tegra/tegra210_ahub.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
sound/soc/tegra/tegra210_ahub.c +3 -1
@@ -60,13 +60,15 @@ static int tegra_ahub_put_value_enum(struct snd_kcontrol *kctl,struct soc_enum *e = (struct soc_enum *)kctl->private_value;struct snd_soc_dapm_update update[TEGRA_XBAR_UPDATE_MAX_REG ] = { };unsigned int *item = uctl->value.enumerated.item; -unsigned int value = e->values[item[0 ]]; +unsigned int value;unsigned int i, bit_pos, reg_idx =0 , reg_val =0 ;int change =0 ;if (item[0 ] >= e->items)return -EINVAL ; + value = e->values[item[0 ]]; +if (value) {/* Get the register index and value to set */ reg_idx = (value -1 ) / (8 * cmpnt->val_bytes);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 559/1266 net/sched: cls_flow: Dont expose folded kernel pointers
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jamal Hadi Salim <[email protected]>
[ Upstream commit f294fc71c4a0fa4964f6428a1b4e7929c1d83125 ]
The flow classifier falls back to addr_fold() for fields that are missing from packet headers. In map mode, userspace controls mask, xor, rshift, addend and divisor, and can observe the resulting classid through class statistics. This allows a tc classifier in a user/network namespace to recover the 32-bit folded value of skb->sk, skb_dst() or skb_nfct().
Align with standard kernel practices for pointer hashing and replace the XOR folding with a keyed siphash (which is cryptographically secure)
--- net/sched/cls_flow.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-)
net/sched/cls_flow.c +9 -3
@@ -21,6 +21,7 @@#include <net/inet_sock.h> #include <net/pkt_cls.h> +#include <linux/siphash.h> #include <net/ip.h> #include <net/route.h> #include <net/flow_dissector.h>
@@ -57,11 +58,15 @@ struct flow_filter {struct rcu_work rwork; }; +static siphash_aligned_key_t flow_keys_secret__read_mostly ; +static inline u32 addr_fold (void *addr) { -unsigned long a = (unsigned long )addr; - -return (a &0xFFFFFFFF ) ^ (BITS_PER_LONG >32 ? a >>32 :0 ); +#ifdef CONFIG_64BIT +return (u32 )siphash_1u64 ((u64 )addr, &flow_keys_secret); +#else +return (u32 )siphash_1u32 ((u32 )addr, &flow_keys_secret); +#endif }static u32 flow_get_src (const struct sk_buff *skb,const struct flow_keys *flow)
@@ -596,6 +601,7 @@ static int flow_init(struct tcf_proto *tp)return -ENOBUFS ;INIT_LIST_HEAD (&head->filters);rcu_assign_pointer (tp->root, head); +net_get_random_once (&flow_keys_secret,sizeof (flow_keys_secret));return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 560/1266 net: fib_rules: Dont dump dying fib_rule in fib_rules_dump().
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kuniyuki Iwashima <[email protected]>
[ Upstream commit 2821e85c058f81c9948a2fb1a634f7b47457d51c ]
rocker_router_fib_event() calls fib_rule_get() during RCU dump.
If the fib_rule is dying, refcount_inc() will complain about it.
Let's call refcount_inc_not_zero() in fib_rules_dump().
--- include/net/fib_rules.h | 5 +++++ net/core/fib_rules.c | 6 +++++- 2 files changed, 10 insertions(+), 1 deletion(-)
include/net/fib_rules.h +5 -0
@@ -107,6 +107,11 @@ static inline void fib_rule_get(struct fib_rule *rule)refcount_inc (&rule->refcnt); } +static inline bool fib_rule_get_safe (struct fib_rule *rule) +{ +return refcount_inc_not_zero (&rule->refcnt); +} +static inline void fib_rule_put (struct fib_rule *rule) {if (refcount_dec_and_test (&rule->refcnt))
net/core/fib_rules.c +5 -1
@@ -328,7 +328,7 @@ int fib_rules_lookup(struct fib_rules_ops *ops, struct flowi *fl,if (err != -EAGAIN ) {if ((arg->flags &FIB_LOOKUP_NOREF ) || -likely (refcount_inc_not_zero (&rule->refcnt))) { +likely (fib_rule_get_safe (rule))) { arg->rule = rule; goto out; }
@@ -386,8 +386,12 @@ int fib_rules_dump(struct net *net, struct notifier_block *nb, int family,if (!ops)return -EAFNOSUPPORT ;list_for_each_entry_rcu (rule, &ops->rules_list, list) { +if (!fib_rule_get_safe (rule)) +continue ; + err =call_fib_rule_notifier (nb,FIB_EVENT_RULE_ADD , rule, family, extack); +fib_rule_put (rule);if (err)break ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 561/1266 bridge: cfm: reject invalid CCM interval at configuration time
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xiang Mei <[email protected]>
[ Upstream commit f3e02edd8322b31b8e6517faa6ba053bf29d1e26 ]
ccm_tx_work_expired() re-arms itself via queue_delayed_work() using the configured exp_interval converted by interval_to_us(). When exp_interval is BR_CFM_CCM_INTERVAL_NONE or out of range, interval_to_us() returns 0, causing the worker to fire immediately in a tight loop that allocates skbs until OOM.
Fix this by validating exp_interval at configuration time:
- Constrain IFLA_BRIDGE_CFM_CC_CONFIG_EXP_INTERVAL to the valid range [BR_CFM_CCM_INTERVAL_3_3_MS, BR_CFM_CCM_INTERVAL_10_MIN] in the netlink policy so userspace cannot set an invalid value.
- Reject starting CCM TX in br_cfm_cc_ccm_tx() when exp_interval has not yet been configured (defaults to 0 from kzalloc).
--- net/bridge/br_cfm.c | 6 ++++++ net/bridge/br_cfm_netlink.c | 4 +++- 2 files changed, 9 insertions(+), 1 deletion(-)
net/bridge/br_cfm.c +6 -0
@@ -805,6 +805,12 @@ int br_cfm_cc_ccm_tx(struct net_bridge *br, const u32 instance, goto save; } +if (!interval_to_us (mep->cc_config.exp_interval)) { +NL_SET_ERR_MSG_MOD (extack, +"Invalid CCM interval" ); +return -EINVAL ; + } +/* Start delayed work to transmit CCM frames. It is done with zero delay * to send first frame immediately */
net/bridge/br_cfm_netlink.c +3 -1
@@ -34,7 +34,9 @@ br_cfm_cc_config_policy[IFLA_BRIDGE_CFM_CC_CONFIG_MAX + 1] = { [IFLA_BRIDGE_CFM_CC_CONFIG_UNSPEC] = { .type = NLA_REJECT }, [IFLA_BRIDGE_CFM_CC_CONFIG_INSTANCE] = { .type = NLA_U32 }, [IFLA_BRIDGE_CFM_CC_CONFIG_ENABLE] = { .type = NLA_U32 }, - [IFLA_BRIDGE_CFM_CC_CONFIG_EXP_INTERVAL] = { .type = NLA_U32 }, + [IFLA_BRIDGE_CFM_CC_CONFIG_EXP_INTERVAL ] = +NLA_POLICY_RANGE (NLA_U32 ,BR_CFM_CCM_INTERVAL_3_3_MS , + BR_CFM_CCM_INTERVAL_10_MIN), [IFLA_BRIDGE_CFM_CC_CONFIG_EXP_MAID ] = { .type = NLA_BINARY, .len = CFM_MAID_LENGTH }, };
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 562/1266 sctp: validate embedded address parameter length
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xin Long <[email protected]>
[ Upstream commit e9361d0ca55c4af12aac09e2572852fa91046229 ]
sctp_verify_asconf() and sctp_verify_param() only validate ADD_IP, DEL_IP, and SET_PRIMARY parameters against a fixed minimum size of sizeof(struct sctp_addip_param) + sizeof(struct sctp_paramhdr). This ensures the outer parameter is large enough to contain an embedded address parameter header, but does not verify that the embedded address parameter's declared length fits within the bounds of the outer parameter.
Later, sctp_process_param() and sctp_process_asconf_param() extract the embedded address parameter and pass it to af->from_addr_param(), which uses the address parameter length to parse the variable-length address payload. A malformed peer can therefore advertise an embedded address parameter length that exceeds the remaining bytes in the enclosing parameter.
Validate that addr_param->p.length does not exceed the space available after the sctp_addip_param header before processing the embedded address parameter. Reject malformed parameters when the embedded address length extends beyond the enclosing parameter bounds.
This prevents out-of-bounds reads when parsing malformed parameters carried in INIT or ASCONF processing paths.
--- net/sctp/sm_make_chunk.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
net/sctp/sm_make_chunk.c +8 -2
@@ -2662,6 +2662,9 @@ static int sctp_process_param(struct sctp_association *asoc, goto fall_through; addr_param = param.v +sizeof (struct sctp_addip_param ); +if (ntohs (addr_param->p.length) > +ntohs (param.p->length) -sizeof (struct sctp_addip_param )) +break ; af =sctp_get_af_specific (param_type2af (addr_param->p.type));if (!af)
@@ -3060,13 +3063,16 @@ static __be16 sctp_process_asconf_param(struct sctp_association *asoc,union sctp_addr addr;struct sctp_af *af; - addr_param = (void *)asconf_param +sizeof (*asconf_param); -if (asconf_param->param_hdr.type !=SCTP_PARAM_ADD_IP && asconf_param->param_hdr.type !=SCTP_PARAM_DEL_IP && asconf_param->param_hdr.type !=SCTP_PARAM_SET_PRIMARY )return SCTP_ERROR_UNKNOWN_PARAM ; + addr_param = (void *)asconf_param +sizeof (*asconf_param); +if (ntohs (addr_param->p.length) > +ntohs (asconf_param->param_hdr.length) -sizeof (*asconf_param)) +return SCTP_ERROR_PROTO_VIOLATION ; +switch (addr_param->p.type) {case SCTP_PARAM_IPV6_ADDRESS :if (!asoc->peer.ipv6_address)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 563/1266 net/sched: sch_hfsc: Dont make class passive twice
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Victor Nogueira <[email protected]>
[ Upstream commit 90b662ea25f5e83bb3b8ccec5b93ced810b92fb8 ]
update_vf() is called from two places for the same class during a single dequeue when the class's child qdisc (e.g. codel/fq_codel) drops its last packets while dequeuing:
1. The child calls qdisc_tree_reduce_backlog(), which, now that the child is empty, invokes hfsc_qlen_notify() -> update_vf(cl, 0, 0) and turns the class passive (cl_nactive is decremented up the hierarchy).
2. hfsc_dequeue() then calls update_vf(cl, qdisc_pkt_len(skb), cur_time) to charge the dequeued bytes.
On the second call the class is already passive, but its child qdisc is still empty, so update_vf() arms go_passive again:
if (cl->qdisc->q.qlen == 0 && cl->cl_flags & HFSC_FSC)
go_passive = 1;The leaf is then skipped by the cl_nactive == 0 check inside the loop, which does not clear go_passive, so the stale go_passive propagates to the parent and decrements its cl_nactive a second time. A parent that still has other active children is driven to cl_nactive == 0 and removed from the vttree, even though those siblings are still backlogged. They are never dequeued again and the qdisc stalls.
Fix this by only arming go_passive when the class is actually active, so an already-passive class no longer triggers a second passive transition. The byte accounting (cl->cl_total += len) still runs for every ancestor, so dequeued bytes continue to be counted exactly once.
--- net/sched/sch_hfsc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/sched/sch_hfsc.c +1 -1
@@ -753,7 +753,7 @@ update_vf(struct hfsc_class *cl, unsigned int len, u64 cur_time)u64 f;/* , myf_bound, delta; */ int go_passive =0 ; -if (cl->qdisc->q.qlen ==0 && cl->cl_flags &HFSC_FSC ) +if (cl->qdisc->q.qlen ==0 && cl->cl_flags &HFSC_FSC && cl->cl_nactive) go_passive =1 ;for (; cl->cl_parent !=NULL ; cl = cl->cl_parent) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 564/1266 tipc: require net admin for TIPCv2 netlink mutators
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Bommarito <[email protected]>
[ Upstream commit 86b0c540e2ea397cde021eecd24145f7c16a3d4e ]
TIPCv2 registers mutating generic-netlink operations without admin permission flags. Generic netlink only checks CAP_NET_ADMIN when an operation sets GENL_ADMIN_PERM or GENL_UNS_ADMIN_PERM, so a local unprivileged process can currently change TIPC state through commands such as TIPC_NL_NET_SET, TIPC_NL_KEY_SET, TIPC_NL_KEY_FLUSH, and bearer enable/disable.
The legacy TIPC netlink API already checks netlink_net_capable(..., CAP_NET_ADMIN) for administrative commands. Give the TIPCv2 mutators the equivalent generic-netlink gate. Use GENL_UNS_ADMIN_PERM, which maps to the same namespace-aware CAP_NET_ADMIN check that netlink_net_capable() performs, so the behaviour matches the legacy path and keeps working for CAP_NET_ADMIN holders in a non-initial user namespace (containers).
A QEMU/KASAN repro run as uid/gid 65534 with zero effective capabilities previously succeeded in changing the network id and node identity, setting and flushing key material, and enabling/disabling a UDP bearer. With this patch applied the same operations fail with -EPERM.
--- net/tipc/netlink.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)
net/tipc/netlink.c +12 -0
@@ -152,11 +152,13 @@ static const struct genl_ops tipc_genl_v2_ops[] = { { .cmd = TIPC_NL_BEARER_DISABLE, .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, + .flags = GENL_UNS_ADMIN_PERM, .doit = tipc_nl_bearer_disable, }, { .cmd = TIPC_NL_BEARER_ENABLE, .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, + .flags = GENL_UNS_ADMIN_PERM, .doit = tipc_nl_bearer_enable, }, {
@@ -168,11 +170,13 @@ static const struct genl_ops tipc_genl_v2_ops[] = { { .cmd = TIPC_NL_BEARER_ADD, .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, + .flags = GENL_UNS_ADMIN_PERM, .doit = tipc_nl_bearer_add, }, { .cmd = TIPC_NL_BEARER_SET, .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, + .flags = GENL_UNS_ADMIN_PERM, .doit = tipc_nl_bearer_set, }, {
@@ -197,11 +201,13 @@ static const struct genl_ops tipc_genl_v2_ops[] = { { .cmd = TIPC_NL_LINK_SET, .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, + .flags = GENL_UNS_ADMIN_PERM, .doit = tipc_nl_node_set_link, }, { .cmd = TIPC_NL_LINK_RESET_STATS, .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, + .flags = GENL_UNS_ADMIN_PERM, .doit = tipc_nl_node_reset_link_stats, }, {
@@ -213,6 +219,7 @@ static const struct genl_ops tipc_genl_v2_ops[] = { { .cmd = TIPC_NL_MEDIA_SET, .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, + .flags = GENL_UNS_ADMIN_PERM, .doit = tipc_nl_media_set, }, {
@@ -228,6 +235,7 @@ static const struct genl_ops tipc_genl_v2_ops[] = { { .cmd = TIPC_NL_NET_SET, .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, + .flags = GENL_UNS_ADMIN_PERM, .doit = tipc_nl_net_set, }, {
@@ -238,6 +246,7 @@ static const struct genl_ops tipc_genl_v2_ops[] = { { .cmd = TIPC_NL_MON_SET, .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, + .flags = GENL_UNS_ADMIN_PERM, .doit = tipc_nl_node_set_monitor, }, {
@@ -255,6 +264,7 @@ static const struct genl_ops tipc_genl_v2_ops[] = { { .cmd = TIPC_NL_PEER_REMOVE, .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, + .flags = GENL_UNS_ADMIN_PERM, .doit = tipc_nl_peer_rm, },#ifdef CONFIG_TIPC_MEDIA_UDP
@@ -269,11 +279,13 @@ static const struct genl_ops tipc_genl_v2_ops[] = { { .cmd = TIPC_NL_KEY_SET, .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, + .flags = GENL_UNS_ADMIN_PERM, .doit = tipc_nl_node_set_key, }, { .cmd = TIPC_NL_KEY_FLUSH, .validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP, + .flags = GENL_UNS_ADMIN_PERM, .doit = tipc_nl_node_flush_key, }, #endif
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 565/1266 tipc: prevent snt_unacked underflow on CONN_ACK
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Bommarito <[email protected]>
[ Upstream commit ab3e10b44ba5411779aac7afd2477917dd77750f ]
tipc_sk_conn_proto_rcv() subtracts the peer-supplied connection ack count from the unsigned 16-bit send counter snt_unacked without checking that it does not exceed the number of messages actually outstanding:
tsk->snt_unacked -= msg_conn_ack(hdr);
msg_conn_ack() is read straight from a received CONN_MANAGER/CONN_ACK message. If the ack count is larger than snt_unacked, the subtraction wraps to a near-maximum value, leaving tsk_conn_cong() permanently true and starving the connection of further transmits.
Validate the ACK count at the start of the CONN_ACK block and drop the message if it acknowledges more messages than are outstanding. A peer (or, for a local connection, the connected peer socket) can otherwise wedge a TIPC connection's send side by sending an oversized connection ack.
--- net/tipc/socket.c | 3 +++ 1 file changed, 3 insertions(+)
net/tipc/socket.c +3 -0
@@ -1367,6 +1367,9 @@ static void tipc_sk_conn_proto_rcv(struct tipc_sock *tsk, struct sk_buff *skb,__skb_queue_tail (xmitq, skb);return ; }else if (mtyp ==CONN_ACK ) { +if (tsk->snt_unacked <msg_conn_ack (hdr)) + goto exit; + was_cong =tsk_conn_cong (tsk);tipc_sk_push_backlog (tsk,msg_nagle_ack (hdr)); tsk->snt_unacked -=msg_conn_ack (hdr);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 566/1266 tipc: reject inverted service ranges from peer bindings
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Bommarito <[email protected]>
[ Upstream commit 2afb648f7b99216c687db1f89739c995e1144153 ]
tipc_update_nametbl() inserts a binding advertised by a peer node using the lower and upper service-range bounds taken directly from the wire, without checking that lower <= upper. The local bind path validates the ordering (tipc_uaddr_valid()), but the name-distribution path does not.
A binding with lower > upper is inserted at the far end of the service-range rbtree (keyed on lower) where no lookup or withdrawal can ever match it (service_range_foreach_match() requires sr->lower <= end). The publication, its service_range node and the augmented rbtree entry are then leaked for the lifetime of the namespace, and there is no per-peer cap equivalent to TIPC_MAX_PUBL on locally created bindings.
Reject inverted ranges in the network path as well. A peer node can otherwise leak unbounded binding-table memory by sending PUBLICATION items with lower > upper.
--- net/tipc/name_distr.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-)
net/tipc/name_distr.c +11 -2
@@ -280,12 +280,21 @@ static bool tipc_update_nametbl(struct net *net, struct distr_item *i, u32 node, u32 dtype) {struct publication *p =NULL ; +u32 lower =ntohl (i->lower); +u32 upper =ntohl (i->upper);struct tipc_socket_addr sk; -struct tipc_uaddr ua;u32 key =ntohl (i->key); +struct tipc_uaddr ua; + +/* A peer-advertised binding with lower > upper can never be matched +* or withdrawn and would leak the publication; the local bind path +* rejects such ranges, so reject ranges learned from the network too. +*/ +if (lower > upper) +return false;tipc_uaddr (&ua,TIPC_SERVICE_RANGE ,TIPC_CLUSTER_SCOPE , -ntohl (i->type),ntohl (i->lower),ntohl (i->upper)); +ntohl (i->type), lower, upper); sk.ref =ntohl (i->port); sk.node = node;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 567/1266 cxl/test: Add check after kzalloc() memory in alloc_mock_res()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dave Jiang <[email protected]>
[ Upstream commit dfe28c8592538152e9611341dae6f7be1735b3f1 ]
alloc_mock_res() calls kzalloc() without checking the return value. Add scope based resource management to deal with the allocated memory cleanly.
--- tools/testing/cxl/test/cxl.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
tools/testing/cxl/test/cxl.c +6 -2
@@ -396,12 +396,16 @@ static void depopulate_all_mock_resources(void)static struct cxl_mock_res *alloc_mock_res (resource_size_t size,int align) { -struct cxl_mock_res *res =kzalloc (sizeof (*res),GFP_KERNEL );struct genpool_data_align data = { .align = align, };unsigned long phys; + struct cxl_mock_res *res __free(kfree) = kzalloc(sizeof(*res), +GFP_KERNEL ); +if (!res) +return NULL ; +INIT_LIST_HEAD (&res->list); phys =gen_pool_alloc_algo (cxl_mock_pool, size, gen_pool_first_fit_align, &data);
@@ -416,7 +420,7 @@ static struct cxl_mock_res *alloc_mock_res(resource_size_t size, int align)list_add (&res->list, &mock_res);mutex_unlock (&mock_res_lock); -return res; +return no_free_ptr (res); }static int populate_cedt (void )
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 568/1266 crypto: marvell/octeontx - fix DMA cleanup using wrong loop index
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Felix Gu <[email protected]>
[ Upstream commit 7891c64c0520519782470ba29bac8a5761e295d8 ]
The sg_cleanup path used list[i] instead of list[j] when unmapping DMA buffers, leaking successfully mapped entries and repeatedly unmapping the failed one.
--- drivers/crypto/marvell/octeontx/otx_cptvf_reqmgr.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/crypto/marvell/octeontx/otx_cptvf_reqmgr.c +2 -2
@@ -157,8 +157,8 @@ static inline int setup_sgio_components(struct pci_dev *pdev, sg_cleanup:for (j =0 ; j < i; j++) {if (list[j].dma_addr) { -dma_unmap_single (&pdev->dev, list[i].dma_addr, - list[i].size,DMA_BIDIRECTIONAL ); +dma_unmap_single (&pdev->dev, list[j].dma_addr, + list[j].size,DMA_BIDIRECTIONAL ); } list[j].dma_addr =0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 569/1266 crypto: cavium/cpt - fix DMA cleanup using wrong loop index
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Felix Gu <[email protected]>
[ Upstream commit 9dbf173bd32d5f81b005008b682bfb50aa093455 ]
The sg_cleanup error path used list[i] instead of list[j] when unmapping DMA buffers, leaking successfully mapped entries and repeatedly unmapping the failed one.
--- drivers/crypto/cavium/cpt/cptvf_reqmanager.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/crypto/cavium/cpt/cptvf_reqmanager.c +2 -2
@@ -108,8 +108,8 @@ static int setup_sgio_components(struct cpt_vf *cptvf, struct buf_ptr *list, sg_cleanup:for (j =0 ; j < i; j++) {if (list[j].dma_addr) { -dma_unmap_single (&pdev->dev, list[i].dma_addr, - list[i].size,DMA_BIDIRECTIONAL ); +dma_unmap_single (&pdev->dev, list[j].dma_addr, + list[j].size,DMA_BIDIRECTIONAL ); } list[j].dma_addr =0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 570/1266 crypto: rng - Free default RNG on module exit
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Herbert Xu <[email protected]>
[ Upstream commit 606ba888b98e0d26a2c4e5c8dc0542e3ad8f0f3a ]
When the rng module is removed the default RNG will be leaked. Call crypto_del_default_rng to free it if possible.
--- crypto/rng.c | 11 +++++++++++ 1 file changed, 11 insertions(+)
crypto/rng.c +11 -0
@@ -259,5 +259,16 @@ void crypto_unregister_rngs(struct rng_alg *algs, int count) }EXPORT_SYMBOL_GPL (crypto_unregister_rngs); +static void __exit rng_exit(void) +{ +int err; + + err =crypto_del_default_rng (); +if (err) +pr_err ("Failed delete default RNG: %d\n" , err); +} + +module_exit (rng_exit); +MODULE_LICENSE ("GPL" );MODULE_DESCRIPTION ("Random Number Generator" );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 571/1266 spi: xilinx: use FIFO occupancy register to determine buffer size
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lars Pöschel <[email protected]>
[ Upstream commit 47f3b5365536e8c38f264824ab15fdb74454e066 ]
The method the driver uses to determine the size of the FIFO has a problem. What it currently does is this:
It stops the SPI hardware and writes to the TX FIFO register until TX FIFO FULL asserts in the status register. But the hardware does not only have the FIFO, it also has a shift register which can hold a byte. This can be seen, when writing a byte to the FIFO (while the SPI hardware is stopped,) the TX FIFO EMPTY is still empty. So, if we have a FIFO size of 16 for example, the current method returns a 17.
This is a problem, at least when using the driver in irq mode. The same size determined for the TX FIFO is also assumed for the RX FIFO. When a SPI transaction wants to write the amount of the FIFO size or more bytes, the following happens, for example with 16 bytes FIFO size:
The driver stops the SPI hardware and writes 17 bytes to the TX FIFO and starts the SPI hardware and goes sleep.
The hardware then shifts out 17 bytes (FIFO + shift register) and simultaneously reads bytes into the RX FIFO, but it only has 16 places, so it looses one byte. Then TX FIFO empty asserts, wakes the driver again, which has a fast path and reads 16 bytes from the RX FIFO, but before reading the last 17th byte (which is lost) it does this:
sr = xspi->read_fn(xspi->regs + XSPI_SR_OFFSET);
if (!(sr & XSPI_SR_RX_EMPTY_MASK)) {
xilinx_spi_rx(xspi);
rx_words--;
}It reads the status register and checks if the RX FIFO is not empty. But it is empty in our case. So this check spins in a while loop forever locking the driver.
This patch fixes the logic to determine the FIFO size.
--- drivers/spi/spi-xilinx.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-)
drivers/spi/spi-xilinx.c +9 -2
@@ -370,11 +370,18 @@ static int xilinx_spi_find_buffer_size(struct xilinx_spi *xspi) xspi->regs + XIPIF_V123B_RESETR_OFFSET);/* Fill the Tx FIFO with as many words as possible */ -do { +while (1 ) { xspi->write_fn (0 , xspi->regs +XSPI_TXD_OFFSET ); sr = xspi->read_fn (xspi->regs +XSPI_SR_OFFSET ); +if (sr &XSPI_SR_TX_FULL_MASK ) +break ; + n_words++; - }while (!(sr &XSPI_SR_TX_FULL_MASK )); + } + +/* Handle the NO FIFO case separately */ +if (!n_words) +return 1 ;return n_words; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 572/1266 ASoC: adau1372: Clear PLL_EN on failed PLL lock without reset GPIO
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guangshuo Li <[email protected]>
[ Upstream commit 69b4141b428bcf2cf7a863950c0d6e5c5ae89ac1 ]
The PLL lock failure path in adau1372_set_power() unwinds by putting the regmap back in cache-only mode, asserting the optional power-down GPIO and disabling mclk.
adau1372_enable_pll() enables CLK_CTRL.PLL_EN before polling the PLL lock bit. If the lock fails on a board without a power-down GPIO, the error path disables mclk and returns an error, but leaves PLL_EN set in the hardware register. The normal power-off path already handles the no-GPIO case by explicitly clearing PLL_EN.
Mirror that cleanup in the PLL lock failure path and clear PLL_EN while the regmap is still live, before switching it back to cache-only mode.
--- sound/soc/codecs/adau1372.c | 5 +++++ 1 file changed, 5 insertions(+)
sound/soc/codecs/adau1372.c +5 -0
@@ -812,6 +812,11 @@ static int adau1372_set_power(struct adau1372 *adau1372, bool enable)if (adau1372->use_pll) { ret =adau1372_enable_pll (adau1372);if (ret) { +if (!adau1372->pd_gpio) +regmap_update_bits (adau1372->regmap, +ADAU1372_REG_CLK_CTRL , +ADAU1372_CLK_CTRL_PLL_EN , +0 );regcache_cache_only (adau1372->regmap, true);if (adau1372->pd_gpio)gpiod_set_value (adau1372->pd_gpio,1 );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 573/1266 power: supply: core: fix supplied_from allocations
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lucas Tsai <[email protected]>
[ Upstream commit ba61aed9a34671222d1149acfc2f0179a9ce7e80 ]
If dts property power-supplies has multiple values, then accessing to psy->supplied_from[i-1] in __power_supply_populate_supplied_from will overrun supplied_from array.
--- drivers/power/supply/power_supply_core.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-)
drivers/power/supply/power_supply_core.c +3 -8
@@ -262,18 +262,13 @@ static int power_supply_check_supplies(struct power_supply *psy)if (cnt ==1 )return 0 ; -/* All supplies found, allocate char ** array for filling */ - psy->supplied_from =devm_kzalloc (&psy->dev,sizeof (*psy->supplied_from), +/* All supplies found, allocate char * array for filling */ + psy->supplied_from =devm_kcalloc (&psy->dev, + cnt -1 ,sizeof (*psy->supplied_from),GFP_KERNEL );if (!psy->supplied_from)return -ENOMEM ; - *psy->supplied_from =devm_kcalloc (&psy->dev, - cnt -1 ,sizeof (**psy->supplied_from), -GFP_KERNEL ); -if (!*psy->supplied_from) -return -ENOMEM ; - return power_supply_populate_supplied_from(psy); }#else
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 574/1266 handshake: Require admin permission for DONE command
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit 81246a65303d9635266b1334490142caaf86a11f ]
ACCEPT and DONE are the two downcalls of the handshake genl family, both intended for use by the trusted handshake agent (tlshd). ACCEPT already requires GENL_ADMIN_PERM; DONE has no privilege check at all.
The fd-lookup in handshake_nl_done_doit() only confirms that some pending handshake request exists for the supplied sockfd; it does not authenticate the sender. An unprivileged process that guesses or observes a valid sockfd can therefore submit a DONE with HANDSHAKE_A_DONE_STATUS == 0, leaving the kernel consumer to proceed as if the handshake succeeded. A non-zero status on a forged DONE tears down a legitimate in-flight handshake before tlshd can report its real result.
--- Documentation/netlink/specs/handshake.yaml | 1 + net/handshake/genl.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-)
Documentation/netlink/specs/handshake.yaml +1 -0
@@ -113,6 +113,7 @@ operations: name: done doc: Handler reports handshake completion attribute-set: done + flags: [admin-perm] do: request: attributes:
net/handshake/genl.c +1 -1
@@ -36,7 +36,7 @@ static const struct genl_split_ops handshake_nl_ops[] = { .doit = handshake_nl_done_doit, .policy = handshake_done_nl_policy, .maxattr = HANDSHAKE_A_DONE_REMOTE_AUTH, - .flags = GENL_CMD_CAP_DO, + .flags = GENL_ADMIN_PERM | GENL_CMD_CAP_DO, }, };
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 575/1266 net/sched: sch_fq_codel: Do not call qdisc_tree_reduce_backlog during peek before restoring qlen
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Victor Nogueira <[email protected]>
[ Upstream commit 097f6fc7b1ae362dd7a9444b2572162fda73b284 ]
Whenever fq_codel drops packets during peek, it calls qdisc_tree_reduce_backlog. An issue arises because it calls qdisc_tree_reduce_backlog before it reincrements the qlen. If qlen drops to zero, but peek returns an skb, the parent's qlen_notify callback will be executed even though fq_codel still has 1 packet on the queue and, thus, will mistakenly deactivate the parent's class causing issues like a recent report [1] and a wild memory access in qfq:
[ 29.371146][ T360] Oops: general protection fault, probably for non-canonical address 0xfbd59c0000000024: 0000 [#1] SMP KASAN NOPTI [ 29.371666][ T360] KASAN: maybe wild-memory-access in range [0xdead000000000120-0xdead000000000127] [ 29.371987][ T360] CPU: 6 UID: 0 PID: 360 Comm: tc Not tainted 7.1.0-rc5-00285-gc530e5b2dbc6-dirty #82 PREEMPT(full) [ 29.372384][ T360] Hardware name: Bochs Bochs, BIOS Bochs 01/01/2011 [ 29.372620][ T360] RIP: 0010:qfq_deactivate_agg (include/linux/list.h:1029 (discriminator 2) include/linux/list.h:1043 (discriminator 2) net/sched/sch_qfq.c:1369 (discriminator 2) net/sched/sch_qfq.c:1395 (discriminator 2)) sch_qfq [ 29.373544][ T360] RSP: 0018:ffff888102417370 EFLAGS: 00010216 [ 29.373800][ T360] RAX: 0000000000000000 RBX: ffff88811224d568 RCX: dffffc0000000000 [ 29.374079][ T360] RDX: 1ffff11021fe1543 RSI: ffff88810ff0aa00 RDI: dffffc0000000000 [ 29.374368][ T360] RBP: ffff88811224c280 R08: dead000000000122 R09: 1bd5a00000000024 [ 29.374649][ T360] R10: fffffbfff7940329 R11: fffffbfff7940329 R12: 0000000000000000 [ 29.374926][ T360] R13: dead000000000100 R14: ffff88811224d580 R15: ffff88811224d578 [ 29.375207][ T360] FS: 00007f5b794e5780(0000) GS:ffff88815d1e9000(0000) knlGS:0000000000000000 [ 29.375545][ T360] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 29.375823][ T360] CR2: 000055ffb091f000 CR3: 000000010a305000 CR4: 0000000000750ef0 [ 29.376103][ T360] PKRU: 55555554 [ 29.376258][ T360] Call Trace: [ 29.376401][ T360] <TASK> ... [ 29.376885][ T360] qfq_reset_qdisc (net/sched/sch_qfq.c:357 net/sched/sch_qfq.c:1487) sch_qfq [ 29.377074][ T360] qdisc_reset (net/sched/sch_generic.c:1057) [ 29.377414][ T360] __qdisc_destroy (net/sched/sch_generic.c:1096) [ 29.377600][ T360] qdisc_graft (net/sched/sch_api.c:1062 net/sched/sch_api.c:1053 net/sched/sch_api.c:1159) [ 29.378593][ T360] tc_get_qdisc (net/sched/sch_api.c:1528 net/sched/sch_api.c:1556)
Fix this by only calling qdisc_tree_reduce_backlog in peek after the qlen is restored.
[1] http://lore.kernel.org/netdev/CAN2cbVe79oj0O9==m4+4x3v+O+qzRagA=2=wkrp9i9=CqYvyZA@mail.gmail.com/
--- net/sched/sch_fq_codel.c | 41 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-)
net/sched/sch_fq_codel.c +39 -2
@@ -278,7 +278,7 @@ static void drop_func(struct sk_buff *skb, void *ctx)qdisc_qstats_drop (sch); } -static struct sk_buff *fq_codel_dequeue (struct Qdisc *sch) +static struct sk_buff *__fq_codel_dequeue (struct Qdisc *sch) {struct fq_codel_sched_data *q =qdisc_priv (sch);struct sk_buff *skb;
@@ -315,12 +315,49 @@ static struct sk_buff *fq_codel_dequeue(struct Qdisc *sch)qdisc_bstats_update (sch, skb); flow->deficit -=qdisc_pkt_len (skb); +return skb; +} + +static void fq_codel_dequeue_drop (struct Qdisc *sch) +{ +struct fq_codel_sched_data *q =qdisc_priv (sch); +if (q->cstats.drop_count) {qdisc_tree_reduce_backlog (sch, q->cstats.drop_count, q->cstats.drop_len); q->cstats.drop_count =0 ; q->cstats.drop_len =0 ; } +} + +static struct sk_buff *fq_codel_dequeue (struct Qdisc *sch) +{ +struct sk_buff *skb; + + skb =__fq_codel_dequeue (sch); + +fq_codel_dequeue_drop (sch); + +return skb; +} + +static struct sk_buff *fq_codel_peek (struct Qdisc *sch) +{ +struct sk_buff *skb =skb_peek (&sch->gso_skb); + +if (!skb) { + skb =__fq_codel_dequeue (sch); + +if (skb) { +__skb_queue_head (&sch->gso_skb, skb); +/* it's still part of the queue */ +qdisc_qstats_backlog_inc (sch, skb); + sch->q.qlen++; + } + +fq_codel_dequeue_drop (sch); + } +return skb; }
@@ -707,7 +744,7 @@ static struct Qdisc_ops fq_codel_qdisc_ops __read_mostly = { .priv_size = sizeof(struct fq_codel_sched_data), .enqueue = fq_codel_enqueue, .dequeue = fq_codel_dequeue, - .peek = qdisc_peek_dequeued, + .peek = fq_codel_peek, .init = fq_codel_init, .reset = fq_codel_reset, .destroy = fq_codel_destroy,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 576/1266 net/sched: sch_codel: Do not call qdisc_tree_reduce_backlog during peek before restoring qlen
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Victor Nogueira <[email protected]>
[ Upstream commit 52f1da34c9f4d5bdc1e8b44242da5c7ba8db85f3 ]
Whenever codel drops packets during peek, it calls qdisc_tree_reduce_backlog. An issue arises because it calls qdisc_tree_reduce_backlog before it reincrements the qlen. If qlen drops to zero, but peek returns an skb, the parent's qlen_notify callback will be executed even though codel still has 1 packet on the queue and, thus, will mistakenly deactivate the parent's class causing issues like a wild memory access when qfq has codel as a child:
[ 36.339843][ T370] Oops: general protection fault, probably for non-canonical address 0xfbd59c0000000024: 0000 [#1] SMP KASAN NOPTI [ 36.340408][ T370] KASAN: maybe wild-memory-access in range [0xdead000000000120-0xdead000000000127] [ 36.340737][ T370] CPU: 2 UID: 0 PID: 370 Comm: tc Not tainted 7.1.0-rc5-00287-g66e13b626592 #87 PREEMPT(full) [ 36.341113][ T370] Hardware name: Bochs Bochs, BIOS Bochs 01/01/2011 [ 36.341357][ T370] RIP: 0010:qfq_deactivate_agg (include/linux/list.h:1029 (discriminator 2) include/linux/list.h:1043 (discriminator 2) net/sched/sch_qfq.c:1369 (discriminator 2) net/sched/sch_qfq.c:1395 (discriminator 2)) sch_qfq [ 36.342221][ T370] RSP: 0018:ffff8881100ef370 EFLAGS: 00010216 [ 36.342422][ T370] RAX: 0000000000000000 RBX: ffff8881058a9568 RCX: dffffc0000000000 [ 36.342664][ T370] RDX: 1ffff11021064dc3 RSI: ffff888108326e00 RDI: dffffc0000000000 [ 36.342905][ T370] RBP: ffff8881058a8280 R08: dead000000000122 R09: 1bd5a00000000024 [ 36.343140][ T370] R10: fffffbfff2940329 R11: fffffbfff2940329 R12: 0000000000000000 [ 36.343383][ T370] R13: dead000000000100 R14: ffff8881058a9580 R15: ffff8881058a9578 [ 36.343631][ T370] FS: 00007fc04b0ca780(0000) GS:ffff888184fef000(0000) knlGS:0000000000000000 [ 36.343911][ T370] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 36.344116][ T370] CR2: 0000557c02c02000 CR3: 000000010e0ba000 CR4: 0000000000750ef0 [ 36.344359][ T370] PKRU: 55555554 [ 36.344481][ T370] Call Trace: ... [ 36.345054][ T370] qfq_reset_qdisc (net/sched/sch_qfq.c:357 net/sched/sch_qfq.c:1487) sch_qfq [ 36.345222][ T370] qdisc_reset (net/sched/sch_generic.c:1057) [ 36.345503][ T370] __qdisc_destroy (net/sched/sch_generic.c:1096) [ 36.345677][ T370] qdisc_graft (net/sched/sch_api.c:1062 net/sched/sch_api.c:1053 net/sched/sch_api.c:1159) [ 36.346335][ T370] tc_get_qdisc (net/sched/sch_api.c:1528 net/sched/sch_api.c:1556)
Fix this by only calling qdisc_tree_reduce_backlog in peek after the qlen is restored.
--- net/sched/sch_codel.c | 48 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 43 insertions(+), 5 deletions(-)
net/sched/sch_codel.c +43 -5
@@ -86,7 +86,7 @@ static void drop_func(struct sk_buff *skb, void *ctx)qdisc_qstats_drop (sch); } -static struct sk_buff *codel_qdisc_dequeue (struct Qdisc *sch) +static struct sk_buff *__codel_qdisc_dequeue (struct Qdisc *sch) {struct codel_sched_data *q =qdisc_priv (sch);struct sk_buff *skb;
@@ -95,13 +95,51 @@ static struct sk_buff *codel_qdisc_dequeue(struct Qdisc *sch) &q->stats, qdisc_pkt_len, codel_get_enqueue_time, drop_func, dequeue_func); +if (skb) +qdisc_bstats_update (sch, skb); +return skb; +} + +static void codel_dequeue_drop (struct Qdisc *sch) +{ +struct codel_sched_data *q =qdisc_priv (sch); +if (q->stats.drop_count) { -qdisc_tree_reduce_backlog (sch, q->stats.drop_count, q->stats.drop_len); +qdisc_tree_reduce_backlog (sch, q->stats.drop_count, + q->stats.drop_len); q->stats.drop_count =0 ; q->stats.drop_len =0 ; } -if (skb) -qdisc_bstats_update (sch, skb); +} + +static struct sk_buff *codel_qdisc_dequeue (struct Qdisc *sch) +{ +struct sk_buff *skb; + + skb =__codel_qdisc_dequeue (sch); + +codel_dequeue_drop (sch); + +return skb; +} + +static struct sk_buff *codel_peek (struct Qdisc *sch) +{ +struct sk_buff *skb =skb_peek (&sch->gso_skb); + +if (!skb) { + skb =__codel_qdisc_dequeue (sch); + +if (skb) { +__skb_queue_head (&sch->gso_skb, skb); +/* it's still part of the queue */ +qdisc_qstats_backlog_inc (sch, skb); + sch->q.qlen++; + } + +codel_dequeue_drop (sch); + } +return skb; }
@@ -276,7 +314,7 @@ static struct Qdisc_ops codel_qdisc_ops __read_mostly = { .enqueue = codel_qdisc_enqueue, .dequeue = codel_qdisc_dequeue, - .peek = qdisc_peek_dequeued, + .peek = codel_peek, .init = codel_init, .reset = codel_reset, .change = codel_change,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 577/1266 net: mana: initialize gdma queue id to INVALID_QUEUE_ID
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Aditya Garg <[email protected]>
[ Upstream commit 5985474e1cb4034680fac2145497a94b0860be50 ]
mana_gd_create_mana_wq_cq() leaves queue->id as 0 (from kzalloc_obj()) until mana_create_wq_obj() assigns the firmware-returned id. If creation fails before that, cleanup calls mana_gd_destroy_cq() with id 0, NULLing gc->cq_table[0] and silently breaking whichever real CQ owns that slot.
Initialize queue->id to INVALID_QUEUE_ID right after allocation, matching mana_gd_create_eq(). The existing (id >= max_num_cqs) guard then short-circuits cleanly.
--- drivers/net/ethernet/microsoft/mana/gdma_main.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/net/ethernet/microsoft/mana/gdma_main.c +2 -0
@@ -840,6 +840,8 @@ int mana_gd_create_mana_wq_cq(struct gdma_dev *gd,if (!queue)return -ENOMEM ; + queue->id =INVALID_QUEUE_ID ; + gmi = &queue->mem_info; err =mana_gd_alloc_memory (gc, spec->queue_size, gmi);if (err)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 578/1266 net: mana: guard TX wq object destroy with INVALID_MANA_HANDLE check
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Aditya Garg <[email protected]>
[ Upstream commit f8fd56977eeea3d6939b1a9cd8bd36f1779b3ad0 ]
mana_create_txq() has several error paths (after mana_alloc_queues() or mana_create_wq_obj() failure) where tx_qp[i].tx_object stays as the INVALID_MANA_HANDLE sentinel set at allocation. mana_destroy_txq() then unconditionally calls mana_destroy_wq_obj() with (u64)-1, which firmware rejects and logs an error.
Mirror the RX-side pattern in mana_destroy_rxq() and skip the destroy when the handle is still INVALID_MANA_HANDLE.
--- 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
@@ -1880,7 +1880,8 @@ static void mana_destroy_txq(struct mana_port_context *apc)netif_napi_del (napi); apc->tx_qp[i].txq.napi_initialized = false; } -mana_destroy_wq_obj (apc,GDMA_SQ , apc->tx_qp[i].tx_object); +if (apc->tx_qp[i].tx_object !=INVALID_MANA_HANDLE ) +mana_destroy_wq_obj (apc,GDMA_SQ , apc->tx_qp[i].tx_object);mana_deinit_cq (apc, &apc->tx_qp[i].tx_cq);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 579/1266 bpf: Run generic devmap egress prog on private skb
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sun Jian <[email protected]>
[ Upstream commit 6001896f00984d317fb75160ba05c4a885fbe2a0 ]
Generic XDP devmap multi redirect uses skb_clone() for intermediate destinations and sends the last destination with the original skb. This can leave multiple destinations sharing the same packet data.
This becomes visible after generic devmap egress-program support was
added: a devmap egress program may mutate packet data, and another destination sharing the same data can observe that mutation.
Native XDP broadcast redirect does not have this issue because xdpf_clone() copies the frame data for each destination. Generic XDP should provide the same per-destination isolation before running a devmap egress program.
Fix this by making cloned skbs private before running the generic devmap egress program. Use skb_copy() instead of skb_unshare() so allocation failure does not consume the skb and the existing caller error paths keep their ownership semantics.
--- kernel/bpf/devmap.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)
kernel/bpf/devmap.c +12 -0
@@ -687,6 +687,18 @@ int dev_map_generic_redirect(struct bpf_dtab_netdev *dst, struct sk_buff *skb,if (unlikely (err))return err; +if (dst->xdp_prog &&skb_cloned (skb)) { +struct sk_buff *nskb; + + nskb =skb_copy (skb,GFP_ATOMIC ); +if (!nskb) +return -ENOMEM ; + + nskb->mac_len = skb->mac_len; +consume_skb (skb); + skb = nskb; + } +/* Redirect has already succeeded semantically at this point, so we just * return 0 even if packet is dropped. Helper below takes care of * freeing skb.
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 580/1266 net/mlx5: Check max_macs devlink param value against max capability
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dragos Tatulea <[email protected]>
[ Upstream commit d7b0413b35715d7b32cb12d4d424613eff85ed2b ]
The max_macs devlink param is checked against the FW max value only at param register time (driver load) and inside the validate callback (devlink param set). The stored DRIVERINIT value persists across FW resets and devlink reloads without any further checks against the max.
If the FW link type changes from Ethernet to IB and a FW reset happens, the MAX cap for log_max_current_uc_list will become zero, but the previously stored max_macs value remains and is unconditionally programmed into the HCA caps in handle_hca_cap(). FW will then return a syndrome during SET_HCA_CAP:
mlx5_cmd_out_err:839:(pid 3831): SET_HCA_CAP(0x109) op_mod(0x0) failed, status bad parameter(0x3), syndrome (0x537801), err(-22) set_hca_cap:907:(pid 3831): handle_hca_cap failed
This results in a failure to register the RDMA device.
This patch skips programming log_max_current_uc_list when the MAX capability is 0 (in case of IB).
--- drivers/net/ethernet/mellanox/mlx5/core/main.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-)
drivers/net/ethernet/mellanox/mlx5/core/main.c +7 -5
@@ -570,7 +570,6 @@ static int handle_hca_cap(struct mlx5_core_dev *dev, void *set_ctx) {struct mlx5_profile *prof = &dev->profile;void *set_hca_cap; -int max_uc_list;int err; err =mlx5_core_get_caps (dev,MLX5_CAP_GENERAL );
@@ -653,10 +652,13 @@ static int handle_hca_cap(struct mlx5_core_dev *dev, void *set_ctx)MLX5_SET (cmd_hca_cap, set_hca_cap, roce,mlx5_is_roce_on (dev)); - max_uc_list =max_uc_list_get_devlink_param (dev); -if (max_uc_list >0 ) -MLX5_SET (cmd_hca_cap, set_hca_cap, log_max_current_uc_list, -ilog2 (max_uc_list)); +if (MLX5_CAP_GEN_MAX (dev, log_max_current_uc_list)) { +int max_uc_list =max_uc_list_get_devlink_param (dev); + +if (max_uc_list >0 ) +MLX5_SET (cmd_hca_cap, set_hca_cap, + log_max_current_uc_list,ilog2 (max_uc_list)); + }return set_caps (dev, set_ctx,MLX5_SET_HCA_CAP_OP_MOD_GENERAL_DEVICE ); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 581/1266 net: wwan: t7xx: check skb_clone in control TX
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ruoyu Wang <[email protected]>
[ Upstream commit 05f789fa90d95d5771230e78453cedff2486039d ]
t7xx_port_ctrl_tx() clones each skb fragment before passing it to the port transmit path. The clone is used immediately to set cloned->len, so an skb_clone() failure results in a NULL pointer dereference.
Check the clone before using it. If previous fragments were already queued, preserve the driver's existing partial-write behavior by returning the number of bytes submitted so far.
--- drivers/net/wwan/t7xx/t7xx_port_wwan.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/net/wwan/t7xx/t7xx_port_wwan.c +2 -0
@@ -74,6 +74,8 @@ static int t7xx_port_ctrl_tx(struct wwan_port *port, struct sk_buff *skb)while (cur) { cloned =skb_clone (cur,GFP_KERNEL ); +if (!cloned) +return cnt ? cnt : -ENOMEM ; cloned->len =skb_headlen (cur); ret =t7xx_port_send_skb (port_private, cloned,0 ,0 );if (ret) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 582/1266 net: bcmgenet: Use weighted round-robin TX DMA arbitration
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ovidiu Panait <[email protected]>
[ Upstream commit fd615abd53110f0f815984e99e7cc51ca6b7d979 ]
Under heavy network traffic, we observed sporadic TX queue timeouts on the Raspberry Pi 4. The timeouts can be reproduced by stress testing the TX path with multiple concurrent iperf UDP streams:
iperf3 -c <ip> -u -b0 -P16 -t60
NETDEV WATCHDOG: CPU: 0: transmit queue 0 timed out 2044 ms NETDEV WATCHDOG: CPU: 3: transmit queue 0 timed out 2004 ms
Investigation showed that the timeouts are caused by the priority-based arbiter. Under heavy load the highest priority queue starves the lower priority ones, causing timeouts. The TX strict priority arbiter is not suitable for the default use case where all the traffic gets spread across all the TX queues.
Therefore, to fix this, switch the TX DMA arbiter to Weighted Round-Robin, which services all queues, so they do not stall. The weights were chosen to follow the existing priority scheme: q0 gets the smallest weight, while q1-4 get the bulk of the TX bandwidth.
--- .../net/ethernet/broadcom/genet/bcmgenet.c | 23 +++++++------------ 1 file changed, 8 insertions(+), 15 deletions(-)
drivers/net/ethernet/broadcom/genet/bcmgenet.c +8 -15
@@ -41,9 +41,8 @@#include "bcmgenet.h" -/* Default highest priority queue for multi queue support */ -#define GENET_Q1_PRIORITY 0 -#define GENET_Q0_PRIORITY 1 +#define GENET_Q0_WEIGHT 1 +#define GENET_Q1_WEIGHT 4#define GENET_Q0_RX_BD_CNT \ (TOTAL_DESC - priv->hw_params->rx_queues * priv->hw_params->rx_bds_per_q)
@@ -2086,13 +2085,6 @@ static netdev_tx_t bcmgenet_xmit(struct sk_buff *skb, struct net_device *dev)int i; index =skb_get_queue_mapping (skb); -/* Mapping strategy: -* queue_mapping = 0, unclassified, packet xmited through ring 0 -* queue_mapping = 1, goes to ring 1. (highest priority queue) -* queue_mapping = 2, goes to ring 2. -* queue_mapping = 3, goes to ring 3. -* queue_mapping = 4, goes to ring 4. -*/ ring = &priv->tx_rings[index]; txq =netdev_get_tx_queue (dev, index);
@@ -2792,8 +2784,9 @@ static void bcmgenet_fini_tx_napi(struct bcmgenet_priv *priv)/* Initialize Tx queues * -* Queues 1-4 are priority-based, each one has 32 descriptors, -* with queue 1 being the highest priority queue. +* Queues 1-4 are the priority queues, each one has 32 descriptors. +* The weighted round-robin arbiter gives them a larger share of TX +* bandwidth than the default queue 0. * * Queue 0 is the default Tx queue with * GENET_Q0_TX_BD_CNT = 256 - 4 * 32 = 128 descriptors.
@@ -2821,8 +2814,8 @@ static void bcmgenet_init_tx_queues(struct net_device *dev) dma_ctrl =0 ; ring_cfg =0 ; -/* Enable strict priority arbiter mode */ -bcmgenet_tdma_writel (priv,DMA_ARBITER_SP ,DMA_ARB_CTRL ); +/* Enable Weighted Round-Robin arbiter mode */ +bcmgenet_tdma_writel (priv,DMA_ARBITER_WRR ,DMA_ARB_CTRL );/* Initialize Tx priority queues */ for (i =0 ; i <= priv->hw_params->tx_queues; i++) {
@@ -2832,7 +2825,7 @@ static void bcmgenet_init_tx_queues(struct net_device *dev) ring_cfg |= (1 << i); dma_ctrl |= (1 << (i +DMA_RING_BUF_EN_SHIFT )); dma_priority[DMA_PRIO_REG_INDEX (i)] |= - (i ?GENET_Q1_PRIORITY :GENET_Q0_PRIORITY ) + (i ?GENET_Q1_WEIGHT :GENET_Q0_WEIGHT ) <<DMA_PRIO_REG_SHIFT (i); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 583/1266 kcm: use WRITE_ONCE() when changing lower socket callbacks
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Runyu Xiao <[email protected]>
[ Upstream commit 47186409c092cd7dd70350999186c700233e854d ]
kcm_attach() replaces a live lower TCP socket's sk_data_ready and sk_write_space callbacks with KCM handlers, and kcm_unattach() restores them later. Those callback-pointer updates are still plain stores even though the same fields can be read and invoked concurrently on other CPUs.
If another CPU observes an older callback snapshot after the live field has already been restored, callback execution can run with a mismatched target and sk_user_data state, leading to stale or misdirected wakeups.
Use WRITE_ONCE() for the callback replacement and restore operations so these shared callback fields follow the same visibility contract already established by the earlier 4022 fixes.
--- net/kcm/kcmsock.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
net/kcm/kcmsock.c +4 -4
@@ -1281,8 +1281,8 @@ static int kcm_attach(struct socket *sock, struct socket *csock, psock->save_write_space = csk->sk_write_space; psock->save_state_change = csk->sk_state_change; csk->sk_user_data = psock; - csk->sk_data_ready = psock_data_ready; - csk->sk_write_space = psock_write_space; +WRITE_ONCE (csk->sk_data_ready, psock_data_ready); +WRITE_ONCE (csk->sk_write_space, psock_write_space); csk->sk_state_change = psock_state_change;write_unlock_bh (&csk->sk_callback_lock);
@@ -1358,8 +1358,8 @@ static void kcm_unattach(struct kcm_psock *psock)*/ write_lock_bh (&csk->sk_callback_lock); csk->sk_user_data =NULL ; - csk->sk_data_ready = psock->save_data_ready; - csk->sk_write_space = psock->save_write_space; +WRITE_ONCE (csk->sk_data_ready, psock->save_data_ready); +WRITE_ONCE (csk->sk_write_space, psock->save_write_space); csk->sk_state_change = psock->save_state_change;strp_stop (&psock->strp);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 584/1266 netfilter: nf_conncount: callers must hold rcu read lock
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Florian Westphal <[email protected]>
[ Upstream commit 64d7d5abe2160bba369b4a8f06bdf5630573bab0 ]
rcu_derefence_raw() should not have been used here, it concealed this bug. Its used because struct rb_node lacks __rcu annotated pointers, so plain rcu_derefence causes sparse warnings.
The major tradeoff is that rcu_derefence_raw() doesn't warn when the caller isn't in a rcu read section.
Extend the rcu read lock scope accordingly and cause sparse warnings, those warnings are the lesser evil.
--- net/netfilter/nf_conncount.c | 6 +++--- net/openvswitch/conntrack.c | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-)
net/netfilter/nf_conncount.c +3 -3
@@ -499,7 +499,7 @@ count_tree(struct net *net, hash =jhash2 (key, data->keylen, conncount_rnd) %CONNCOUNT_SLOTS ; root = &data->root[hash]; - parent =rcu_dereference_raw (root->rb_node); + parent =rcu_dereference (root->rb_node);while (parent) {int diff;
@@ -507,9 +507,9 @@ count_tree(struct net *net, diff =key_diff (key, rbconn->key, data->keylen);if (diff <0 ) { - parent =rcu_dereference_raw (parent->rb_left); + parent =rcu_dereference (parent->rb_left); }else if (diff >0 ) { - parent =rcu_dereference_raw (parent->rb_right); + parent =rcu_dereference (parent->rb_right); }else {int ret;
net/openvswitch/conntrack.c +1 -1
@@ -1774,10 +1774,10 @@ static int ovs_ct_limit_get_zone_limit(struct net *net, }else {rcu_read_lock (); limit =ct_limit_get (info, zone); -rcu_read_unlock (); err =__ovs_ct_limit_get_zone_limit ( net, info->data, zone, limit, reply); +rcu_read_unlock ();if (err)return err; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 585/1266 ALSA: core: Fix unintuitive behavior of snd_power_ref_and_wait()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Takashi Iwai <[email protected]>
[ Upstream commit b113a891252c3fa4fab11ec8c2894a22ecaf278c ]
snd_power_ref_and_wait() takes the power refcount and doesn't leave it no matter whether it returns an error or not. However, the majority of callers don't expect but just returns without unreferencing in the caller side upon errors.
For addressing the potential refcount unbalance, rather correct the behavior of snd_power_ref_wait() to unreference upon returning an error.
Note that the problem above is likely negligible; the function returns an error only when the sound card is being shutdown, hence it doesn't matter about the power refcount any longer at such a state.
--- sound/core/init.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-)
sound/core/init.c +8 -3
@@ -1154,7 +1154,7 @@ EXPORT_SYMBOL(snd_card_file_remove);* typically around calling control ops. * * The caller needs to pull down the refcount via snd_power_unref() later -* no matter whether the error is returned from this function or not. +* when this function returns 0. * * Return: Zero if successful, or a negative error code. */
@@ -1167,7 +1167,11 @@ int snd_power_ref_and_wait(struct snd_card *card) card->shutdown ||snd_power_get_state (card) ==SNDRV_CTL_POWER_D0 , snd_power_unref(card), snd_power_ref(card)); -return card->shutdown ? -ENODEV :0 ; +if (card->shutdown) { +snd_power_unref (card); +return -ENODEV ; + } +return 0 ; }EXPORT_SYMBOL_GPL (snd_power_ref_and_wait);
@@ -1184,7 +1188,8 @@ int snd_power_wait(struct snd_card *card)int ret; ret =snd_power_ref_and_wait (card); -snd_power_unref (card); +if (!ret) +snd_power_unref (card);return ret; }EXPORT_SYMBOL (snd_power_wait);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 586/1266 cifs: remove all cifs files before kill super
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jian Zhang <[email protected]>
[ Upstream commit 6d9a4aaaa8b2612b5ef9d581e2f286a458b71ee1 ]
Cifs files may be put into fileinfo_put_wq during umounting cifs. After umount done, cifsFileInfo_put_final is called, which cause following BUG:
BUG: kernel NULL pointer dereference, address: 0000000000000000 ... [ 134.222152] list_lru_add+0x64/0x1a0 [ 134.222399] ? cifs_put_tcon+0x171/0x340 [cifs] [ 134.222772] d_lru_add+0x44/0x60 [ 134.222997] dput+0x1fc/0x210 [ 134.223213] cifsFileInfo_put_final+0x11a/0x140 [cifs] [ 134.223576] process_one_work+0x17c/0x320 [ 134.223843] worker_thread+0x188/0x280 [ 134.224084] ? __pfx_worker_thread+0x10/0x10 [ 134.224366] kthread+0xcc/0x100 [ 134.224576] ? __pfx_kthread+0x10/0x10 [ 134.224827] ret_from_fork+0x30/0x50 [ 134.225063] ? __pfx_kthread+0x10/0x10 [ 134.225328] ret_from_fork_asm+0x1b/0x30
This can be reproduce by following:
unshare -n bash -c "
mkdir -p ${CIFS_MNT}
ip netns attach root 1
ip link add eth0 type veth peer veth0 netns root
ip link set eth0 up
ip -n root link set veth0 up
ip addr add 192.168.0.2/24 dev eth0
ip -n root addr add 192.168.0.1/24 dev veth0
ip route add default via 192.168.0.1 dev eth0
ip netns exec root sysctl net.ipv4.ip_forward=1
ip netns exec root iptables -t nat -A POSTROUTING -s 192.168.0.2 -o
${DEV} -j MASQUERADE
mount -t cifs ${CIFS_PATH} ${CIFS_MNT} -o vers=3.0,sec=ntlmssp,credentials=${CIFS_CRED},rsize=65536,wsize=65536,cache=none,echo_interval=1 touch ${CIFS_MNT}/a.txt
ip netns exec root iptables -t nat -D POSTROUTING -s 192.168.0.2 -o
${DEV} -j MASQUERADE
"
umount ${CIFS_MNT}
--- fs/smb/client/connect.c | 3 +++ 1 file changed, 3 insertions(+)
fs/smb/client/connect.c +3 -0
@@ -3968,6 +3968,9 @@ cifs_umount(struct cifs_sb_info *cifs_sb) }spin_unlock (&cifs_sb->tlink_tree_lock); +flush_workqueue (serverclose_wq); +flush_workqueue (fileinfo_put_wq); +kfree (cifs_sb->prepath);call_rcu (&cifs_sb->rcu, delayed_free); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 587/1266 smb/client: always return a value for FS_IOC_GETFLAGS
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Huiwen He <[email protected]>
[ Upstream commit 7acbaa16b99edaf8ef432229d4b7a6f3b666767d ]
Currently, repeated lsattr calls on a regular CIFS file without the compressed attribute may show random flags:
$ touch test.bin $ lsattr test.bin s-S-ia-A-EjI---------m test.bin $ lsattr test.bin ------d-cEjI---------m test.bin
The lsattr reproducer depends on the previous contents of its userspace buffer, so it may not reproduce on every setup. A deterministic reproducer is to initialize the ioctl argument before FS_IOC_GETFLAGS on a file without the compressed attribute:
int flags = 0x7fffffff;
ioctl(fd, FS_IOC_GETFLAGS, &flags);On an affected kernel, flags remains 0x7fffffff. With the fix, it is set to 0.
This happens because when the cached inode does not have the compressed bit set, the CIFS fallback path in FS_IOC_GETFLAGS returns success without calling put_user() to write the zero flags value into the user buffer. As a result, the caller observes stale contents from its own buffer.
Fix this by always writing the visible flags value back to the user buffer before returning success, even when the value is zero.
--- fs/smb/client/ioctl.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-)
fs/smb/client/ioctl.c +5 -7
@@ -376,13 +376,11 @@ long cifs_ioctl(struct file *filep, unsigned int command, unsigned long arg) }#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ #endif /* CONFIG_CIFS_POSIX */ - rc =0 ; -if (CIFS_I (inode)->cifsAttrs &ATTR_COMPRESSED ) { -/* add in the compressed bit */ - ExtAttrBits =FS_COMPR_FL ; - rc =put_user (ExtAttrBits &FS_FL_USER_VISIBLE , - (int __user *)arg); - } +if (CIFS_I (inode)->cifsAttrs &FILE_ATTRIBUTE_COMPRESSED ) + ExtAttrBits |=FS_COMPR_FL ; + + rc =put_user (ExtAttrBits &FS_FL_USER_VISIBLE , + (int __user *)arg);break ;case FS_IOC_SETFLAGS :if (pSMBFile ==NULL )
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 588/1266 selftests/bpf: Initialize operation name before use
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Leo Yan <[email protected]>
[ Upstream commit 55ffbe8a15b1254f44d56952fb425a10e3f15c31 ]
ASAN reports stack-buffer-overflow due to the uninitialized op_name.
Initialize it to fix the issue.
--- tools/testing/selftests/bpf/prog_tests/verifier_log.c | 1 + 1 file changed, 1 insertion(+)
tools/testing/selftests/bpf/prog_tests/verifier_log.c +1 -0
@@ -317,6 +317,7 @@ static void verif_btf_log_subtest(bool bad_btf) res =load_btf (&opts, true);ASSERT_EQ (res, -ENOSPC ,"half_log_fd" );ASSERT_EQ (strlen (logs.buf),24 ,"log_fixed_25" ); +strscpy (op_name,"log_fixed" ,sizeof (op_name));ASSERT_STRNEQ (logs.buf, logs.reference,24 , op_name);/* validate rolling verifier log logic: try all variations of log buf
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 589/1266 bpf: Fix bpf_get/setsockopt to tos for ipv4-mapped ipv6 socket
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Leon Hwang <[email protected]>
[ Upstream commit ca0f587c029afa66227f7b932450b1c417403394 ]
When TCP over IPv4 via INET6 API, bpf_get/setsockopt with ipv4 will fail, because sk->sk_family is AF_INET6. With ipv6 will success, not take effect, because inet_csk(sk)->icsk_af_ops is ipv6_mapped and use ip_queue_xmit, inet_sk(sk)->tos.
To relax this restriction, allow getting/setting tos for those possible ipv4-mapped ipv6 sockets.
--- net/core/filter.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-)
net/core/filter.c +14 -1
@@ -5455,11 +5455,24 @@ static int sol_tcp_sockopt(struct sock *sk, int optname, KERNEL_SOCKPTR(optval), *optlen); } +static bool sk_allows_sol_ip_sockopt (struct sock *sk) +{ +switch (sk->sk_family) { +case AF_INET : +return true; +case AF_INET6 : +/* Allow getting/setting sockopt for possible ipv4-mapped ipv6 socket. */ +return sk->sk_type !=SOCK_RAW && !ipv6_only_sock (sk); +default : +return false; + } +} +static int sol_ip_sockopt (struct sock *sk,int optname,char *optval,int *optlen,bool getopt) { -if (sk->sk_family !=AF_INET ) +if (!sk_allows_sol_ip_sockopt (sk))return -EINVAL ;switch (optname) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 590/1266 bpf, sockmap: reject overflowing copy + len in bpf_msg_push_data()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Weiming Shi <[email protected]>
[ Upstream commit 0c0a8ed85349dae298712d79cb276acfeb794d82 ]
When the scatterlist ring is full or nearly full, bpf_msg_push_data() enters a copy fallback path and computes copy + len for the page allocation size. Since len comes from BPF with arg3_type = ARG_ANYTHING and both are u32, a crafted len can wrap the sum to a small value, causing an undersized allocation followed by an out-of-bounds memcpy.
BUG: unable to handle page fault for address: ffffed104089a402 Oops: Oops: 0000 [#1] SMP KASAN NOPTI Call Trace: __asan_memcpy (mm/kasan/shadow.c:105) bpf_msg_push_data (net/core/filter.c:2852 net/core/filter.c:2788) bpf_prog_9ed8b5711920a7d7+0x2e/0x36 sk_psock_msg_verdict (net/core/skmsg.c:934) tcp_bpf_sendmsg (net/ipv4/tcp_bpf.c:421 net/ipv4/tcp_bpf.c:584) __sys_sendto (net/socket.c:2206) do_syscall_64 (arch/x86/entry/syscall_64.c:94) entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:130)
Add an overflow check before the allocation.
--- net/core/filter.c | 3 +++ 1 file changed, 3 insertions(+)
net/core/filter.c +3 -0
@@ -2822,6 +2822,9 @@ BPF_CALL_4(bpf_msg_push_data, struct sk_msg *, msg, u32, start,if (!space || (space ==1 && start != offset)) copy = msg->sg.data[i].length; +if (unlikely (copy + len < copy)) +return -EINVAL ; + page =alloc_pages (__GFP_NOWARN |GFP_ATOMIC | __GFP_COMP,get_order (copy + len));if (unlikely (!page))
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 591/1266 bpf, sockmap: fix integer overflow in bpf_msg_pop_data() bounds check
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sechang Lim <[email protected]>
[ Upstream commit a48802fb2cd2d1e23651989f8ff4d15e9d5dad54 ]
start and len are u32, so
u64 last = start + len;
evaluates start + len in 32-bit and wraps before storing it in last. The bounds check
if (start >= offset + l || last > msg->sg.size) return -EINVAL;
can then be passed with an out-of-range start/len, after which the pop loop runs off the end of the scatterlist and sk_msg_shift_left() calls put_page() on the empty msg->sg.end slot:
Oops: general protection fault, probably for non-canonical address 0xdffffc0000000001: 0000 [#1] SMP KASAN PTI KASAN: null-ptr-deref in range [0x0000000000000008-0x000000000000000f] RIP: 0010:sk_msg_shift_left net/core/filter.c:2957 [inline] RIP: 0010:____bpf_msg_pop_data net/core/filter.c:3103 [inline] RIP: 0010:bpf_msg_pop_data+0x753/0x1a10 net/core/filter.c:2984 Call Trace: <TASK> bpf_prog_4cc92c278f4d5d56+0x1b1/0x1e8 bpf_prog_run_pin_on_cpu+0x107/0x320 include/linux/filter.h:746 sk_psock_msg_verdict+0x357/0x7f0 net/core/skmsg.c:934 tcp_bpf_send_verdict net/ipv4/tcp_bpf.c:420 [inline] tcp_bpf_sendmsg+0x766/0x1ae0 net/ipv4/tcp_bpf.c:583 __sock_sendmsg+0x153/0x1c0 net/socket.c:802 __sys_sendto+0x326/0x430 net/socket.c:2265 __x64_sys_sendto+0xe3/0x100 net/socket.c:2268 do_syscall_64+0x14c/0x480 entry_SYSCALL_64_after_hwframe+0x77/0x7f </TASK>
Widen the addition with a (u64) cast so the bound is evaluated in 64-bit and a len near U32_MAX no longer wraps below msg->sg.size.
While here, change pop from int to u32. It counts bytes against the unsigned scatterlist lengths and can never be negative, so the signed type only invites sign-confusion in the pop loop.
--- net/core/filter.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
net/core/filter.c +2 -2
@@ -2988,8 +2988,8 @@ BPF_CALL_4(bpf_msg_pop_data, struct sk_msg *, msg, u32, start, u32, len, u64, flags) {u32 i =0 , l =0 , space, offset =0 ; -u64 last = start + len; -int pop; +u64 last = (u64 )start + len; +u32 pop;if (unlikely (flags))return -EINVAL ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 592/1266 MIPS: mm: Fix out-of-bounds write in maar_res_walk()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yadan Fan <[email protected]>
[ Upstream commit 1b001b16bc88f3f7817e228acfd91ee01bdcfcce ]
maar_res_walk() uses wi->num_cfg as the index into the fixed-size wi->cfg array, but checks whether the array is full only after it has filled the selected entry. If walk_system_ram_range() reports more than 16 memory ranges, the overflow call writes one struct maar_config past the end of the array before WARN_ON() prevents num_cfg from advancing.
Move the full-array check before taking the array slot and return non-zero when the scratch array is full, so walk_system_ram_range() terminates the walk instead of invoking the callback for further ranges.
--- arch/mips/mm/init.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-)
arch/mips/mm/init.c +8 -4
@@ -281,9 +281,15 @@ static int maar_res_walk(unsigned long start_pfn, unsigned long nr_pages, void *data) {struct maar_walk_info *wi = data; -struct maar_config *cfg = &wi->cfg[wi->num_cfg]; +struct maar_config *cfg;unsigned int maar_align; +/* Ensure we don't overflow the cfg array */ +if (WARN_ON (wi->num_cfg >=ARRAY_SIZE (wi->cfg))) +return -1 ; + + cfg = &wi->cfg[wi->num_cfg]; +/* MAAR registers hold physical addresses right shifted by 4 bits */ maar_align =BIT (MIPS_MAAR_ADDR_SHIFT +4 );
@@ -292,9 +298,7 @@ static int maar_res_walk(unsigned long start_pfn, unsigned long nr_pages, cfg->upper =ALIGN_DOWN (PFN_PHYS (start_pfn + nr_pages), maar_align) -1 ; cfg->attrs =MIPS_MAAR_S ; -/* Ensure we don't overflow the cfg array */ -if (!WARN_ON (wi->num_cfg >=ARRAY_SIZE (wi->cfg))) - wi->num_cfg++; + wi->num_cfg++;return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 593/1266 powerpc/perf: fix preempt count underflow in fsl_emb_pmu_del
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Aboorva Devarajan <[email protected]>
[ Upstream commit 81e3a86030462824a67d697739cf3f387f4ba350 ]
fsl_emb_pmu_del() unconditionally calls put_cpu_var(cpu_hw_events) at the 'out:' label, but only calls the matching get_cpu_var() after the 'i < 0' early-return check. When event->hw.idx is negative the function jumps to 'out:' without having taken get_cpu_var(), and the trailing put_cpu_var() then issues an unmatched preempt_enable(), underflowing preempt_count.
On a CONFIG_PREEMPT=y kernel preempt_count would underflow and eventually present as a 'scheduling while atomic' BUG.
Move put_cpu_var() to pair with get_cpu_var() so the percpu access is correctly bracketed and the 'out:' label only handles perf_pmu_enable.
--- arch/powerpc/perf/core-fsl-emb.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
arch/powerpc/perf/core-fsl-emb.c +2 -1
@@ -366,9 +366,10 @@ static void fsl_emb_pmu_del(struct perf_event *event, int flags) cpuhw->n_events--; +put_cpu_var (cpu_hw_events); + out:perf_pmu_enable (event->pmu); -put_cpu_var (cpu_hw_events); }static void fsl_emb_pmu_start (struct perf_event *event,int ef_flags)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 594/1266 powerpc/powernv: fix preempt count leak in pnv_kexec_wait_secondaries_down
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Aboorva Devarajan <[email protected]>
[ Upstream commit 0ecd26e93e698c8327521910fc6296f5b84a4b92 ]
pnv_kexec_wait_secondaries_down() calls get_cpu() to obtain the current CPU id but never calls the matching put_cpu(), leaking one preempt_disable() nesting level on every invocation.
In practice the imbalance does not trigger a visible splat because the kexec teardown path is a one-way trip: IRQs are already disabled, no schedule() occurs after the leak, and default_machine_kexec() overwrites preempt_count with HARDIRQ_OFFSET before jumping into kexec_sequence() which never returns. However the bookkeeping is still wrong.
The function only needs the current CPU id, and this path runs with interrupts disabled and the CPU pinned, so the preempt_disable() side-effect of get_cpu() is unnecessary. Replace it with raw_smp_processor_id().
--- arch/powerpc/platforms/powernv/setup.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
arch/powerpc/platforms/powernv/setup.c +2 -1
@@ -396,7 +396,8 @@ static void pnv_kexec_wait_secondaries_down(void) {int my_cpu, i, notified =-1 ; - my_cpu =get_cpu (); +/* Called with interrupts disabled, so the CPU is pinned. */ + my_cpu =raw_smp_processor_id ();for_each_online_cpu (i) {uint8_t status;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 595/1266 powerpc/kexec: fix double get_cpu() imbalance in kexec_prepare_cpus
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Aboorva Devarajan <[email protected]>
[ Upstream commit 5c86f1c1f972761a04bf22f4c0618d1aa714185b ]
kexec_prepare_cpus_wait() calls get_cpu() internally to obtain the current CPU id. kexec_prepare_cpus() calls kexec_prepare_cpus_wait() twice -- once for KEXEC_STATE_IRQS_OFF and once for KEXEC_STATE_REAL_MODE -- but only issues a single put_cpu() at the end, leaving preempt_count elevated by one extra nesting level.
In practice the imbalance does not trigger a 'scheduling while atomic' splat because the kexec path is a one-way trip: IRQs are already disabled, no schedule() occurs after the leak, and default_machine_kexec() overwrites preempt_count with HARDIRQ_OFFSET before jumping into kexec_sequence() which never returns. However the bookkeeping is still wrong.
kexec_prepare_cpus() calls local_irq_disable()/hard_irq_disable() before invoking kexec_prepare_cpus_wait(), so the CPU is already pinned and the get_cpu()/put_cpu() preempt_disable() bracketing is unnecessary. Only the current CPU id is needed, so replace get_cpu() with raw_smp_processor_id() and drop the now-unneeded put_cpu().
--- arch/powerpc/kexec/core_64.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-)
arch/powerpc/kexec/core_64.c +1 -3
@@ -167,7 +167,7 @@ static void kexec_prepare_cpus_wait(int wait_state)int my_cpu, i, notified=-1 ;hw_breakpoint_disable (); - my_cpu =get_cpu (); + my_cpu =raw_smp_processor_id ();/* Make sure each CPU has at least made it to the state we need. * * FIXME: There is a (slim) chance of a problem if not all of the CPUs
@@ -265,8 +265,6 @@ static void kexec_prepare_cpus(void)/* after we tell the others to go down */ if (ppc_md.kexec_cpu_down) ppc_md.kexec_cpu_down(0, 0); - - put_cpu(); }#else /* ! SMP */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 596/1266 KEYS: Use acquire when reading state in keyring search
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Gui-Dong Han <[email protected]>
[ Upstream commit c1201b37f666f6466ab1fd3a381c2b7a4b7e9fee ]
The negative-key race fix added release/acquire ordering for key use.
Publish payload before state; read state before payload.
keyring_search_iterator() still uses READ_ONCE() before match callbacks. An asymmetric match callback calls asymmetric_key_ids(), which reads key->payload.data[asym_key_ids].
Use key_read_state() there to complete that ordering.
--- security/keys/keyring.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
security/keys/keyring.c +1 -1
@@ -576,7 +576,7 @@ static int keyring_search_iterator(const void *object, void *iterator_data)struct keyring_search_context *ctx = iterator_data;const struct key *key =keyring_ptr_to_key (object);unsigned long kflags =READ_ONCE (key->flags); -short state =READ_ONCE (key->state); +short state =key_read_state (key);kenter ("{%d}" , key->serial);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 597/1266 tipc: fix UAF in tipc_l2_send_msg()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit f4c3d89fc986b0da196ddfc6cfe0ea5d5d08bec6 ]
Syzbot reported a slab-use-after-free in ipvlan_hard_header() when called from tipc_l2_send_msg().
The root cause is that tipc_disable_l2_media() calls synchronize_net() while b->media_ptr is still valid. This allows concurrent RCU readers to obtain the device pointer after synchronize_net() has finished. The pointer is cleared later in bearer_disable(), but without any subsequent synchronization, allowing the device to be freed while still in use by readers.
Fix this by clearing b->media_ptr in tipc_disable_l2_media() before calling synchronize_net().
This is safe to do now because the call order in bearer_disable() was reversed in 0d051bf93c06 ("tipc: make bearer packet filtering generic") to call tipc_node_delete_links() (which needs the pointer) before disable_media().
https: //lore.kernel.org/netdev/[email protected]/T/#u
--- net/tipc/bearer.c | 1 + 1 file changed, 1 insertion(+)
net/tipc/bearer.c +1 -0
@@ -482,6 +482,7 @@ void tipc_disable_l2_media(struct tipc_bearer *b) dev = (struct net_device *)rtnl_dereference (b->media_ptr);dev_remove_pack (&b->pt);RCU_INIT_POINTER (dev->tipc_ptr,NULL ); +RCU_INIT_POINTER (b->media_ptr,NULL );synchronize_net ();dev_put (dev); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 598/1266 tcp: ipv6: clamp default adverting MSS to avoid GSO_BY_FRAGS (0xFFFF)
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit 2bf43d0e2e6a27d52a7d624e2d6b9116972e8a22 ]
When MTU is large, ip6_default_advmss() can return IPV6_MAXPLEN (65535). This is interpreted by TCP as mss_clamp, allowing the MSS to reach 65535.
However, 0xFFFF is also used as a magic value GSO_BY_FRAGS in the kernel. If a TCP packet with gso_size=0xFFFF is passed to skb_segment(), it will be mistakenly treated as GSO_BY_FRAGS, leading to a NULL pointer dereference because local TCP packets do not use frag_list.
Fix this by returning min(IPV6_MAXPLEN, GSO_BY_FRAGS - 1) (65534) from ip6_default_advmss() when MTU is large.
Also update the stale comment in ip6_default_advmss() which suggested that IPV6_MAXPLEN is returned to mean "any MSS".
--- net/ipv6/route.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
net/ipv6/route.c +3 -3
@@ -3251,11 +3251,11 @@ static unsigned int ip6_default_advmss(const struct dst_entry *dst)/* * Maximal non-jumbo IPv6 payload is IPV6_MAXPLEN and * corresponding MSS is IPV6_MAXPLEN - tcp_header_size. -* IPV6_MAXPLEN is also valid and means: "any MSS, -* rely only on pmtu discovery" +* Limit the default MSS to GSO_BY_FRAGS - 1 to avoid +* collision with the GSO_BY_FRAGS magic value (0xFFFF). */ if (mtu >IPV6_MAXPLEN -sizeof (struct tcphdr )) - mtu =IPV6_MAXPLEN ; + mtu = min_t(unsigned int, IPV6_MAXPLEN, GSO_BY_FRAGS - 1);return mtu; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 599/1266 ionic: Fix check in ionic_get_link_ext_stats
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Brett Creeley <[email protected]>
[ Upstream commit 7678e69079c10b2fb10977f28f44ddb22971ea5b ]
The current check will fail if SR-IOV is not initialized for the physical function; this is because is_physfn is 0 if sriov_init() isn't run or fails. Change the check that prevents getting the link down count to use is_virtfn instead so that VFs don't get this functionality, which was the original intent.
--- drivers/net/ethernet/pensando/ionic/ionic_ethtool.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-)
drivers/net/ethernet/pensando/ionic/ionic_ethtool.c +9 -2
@@ -114,8 +114,15 @@ static void ionic_get_link_ext_stats(struct net_device *netdev, {struct ionic_lif *lif =netdev_priv (netdev); -if (lif->ionic->pdev->is_physfn) - stats->link_down_events = lif->link_down_count; +if (lif->ionic->pdev->is_virtfn) +return ; + +if (!lif->ionic->idev.port_info) { +netdev_err_once (netdev,"port_info not initialized\n" ); +return ; + } + + stats->link_down_events = lif->link_down_count; } static int ionic_get_link_ksettings(struct net_device *netdev,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 600/1266 ksmbd: fix use-after-free in same_client_has_lease()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guangshuo Li <[email protected]>
[ Upstream commit 65b655f65c3ca1ab5d598d3832bb0ff531725858 ]
same_client_has_lease() returns an opinfo pointer from ci->m_op_list after dropping ci->m_lock without taking a reference.
smb_grant_oplock() then dereferences that pointer in copy_lease() and when checking breaking_cnt. A concurrent close can remove the old lease from ci->m_op_list and drop the last reference before the caller uses the returned pointer, leading to a use-after-free.
Take a reference when same_client_has_lease() selects an existing lease, drop any previous match while scanning, and release the returned reference in smb_grant_oplock() after copying the lease state.
--- fs/smb/server/oplock.c | 6 ++++++ 1 file changed, 6 insertions(+)
fs/smb/server/oplock.c +6 -0
@@ -531,7 +531,12 @@ static struct oplock_info *same_client_has_lease(struct ksmbd_inode *ci, ret =compare_guid_key (opinfo, client_guid, lctx->lease_key);if (ret) { +if (!atomic_inc_not_zero (&opinfo->refcount)) +continue ; +if (m_opinfo) +opinfo_put (m_opinfo); m_opinfo = opinfo; +/* skip upgrading lease about breaking lease */ if (atomic_read (&opinfo->breaking_cnt))continue ;
@@ -1249,6 +1254,7 @@ int smb_grant_oplock(struct ksmbd_work *work, int req_op_level, u64 pid,if (atomic_read (&m_opinfo->breaking_cnt)) opinfo->o_lease->flags =SMB2_LEASE_FLAG_BREAK_IN_PROGRESS_LE ; +opinfo_put (m_opinfo); goto out; } }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 601/1266 mfd: cs42l43: Sanity check firmware size
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Charles Keepax <[email protected]>
[ Upstream commit b6ef1a74b3ec254f87a6a3c554fe8f8083ebd37c ]
Currently the code checks if a firmware was received, however it does not verify that the firmware size is larger than the firmware header. As the firmware pointer is dereferenced as a pointer to the header structure this could lead to an out of bounds memory access. Add the missing check.
--- drivers/mfd/cs42l43.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/mfd/cs42l43.c +1 -1
@@ -666,7 +666,7 @@ static void cs42l43_mcu_load_firmware(const struct firmware *firmware, void *conunsigned int loadaddr, val;int ret; -if (!firmware) { +if (!firmware || firmware->size <sizeof (*hdr)) {dev_err (cs42l43->dev,"Failed to load firmware\n" ); cs42l43->firmware_error = -ENODEV ; goto err;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 602/1266 ocfs2: fix circular locking dependency in ocfs2_dio_end_io_write
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Aleksandr Nogikh <[email protected]>
[ Upstream commit ff6f26c58421614b02694ac9d219ac61d924bc68 ]
A circular locking dependency involves INODE_ALLOC_SYSTEM_INODE, EXTENT_ALLOC_SYSTEM_INODE, and ORPHAN_DIR_SYSTEM_INODE.
1. ocfs2_mknod() acquires INODE_ALLOC then EXTENT_ALLOC.
2. ocfs2_dio_end_io_write() acquires EXTENT_ALLOC for unwritten extents, then ORPHAN_DIR via ocfs2_del_inode_from_orphan() while still holding EXTENT_ALLOC.
3. ocfs2_wipe_inode() acquires ORPHAN_DIR then INODE_ALLOC via ocfs2_remove_inode.
Break the cycle in ocfs2_dio_end_io_write() by freeing the allocation contexts (releasing EXTENT_ALLOC) before acquiring ORPHAN_DIR.
WARNING: possible circular locking dependency detected
------------------------------------------------------
is trying to acquire lock:ffff8881e78b33a0 (&ocfs2_sysfile_lock_key[INODE_ALLOC_SYSTEM_INODE]){+.+.}-{4:4}, at:ocfs2_evict_inode+0x1539/0x43b0 fs/ocfs2/inode.c:1299
but task is already holding lock:ffff8881e78b4fa0 (&ocfs2_sysfile_lock_key[ORPHAN_DIR_SYSTEM_INODE]){+.+.}-{4:4}, at:ocfs2_evict_inode+0xe97/0x43b0 fs/ocfs2/inode.c:1299
the existing dependency chain (in reverse order) is:
-> #2 (&ocfs2_sysfile_lock_key[ORPHAN_DIR_SYSTEM_INODE]){+.+.}-{4:4}:
inode_lock include/linux/fs.h:1029 [inline]
ocfs2_del_inode_from_orphan+0x12e/0x7a0 fs/ocfs2/namei.c:2728
ocfs2_dio_end_io+0xf9c/0x1370 fs/ocfs2/aops.c:2418
dio_complete+0x25b/0x790 fs/direct-io.c:281-> #1 (&ocfs2_sysfile_lock_key[EXTENT_ALLOC_SYSTEM_INODE]){+.+.}-{4:4}:
inode_lock include/linux/fs.h:1029 [inline]
ocfs2_reserve_suballoc_bits+0x16d/0x4840 fs/ocfs2/suballoc.c:882
ocfs2_reserve_new_metadata_blocks+0x415/0x9a0
fs/ocfs2/suballoc.c:1078
ocfs2_mknod+0x10f3/0x2260 fs/ocfs2/namei.c:351-> #0 (&ocfs2_sysfile_lock_key[INODE_ALLOC_SYSTEM_INODE]){+.+.}-{4:4}:
__lock_acquire+0x15a5/0x2cf0 kernel/locking/lockdep.c:5237
lock_acquire+0x106/0x350 kernel/locking/lockdep.c:5868
down_write+0x96/0x200 kernel/locking/rwsem.c:1625
inode_lock include/linux/fs.h:1029 [inline]
ocfs2_remove_inode fs/ocfs2/inode.c:733 [inline]
ocfs2_wipe_inode fs/ocfs2/inode.c:896 [inline]
ocfs2_delete_inode fs/ocfs2/inode.c:1157 [inline]
ocfs2_evict_inode+0x1539/0x43b0 fs/ocfs2/inode.c:1299
Chain exists of:
&ocfs2_sysfile_lock_key[INODE_ALLOC_SYSTEM_INODE] -->
&ocfs2_sysfile_lock_key[EXTENT_ALLOC_SYSTEM_INODE] -->
&ocfs2_sysfile_lock_key[ORPHAN_DIR_SYSTEM_INODE]
Possible unsafe locking scenario: CPU0 CPU1
---- ----
lock(&ocfs2_sysfile_lock_key[ORPHAN_DIR_SYSTEM_INODE]);
lock(&ocfs2_sysfile_lock_key[EXTENT_ALLOC_SYSTEM_INODE]);
lock(&ocfs2_sysfile_lock_key[ORPHAN_DIR_SYSTEM_INODE]); lock(&ocfs2_sysfile_lock_key[INODE_ALLOC_SYSTEM_INODE]);
*** DEADLOCK ***
--- fs/ocfs2/aops.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-)
fs/ocfs2/aops.c +9 -4
@@ -2400,6 +2400,15 @@ static int ocfs2_dio_end_io_write(struct inode *inode, unlock:up_write (&oi->ip_alloc_sem); +if (data_ac) { +ocfs2_free_alloc_context (data_ac); + data_ac =NULL ; + } +if (meta_ac) { +ocfs2_free_alloc_context (meta_ac); + meta_ac =NULL ; + } +/* everything looks good, let's start the cleanup */ if (!ret && dwc->dw_orphaned) {BUG_ON (dwc->dw_writer_pid !=task_pid_nr (current));
@@ -2411,10 +2420,6 @@ static int ocfs2_dio_end_io_write(struct inode *inode,ocfs2_inode_unlock (inode,1 );brelse (di_bh); out: -if (data_ac) -ocfs2_free_alloc_context (data_ac); -if (meta_ac) -ocfs2_free_alloc_context (meta_ac);ocfs2_run_deallocs (osb, &dealloc);ocfs2_dio_free_write_ctx (inode, dwc);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 603/1266 net/9p: fix race condition on rdma->state in trans_rdma.c
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yizhou Zhao <[email protected]>
[ Upstream commit 7d54894a1ee265a72d70f7cae1da6cc774cccc71 ]
The rdma->state field is modified without holding req_lock in both recv_done() and p9_cm_event_handler(), while rdma_request() accesses the same field under the req_lock spinlock. This inconsistent locking creates a race condition:
- recv_done() running in softirq completion context sets rdma->state = P9_RDMA_FLUSHING without acquiring req_lock
- p9_cm_event_handler() modifies rdma->state at multiple points (ADDR_RESOLVED, ROUTE_RESOLVED, ESTABLISHED, CLOSED) without req_lock
- rdma_request() uses spin_lock_irqsave(&rdma->req_lock, flags) to protect the read-modify-write of rdma->state
The race can cause lost state transitions: recv_done() or the CM event handler could set state to FLUSHING/CLOSED while rdma_request() is concurrently checking or modifying state under the lock, leading to the FLUSHING transition being silently overwritten by CLOSING. This corrupts the connection state machine and can cause use-after-free on RDMA request objects during teardown.
Fix by adding req_lock protection to all rdma->state modifications in recv_done() and p9_cm_event_handler(), matching the pattern already used in rdma_request(). Use spin_lock_irqsave/spin_unlock_irqrestore in the CM event handler since it can race with recv_done() which runs in softirq context.
Tested with a kernel module that races two threads (simulating rdma_request and recv_done/CM handler) on rdma->state with proper
locking: 5.5M+ FLUSHING writes over 27M iterations with 0 lost transitions.
Message-ID: <[email protected]>
--- net/9p/trans_rdma.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-)
net/9p/trans_rdma.c +17 -2
@@ -240,25 +240,36 @@ p9_cm_event_handler(struct rdma_cm_id *id, struct rdma_cm_event *event) {struct p9_client *c = id->context;struct p9_trans_rdma *rdma = c->trans; +unsigned long flags; +switch (event->event) {case RDMA_CM_EVENT_ADDR_RESOLVED : +spin_lock_irqsave (&rdma->req_lock, flags);BUG_ON (rdma->state !=P9_RDMA_INIT ); rdma->state =P9_RDMA_ADDR_RESOLVED ; +spin_unlock_irqrestore (&rdma->req_lock, flags);break ;case RDMA_CM_EVENT_ROUTE_RESOLVED : +spin_lock_irqsave (&rdma->req_lock, flags);BUG_ON (rdma->state !=P9_RDMA_ADDR_RESOLVED ); rdma->state =P9_RDMA_ROUTE_RESOLVED ; +spin_unlock_irqrestore (&rdma->req_lock, flags);break ;case RDMA_CM_EVENT_ESTABLISHED : +spin_lock_irqsave (&rdma->req_lock, flags);BUG_ON (rdma->state !=P9_RDMA_ROUTE_RESOLVED ); rdma->state =P9_RDMA_CONNECTED ; +spin_unlock_irqrestore (&rdma->req_lock, flags);break ;case RDMA_CM_EVENT_DISCONNECTED : -if (rdma) +if (rdma) { +spin_lock_irqsave (&rdma->req_lock, flags); rdma->state =P9_RDMA_CLOSED ; +spin_unlock_irqrestore (&rdma->req_lock, flags); + } c->status = Disconnected;break ;
@@ -296,6 +307,7 @@ recv_done(struct ib_cq *cq, struct ib_wc *wc)struct p9_req_t *req;int err =0 ;int16_t tag; +unsigned long flags; req =NULL ; ib_dma_unmap_single(rdma->cm_id->device, c->busa, client->msize,
@@ -332,7 +344,10 @@ recv_done(struct ib_cq *cq, struct ib_wc *wc) err_out:p9_debug (P9_DEBUG_ERROR ,"req %p err %d status %d\n" , req, err, wc->status); - rdma->state =P9_RDMA_FLUSHING ; +spin_lock_irqsave (&rdma->req_lock, flags); +if (rdma->state <P9_RDMA_FLUSHING ) + rdma->state =P9_RDMA_FLUSHING ; +spin_unlock_irqrestore (&rdma->req_lock, flags); client->status = Disconnected; goto out; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 604/1266 staging: nvec: fix use-after-free in nvec_rx_completed()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alexandru Hossu <[email protected]>
[ Upstream commit 26813881181deb3a32fbb59eadb2599cbe8423f6 ]
In nvec_rx_completed(), when an incomplete RX transfer is detected, nvec_msg_free() is called to return the message back to the pool by clearing its 'used' atomic flag. Immediately after this, the code accesses nvec->rx->data[0] to check the message type.
Since nvec_msg_free() marks the pool slot as available via atomic_set(), any concurrent or subsequent call to nvec_msg_alloc() could claim that same slot and overwrite its data[] array. Reading nvec->rx->data[0] after freeing the message is therefore a use-after-free.
Fix this by saving the message type byte before calling nvec_msg_free(), then using the saved value for the battery quirk check.
--- drivers/staging/nvec/nvec.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/staging/nvec/nvec.c +3 -1
@@ -489,6 +489,8 @@ static void nvec_tx_completed(struct nvec_chip *nvec)static void nvec_rx_completed (struct nvec_chip *nvec) {if (nvec->rx->pos !=nvec_msg_size (nvec->rx)) { +unsigned char msg_type = nvec->rx->data[0 ]; +dev_err (nvec->dev,"RX incomplete: Expected %u bytes, got %u\n" , (uint )nvec_msg_size (nvec->rx), (uint )nvec->rx->pos);
@@ -497,7 +499,7 @@ static void nvec_rx_completed(struct nvec_chip *nvec) nvec->state =0 ;/* Battery quirk - Often incomplete, and likes to crash */ -if (nvec->rx->data[0 ] ==NVEC_BAT ) +if (msg_type ==NVEC_BAT )complete (&nvec->ec_transfer);return ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 605/1266 coresight: cti: Fix DT filter signals silently ignored
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yingchao Deng <[email protected]>
[ Upstream commit 551bb2fd5e4ed63d33aa11f07102cce5179b7595 ]
In cti_plat_process_filter_sigs(), after allocating a temporary cti_trig_grp struct via kzalloc_obj(), the code never assigns tg->nr_sigs = nr_filter_sigs. Since kzalloc zero-initialises the struct, tg->nr_sigs remains 0. cti_plat_read_trig_group() guards with:
if (!tgrp->nr_sigs)
return 0;so it returns immediately without reading any signal indices from DT.
Fix by assigning tg->nr_sigs before calling cti_plat_read_trig_group().
--- drivers/hwtracing/coresight/coresight-cti-platform.c | 1 + 1 file changed, 1 insertion(+)
drivers/hwtracing/coresight/coresight-cti-platform.c +1 -0
@@ -329,6 +329,7 @@ static int cti_plat_process_filter_sigs(struct cti_drvdata *drvdata,if (!tg)return -ENOMEM ; + tg->nr_sigs = nr_filter_sigs; err =cti_plat_read_trig_group (tg, fwnode,CTI_DT_FILTER_OUT_SIGS );if (!err) drvdata->config.trig_out_filter |= tg->used_mask;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 606/1266 coresight: etm4x: Correct TRCVMIDCCTLR1 save and restore
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Leo Yan <[email protected]>
[ Upstream commit 0ec0a8785d21f63db520bd9d2a67c55e855d36a8 ]
It is a typo to use trcvmidcctlr0 to save and restore TRCVMIDCCTLR1. Use trcvmidcctlr1 instead.
--- drivers/hwtracing/coresight/coresight-etm4x-core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/hwtracing/coresight/coresight-etm4x-core.c +2 -2
@@ -1837,7 +1837,7 @@ static int __etm4_cpu_save(struct etmv4_drvdata *drvdata) state->trcvmidcctlr0 =etm4x_read32 (csa,TRCVMIDCCTLR0 );if (drvdata->numvmidc >4 ) - state->trcvmidcctlr0 =etm4x_read32 (csa,TRCVMIDCCTLR1 ); + state->trcvmidcctlr1 =etm4x_read32 (csa,TRCVMIDCCTLR1 ); state->trcclaimset =etm4x_read32 (csa,TRCCLAIMCLR );
@@ -1963,7 +1963,7 @@ static void __etm4_cpu_restore(struct etmv4_drvdata *drvdata)etm4x_relaxed_write32 (csa, state->trcvmidcctlr0,TRCVMIDCCTLR0 );if (drvdata->numvmidc >4 ) -etm4x_relaxed_write32 (csa, state->trcvmidcctlr0,TRCVMIDCCTLR1 ); +etm4x_relaxed_write32 (csa, state->trcvmidcctlr1,TRCVMIDCCTLR1 );etm4x_relaxed_write32 (csa, state->trcclaimset,TRCCLAIMSET );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 607/1266 PCI/ASPM: Dont reconfigure ASPM entering low-power state
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Carlos Bilbao <[email protected]>
[ Upstream commit c855c9921da72e535c24737c748f603a52d03f7e ]
Reconfiguring ASPM when a device transitions to low-power state can enable L1.1/L1.2 substates on the PCIe link at a time when the device is sleeping and may be unable to exit them. ASPM should be reconfigured on D0 entry (resume), not on the way down.
pci_set_low_power_state() calls pcie_aspm_pm_state_change() after writing D3hot to PCI_PM_CTRL. pcie_aspm_pm_state_change() resets link->aspm_capable to link->aspm_support and then calls pcie_config_aspm_path(), which can enable ASPM L1.1/L1.2 substates on the PCIe link. If the device cannot recover the link from L1.2 while in D3hot, subsequent config space reads return 0xFFFF ("device inaccessible") and pci_power_up() fails with messages like:
vfio-pci 0000:5d:00.0: Unable to change power state from D3hot to D0, device inaccessible
This was observed on NVIDIA H100 SXM5 GPUs bound to vfio-pci when Linux runtime PM suspends them to D3hot: the GPU becomes permanently inaccessible and disappears from the PCIe bus.
The call to pcie_aspm_pm_state_change() in pci_set_low_power_state() was restored by f93e71aea6c6 ("Revert "PCI/ASPM: Remove pcie_aspm_pm_state_change()""), which reverted 08d0cc5f3426 ("PCI/ASPM:
Remove pcie_aspm_pm_state_change()"). The revert was necessary because the removal broke suspend/resume on certain platforms that required ASPM to be reconfigured on D0 entry. However, the revert restored the call in both pci_set_full_power_state() (D0 entry) and pci_set_low_power_state() (low-power entry).
Only the D0-entry call is needed to fix the suspend/resume regression. The low-power-entry call is harmful: reconfiguring ASPM immediately after putting a device into D3hot can enable link substates that the device or platform cannot exit while the device is sleeping.
Remove the pcie_aspm_pm_state_change() call from pci_set_low_power_state(). ASPM will still be reconfigured correctly when the device returns to D0 via pci_set_full_power_state().
--- drivers/pci/pci.c | 3 --- 1 file changed, 3 deletions(-)
drivers/pci/pci.c +0 -3
@@ -1518,9 +1518,6 @@ static int pci_set_low_power_state(struct pci_dev *dev, pci_power_t state, boolpci_power_name (dev->current_state), pci_power_name(state)); -if (dev->bus->self) -pcie_aspm_pm_state_change (dev->bus->self, locked); -return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 608/1266 PCI: Introduce named defines for PCI ROM
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guixin Liu <[email protected]>
[ Upstream commit 113e86bc58a918f85d250723436a4d541a873358 ]
Convert the magic numbers associated with PCI ROM into named definitions. Some of these definitions will be used in the second fix patch.
Stable-dep-of: 538796b807fc ("PCI: Check ROM header and data structure addr before accessing")
--- drivers/pci/rom.c | 40 ++++++++++++++++++++++++++++------------ 1 file changed, 28 insertions(+), 12 deletions(-)
drivers/pci/rom.c +28 -12
@@ -5,13 +5,28 @@* (C) Copyright 2004 Jon Smirl <[email protected]> * (C) Copyright 2004 Silicon Graphics, Inc. Jesse Barnes <[email protected]> */ + +#include <linux/bits.h> #include <linux/kernel.h> #include <linux/export.h> #include <linux/pci.h> +#include <linux/sizes.h> #include <linux/slab.h> #include "pci.h" +#define PCI_ROM_HEADER_SIZE 0x1A +#define PCI_ROM_POINTER_TO_DATA_STRUCT 0x18 +#define PCI_ROM_LAST_IMAGE_INDICATOR 0x15 +#define PCI_ROM_LAST_IMAGE_INDICATOR_BIT BIT(7) +#define PCI_ROM_IMAGE_LEN 0x10 +#define PCI_ROM_IMAGE_SECTOR_SIZE SZ_512 +#define PCI_ROM_IMAGE_SIGNATURE 0xAA55 + +/* Data structure signature is "PCIR" in ASCII representation */ +#define PCI_ROM_DATA_STRUCT_SIGNATURE 0x52494350 +#define PCI_ROM_DATA_STRUCT_LEN 0x0A +/** * pci_enable_rom - enable ROM decoding for a PCI device * @pdev: PCI device to enable
@@ -91,26 +106,27 @@ static size_t pci_get_rom_size(struct pci_dev *pdev, void __iomem *rom, do { void __iomem *pds; /* Standard PCI ROMs start out with these bytes 55 AA */ - if (readw(image) != 0xAA55) { - pci_info(pdev, "Invalid PCI ROM header signature: expecting 0xaa55, got %#06x\n", - readw(image)); + if (readw(image) != PCI_ROM_IMAGE_SIGNATURE) { + pci_info(pdev, "Invalid PCI ROM header signature: expecting %#06x, got %#06x\n", + PCI_ROM_IMAGE_SIGNATURE, readw(image)); break; } - /* get the PCI data structure and check its "PCIR" signature */ - pds = image + readw(image + 24); - if (readl(pds) != 0x52494350) { - pci_info(pdev, "Invalid PCI ROM data signature: expecting 0x52494350, got %#010x\n", - readl(pds)); + /* Get the PCI data structure and check its "PCIR" signature */ + pds = image + readw(image + PCI_ROM_POINTER_TO_DATA_STRUCT); + if (readl(pds) != PCI_ROM_DATA_STRUCT_SIGNATURE) { + pci_info(pdev, "Invalid PCI ROM data signature: expecting %#010x, got %#010x\n", + PCI_ROM_DATA_STRUCT_SIGNATURE, readl(pds)); break; } - last_image = readb(pds + 21) & 0x80; - length = readw(pds + 16); - image += length * 512; + last_image = readb(pds + PCI_ROM_LAST_IMAGE_INDICATOR) & + PCI_ROM_LAST_IMAGE_INDICATOR_BIT; + length = readw(pds + PCI_ROM_IMAGE_LEN); + image += length * PCI_ROM_IMAGE_SECTOR_SIZE; /* Avoid iterating through memory outside the resource window */ if (image >= rom + size) break; if (!last_image) { - if (readw(image) != 0xAA55) { + if (readw(image) != PCI_ROM_IMAGE_SIGNATURE) { pci_info(pdev, "No more image in the PCI ROM\n"); break; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 609/1266 PCI: Check ROM header and data structure addr before accessing
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guixin Liu <[email protected]>
[ Upstream commit 538796b807fcfb81b2ce40cc97a614fd8588feb5 ]
We meet a crash when running stress-ng on x86_64 machine:
BUG: unable to handle page fault for address: ffa0000007f40000
RIP: 0010:pci_get_rom_size+0x52/0x220
Call Trace:
<TASK>
pci_map_rom+0x80/0x130
pci_read_rom+0x4b/0xe0
kernfs_file_read_iter+0x96/0x180
vfs_read+0x1b1/0x300Our analysis reveals that the ROM space's start address is 0xffa0000007f30000, and size is 0x10000. Because of broken ROM space, before calling readl(pds), the pds's value is 0xffa0000007f3ffff, which is already pointed to the ROM space end, invoking readl() would read 4 bytes therefore cause an out-of-bounds access and trigger a crash. Fix this by adding image header and data structure checking.
We also found another crash on arm64 machine:
Unable to handle kernel paging request at virtual address ffff8000dd1393ff Mem abort info: ESR = 0x0000000096000021 EC = 0x25: DABT (current EL), IL = 32 bits SET = 0, FnV = 0 EA = 0, S1PTW = 0 FSC = 0x21: alignment fault
The call trace is the same with x86_64, but the crash reason is that the data structure addr is not aligned with 4, and arm64 machine report "alignment fault". Fix this by adding alignment checking.
--- drivers/pci/rom.c | 123 +++++++++++++++++++++++++++++++++++++++------- 1 file changed, 105 insertions(+), 18 deletions(-)
drivers/pci/rom.c +105 -18
@@ -6,9 +6,12 @@* (C) Copyright 2004 Silicon Graphics, Inc. Jesse Barnes <[email protected]> */ +#include <linux/align.h> #include <linux/bits.h> #include <linux/kernel.h> #include <linux/export.h> +#include <linux/io.h> +#include <linux/overflow.h> #include <linux/pci.h> #include <linux/sizes.h> #include <linux/slab.h>
@@ -27,6 +30,15 @@#define PCI_ROM_DATA_STRUCT_SIGNATURE 0x52494350#define PCI_ROM_DATA_STRUCT_LEN 0x0A +/* +* Per PCI Firmware r3.3, sec 5.1.3, a conformant PCI Data Structure is at +* least 24 bytes (0x18), large enough to cover every fixed field this +* driver reads (up to the Indicator byte at offset 0x15). Reject smaller +* device-claimed lengths so the follow-up readers in pci_get_rom_size() +* cannot escape the mapped ROM window. +*/ +#define PCI_ROM_DATA_STRUCT_MIN_LEN 0x18 +/** * pci_enable_rom - enable ROM decoding for a PCI device * @pdev: PCI device to enable
@@ -84,6 +96,91 @@ void pci_disable_rom(struct pci_dev *pdev) }EXPORT_SYMBOL_GPL (pci_disable_rom); +static bool pci_rom_header_valid (struct pci_dev *pdev,void __iomem *image, +void __iomem *rom,size_t size, +bool expect_valid) +{ +unsigned long rom_end = (unsigned long )rom + size -1 ; +unsigned long header_end; +u16 signature; + +/* +* Per PCI Firmware r3.3, sec 5.1, each image must start on a +* 512-byte boundary and must contain the PCI Expansion ROM header. +* Because @rom is page-aligned (returned by ioremap()), checking +* 512-byte alignment of @image is equivalent to enforcing the +* spec's sector-aligned layout within the ROM. This also +* satisfies the natural-alignment requirement of readw() on archs +* such as arm64 that disallow unaligned IOMEM access. +*/ +if (!IS_ALIGNED ((unsigned long )image,PCI_ROM_IMAGE_SECTOR_SIZE )) +return false; + +if (check_add_overflow ((unsigned long )image,PCI_ROM_HEADER_SIZE -1 , + &header_end)) +return false; + +if (image < rom || header_end > rom_end) +return false; + +/* Standard PCI ROMs start out with these bytes 55 AA */ + signature =readw (image); +if (signature !=PCI_ROM_IMAGE_SIGNATURE ) { +if (expect_valid) { +pci_info (pdev,"Invalid PCI ROM header signature: expecting %#06x, got %#06x\n" , +PCI_ROM_IMAGE_SIGNATURE , signature); + }else { +pci_info (pdev,"No more images in PCI ROM\n" ); + } +return false; + } + +return true; +} + +static bool pci_rom_data_struct_valid (struct pci_dev *pdev,void __iomem *pds, +void __iomem *rom,size_t size) +{ +unsigned long rom_end = (unsigned long )rom + size -1 ; +unsigned long end; +u32 signature; +u16 data_len; + +/* +* Some CPU architectures require IOMEM access addresses to be +* aligned, for example arm64, so since we're about to call +* readl(), check here for 4-byte alignment. +*/ +if (!IS_ALIGNED ((unsigned long )pds,4 )) +return false; + +if (check_add_overflow ((unsigned long )pds,PCI_ROM_DATA_STRUCT_LEN +1 , + &end)) +return false; + +if (pds < rom || end > rom_end) +return false; + + signature =readl (pds); +if (signature !=PCI_ROM_DATA_STRUCT_SIGNATURE ) { +pci_info (pdev,"Invalid PCI ROM data signature: expecting %#010x, got %#010x\n" , +PCI_ROM_DATA_STRUCT_SIGNATURE , signature); +return false; + } + + data_len =readw (pds +PCI_ROM_DATA_STRUCT_LEN ); +if (data_len <PCI_ROM_DATA_STRUCT_MIN_LEN || data_len ==U16_MAX ) +return false; + +if (check_add_overflow ((unsigned long )pds, data_len -1 , &end)) +return false; + +if (end > rom_end) +return false; + +return true; +} +/** * pci_get_rom_size - obtain the actual size of the ROM image * @pdev: target PCI device
@@ -99,38 +196,28 @@ static size_t pci_get_rom_size(struct pci_dev *pdev, void __iomem *rom, size_t size) {void __iomem *image; -int last_image;unsigned int length; +bool last_image; image = rom;do {void __iomem *pds; -/* Standard PCI ROMs start out with these bytes 55 AA */ -if (readw (image) !=PCI_ROM_IMAGE_SIGNATURE ) { -pci_info (pdev,"Invalid PCI ROM header signature: expecting %#06x, got %#06x\n" , -PCI_ROM_IMAGE_SIGNATURE ,readw (image)); +if (!pci_rom_header_valid (pdev, image, rom, size, true))break ; - } +/* Get the PCI data structure and check its "PCIR" signature */ pds = image +readw (image +PCI_ROM_POINTER_TO_DATA_STRUCT ); -if (readl (pds) !=PCI_ROM_DATA_STRUCT_SIGNATURE ) { -pci_info (pdev,"Invalid PCI ROM data signature: expecting %#010x, got %#010x\n" , -PCI_ROM_DATA_STRUCT_SIGNATURE ,readl (pds)); +if (!pci_rom_data_struct_valid (pdev, pds, rom, size))break ; - } + last_image =readb (pds +PCI_ROM_LAST_IMAGE_INDICATOR ) &PCI_ROM_LAST_IMAGE_INDICATOR_BIT ; length =readw (pds +PCI_ROM_IMAGE_LEN ); image += length *PCI_ROM_IMAGE_SECTOR_SIZE ; -/* Avoid iterating through memory outside the resource window */ -if (image >= rom + size) + +if (!last_image && + !pci_rom_header_valid (pdev, image, rom, size, false))break ; -if (!last_image) { -if (readw (image) !=PCI_ROM_IMAGE_SIGNATURE ) { -pci_info (pdev,"No more image in the PCI ROM\n" ); -break ; - } - } }while (length && !last_image);/* never return a size larger than the PCI resource window */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 610/1266 x86/platform/olpc: xo15: Drop wakeup source on driver removal
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Rafael J. Wysocki <[email protected]>
[ Upstream commit cc966553e6ff0849978b5754531b768b0ff54985 ]
Prevent leaking a wakeup source object after removing the driver by adding appropriate cleanup code to its remove callback function.
--- arch/x86/platform/olpc/olpc-xo15-sci.c | 1 + 1 file changed, 1 insertion(+)
arch/x86/platform/olpc/olpc-xo15-sci.c +1 -0
@@ -185,6 +185,7 @@ static int xo15_sci_add(struct acpi_device *device)static void xo15_sci_remove (struct acpi_device *device) { +device_init_wakeup (&device->dev, false);acpi_disable_gpe (NULL , xo15_sci_gpe);acpi_remove_gpe_handler (NULL , xo15_sci_gpe, xo15_sci_gpe_handler);cancel_work_sync (&sci_work);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 611/1266 platform/x86: xo15-ebook: Fix wakeup source and GPE handling
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Rafael J. Wysocki <[email protected]>
[ Upstream commit b2fc2c6ebbd2d49935c8960755d8170faead2159 ]
The device_set_wakeup_enable() call in ebook_switch_add() doesn't actually do anything because power.can_wakeup is not set for ACPI device objects. Moreover, had it done anything, it would have registered a wakeup source object that wouldn't have been used going forward and that wakeup source would have been leaked after driver removal because ebook_switch_remove() doesn't clean it up. Accordingly, remove that call from ebook_switch_add().
Also prevent leaking an enabled ACPI GPE after removing the driver by adding appropriate cleanup code to ebook_switch_remove().
--- drivers/platform/x86/xo15-ebook.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
drivers/platform/x86/xo15-ebook.c +6 -1
@@ -38,6 +38,7 @@ MODULE_DEVICE_TABLE(acpi, ebook_device_ids);struct ebook_switch {struct input_dev *input;char phys[32 ];/* for input device */ +bool gpe_enabled; };static int ebook_send_state (struct acpi_device *device)
@@ -131,7 +132,7 @@ static int ebook_switch_add(struct acpi_device *device)/* Button's GPE is run-wake GPE */ acpi_enable_gpe (device->wakeup.gpe_device, device->wakeup.gpe_number); -device_set_wakeup_enable (&device->dev, true); + button->gpe_enabled = true; }return 0 ;
@@ -147,6 +148,10 @@ static void ebook_switch_remove(struct acpi_device *device) {struct ebook_switch *button =acpi_driver_data (device); +if (button->gpe_enabled) +acpi_disable_gpe (device->wakeup.gpe_device, + device->wakeup.gpe_number); +input_unregister_device (button->input);kfree (button); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 612/1266 perf sched: Add missing mmap2 handler in timehist
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ian Rogers <[email protected]>
[ Upstream commit 91182741369b261c441e63e6678893032a6d7e4c ]
perf_sched__timehist() registers event handlers for options using the sched->tool struct. It registers handlers for MMAP, COMM, EXIT, FORK, etc. but completely omits registering a handler for MMAP2 events.
Failing to register both MMAP and MMAP2 handlers causes modern systems (which primarily output MMAP2 records) to silently drop VMA map mappings. This results in uninitialized machine/thread mapping structures, making it impossible to resolve shared library instruction pointers (IPs) to dynamic symbols/DSOs during timehist callchain analysis.
Fix this by correctly registering perf_event__process_mmap2 in sched->tool inside perf_sched__timehist().
--- tools/perf/builtin-sched.c | 1 + 1 file changed, 1 insertion(+)
tools/perf/builtin-sched.c +1 -0
@@ -3067,6 +3067,7 @@ static int perf_sched__timehist(struct perf_sched *sched)*/ sched->tool.sample = perf_timehist__process_sample; sched->tool.mmap = perf_event__process_mmap; + sched->tool.mmap2 = perf_event__process_mmap2; sched->tool.comm = perf_event__process_comm; sched->tool.exit = perf_event__process_exit; sched->tool.fork = perf_event__process_fork;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 613/1266 PCI: loongson: Do not ignore downstream devices on external bridges
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Rong Zhang <[email protected]>
[ Upstream commit 1389ab9bf9f627d4daed86f492091b00f110aa86 ]
Loongson PCI host controllers have a hardware quirk that requires software to ignore downstream devices with device number > 0 on the internal bridges. The current implementation applies the workaround to all non-root buses, which breaks external bridges (e.g., PCIe switches) with multiple downstream devices.
Fix it by only applying the workaround to internal bridges.
Tested on Loongson-LS3A4000-7A1000-NUC-SE, using AMD Promontory 21 chipset add-in card [1].
$ lspci -tnnnvvv
-[0000:00]-+-00.0 Loongson Technology LLC 7A1000 Chipset Hyper Transport Bridge Controller [0014:7a00]
+-00.1 Loongson Technology LLC 7A2000 Chipset Hyper Transport Bridge Controller [0014:7a10]
+-03.0 Loongson Technology LLC 2K1000/2000 / 7A1000 Chipset Gigabit Ethernet Controller [0014:7a03]
+-04.0 Loongson Technology LLC 2K1000 / 7A1000/2000 Chipset USB OHCI Controller [0014:7a24]
+-04.1 Loongson Technology LLC 2K1000 / 7A1000/2000 Chipset USB EHCI Controller [0014:7a14]
+-05.0 Loongson Technology LLC 2K1000 / 7A1000/2000 Chipset USB OHCI Controller [0014:7a24]
+-05.1 Loongson Technology LLC 2K1000 / 7A1000/2000 Chipset USB EHCI Controller [0014:7a14]
+-06.0 Loongson Technology LLC 7A1000 Chipset Vivante GC1000 GPU [0014:7a15]
+-06.1 Loongson Technology LLC 2K1000 / 7A1000 Chipset Display Controller [0014:7a06]
+-07.0 Loongson Technology LLC 2K1000/2000/3000 / 3B6000M / 7A1000/2000 Chipset HD Audio Controller [0014:7a07]
+-08.0 Loongson Technology LLC 2K1000 / 7A1000 Chipset 3Gb/s SATA AHCI Controller [0014:7a08]
+-08.1 Loongson Technology LLC 2K1000 / 7A1000 Chipset 3Gb/s SATA AHCI Controller [0014:7a08]
+-08.2 Loongson Technology LLC 2K1000 / 7A1000 Chipset 3Gb/s SATA AHCI Controller [0014:7a08]
+-09.0-[01]----00.0 Qualcomm Technologies, Inc QCNFA765 Wireless Network Adapter [17cb:1103]
+-0a.0-[02]----00.0 Etron Technology, Inc. EJ188/EJ198 USB 3.0 Host Controller [1b6f:7052]
+-0f.0-[03-08]----00.0-[04-08]--+-00.0-[05]----00.0 Shenzhen Longsys Electronics Co., Ltd. FORESEE XP1000 / Lexar Professional CFexpress Type B Gold series, NM620 PCIe NVME SSD (DRAM-less) [1d97:5216]
| +-08.0-[06]----00.0 MAXIO Technology (Hangzhou) Ltd. NVMe SSD Controller MAP1202 (DRAM-less) [1e4b:1202]
| +-0c.0-[07]----00.0 Advanced Micro Devices, Inc. [AMD] 600 Series Chipset USB 3.2 Controller [1022:43f7]
| \-0d.0-[08]----00.0 Advanced Micro Devices, Inc. [AMD] 600 Series Chipset SATA Controller [1022:43f6]
\-16.0 Loongson Technology LLC 7A1000 Chipset SPI Controller [0014:7a0b]--- drivers/pci/controller/pci-loongson.c | 31 ++++++++++++++------------- 1 file changed, 16 insertions(+), 15 deletions(-)
drivers/pci/controller/pci-loongson.c +16 -15
@@ -80,6 +80,18 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_LOONGSON,DECLARE_PCI_FIXUP_EARLY (PCI_VENDOR_ID_LOONGSON ,DEV_LS7A_LPC , system_bus_quirk); +static const struct pci_device_id loongson_internal_bridge_devids[] = { + {PCI_VDEVICE (LOONGSON ,DEV_LS2K_PCIE_PORT0 ) }, + {PCI_VDEVICE (LOONGSON ,DEV_LS7A_PCIE_PORT0 ) }, + {PCI_VDEVICE (LOONGSON ,DEV_LS7A_PCIE_PORT1 ) }, + {PCI_VDEVICE (LOONGSON ,DEV_LS7A_PCIE_PORT2 ) }, + {PCI_VDEVICE (LOONGSON ,DEV_LS7A_PCIE_PORT3 ) }, + {PCI_VDEVICE (LOONGSON ,DEV_LS7A_PCIE_PORT4 ) }, + {PCI_VDEVICE (LOONGSON ,DEV_LS7A_PCIE_PORT5 ) }, + {PCI_VDEVICE (LOONGSON ,DEV_LS7A_PCIE_PORT6 ) }, + {0 , }, +}; +/* * Some Loongson PCIe ports have hardware limitations on their Maximum Read * Request Size. They can't handle anything larger than this. Sane
@@ -92,24 +104,13 @@ static void loongson_set_min_mrrs_quirk(struct pci_dev *pdev) {struct pci_bus *bus = pdev->bus;struct pci_dev *bridge; -static const struct pci_device_id bridge_devids[] = { - {PCI_VDEVICE (LOONGSON ,DEV_LS2K_PCIE_PORT0 ) }, - {PCI_VDEVICE (LOONGSON ,DEV_LS7A_PCIE_PORT0 ) }, - {PCI_VDEVICE (LOONGSON ,DEV_LS7A_PCIE_PORT1 ) }, - {PCI_VDEVICE (LOONGSON ,DEV_LS7A_PCIE_PORT2 ) }, - {PCI_VDEVICE (LOONGSON ,DEV_LS7A_PCIE_PORT3 ) }, - {PCI_VDEVICE (LOONGSON ,DEV_LS7A_PCIE_PORT4 ) }, - {PCI_VDEVICE (LOONGSON ,DEV_LS7A_PCIE_PORT5 ) }, - {PCI_VDEVICE (LOONGSON ,DEV_LS7A_PCIE_PORT6 ) }, - {0 , }, - };/* look for the matching bridge */ while (!pci_is_root_bus (bus)) { bridge = bus->self; bus = bus->parent; -if (pci_match_id (bridge_devids, bridge)) { +if (pci_match_id (loongson_internal_bridge_devids, bridge)) {if (pcie_get_readrq (pdev) >256 ) {pci_info (pdev,"limiting MRRS to 256\n" );pcie_set_readrq (pdev,256 );
@@ -230,11 +231,11 @@ static void __iomem *pci_loongson_map_bus(struct pci_bus *bus,struct loongson_pci *priv =pci_bus_to_loongson_pci (bus);/* -* Do not read more than one device on the bus other than -* the host bus. +* Do not read more than one device on the internal bridges. */ if ((priv->data->flags &FLAG_DEV_FIX ) && bus->self) { -if (!pci_is_root_bus (bus) && (device >0 )) +if (!pci_is_root_bus (bus) && (device >0 ) && +pci_match_id (loongson_internal_bridge_devids, bus->self))return NULL ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 614/1266 bus: mhi: ep: Fix potential deadlock in mhi_ep_reset_worker()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sumit Kumar <[email protected]>
[ Upstream commit 9dece4435d396e9877e27483552b910ba8654169 ]
There is a potential deadlock scenario in mhi_ep_reset_worker() where the state_lock mutex is acquired twice in the same call chain:
mhi_ep_reset_worker()
mutex_lock(&mhi_cntrl->state_lock)
mhi_ep_power_up()
mhi_ep_set_ready_state()
mutex_lock(&mhi_cntrl->state_lock) <- DeadlockFix this by releasing the state_lock before calling mhi_ep_power_up(). The lock is only needed to protect current MHI state read operation. The lock can be safely released before proceeding with the power up sequence.
--- drivers/bus/mhi/ep/main.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-)
drivers/bus/mhi/ep/main.c +3 -4
@@ -1071,11 +1071,12 @@ static void mhi_ep_reset_worker(struct work_struct *work)mhi_ep_power_down (mhi_cntrl); -mutex_lock (&mhi_cntrl->state_lock); -/* Reset MMIO to signal host that the MHI_RESET is completed in endpoint */ mhi_ep_mmio_reset (mhi_cntrl); + +mutex_lock (&mhi_cntrl->state_lock); cur_state = mhi_cntrl->mhi_state; +mutex_unlock (&mhi_cntrl->state_lock);/* * Only proceed further if the reset is due to SYS_ERR. The host will
@@ -1084,8 +1085,6 @@ static void mhi_ep_reset_worker(struct work_struct *work)*/ if (cur_state ==MHI_STATE_SYS_ERR )mhi_ep_power_up (mhi_cntrl); - -mutex_unlock (&mhi_cntrl->state_lock); }/*
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 615/1266 phy: phy-can-transceiver: Check driver match and driver data against NULL
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Andy Shevchenko <[email protected]>
[ Upstream commit ebee9004cc0200b2b708ebf7ac625d35c71c049f ]
Every platform driver can be forced to match a device that doesn't match its list of device IDs because of device_match_driver_override() so platform drivers that rely on the existence of a device's driver data need to verify its presence.
Accordingly, add requisite match and driver data checks against NULL to the driver where they are missing.
--- drivers/phy/phy-can-transceiver.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/phy/phy-can-transceiver.c +3 -0
@@ -111,6 +111,9 @@ static int can_transceiver_phy_probe(struct platform_device *pdev)return -ENOMEM ; match =of_match_node (can_transceiver_phy_ids, pdev->dev.of_node); +if (!match || !match->data) +return -ENODEV ; + drvdata = match->data;if (of_property_read_bool (dev->of_node,"mux-states" )) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 616/1266 perf pmu: Skip test on Arm64 when #slots is zero
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Leo Yan <[email protected]>
[ Upstream commit 2e2ba7d1ea554ee6e9e751a53eebf3e9270b0670 ]
Some Arm64 PMUs expose 'caps/slots' as 0 when the slot count is not implemented, tool_pmu__read_event() currently returns false for this, so metrics that reference #slots are reported as syntax error.
Since the commit 3a61fd866ef9 ("perf expr: Return -EINVAL for syntax error in expr__find_ids()"), these syntax errors are populated as failures and make the PMU metric test fail:
9.3: Parsing of PMU event table metrics:
--- start ---
...
Found metric 'backend_bound'
metric expr 100 * (stall_slot_backend / (#slots * cpu_cycles)) for backend_bound parsing metric: 100 * (stall_slot_backend / (#slots * cpu_cycles)) Failure to read '#slots'
literal: #slots = nan
syntax error
Fail to parse metric or group `backend_bound'
...
---- end(-1) ----
9.3: Parsing of PMU event table metrics : FAILED!
This commit introduces a new function is_expected_broken_metric() to identify broken metrics, and treats metrics containing "#slots" as expected broken when #slots == 0 on Arm64 platforms.
--- tools/perf/tests/pmu-events.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-)
tools/perf/tests/pmu-events.c +22 -2
@@ -15,6 +15,7 @@#include "util/expr.h" #include "util/hashmap.h" #include "util/parse-events.h" +#include "util/tool_pmu.h" #include "metricgroup.h" #include "stat.h"
@@ -804,6 +805,26 @@ struct metric {struct metric_ref metric_ref; }; +static bool is_expected_broken_metric (const struct pmu_metric *pm) +{ +if (!strcmp (pm->metric_name,"M1" ) || !strcmp (pm->metric_name,"M2" ) || + !strcmp (pm->metric_name,"M3" )) +return true; + +#if defined(__aarch64__) +/* +* Arm64 platforms may return "#slots == 0", which is treated as a +* syntax error by the parser. Don't test these metrics when running +* on such platforms. +*/ +if (strstr (pm->metric_expr,"#slots" ) && + !tool_pmu__cpu_slots_per_cycle ()) +return true; +#endif + +return false; +} +static int test__parsing_callback (const struct pmu_metric *pm,const struct pmu_metrics_table *table,void *data)
@@ -842,8 +863,7 @@ static int test__parsing_callback(const struct pmu_metric *pm, err =metricgroup__parse_groups_test (evlist, table, pm->metric_name, &metric_events);if (err) { -if (!strcmp (pm->metric_name,"M1" ) || !strcmp (pm->metric_name,"M2" ) || - !strcmp (pm->metric_name,"M3" )) { +if (is_expected_broken_metric (pm)) { (*failures)--;pr_debug ("Expected broken metric %s skipping\n" , pm->metric_name); err =0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 617/1266 mailbox: mtk-adsp: fix UAF during device teardown
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sergey Senozhatsky <[email protected]>
[ Upstream commit b57d1a40bc43258372fa1f4d39305e093947a262 ]
When the SOF audio driver fails to initialize (e.g. firmware boot timeout), its devres unwind frees the snd_sof_dev object that the mailbox client (mtk-adsp-ipc) reaches via chan->cl->rx_callback. The mtk-adsp-mailbox shutdown clears the mailbox command registers but leaves the IRQ line unmasked, so a late interrupt can still queue a threaded handler after mbox_free_channel() had cleared chan->cl, and mbox_chan_received_data() would then trigger UAF:
BUG: KASAN: slab-use-after-free in sof_ipc3_validate_fw_version sof_ipc3_validate_fw_version sof_ipc3_do_rx_work sof_ipc3_rx_msg mt8196_dsp_handle_request mtk_adsp_ipc_recv mbox_chan_received_data mtk_adsp_mbox_isr irq_thread_fn Freed by task ...: kfree devres_release_all really_probe ... (sof-audio-of-mt8196 probe failure)
The crash was observed roughly three seconds after the failed probe.
disable_irq() in shutdown and enable_irq() in startup. disable_irq() also waits for any in-flight interrupts, so by the time mbox_free_channel() proceeds to clear chan->cl no rx_callback can run.
In addition, request the IRQ with IRQF_NO_AUTOEN so it stays masked between probe and the first client bind — otherwise an early interrupt can crash on chan->cl == NULL in mbox_chan_received_data().
--- drivers/mailbox/mtk-adsp-mailbox.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
drivers/mailbox/mtk-adsp-mailbox.c +8 -1
@@ -19,6 +19,7 @@ struct mtk_adsp_mbox_priv {struct mbox_controller mbox;void __iomem *va_mboxreg;const struct mtk_adsp_mbox_cfg *cfg; +int irq; };struct mtk_adsp_mbox_cfg {
@@ -67,6 +68,8 @@ static int mtk_adsp_mbox_startup(struct mbox_chan *chan)writel (0xFFFFFFFF , priv->va_mboxreg + priv->cfg->clr_in);writel (0xFFFFFFFF , priv->va_mboxreg + priv->cfg->clr_out); +enable_irq (priv->irq); +return 0 ; }
@@ -74,6 +77,8 @@ static void mtk_adsp_mbox_shutdown(struct mbox_chan *chan) {struct mtk_adsp_mbox_priv *priv =get_mtk_adsp_mbox_priv (chan->mbox); +disable_irq (priv->irq); +/* Clear ADSP mbox command */ writel (0xFFFFFFFF , priv->va_mboxreg + priv->cfg->clr_in);writel (0xFFFFFFFF , priv->va_mboxreg + priv->cfg->clr_out);
@@ -139,8 +144,10 @@ static int mtk_adsp_mbox_probe(struct platform_device *pdev)if (irq <0 )return irq; + priv->irq = irq; ret =devm_request_threaded_irq (dev, irq, mtk_adsp_mbox_irq, - mtk_adsp_mbox_isr,IRQF_TRIGGER_NONE , + mtk_adsp_mbox_isr, +IRQF_TRIGGER_NONE |IRQF_NO_AUTOEN ,dev_name (dev), mbox->chans);if (ret <0 )return ret;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 618/1266 staging: most: video: avoid double free on video register failure
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guangshuo Li <[email protected]>
[ Upstream commit 7cb1c5b32a2bfde961fff8d5204526b609bcb30a ]
comp_register_videodev() allocates a video_device with video_device_alloc() and releases it if video_register_device() fails.
This can double free the video_device when __video_register_device() reaches device_register() and that call fails:
video_register_device()
-> __video_register_device()
-> device_register() fails
-> put_device(&vdev->dev)
-> v4l2_device_release()
-> vdev->release(vdev)
-> video_device_release(vdev) comp_register_videodev()
-> video_device_release(mdev->vdev)
Use video_device_release_empty() while registering the device so that registration failure paths do not free mdev->vdev through vdev->release(). comp_register_videodev() then releases mdev->vdev exactly once on failure. Restore video_device_release() after successful registration so the registered device keeps its normal lifetime handling.
This issue was found by a static analysis tool I am developing.
--- drivers/staging/most/video/video.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
drivers/staging/most/video/video.c +6 -1
@@ -415,6 +415,7 @@ static int comp_register_videodev(struct most_video_dev *mdev)/* Fill the video capture device struct */ *mdev->vdev = comp_videodev_template; + mdev->vdev->release = video_device_release_empty; mdev->vdev->v4l2_dev = &mdev->v4l2_dev; mdev->vdev->lock = &mdev->lock; snprintf(mdev->vdev->name, sizeof(mdev->vdev->name), "MOST: %s",
@@ -427,9 +428,13 @@ static int comp_register_videodev(struct most_video_dev *mdev)v4l2_err (&mdev->v4l2_dev,"video_register_device failed (%d)\n" , ret);video_device_release (mdev->vdev); +return ret; } -return ret; + mdev->vdev->release = video_device_release; + +return 0 ; + }static void comp_unregister_videodev (struct most_video_dev *mdev)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 619/1266 usb: host: max3421: Fix shift-out-of-bounds in max3421_hub_control()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Seungjin Bae <[email protected]>
[ Upstream commit cff06b03b530ae1fe8a13e93a7848f2130e00fb4 ]
The max3421_hub_control() function handles USB hub class requests to the virtual root hub. In the default branches of both the ClearPortFeature and SetPortFeature switch statements, it modifies max3421_hcd->port_status by left shifting 1 by the request's value parameter. However, it does not validate whether this shift will exceed the width of port_status.
So if a malicious userspace task with access to the root hub via /dev/bus/usb/.../001 issues a USBDEVFS_CONTROL ioctl with wValue greater than or equal to 32, the left shift operation invokes shift-out-of-bounds undefined behavior. This results in arbitrary bit corruption of port_status, including the normally-immutable change bits, which can bypass internal state checks and confuse the hub status.
Fix this by rejecting requests whose value exceeds the shift width before performing the shift.
This issue was found using a KLEE-based symbolic execution tool for kernel drivers that I'm currently developing.
--- drivers/usb/host/max3421-hcd.c | 4 ++++ 1 file changed, 4 insertions(+)
drivers/usb/host/max3421-hcd.c +4 -0
@@ -1694,6 +1694,8 @@ max3421_hub_control(struct usb_hcd *hcd, u16 type_req, u16 value, u16 index, !pdata->vbus_active_level); fallthrough;default : +if (value >=32 ) + goto error; max3421_hcd->port_status &= ~(1 << value); }break ;
@@ -1747,6 +1749,8 @@ max3421_hub_control(struct usb_hcd *hcd, u16 type_req, u16 value, u16 index,max3421_reset_port (hcd); fallthrough;default : +if (value >=32 ) + goto error;if ((max3421_hcd->port_status &USB_PORT_STAT_POWER ) !=0 ) max3421_hcd->port_status |= (1 << value);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 620/1266 usb: host: max3421: Reject hub port requests for non-existent ports
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Seungjin Bae <[email protected]>
[ Upstream commit 11b5c101e2fd206104b05bc92554d356989423a8 ]
The max3421_hub_control() function handles USB hub class requests to the virtual root hub. The GetPortStatus case correctly rejects requests with index != 1, since the virtual root hub has only a single port. However, the ClearPortFeature and SetPortFeature cases lack the same check.
Fix this by extending the index != 1 rejection to both cases, matching the existing behavior of GetPortStatus.
--- drivers/usb/host/max3421-hcd.c | 4 ++++ 1 file changed, 4 insertions(+)
drivers/usb/host/max3421-hcd.c +4 -0
@@ -1685,6 +1685,8 @@ max3421_hub_control(struct usb_hcd *hcd, u16 type_req, u16 value, u16 index,case ClearHubFeature:break ;case ClearPortFeature: +if (index !=1 ) + goto error;switch (value) {case USB_PORT_FEAT_SUSPEND :break ;
@@ -1728,6 +1730,8 @@ max3421_hub_control(struct usb_hcd *hcd, u16 type_req, u16 value, u16 index,break ;case SetPortFeature: +if (index !=1 ) + goto error;switch (value) {case USB_PORT_FEAT_LINK_STATE :case USB_PORT_FEAT_U1_TIMEOUT :
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 621/1266 char: tlclk: fix use-after-free in tlclk_cleanup()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: James Kim <[email protected]>
[ Upstream commit bbf003b7794d6ad6f939fdd29f1f1bde8ac554c1 ]
This patch improves the module cleanup process in the tlclk driver to prevent potential use-after-free and race conditions.
Currently, the file_operations structure does not specify the .owner field, which could allow the module to be unloaded while user-space processes are still interacting with the device. Additionally, the tlclk_cleanup() function frees the alarm_events memory before ensuring that blocked processes in the waitqueue are fully awakened and that the switchover_timer has completed.
To address these cases, this patch:
- Sets '.owner = THIS_MODULE' in tlclk_fops to safely defer module unloading while the device is in use.
- Updates tlclk_cleanup() to explicitly wake up all blocked readers (wake_up_all), properly release hardware I/O regions, and safely delete the timer (timer_delete_sync) prior to freeing memory.
--- drivers/char/tlclk.c | 4 ++++ 1 file changed, 4 insertions(+)
drivers/char/tlclk.c +4 -0
@@ -263,6 +263,7 @@ static ssize_t tlclk_read(struct file *filp, char __user *buf, size_t count, }static const struct file_operations tlclk_fops = { + .owner =THIS_MODULE , .read = tlclk_read, .open = tlclk_open, .release = tlclk_release,
@@ -852,6 +853,9 @@ static void __exit tlclk_cleanup(void)misc_deregister (&tlclk_miscdev);unregister_chrdev (tlclk_major,"telco_clock" ); + got_event =1 ; +wake_up_all (&wq); +release_region (TLCLK_BASE ,8 );del_timer_sync (&switchover_timer);kfree (alarm_events);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 622/1266 perf header: Sanity check HEADER_EVENT_DESC attr.size before swap
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit 944f65c8b8231d26d4db6be67bcb641142603cb4 ]
read_event_desc() reads nre (event count), sz (attr size), and nr (IDs per event) from the file and uses them to control allocations and loops without validating them against the section size.
A crafted perf.data could trigger large allocations or many loop iterations before __do_read() eventually rejects the reads.
Add bounds checks in read_event_desc():
- Reject sz smaller than PERF_ATTR_SIZE_VER0.
- Require at least one event (nre > 0).
- Check that nre events fit in the remaining section, using the minimum per-event footprint of sz + sizeof(u32).
- Pre-swap attr->size to native byte order, then reject values below PERF_ATTR_SIZE_VER0 or above sz before calling perf_event__attr_swap() to prevent heap out-of-bounds access.
- Handle ABI0 (attr.size == 0): substitute PERF_ATTR_SIZE_VER0, and on native-endian files write the value back so free_event_desc() does not treat the zero as its end-of-array sentinel (it iterates while attr.size != 0). The swap path skips the write-back — perf_event__attr_swap() has its own ABI0 fallback that sets VER0 after swapping.
- Check that nr IDs fit in the remaining section before allocating.
--- tools/perf/util/header.c | 54 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+)
tools/perf/util/header.c +54 -0
@@ -1940,9 +1940,28 @@ static struct evsel *read_event_desc(struct feat_fd *ff)if (do_read_u32 (ff, &nre)) goto error; +/* Size of each of the nre attributes. */ if (do_read_u32 (ff, &sz)) goto error; +/* +* Require at least one event with an attr no smaller than the +* first published struct, and reject sz values where +* sz + sizeof(u32) would overflow size_t (possible on 32-bit) +* or nre == UINT32_MAX where nre + 1 wraps to 0 in the calloc. +* +* The minimum section footprint per event is sz bytes for the +* attr plus a u32 for the id count, check that nre events fit. +*/ +if (!nre || sz <PERF_ATTR_SIZE_VER0 || + sz > ff->size || (size_t )sz >SIZE_MAX -sizeof (u32) || + nre ==UINT32_MAX || + nre > (ff->size - ff->offset) / (sz +sizeof (u32))) { +pr_err ("Invalid HEADER_EVENT_DESC: nre=%u sz=%u (min %d)\n" , + nre, sz,PERF_ATTR_SIZE_VER0 ); + goto error; + } +/* buffer to hold on file attr struct */ buf =malloc (sz);if (!buf)
@@ -1958,6 +1977,9 @@ static struct evsel *read_event_desc(struct feat_fd *ff) msz = sz;for (i =0 , evsel = events; i < nre; evsel++, i++) { +struct perf_event_attr *attr = buf; +u32 attr_size; + evsel->core.idx = i;/*
@@ -1967,6 +1989,32 @@ static struct evsel *read_event_desc(struct feat_fd *ff)if (__do_read (ff, buf, sz)) goto error; +/* Reject before attr_swap to prevent OOB via bswap_safe() */ + attr_size = ff->ph->needs_swap ?bswap_32 (attr->size) : attr->size; +/* ABI0: size == 0 means the producer didn't set it */ +if (!attr_size) { + attr_size =PERF_ATTR_SIZE_VER0 ; +/* +* Write back so free_event_desc() doesn't +* treat this event as the end-of-array sentinel +* (it iterates while attr.size != 0). +* +* Only for native — the swap path must NOT +* write native-endian VER0 here because +* perf_event__attr_swap() would re-swap it +* to 0x40000000, defeating bswap_safe() bounds. +* perf_event__attr_swap() has its own ABI0 +* fallback that sets VER0 after swapping. +*/ +if (!ff->ph->needs_swap) + attr->size = attr_size; + } +if (attr_size <PERF_ATTR_SIZE_VER0 || attr_size > sz) { +pr_err ("Event %d attr.size (%u) invalid (min: %d, max: %u)\n" , + i, attr_size,PERF_ATTR_SIZE_VER0 , sz); + goto error; + } +if (ff->ph->needs_swap)perf_event__attr_swap (buf);
@@ -1988,6 +2036,12 @@ static struct evsel *read_event_desc(struct feat_fd *ff)if (!nr)continue ; +/* Prevent oversized allocation from crafted nr */ +if (nr > (ff->size - ff->offset) /sizeof (*id)) { +pr_err ("Event %d: id count %u exceeds remaining section\n" , i, nr); + goto error; + } + id =calloc (nr,sizeof (*id));if (!id) goto error;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 623/1266 iio: light: si1133: reset counter to prevent race condition
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Joshua Crofts <[email protected]>
[ Upstream commit 0a5f45ed2342aabae1e32c72558d15be28940a95 ]
Sashiko reported a potential race condition happening when the driver returns an errno after a timeout in the si1133_command() function. The premature exit causes the hardware and software counters to become out of sync by not updating data->rsp_seq, therefore the internal hardware counter keeps incrementing.
Fix this by adding a call to si1133_cmd_reset_counter() before returning from timeout.
--- drivers/iio/light/si1133.c | 5 +++++ 1 file changed, 5 insertions(+)
drivers/iio/light/si1133.c +5 -0
@@ -427,6 +427,11 @@ static int si1133_command(struct si1133_data *data, u8 cmd)dev_warn (dev,"Failed to read command 0x%02x, ret=%d\n" , cmd, err); +/* +* Reset counter on err to prevent software and hardware +* counters being out of sync. +*/ +si1133_cmd_reset_counter (data); goto out; } }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 624/1266 iio: light: si1133: prevent race condition on timeout
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Joshua Crofts <[email protected]>
[ Upstream commit 8c50a95ceb230d17801758a9e41ffbbbe46f8b4d ]
Sashiko reported a bug where the si1133_command exits on timeout without halting the sensor or masking the interrupt. If the sensor completes the command later, any subsequent command to the sensor will cause the IRQ handler to complete immediately, returning stale data to the driver all while the command hasn't finished yet, shifting all potential reads in the future.
Fix this by masking the IRQ if wait_for_completion_timeout() fails. When initiating a new command, do a dummy read of the IRQ_STATUS register and turn the IRQ back on.
--- drivers/iio/light/si1133.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
drivers/iio/light/si1133.c +8 -1
@@ -395,8 +395,14 @@ static int si1133_command(struct si1133_data *data, u8 cmd) expected_seq = (data->rsp_seq +1 ) &SI1133_MAX_CMD_CTR ; -if (cmd ==SI1133_CMD_FORCE ) +if (cmd ==SI1133_CMD_FORCE ) { +/* Flush pending IRQs from a previous timeout. */ +regmap_read (data->regmap,SI1133_REG_IRQ_STATUS , &resp); +regmap_write (data->regmap,SI1133_REG_IRQ_ENABLE , +SI1133_IRQ_CHANNEL_ENABLE ); +reinit_completion (&data->completion); + } err =regmap_write (data->regmap,SI1133_REG_COMMAND , cmd);if (err) {
@@ -409,6 +415,7 @@ static int si1133_command(struct si1133_data *data, u8 cmd)/* wait for irq */ if (!wait_for_completion_timeout (&data->completion,msecs_to_jiffies (SI1133_COMPLETION_TIMEOUT_MS ))) { +regmap_write (data->regmap,SI1133_REG_IRQ_ENABLE ,0 ); err = -ETIMEDOUT ; goto out; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 625/1266 iio: magnetometer: ak8975: fix potential kernel stack memory leak
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Joshua Crofts <[email protected]>
[ Upstream commit a9a00d727b7bbc5e913a919530a9dd468935bf95 ]
Currently in the AK8975 driver there are four instances where potential uninitialized kernel stack memory leaks can occur. If i2c_smbus_read_i2c_block_data_or_emulated() returns a value less than the size of the buffer, uninitialized bytes are retained in the buffer and later the buffer is passed on to IIO buffers, potentially leaking memory to userspace.
Fix this by adding checks whether the return value of the function is equal to the size of the buffer and subsequently if the value is lesser than zero to distinguish from a returned error code.
--- drivers/iio/magnetometer/ak8975.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+)
drivers/iio/magnetometer/ak8975.c +14 -0
@@ -464,6 +464,10 @@ static int ak8975_who_i_am(struct i2c_client *client,dev_err (&client->dev,"Error reading WIA\n" );return ret; } +if (ret !=sizeof (wia_val)) { +dev_err (&client->dev,"Error reading WIA\n" ); +return -EIO ; + }if (wia_val[0 ] !=AK8975_DEVICE_ID )return -ENODEV ;
@@ -580,6 +584,10 @@ static int ak8975_setup(struct i2c_client *client)dev_err (&client->dev,"Not able to read asa data\n" );return ret; } +if (ret !=sizeof (data->asa)) { +dev_err (&client->dev,"Error reading asa data\n" ); +return -EIO ; + }/* After reading fuse ROM data set power-down mode */ ret =ak8975_set_mode (data,POWER_DOWN );
@@ -719,6 +727,10 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val) sizeof(rval), (u8*)&rval);if (ret <0 ) goto exit; +if (ret !=sizeof (rval)) { + ret = -EIO ; + goto exit; + }/* Read out ST2 for release lock on measurment data. */ ret =i2c_smbus_read_byte_data (client, data->def->ctrl_regs[ST2 ]);
@@ -848,6 +860,8 @@ static void ak8975_fill_buffer(struct iio_dev *indio_dev) (u8 *)fval);if (ret <0 ) goto unlock; +if (ret !=sizeof (fval)) + goto unlock;mutex_unlock (&data->lock);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 626/1266 iio: adc: xilinx-ams: fix out-of-bounds channel lookup in event handling
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guilherme Ivo Bozi <[email protected]>
[ Upstream commit 947eb6f0a274f8b15a0248051a65b069effd5057 ]
ams_event_to_channel() may return a pointer past the end of dev->channels when no matching scan_index is found. This can lead to invalid memory access in ams_handle_event().
Add a bounds check in ams_event_to_channel() and return NULL when no channel is found. Also guard the caller to safely handle this case.
--- drivers/iio/adc/xilinx-ams.c | 5 +++++ 1 file changed, 5 insertions(+)
drivers/iio/adc/xilinx-ams.c +5 -0
@@ -861,6 +861,9 @@ static const struct iio_chan_spec *ams_event_to_channel(struct iio_dev *dev,if (dev->channels[i].scan_index == scan_index)break ; +if (i == dev->num_channels) +return NULL ; +return &dev->channels[i]; }
@@ -1002,6 +1005,8 @@ static void ams_handle_event(struct iio_dev *indio_dev, u32 event)const struct iio_chan_spec *chan; chan =ams_event_to_channel (indio_dev, event); +if (!chan) +return ;if (chan->type ==IIO_TEMP ) {/*
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 627/1266 iio: accel: mma8452: handle I2C read error(s) in mma8452_read()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sanjay Chitroda <[email protected]>
[ Upstream commit 5bdff291d20c31b365d9ddfe9c426fbfb41da5bb ]
Currently, If i2c_smbus_read_i2c_block_data() fails but mma8452_set_runtime_pm_state() succeeds, mma8452_read() returns 0.
As a result, the caller mma8452_read_raw() assumes the read was successful and proceeds to use a buffer containing uninitialized stack memory.
Add proper checking of the I2C read return value and propagate errors to the caller.
--- drivers/iio/accel/mma8452.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/iio/accel/mma8452.c +2 -0
@@ -254,6 +254,8 @@ static int mma8452_read(struct mma8452_data *data, __be16 buf[3]) ret =i2c_smbus_read_i2c_block_data (data->client,MMA8452_OUT_X ,3 *sizeof (__be16), (u8 *)buf); +if (ret <0 ) +return ret; ret =mma8452_set_runtime_pm_state (data->client, false);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 628/1266 iio: tcs3472: power down chip on probe failure
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Aldo Conte <[email protected]>
[ Upstream commit b39f3bb9f5580d19bc0c10dea9224d75fed45f1d ]
If tcs3472_probe() fails after enabling the chip (by writing PON | AEN to the ENABLE register), the error paths return without powering down the device.
Add an 'error_powerdown' label at the end of the cleanup chain that calls tcs3472_powerdown() to power down the chip. The existing label cascade is rerouted to fall through to the new label.
Move tcs3472_powerdown() above tcs3472_probe() so the probe can call it without a forward declaration.
Found by code inspection while reviewing the probe error paths in preparation for the devm_ conversion.
--- drivers/iio/light/tcs3472.c | 38 +++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-)
drivers/iio/light/tcs3472.c +20 -18
@@ -442,6 +442,23 @@ static const struct iio_info tcs3472_info = { .attrs = &tcs3472_attribute_group, }; +static int tcs3472_powerdown (struct tcs3472_data *data) +{ +int ret; +u8 enable_mask =TCS3472_ENABLE_AEN |TCS3472_ENABLE_PON ; + +mutex_lock (&data->lock); + + ret =i2c_smbus_write_byte_data (data->client,TCS3472_ENABLE , + data->enable & ~enable_mask); +if (!ret) + data->enable &= ~enable_mask; + +mutex_unlock (&data->lock); + +return ret; +} +static int tcs3472_probe (struct i2c_client *client) {struct tcs3472_data *data;
@@ -515,7 +532,7 @@ static int tcs3472_probe(struct i2c_client *client) ret =iio_triggered_buffer_setup (indio_dev,NULL , tcs3472_trigger_handler,NULL );if (ret <0 ) -return ret; + goto error_powerdown;if (client->irq) { ret = request_threaded_irq(client->irq, NULL,
@@ -538,23 +555,8 @@ static int tcs3472_probe(struct i2c_client *client)free_irq (client->irq, indio_dev); buffer_cleanup:iio_triggered_buffer_cleanup (indio_dev); -return ret; -} - -static int tcs3472_powerdown (struct tcs3472_data *data) -{ -int ret; -u8 enable_mask =TCS3472_ENABLE_AEN |TCS3472_ENABLE_PON ; - -mutex_lock (&data->lock); - - ret =i2c_smbus_write_byte_data (data->client,TCS3472_ENABLE , - data->enable & ~enable_mask); -if (!ret) - data->enable &= ~enable_mask; - -mutex_unlock (&data->lock); - +error_powerdown: +tcs3472_powerdown (data);return ret; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 629/1266 clk: at91: keep securam node alive while mapping it
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yuho Choi <[email protected]>
[ Upstream commit 22fa1c39ba6fe726b547c877c924379b7fee260a ]
pmc_register_ops() gets an owned reference to the "atmel,sama5d2-securam" node with of_find_compatible_node(). The success path dropped that reference before passing the node to of_iomap(), leaving of_iomap() to consume a node pointer after the caller had released its reference.
Move of_node_put() after of_iomap() so the node remains referenced for the mapping operation. The unavailable-node error path already releases the reference.
--- drivers/clk/at91/pmc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/clk/at91/pmc.c +1 -1
@@ -176,9 +176,9 @@ static int __init pmc_register_ops(void)of_node_put (np);return -ENODEV ; } -of_node_put (np); at91_pmc_backup_suspend =of_iomap (np,0 ); +of_node_put (np);if (!at91_pmc_backup_suspend) {pr_warn ("%s(): unable to map securam\n" , __func__);return -ENOMEM ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 630/1266 HID: logitech-hidpp: remove excess kernel-doc member in hidpp_scroll_counter
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Rosen Penev <[email protected]>
[ Upstream commit f22a5db8a7d38152556f230d6d68e59dbc27971b ]
The @dev member described in the kernel-doc does not exist in the struct. Remove the stale entry.
--- drivers/hid/hid-logitech-hidpp.c | 1 - 1 file changed, 1 deletion(-)
drivers/hid/hid-logitech-hidpp.c +0 -1
@@ -163,7 +163,6 @@ struct hidpp_battery {/** * struct hidpp_scroll_counter - Utility class for processing high-resolution * scroll events. -* @dev: the input device for which events should be reported. * @wheel_multiplier: the scalar multiplier to be applied to each wheel event * @remainder: counts the number of high-resolution units moved since the last * low-resolution event (REL_WHEEL or REL_HWHEEL) was sent. Should
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 631/1266 fs/ntfs3: add bounds check to run_get_highest_vcn()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Konstantin Komarov <[email protected]>
[ Upstream commit bb11485a87fbb2254b62cfed630b699d50e57da8 ]
run_get_highest_vcn() parses a packed NTFS mapping-pairs buffer without any length bound, relying solely on a 0x00 terminator to stop. A crafted $LogFile UpdateMappingPairs record whose embedded attribute contains mapping-pairs runs without a terminator causes the function to read past the slab allocation, triggering a KASAN slab-out-of-bounds read on mount.
The sibling function run_unpack() received an analogous bounds-check in commit b62567bca474 ("ntfs3: add buffer boundary checks to run_unpack()"), but run_get_highest_vcn() was missed.
Take a run_buf_size parameter and reject any run header whose payload would extend past the buffer end, mirroring the pattern used by run_unpack(). The caller in fslog.c passes the remaining attribute bytes after the mapping-pairs offset.
KASAN report (on mainline v7.1 merge window HEAD):
BUG: KASAN: slab-out-of-bounds in run_get_highest_vcn+0x3c0/0x410 Read of size 1 at addr ffff88800e2d5400 by task mount/72 Call Trace: run_get_highest_vcn+0x3c0/0x410 do_action.isra.0+0x3ba8/0x7b50 log_replay+0x9ddd/0x10200 ntfs_loadlog_and_replay+0x4ad/0x610 ntfs_fill_super+0x214a/0x4540
--- fs/ntfs3/fslog.c | 5 ++++- fs/ntfs3/ntfs_fs.h | 3 ++- fs/ntfs3/run.c | 9 +++++++-- 3 files changed, 13 insertions(+), 4 deletions(-)
fs/ntfs3/fslog.c +4 -1
@@ -3364,7 +3364,10 @@ static int do_action(struct ntfs_log *log, struct OPEN_ATTR_ENRTY *oe,memmove (Add2Ptr (attr, aoff), data, dlen);if (run_get_highest_vcn (le64_to_cpu (attr->nres.svcn), -attr_run (attr), &t64)) { +attr_run (attr), +le32_to_cpu (attr->size) - +le16_to_cpu (attr->nres.run_off), + &t64)) { goto dirty_vol; }
fs/ntfs3/ntfs_fs.h +2 -1
@@ -816,7 +816,8 @@ int run_unpack_ex(struct runs_tree *run, struct ntfs_sb_info *sbi, CLST ino,#else #define run_unpack_ex run_unpack#endif -int run_get_highest_vcn (CLST vcn,const u8 *run_buf,u64 *highest_vcn); +int run_get_highest_vcn (CLST vcn,const u8 *run_buf,size_t run_buf_size, +u64 *highest_vcn);int run_clone (const struct runs_tree *run,struct runs_tree *new_run);/* Globals from super.c */
fs/ntfs3/run.c +7 -2
@@ -1155,18 +1155,23 @@ int run_unpack_ex(struct runs_tree *run, struct ntfs_sb_info *sbi, CLST ino,* Return the highest vcn from a mapping pairs array * it used while replaying log file. */ -int run_get_highest_vcn (CLST vcn,const u8 *run_buf,u64 *highest_vcn) +int run_get_highest_vcn (CLST vcn,const u8 *run_buf,size_t run_buf_size, +u64 *highest_vcn) { +const u8 *run_last = run_buf + run_buf_size;u64 vcn64 = vcn;u8 size_size; -while ((size_size = *run_buf &0xF )) { +while (run_buf < run_last && (size_size = *run_buf &0xF )) {u8 offset_size = *run_buf++ >>4 ;u64 len;if (size_size >8 || offset_size >8 )return -EINVAL ; +if (run_buf + size_size + offset_size > run_last) +return -EINVAL ; + len =run_unpack_s64 (run_buf, size_size,0 );if (!len)return -EINVAL ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 632/1266 fs/ntfs3: fix mount failure on 64K page-size kernels
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jamie Nguyen <[email protected]>
[ Upstream commit b7a9125cac8645245d2473c6c0a50e338280ad23 ]
On 64K page-size kernels, mounting NTFS volumes smaller than ~650 MB fails with EINVAL. The issue is in log_replay(): the initial log page size probe uses PAGE_SIZE (65536) instead of DefaultLogPageSize (4096) when PAGE_SIZE exceeds DefaultLogPageSize * 2.
This makes norm_file_page() require the $LogFile to be at least 50 * 65536 = 3.2 MB, but mkfs.ntfs creates a $LogFile of only ~1.5 MB for a typical 300 MB volume. norm_file_page() returns 0 and the mount is rejected with EINVAL.
On 4K kernels the #if guard evaluates to true, so use_default=true is passed and DefaultLogPageSize (4096) is used, requiring only ~200 KB. This path works fine.
Fix this by always passing use_default=true, which forces the initial probe to use DefaultLogPageSize regardless of the kernel's PAGE_SIZE. This is safe because, after reading the on-disk restart area, log_replay() already re-adjusts log->page_size to match the volume's actual sys_page_size.
Also fix read_log_page() to pass log->page_size instead of PAGE_SIZE to ntfs_fix_post_read(), matching the actual buffer size.
--- fs/ntfs3/fslog.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-)
fs/ntfs3/fslog.c +1 -5
@@ -1170,7 +1170,7 @@ static int read_log_page(struct ntfs_log *log, u32 vbo, goto out;if (page_buf->rhdr.sign !=NTFS_FFFF_SIGNATURE ) -ntfs_fix_post_read (&page_buf->rhdr,PAGE_SIZE , false); +ntfs_fix_post_read (&page_buf->rhdr, log->page_size, false);if (page_buf != *buffer)memcpy (*buffer,Add2Ptr (page_buf, page_off), bytes);
@@ -3800,11 +3800,7 @@ int log_replay(struct ntfs_inode *ni, bool *initialized) log->l_size = log->orig_file_size = ni->vfs_inode.i_size;/* Get the size of page. NOTE: To replay we can use default page. */ -#if PAGE_SIZE >= DefaultLogPageSize &&PAGE_SIZE <= DefaultLogPageSize *2 log->page_size =norm_file_page (PAGE_SIZE , &log->l_size, true); -#else - log->page_size =norm_file_page (PAGE_SIZE , &log->l_size, false); -#endif if (!log->page_size) { err = -EINVAL ; goto out;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 633/1266 drm/amd/display: Add missing kdoc for ALLM parameters
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Srinivasan Shanmugam <[email protected]>
[ Upstream commit d4c6ec729fb7a8bf8a27b19bd70a1b945ad93dac ]
Add descriptions for the missing parameters for ALLMEnabled and ALLMValue to keep the function documentation synchronized with the function prototype mod_build_hf_vsif_infopacket().
Fixes the below with gcc W=1:../display/modules/info_packet/info_packet.c:507 function parameter 'ALLMEnabled' not described in 'mod_build_hf_vsif_infopacket' ../display/modules/info_packet/info_packet.c:507 function parameter 'ALLMValue' not described in 'mod_build_hf_vsif_infopacket'
--- drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/gpu/drm/amd/display/modules/info_packet/info_packet.c +2 -0
@@ -447,6 +447,8 @@ void mod_build_vsc_infopacket(const struct dc_stream_state *stream,* * @stream: contains data we may need to construct VSIF (i.e. timing_3d_format, etc.) * @info_packet: output structure where to store VSIF +* @ALLMEnabled: indicates whether ALLM HF-VSIF should be generated +* @ALLMValue: ALLM bit value to advertise in HF-VSIF */ void mod_build_hf_vsif_infopacket (const struct dc_stream_state *stream,struct dc_info_packet *info_packet)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 634/1266 dmaengine: imx-sdma: Refine spba bus searching in probe
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shengjiu Wang <[email protected]>
[ Upstream commit d52d42e2e5d9f13166e81ac837ebb023d1306e61 ]
There are multi spba-busses for i.MX8M* platforms, if only search for the first spba-bus in DT, the found spba-bus may not the real bus of audio devices, which cause issue for sdma p2p case, as the sdma p2p script presently does not deal with the transactions involving two devices connected to the AIPS bus.
Search the SDMA parent node first, which should be the AIPS bus, then search the child node whose compatible string is spba-bus under that AIPS bus for the above multi spba-busses case.
--- drivers/dma/imx-sdma.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/dma/imx-sdma.c +3 -1
@@ -2321,7 +2321,9 @@ static int sdma_probe(struct platform_device *pdev) goto err_register; } - spba_bus =of_find_compatible_node (NULL ,NULL ,"fsl,spba-bus" ); + struct device_node *sdma_parent_np __free(device_node) = of_get_parent(np); + + spba_bus =of_get_compatible_child (sdma_parent_np,"fsl,spba-bus" ); ret =of_address_to_resource (spba_bus,0 , &spba_res);if (!ret) { sdma->spba_start_addr = spba_res.start;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 635/1266 perf: Fix off-by-one stack buffer overflow in kallsyms__parse()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Rui Qi <[email protected]>
[ Upstream commit 68018df3f55eba96a20dd703f5f276a6518f4963 ]
In kallsyms__parse(), the loop reading symbol names iterates with i < sizeof(symbol_name), which allows i to reach sizeof(symbol_name) upon loop exit. The subsequent symbol_name[i] = '\0' then writes one byte past the end of the stack-allocated symbol_name[] array.
Fix this by changing the loop bound to KSYM_NAME_LEN, so the null terminator always lands within the array. The overflow is triggerable by a kallsyms entry with a symbol name of KSYM_NAME_LEN+1 or more characters (e.g., long Rust mangled names or a malicious /proc/kallsyms).
--- tools/lib/symbol/kallsyms.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
tools/lib/symbol/kallsyms.c +4 -1
@@ -60,7 +60,7 @@ int kallsyms__parse(const char *filename, void *arg,read_to_eol (&io);continue ; } -for (i =0 ; i <sizeof (symbol_name); i++) { +for (i =0 ; i <KSYM_NAME_LEN ; i++) { ch =io__get_char (&io);if (ch <0 || ch =='\n' )break ;
@@ -68,6 +68,9 @@ int kallsyms__parse(const char *filename, void *arg, } symbol_name[i] ='\0' ; +if (i ==KSYM_NAME_LEN ) +read_to_eol (&io); + err =process_symbol (arg, symbol_name, symbol_type, start);if (err)break ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 636/1266 perf tools: Guard test_bit from out-of-bounds sample CPU
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit a5498ccf8079fc91c938f122ff9697b0c526b2fd ]
When PERF_SAMPLE_CPU is absent from a perf.data file, sample->cpu is initialized to (u32)-1 by evsel__parse_sample(). Five call sites pass this value directly to test_bit(sample->cpu, cpu_bitmap), reading massively out of bounds past the DECLARE_BITMAP(..., MAX_NR_CPUS) allocation of 4096 bits.
Add a sample->cpu >= MAX_NR_CPUS guard before each test_bit() call, matching the existing safe pattern in builtin-kwork.c. This catches both the (u32)-1 sentinel and any corrupted CPU value exceeding the bitmap size.
--- tools/perf/builtin-annotate.c | 3 ++- tools/perf/builtin-diff.c | 3 ++- tools/perf/builtin-report.c | 3 ++- tools/perf/builtin-sched.c | 6 ++++-- 4 files changed, 10 insertions(+), 5 deletions(-)
tools/perf/builtin-annotate.c +2 -1
@@ -287,7 +287,8 @@ static int process_sample_event(struct perf_tool *tool, goto out_put; } -if (ann->cpu_list && !test_bit (sample->cpu, ann->cpu_bitmap)) +if (ann->cpu_list && (sample->cpu >=MAX_NR_CPUS || + !test_bit (sample->cpu, ann->cpu_bitmap))) goto out_put; if (!al.filtered &&
tools/perf/builtin-diff.c +2 -1
@@ -417,7 +417,8 @@ static int diff__process_sample_event(struct perf_tool *tool, goto out; } -if (cpu_list && !test_bit (sample->cpu, cpu_bitmap)) { +if (cpu_list && (sample->cpu >=MAX_NR_CPUS || + !test_bit (sample->cpu, cpu_bitmap))) { ret =0 ; goto out; }
tools/perf/builtin-report.c +2 -1
@@ -298,7 +298,8 @@ static int process_sample_event(struct perf_tool *tool,if (symbol_conf.hide_unresolved && al.sym ==NULL ) goto out_put; -if (rep->cpu_list && !test_bit (sample->cpu, rep->cpu_bitmap)) +if (rep->cpu_list && (sample->cpu >=MAX_NR_CPUS || + !test_bit (sample->cpu, rep->cpu_bitmap))) goto out_put;if (sort__mode ==SORT_MODE__BRANCH ) {
tools/perf/builtin-sched.c +4 -2
@@ -2085,7 +2085,8 @@ static void timehist_print_sample(struct perf_sched *sched,char nstr[30 ];u64 wait_time; -if (cpu_list && !test_bit (sample->cpu, cpu_bitmap)) +if (cpu_list && (sample->cpu >=MAX_NR_CPUS || + !test_bit (sample->cpu, cpu_bitmap)))return ;timestamp__scnprintf_usec (t, tstr,sizeof (tstr));
@@ -2671,7 +2672,8 @@ static int timehist_sched_change_event(struct perf_tool *tool, }if (!sched->idle_hist ||thread__tid (thread) ==0 ) { -if (!cpu_list ||test_bit (sample->cpu, cpu_bitmap)) +if (!cpu_list || (sample->cpu <MAX_NR_CPUS && +test_bit (sample->cpu, cpu_bitmap)))timehist_update_runtime_stats (tr, t, tprev);if (sched->idle_hist) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 637/1266 perf sched: Replace BUG_ON on invalid CPU with graceful skip
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit 1e2c83f732deb329ebce23e26cbc482f4c4bf194 ]
latency_switch_event(), latency_runtime_event(), and map_switch_event() use BUG_ON(cpu >= MAX_CPUS || cpu < 0) to validate the sample CPU. When PERF_SAMPLE_CPU is absent from the sample type, evsel__parse_sample() initializes sample->cpu to (u32)-1. Casting this to int yields -1, which triggers the BUG_ON and aborts perf sched.
The central CPU validation in perf_session__deliver_event() intentionally preserves the (u32)-1 sentinel for downstream tools like perf script and perf inject, so leaf callbacks must handle it themselves.
Replace the three BUG_ON calls with graceful skips using pr_warning(), matching the existing pattern in process_sched_switch_event() and process_sched_runtime_event() earlier in the same file. Include the file offset for cross-referencing with perf report -D.
Stable-dep-of: 8cbca8a480e1 ("perf sched: Fix NULL dereference in latency_runtime_event")
--- tools/perf/builtin-sched.c | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-)
tools/perf/builtin-sched.c +19 -3
@@ -1154,7 +1154,12 @@ static int latency_switch_event(struct perf_sched *sched,int cpu = sample->cpu, err =-1 ;s64 delta; -BUG_ON (cpu >=MAX_CPUS || cpu <0 ); +/* perf.data is untrusted input — CPU may be absent or corrupted */ +if (cpu >=MAX_CPUS || cpu <0 ) { +pr_warning ("WARNING: at offset %#" PRIx64": out-of-bound sample CPU %d, skipping sample\n" , + sample->file_offset, cpu); +return 0 ; + } timestamp0 = sched->cpu_last_switched[cpu]; sched->cpu_last_switched[cpu] = timestamp;
@@ -1225,7 +1230,13 @@ static int latency_runtime_event(struct perf_sched *sched,if (thread ==NULL )return -1 ; -BUG_ON (cpu >=MAX_CPUS || cpu <0 ); +/* perf.data is untrusted input — CPU may be absent or corrupted */ +if (cpu >=MAX_CPUS || cpu <0 ) { +pr_warning ("WARNING: at offset %#" PRIx64": out-of-bound sample CPU %d, skipping sample\n" , + sample->file_offset, cpu); + err =0 ; + goto out_put; + }if (!atoms) {if (thread_atoms_insert (sched, thread)) goto out_put;
@@ -1596,7 +1607,12 @@ static int map_switch_event(struct perf_sched *sched, struct evsel *evsel,const char *color =PERF_COLOR_NORMAL ;char stimestamp[32 ]; -BUG_ON (this_cpu.cpu >=MAX_CPUS || this_cpu.cpu <0 ); +/* perf.data is untrusted input — CPU may be absent or corrupted */ +if (this_cpu.cpu >=MAX_CPUS || this_cpu.cpu <0 ) { +pr_warning ("WARNING: at offset %#" PRIx64": out-of-bound sample CPU %d, skipping sample\n" , + sample->file_offset, this_cpu.cpu); +return 0 ; + }if (this_cpu.cpu > sched->max_cpu.cpu) sched->max_cpu = this_cpu;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 638/1266 perf sched: Fix NULL dereference in latency_runtime_event
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit 8cbca8a480e15f6326ce94287570993f27a4b2d5 ]
latency_runtime_event() passes the return value of machine__findnew_thread() directly to thread_atoms_search() at line 1216, before checking for NULL at line 1220. thread_atoms_search() calls pid_cmp() which dereferences the thread pointer via thread__tid(), causing a NULL pointer dereference if the allocation fails.
All other callers of thread_atoms_search() in this file (latency_switch_event, latency_wakeup_event, latency_migrate_task_event) correctly check for NULL first.
Move the atoms assignment after the NULL check to match the pattern used by the other callers.
--- tools/perf/builtin-sched.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
tools/perf/builtin-sched.c +3 -1
@@ -1223,13 +1223,15 @@ static int latency_runtime_event(struct perf_sched *sched,const u32 pid =evsel__intval (evsel, sample,"pid" );const u64 runtime =evsel__intval (evsel, sample,"runtime" );struct thread *thread =machine__findnew_thread (machine,-1 , pid); -struct work_atoms *atoms =thread_atoms_search (&sched->atom_root, thread, &sched->cmp_pid); +struct work_atoms *atoms;u64 timestamp = sample->time;int cpu = sample->cpu, err =-1 ;if (thread ==NULL )return -1 ; + atoms =thread_atoms_search (&sched->atom_root, thread, &sched->cmp_pid); +/* perf.data is untrusted input — CPU may be absent or corrupted */ if (cpu >=MAX_CPUS || cpu <0 ) { pr_warning("WARNING: at offset %#" PRIx64 ": out-of-bound sample CPU %d, skipping sample\n",
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 639/1266 perf tools: Add bounds check to cpu__get_node()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit 1e7921d7227de5da0dfc167943092c823ec7e49b ]
cpu__get_node() accesses cpunode_map[cpu.cpu] without checking against max_cpu_num, the allocation size of cpunode_map. Callers such as builtin-kmem.c:evsel__process_alloc_event() pass sample->cpu from perf.data events, which may exceed the host's CPU count when analyzing cross-machine recordings.
Add a bounds check against max_cpu_num before indexing, returning -1 for out-of-range values. This is a central fix that protects all callers.
--- tools/perf/util/cpumap.c | 4 ++++ 1 file changed, 4 insertions(+)
tools/perf/util/cpumap.c +4 -0
@@ -498,6 +498,10 @@ int cpu__get_node(struct perf_cpu cpu)return -1 ; } +/* cpunode_map allocated for max_cpu_num entries; input may be untrusted */ +if (cpu.cpu <0 || cpu.cpu >= max_cpu_num.cpu) +return -1 ; +return cpunode_map[cpu.cpu]; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 640/1266 perf mmap: Guard cpu__get_node() return in aio_bind()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit f32dc302a090f48893477ef297a888db109ec0bd ]
perf_mmap__aio_bind() passes the cpu__get_node() return value directly to an unsigned long variable (node_index). When cpu__get_node() returns -1 for an unknown CPU, the implicit int-to-unsigned-long conversion sign-extends it to ULONG_MAX.
This causes bitmap_zalloc(ULONG_MAX + 1) which wraps to bitmap_zalloc(0), returning a zero-sized allocation. The subsequent __set_bit(ULONG_MAX, node_mask) then writes massively out of bounds.
Check the return value in a signed temporary before assigning to node_index, and skip the NUMA binding when the node is unknown.
--- tools/perf/util/mmap.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
tools/perf/util/mmap.c +7 -1
@@ -103,9 +103,15 @@ static int perf_mmap__aio_bind(struct mmap *map, int idx, struct perf_cpu cpu, iint err =0 ;if (affinity !=PERF_AFFINITY_SYS &&cpu__max_node () >1 ) { +int node; + data = map->aio.data[idx]; mmap_len =mmap__mmap_len (map); - node_index =cpu__get_node (cpu); + node =cpu__get_node (cpu); +/* -1 sign-extends to ULONG_MAX, wrapping bitmap_zalloc(0) and OOB __set_bit */ +if (node <0 ) +return 0 ; + node_index = node; node_mask =bitmap_zalloc (node_index +1 );if (!node_mask) {pr_err ("Failed to allocate node mask for mbind: error %m\n" );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 641/1266 perf c2c: Bounds-check CPU and node IDs before bitmap and array access
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit 65117c3da50f749f4c22eb7a7effc53453dff57f ]
c2c_he__set_cpu() passes sample->cpu directly to __set_bit(cpu, cpuset) after only checking for the (u32)-1 sentinel. The cpuset bitmap is allocated with c2c.cpus_cnt bits (from env->nr_cpus_avail), so a crafted perf.data with CPU IDs exceeding that count causes out-of-bounds heap writes.
c2c_he__set_node() similarly passes the node ID from mem2node__node() to __set_bit(node, nodeset) after only checking for negative values. The nodeset bitmap is sized to c2c.nodes_cnt (from env->nr_numa_nodes), so a node ID exceeding that causes OOB writes.
process_sample_event() indexes c2c.cpu2node[cpu] and c2c_he->node_stats[node] without bounds checking. Both arrays are sized to c2c.cpus_cnt and c2c.nodes_cnt respectively.
Add bounds checks in all three paths:
- c2c_he__set_cpu(): return if sample->cpu >= c2c.cpus_cnt
- c2c_he__set_node(): return if node >= c2c.nodes_cnt
- process_sample_event(): clamp cpu to 0 if >= cpus_cnt, guard node_stats access with bounds check
--- tools/perf/builtin-c2c.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-)
tools/perf/builtin-c2c.c +17 -2
@@ -229,6 +229,10 @@ static void c2c_he__set_cpu(struct c2c_hist_entry *c2c_he, "WARNING: no sample cpu value"))return ; +/* cpuset bitmap has c2c.cpus_cnt bits from env->nr_cpus_avail */ +if (sample->cpu >= (unsigned int )c2c.cpus_cnt) +return ; +__set_bit (sample->cpu, c2c_he->cpuset); }
@@ -246,6 +250,10 @@ static void c2c_he__set_node(struct c2c_hist_entry *c2c_he,if (WARN_ONCE (node <0 ,"WARNING: failed to find node\n" ))return ; +/* nodeset bitmap has c2c.nodes_cnt bits from env->nr_numa_nodes */ +if (node >= c2c.nodes_cnt) +return ; +__set_bit (node, c2c_he->nodeset);if (c2c_he->paddr != sample->phys_addr) {
@@ -345,7 +353,12 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused,* Doing node stats only for single callchain data. */ int cpu = sample->cpu == (unsigned int )-1 ?0 : sample->cpu; -int node = c2c.cpu2node[cpu]; +int node; + +/* cpu2node[] has c2c.cpus_cnt entries; large u32 wraps signed negative */ +if (cpu <0 || cpu >= c2c.cpus_cnt) + cpu =0 ; + node = c2c.cpu2node[cpu]; mi = mi_dup;
@@ -362,7 +375,9 @@ static int process_sample_event(struct perf_tool *tool __maybe_unused, c2c_he = container_of(he, struct c2c_hist_entry, he);c2c_add_stats (&c2c_he->stats, &stats);c2c_add_stats (&c2c_hists->stats, &stats); -c2c_add_stats (&c2c_he->node_stats[node], &stats); +/* node_stats[] has c2c.nodes_cnt entries */ +if (node >=0 && node < c2c.nodes_cnt) +c2c_add_stats (&c2c_he->node_stats[node], &stats);compute_stats (c2c_he, &stats, sample->weight);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 642/1266 perf sched: Clean up idle_threads entry on init failure
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit cda5a94ad9181cd60cbf04be11d524201bf489a2 ]
get_idle_thread() allocates a thread via thread__new() and stores it in idle_threads[cpu], then calls init_idle_thread() to set up the private data. If init_idle_thread() fails (e.g. OOM for the idle_thread_runtime struct), the function returns NULL but leaves the partially initialized thread in idle_threads[cpu].
On subsequent calls for the same CPU, get_idle_thread() finds a non-NULL idle_threads[cpu], skips allocation, and returns thread__get() on a thread that has no priv data. Callers then get a thread whose thread__priv() returns NULL, leading to unexpected behavior.
Release the thread and reset the slot to NULL on init failure so the entry doesn't persist in a corrupted state.
--- tools/perf/builtin-sched.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
tools/perf/builtin-sched.c +4 -1
@@ -2372,8 +2372,11 @@ static struct thread *get_idle_thread(int cpu) idle_threads[cpu] =thread__new (0 ,0 );if (idle_threads[cpu]) { -if (init_idle_thread (idle_threads[cpu]) <0 ) +if (init_idle_thread (idle_threads[cpu]) <0 ) { +/* clean up so next call doesn't find a half-initialized thread */ +thread__zput (idle_threads[cpu]);return NULL ; + } } }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 643/1266 perf sched: Replace BUG_ON and add NULL checks in replay event helpers
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit 75eafe4a3a93a0143a20c0cc286bfb9008ac1478 ]
get_new_event() has three issues:
1. The zalloc() result is dereferenced without a NULL check, crashing on allocation failure.
2. BUG_ON(!task->atoms) kills the process when realloc() fails. Since perf.data is untrusted input, this should be a graceful error.
3. The realloc pattern assigns directly to task->atoms, losing the old pointer on failure. task->nr_events is also incremented before the realloc, leaving corrupted state on failure.
Fix get_new_event() to:
- Check the zalloc() result before dereferencing
- Use a temporary for realloc() to avoid losing the old pointer
- Increment nr_events only after successful realloc
- Return NULL instead of calling BUG_ON on failure
Also fix add_sched_event_wakeup() where zalloc() for wait_sem is passed to sem_init() without a NULL check.
Update all callers (add_sched_event_run, add_sched_event_wakeup, add_sched_event_sleep) to handle NULL returns by returning early. The replay may produce incomplete output on OOM but will not crash.
--- tools/perf/builtin-sched.c | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-)
tools/perf/builtin-sched.c +25 -3
@@ -363,14 +363,25 @@ get_new_event(struct task_desc *task, u64 timestamp)struct sched_atom *event =zalloc (sizeof (*event));unsigned long idx = task->nr_events;size_t size; +struct sched_atom **atoms_p; + +if (event ==NULL ) { +pr_err ("ERROR: sched: failed to allocate event\n" ); +return NULL ; + } event->timestamp = timestamp; event->nr = idx; + size =sizeof (struct sched_atom *) * (task->nr_events +1 ); + atoms_p =realloc (task->atoms, size); +if (!atoms_p) { +pr_err ("ERROR: sched: failed to grow atoms array\n" ); +free (event); +return NULL ; + } + task->atoms = atoms_p; task->nr_events++; - size =sizeof (struct sched_atom *) * task->nr_events; - task->atoms =realloc (task->atoms, size); -BUG_ON (!task->atoms); task->atoms[idx] = event;
@@ -401,6 +412,8 @@ static void add_sched_event_run(struct perf_sched *sched, struct task_desc *task } event =get_new_event (task, timestamp); +if (event ==NULL ) +return ; event->type =SCHED_EVENT_RUN ; event->duration = duration;
@@ -414,6 +427,8 @@ static void add_sched_event_wakeup(struct perf_sched *sched, struct task_desc *tstruct sched_atom *event, *wakee_event; event =get_new_event (task, timestamp); +if (event ==NULL ) +return ; event->type =SCHED_EVENT_WAKEUP ; event->wakee = wakee;
@@ -428,6 +443,10 @@ static void add_sched_event_wakeup(struct perf_sched *sched, struct task_desc *t } wakee_event->wait_sem =zalloc (sizeof (*wakee_event->wait_sem)); +if (!wakee_event->wait_sem) { +pr_err ("ERROR: sched: failed to allocate semaphore\n" ); +return ; + }sem_init (wakee_event->wait_sem,0 ,0 ); wakee_event->specific_wait =1 ; event->wait_sem = wakee_event->wait_sem;
@@ -440,6 +459,9 @@ static void add_sched_event_sleep(struct perf_sched *sched, struct task_desc *ta {struct sched_atom *event =get_new_event (task, timestamp); +if (event ==NULL ) +return ; + event->type =SCHED_EVENT_SLEEP ; sched->nr_sleep_events++;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 644/1266 perf mmap: Fix NULL deref in aio cleanup on alloc failure
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit 25627346b10e6a564610ea2c49dc6dd54812226d ]
perf_mmap__aio_mmap() sets map->aio.nr_cblocks before allocating the data array. If calloc() for aiocb or cblocks fails before the data array is allocated, the return -1 path leads to perf_mmap__aio_munmap() which loops nr_cblocks times calling perf_mmap__aio_free(). Both versions of perf_mmap__aio_free() (NUMA and non-NUMA) dereference map->aio.data[idx] without checking if data is NULL, causing a NULL pointer dereference.
Add NULL checks for map->aio.data at the top of both perf_mmap__aio_free() variants so the cleanup path is safe when allocation fails partway through perf_mmap__aio_mmap().
--- tools/perf/util/mmap.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-)
tools/perf/util/mmap.c +6 -4
@@ -88,10 +88,10 @@ static int perf_mmap__aio_alloc(struct mmap *map, int idx)static void perf_mmap__aio_free (struct mmap *map,int idx) { -if (map->aio.data[idx]) { -munmap (map->aio.data[idx],mmap__mmap_len (map)); - map->aio.data[idx] =NULL ; - } +if (!map->aio.data || !map->aio.data[idx]) +return ; +munmap (map->aio.data[idx],mmap__mmap_len (map)); + map->aio.data[idx] =NULL ; }static int perf_mmap__aio_bind (struct mmap *map,int idx,struct perf_cpu cpu,int affinity)
@@ -140,6 +140,8 @@ static int perf_mmap__aio_alloc(struct mmap *map, int idx)static void perf_mmap__aio_free (struct mmap *map,int idx) { +if (!map->aio.data) +return ;zfree (&(map->aio.data[idx])); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 645/1266 perf c2c: Fix use-after-free in he__get_c2c_hists() error path
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit 5e5e6196d737c5be03d20647428316b36621608d ]
he__get_c2c_hists() assigns c2c_he->hists before calling c2c_hists__init(). If init fails, the error path calls free(hists) but leaves c2c_he->hists pointing to freed memory. On teardown, c2c_he_free() finds the non-NULL pointer and calls hists__delete_entries() on it, causing a use-after-free.
Set c2c_he->hists to NULL before freeing so teardown skips the already-freed allocation.
--- tools/perf/builtin-c2c.c | 1 + 1 file changed, 1 insertion(+)
tools/perf/builtin-c2c.c +1 -0
@@ -215,6 +215,7 @@ he__get_c2c_hists(struct hist_entry *he, ret =c2c_hists__init (hists, sort, nr_header_lines);if (ret) { + c2c_he->hists =NULL ;free (hists);return NULL ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 646/1266 dmaengine: qcom: gpi: set DMA_PRIVATE capability
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Icenowy Zheng <[email protected]>
[ Upstream commit 4e351f408743354d54ee1af5193fc78234f2044e ]
The GPI DMA controller is only responsible for QUP peripherals, and cannot work as a general-purpose DMA accelerator.
Set DMA_PRIVATE capability for it.
This fixes error messages about GPI being shown when an async-tx consumer is loaded.
--- drivers/dma/qcom/gpi.c | 1 + 1 file changed, 1 insertion(+)
drivers/dma/qcom/gpi.c +1 -0
@@ -2252,6 +2252,7 @@ static int gpi_probe(struct platform_device *pdev)/* clear and Set capabilities */ dma_cap_zero (gpi_dev->dma_device.cap_mask);dma_cap_set (DMA_SLAVE , gpi_dev->dma_device.cap_mask); +dma_cap_set (DMA_PRIVATE , gpi_dev->dma_device.cap_mask);/* configure dmaengine apis */ gpi_dev->dma_device.directions =BIT (DMA_DEV_TO_MEM ) |BIT (DMA_MEM_TO_DEV );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 647/1266 dmaengine: Fix possible use after free
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nuno Sá <[email protected]>
[ Upstream commit 92f853f0645aebf1d05d333e97ab7c342ace1892 ]
In dma_release_channel(), check chan->device->privatecnt after call dma_chan_put(). However, dma_chan_put() call dma_device_put() which could release the last reference of the device if the DMA provider is already gone and hence free it.
Fixes it by moving dma_chan_put() after the check.
--- drivers/dma/dmaengine.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/dma/dmaengine.c +2 -1
@@ -905,11 +905,12 @@ void dma_release_channel(struct dma_chan *chan)mutex_lock (&dma_list_mutex);WARN_ONCE (chan->client_count !=1 ,"chan reference count %d != 1\n" , chan->client_count); -dma_chan_put (chan);/* drop PRIVATE cap enabled by __dma_request_channel() */ if (--chan->device->privatecnt ==0 )dma_cap_clear (DMA_PRIVATE , chan->device->cap_mask); +dma_chan_put (chan); +if (chan->slave) {sysfs_remove_link (&chan->dev->device.kobj,DMA_SLAVE_NAME );sysfs_remove_link (&chan->slave->kobj, chan->name);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 648/1266 clk: qcom: a53: Corrected frequency multiplier for 1152MHz
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Phillip Varney <[email protected]>
[ Upstream commit bb56147ea9fce98ebde1d367335ba006cba61fbd ]
The 1152MHz frequency entry for the a53 currently selects a multiplier of 62, giving 1190MHz. This changes the mulitiplier to 60 giving the intended 1152MHz.
--- drivers/clk/qcom/a53-pll.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/clk/qcom/a53-pll.c +1 -1
@@ -20,7 +20,7 @@static const struct pll_freq_tbl a53pll_freq[] = { {998400000 ,52 ,0x0 ,0x1 ,0 }, {1094400000 ,57 ,0x0 ,0x1 ,0 }, - {1152000000 ,62 ,0x0 ,0x1 ,0 }, + {1152000000 ,60 ,0x0 ,0x1 ,0 }, {1209600000 ,63 ,0x0 ,0x1 ,0 }, {1248000000 ,65 ,0x0 ,0x1 ,0 }, {1363200000 ,71 ,0x0 ,0x1 ,0 },
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 649/1266 pNFS/filelayout: fix cheking if a layout is striped
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sagi Grimberg <[email protected]>
[ Upstream commit 91668417d4e925c98cae4a55b1b9860380ddbf16 ]
A layout can still be striped with num_fh = 1 as it is perfectly possible that both MDS and DSs can handle the same filehandle. Hence check according to stripe_count > 1, which is the correct check to begin with.
We should not be called with flseg->dsaddr = NULL, but if for some reason we do, return our best guess with is flseg->num_fh > 1.
--- fs/nfs/filelayout/filelayout.c | 2 ++ 1 file changed, 2 insertions(+)
fs/nfs/filelayout/filelayout.c +2 -0
@@ -786,6 +786,8 @@ filelayout_alloc_lseg(struct pnfs_layout_hdr *layoutid,static bool filelayout_lseg_is_striped (const struct nfs4_filelayout_segment *flseg) { +if (flseg->dsaddr) +return flseg->dsaddr->stripe_count >1 ;return flseg->num_fh >1 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 650/1266 xprtrdma: Remove temp allocation of rpcrdma_rep objects
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit 0e13dd9ea8be46f980a46c3ffd8cb786f3e2fb5b ]
The original code was designed so that most calls to rpcrdma_rep_create() would occur on the NUMA node that the device preferred. There are a few cases where that's not possible, so those reps are marked as temporary.
However, we have the device (and its preferred node) already in rpcrdma_rep_create(), so let's use that to guarantee the memory is allocated from the correct node.
Stable-dep-of: e786233d2e0b ("xprtrdma: Decouple req recycling from RPC completion")
--- net/sunrpc/xprtrdma/rpc_rdma.c | 3 +- net/sunrpc/xprtrdma/verbs.c | 57 ++++++++++++++------------------- net/sunrpc/xprtrdma/xprt_rdma.h | 3 +- 3 files changed, 26 insertions(+), 37 deletions(-)
net/sunrpc/xprtrdma/rpc_rdma.c +1 -2
@@ -1471,8 +1471,7 @@ void rpcrdma_reply_handler(struct rpcrdma_rep *rep) credits =1 ;/* don't deadlock */ else if (credits > r_xprt->rx_ep->re_max_requests) credits = r_xprt->rx_ep->re_max_requests; -rpcrdma_post_recvs (r_xprt, credits + (buf->rb_bc_srv_max_requests <<1 ), - false); +rpcrdma_post_recvs (r_xprt, credits + (buf->rb_bc_srv_max_requests <<1 ));if (buf->rb_credits != credits)rpcrdma_update_cwnd (r_xprt, credits);
net/sunrpc/xprtrdma/verbs.c +24 -33
146 lines not on this page · raw message
net/sunrpc/xprtrdma/xprt_rdma.h +1 -2
@@ -198,7 +198,6 @@ struct rpcrdma_rep {__be32 rr_proc;int rr_wc_flags;u32 rr_inv_rkey; -bool rr_temp;struct rpcrdma_regbuf *rr_rdmabuf;struct rpcrdma_xprt *rr_rxprt;struct rpc_rqst *rr_rqst;
@@ -466,7 +465,7 @@ void rpcrdma_flush_disconnect(struct rpcrdma_xprt *r_xprt, struct ib_wc *wc);int rpcrdma_xprt_connect (struct rpcrdma_xprt *r_xprt);void rpcrdma_xprt_disconnect (struct rpcrdma_xprt *r_xprt); -void rpcrdma_post_recvs (struct rpcrdma_xprt *r_xprt,int needed,bool temp); +void rpcrdma_post_recvs (struct rpcrdma_xprt *r_xprt,int needed);/* * Buffer calls - xprtrdma/verbs.c
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 651/1266 xprtrdma: Avoid 250 ms delay on backlog wakeup
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit 100142093e22b3f7741ac88e94878bb3694e306f ]
Commit a721035477fb ("SUNRPC/xprt: async tasks mustn't block waiting for memory") changed xprt_rdma_alloc_slot() to set tk_status to -ENOMEM so that call_reserveresult() would sleep HZ/4 before retrying. That rationale applies to xprt_dynamic_alloc_slot(), where an immediate retry under memory pressure wastes CPU, but not to the RDMA backlog path: a task woken from the backlog has a slot waiting for it, so the 250 ms rpc_delay adds latency without benefit.
This also aligns the code with the existing kernel-doc for xprt_rdma_alloc_slot(), which already documented %-EAGAIN.
Stable-dep-of: e786233d2e0b ("xprtrdma: Decouple req recycling from RPC completion")
--- net/sunrpc/xprtrdma/transport.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/sunrpc/xprtrdma/transport.c +1 -1
@@ -511,7 +511,7 @@ xprt_rdma_alloc_slot(struct rpc_xprt *xprt, struct rpc_task *task)return ; out_sleep: - task->tk_status = -ENOMEM ; + task->tk_status = -EAGAIN ;xprt_add_backlog (xprt, task); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 652/1266 xprtrdma: Close lost-wakeup race in xprt_rdma_alloc_slot
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit 765bde47fe7f197dabeb12da76831f40d0b20377 ]
xprt_rdma_alloc_slot() and xprt_rdma_free_slot() lack serialization between the buffer pool and the backlog queue. A buffer freed after rpcrdma_buffer_get() finds the pool empty but before rpc_sleep_on() places the task on the backlog is returned to the pool with no waiter to wake, leaving the task stuck on the backlog indefinitely.
After joining the backlog, re-check the pool and route any recovered buffer through xprt_wake_up_backlog(), whose queue lock serializes with concurrent wakeups and avoids double-assignment of slots.
Because xprt_rdma_free_slot() does not hold reserve_lock, the XPRT_CONGESTED double-check in xprt_throttle_congested() is
ineffective: a task can join the backlog through that path after free_slot has already found it empty and cleared the bit. Avoid this by using xprt_add_backlog_noncongested(), which queues the task without setting XPRT_CONGESTED, so every allocation reaches xprt_rdma_alloc_slot() and its post-sleep re-check.
Stable-dep-of: e786233d2e0b ("xprtrdma: Decouple req recycling from RPC completion")
--- include/linux/sunrpc/xprt.h | 2 ++ net/sunrpc/xprt.c | 16 ++++++++++++++++ net/sunrpc/xprtrdma/transport.c | 15 ++++++++++++++- 3 files changed, 32 insertions(+), 1 deletion(-)
include/linux/sunrpc/xprt.h +2 -0
@@ -398,6 +398,8 @@ struct rpc_xprt * xprt_alloc(struct net *net, size_t size, unsigned int max_req);void xprt_free (struct rpc_xprt *);void xprt_add_backlog (struct rpc_xprt *xprt,struct rpc_task *task); +void xprt_add_backlog_noncongested (struct rpc_xprt *xprt, +struct rpc_task *task);bool xprt_wake_up_backlog (struct rpc_xprt *xprt,struct rpc_rqst *req);void xprt_cleanup_ids (void );
net/sunrpc/xprt.c +16 -0
@@ -1651,6 +1651,22 @@ void xprt_add_backlog(struct rpc_xprt *xprt, struct rpc_task *task) }EXPORT_SYMBOL_GPL (xprt_add_backlog); +/** +* xprt_add_backlog_noncongested - queue task on backlog +* @xprt: transport whose backlog queue receives the task +* @task: task to queue +* +* Like xprt_add_backlog, but does not set XPRT_CONGESTED. +* For transports whose free_slot path does not synchronize +* with xprt_throttle_congested via reserve_lock. +*/ +void xprt_add_backlog_noncongested (struct rpc_xprt *xprt, +struct rpc_task *task) +{ +rpc_sleep_on (&xprt->backlog, task, xprt_complete_request_init); +} +EXPORT_SYMBOL_GPL (xprt_add_backlog_noncongested); +static bool __xprt_set_rq (struct rpc_task *task,void *data) {struct rpc_rqst *req = data;
net/sunrpc/xprtrdma/transport.c +14 -1
@@ -512,7 +512,20 @@ xprt_rdma_alloc_slot(struct rpc_xprt *xprt, struct rpc_task *task) out_sleep: task->tk_status = -EAGAIN ; -xprt_add_backlog (xprt, task); +xprt_add_backlog_noncongested (xprt, task); +/* A buffer freed between buffer_get and rpc_sleep_on +* goes back to the pool with no waiter to wake. +* Re-check after joining the backlog to close that gap. +*/ + req =rpcrdma_buffer_get (&r_xprt->rx_buf); +if (req) { +struct rpc_rqst *rqst = &req->rl_slot; + +if (!xprt_wake_up_backlog (xprt, rqst)) { +memset (rqst,0 ,sizeof (*rqst)); +rpcrdma_buffer_put (&r_xprt->rx_buf, req); + } + } }/**
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 653/1266 xprtrdma: Post receive buffers after RPC completion
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit 704f3f640f72db4d44ec5ce3db8d4e150c974bc7 ]
rpcrdma_post_recvs() runs in CQ poll context and its cost falls on the latency-critical path between polling a Receive completion and waking the RPC consumer. Every cycle spent refilling the Receive Queue delays delivery of the reply to the NFS layer.
Move the rpcrdma_post_recvs() call in rpcrdma_reply_handler() to after the RPC has been decoded and completed. The larger batch size from the preceding patch provides sufficient Receive Queue headroom to absorb the brief delay before buffers are replenished.
Stable-dep-of: e786233d2e0b ("xprtrdma: Decouple req recycling from RPC completion")
--- net/sunrpc/xprtrdma/rpc_rdma.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-)
net/sunrpc/xprtrdma/rpc_rdma.c +9 -5
@@ -1471,7 +1471,6 @@ void rpcrdma_reply_handler(struct rpcrdma_rep *rep) credits =1 ;/* don't deadlock */ else if (credits > r_xprt->rx_ep->re_max_requests) credits = r_xprt->rx_ep->re_max_requests; -rpcrdma_post_recvs (r_xprt, credits + (buf->rb_bc_srv_max_requests <<1 ));if (buf->rb_credits != credits)rpcrdma_update_cwnd (r_xprt, credits);
@@ -1490,15 +1489,20 @@ void rpcrdma_reply_handler(struct rpcrdma_rep *rep)/* LocalInv completion will complete the RPC */ else kref_put(&req->rl_kref, rpcrdma_reply_done); -return ; -out_badversion: -trace_xprtrdma_reply_vers_err (rep); - goto out; +out_post: +rpcrdma_post_recvs (r_xprt, + credits + (buf->rb_bc_srv_max_requests <<1 )); +return ; out_norqst:spin_unlock (&xprt->queue_lock);trace_xprtrdma_reply_rqst_err (rep); +rpcrdma_rep_put (buf, rep); + goto out_post; + +out_badversion: +trace_xprtrdma_reply_vers_err (rep); goto out; out_shortreply:
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 654/1266 xprtrdma: Use sendctx DMA state for Send signaling
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit 2797ae7c929610fb2d2303a996a08173fa096730 ]
Send signaling matters only when the prepared Send has page mappings to unmap. Today that test is expressed indirectly with rl_kref, because the Send-side reference is taken only for Sends with mapped SGEs.
Split the SGE DMA unmap loop into its own helper and use sc_unmap_count directly for the signaling decision. This keeps the current behavior but removes one dependency on the old rl_kref semantics before the request lifetime rules are changed.
Stable-dep-of: e786233d2e0b ("xprtrdma: Decouple req recycling from RPC completion")
--- net/sunrpc/xprtrdma/frwr_ops.c | 2 +- net/sunrpc/xprtrdma/rpc_rdma.c | 22 +++++++++++++--------- 2 files changed, 14 insertions(+), 10 deletions(-)
net/sunrpc/xprtrdma/frwr_ops.c +1 -1
@@ -404,7 +404,7 @@ int frwr_send(struct rpcrdma_xprt *r_xprt, struct rpcrdma_req *req) ++num_wrs; } -if ((kref_read (&req->rl_kref) >1 ) || num_wrs > ep->re_send_count) { +if (req->rl_sendctx->sc_unmap_count || num_wrs > ep->re_send_count) { send_wr->send_flags |=IB_SEND_SIGNALED ; ep->re_send_count = min_t(unsigned int, ep->re_send_batch, num_wrs - ep->re_send_count);
net/sunrpc/xprtrdma/rpc_rdma.c +13 -9
@@ -526,19 +526,11 @@ static void rpcrdma_sendctx_done(struct kref *kref) rep->rr_rxprt->rx_stats.reply_waits_for_send++; } -/** -* rpcrdma_sendctx_unmap - DMA-unmap Send buffer -* @sc: sendctx containing SGEs to unmap -* -*/ -void rpcrdma_sendctx_unmap (struct rpcrdma_sendctx *sc) +static void rpcrdma_sendctx_dma_unmap (struct rpcrdma_sendctx *sc) {struct rpcrdma_regbuf *rb = sc->sc_req->rl_sendbuf;struct ib_sge *sge; -if (!sc->sc_unmap_count) -return ; -/* The first two SGEs contain the transport header and * the inline buffer. These are always left mapped so * they can be cheaply re-used.
@@ -547,7 +539,19 @@ void rpcrdma_sendctx_unmap(struct rpcrdma_sendctx *sc) ++sge, --sc->sc_unmap_count)ib_dma_unmap_page (rdmab_device (rb), sge->addr, sge->length,DMA_TO_DEVICE ); +} + +/** +* rpcrdma_sendctx_unmap - DMA-unmap Send buffer +* @sc: sendctx containing SGEs to unmap +* +*/ +void rpcrdma_sendctx_unmap (struct rpcrdma_sendctx *sc) +{ +if (!sc->sc_unmap_count) +return ; +rpcrdma_sendctx_dma_unmap (sc);kref_put (&sc->sc_req->rl_kref, rpcrdma_sendctx_done); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 655/1266 xprtrdma: Decouple req recycling from RPC completion
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit e786233d2e0bbff9a82e43f02ae3a46ab4b08ec3 ]
rl_kref formerly served two distinct lifetimes through a single
refcount: it gated when a Reply could wake its RPC task, and it gated when an rpcrdma_req could return to its free pool. The marshal path took the Send-side reference only when SGEs needed DMA-unmap (sc_unmap_count > 0), which made a Send carrying only pre-registered buffers an exception: the Reply handler dropped rl_kref from 1 to 0 and freed the req while the HCA might still be DMA-reading from its send buffer.
Give rl_kref a narrower job. The RPC layer takes one reference when slot allocation hands a req out. rpcrdma_prepare_send_sges() takes a Send-side reference unconditionally after WR preparation succeeds. xprt_rdma_free_slot() and xprt_rdma_bc_free_rqst() drop the RPC-layer reference; rpcrdma_sendctx_unmap() drops the Send-side reference. The req returns to its free pool only after both owners have signed off.
The existing kref_init(&req->rl_kref) call in rpcrdma_prepare_send_sges() is removed. Initialization moves to the slot-allocation paths (xprt_rdma_alloc_slot and rpcrdma_bc_rqst_get), and the release callback re-arms rl_kref before the req returns to a free pool. A re-init in the marshal path would discard the RPC-layer reference that already exists on entry.
Three invariants follow:
- Any rpcrdma_req held by an rpc_rqst has rl_kref >= 1. xprt_rdma_alloc_slot(), rpcrdma_bc_rqst_get(), and the backlog-wake branch in xprt_rdma_alloc_slot() each kref_init rl_kref before publishing the req. Without this invariant, an RPC task that aborts between slot allocation and marshal (gss_refresh failure or signal during call_connect, for example) would drive xprt_release() -> xprt_rdma_free_slot() -> kref_put against a refcount of zero, saturating refcount_t and stranding the slot.
- The Send-side reference is taken only after WR prep succeeds. A mapping failure in rpcrdma_prepare_send_sges() runs rpcrdma_sendctx_cancel(), which DMA-unmaps the sendctx and clears sc_req without touching rl_kref. The sendctx ring walks in rpcrdma_sendctx_put_locked() and rpcrdma_sendctxs_destroy() skip entries with sc_req == NULL, so a burst of -EIO marshal failures cannot hold reqs off rb_send_bufs.
- The release callback re-arms rl_kref so the next consumer enters with the invariant satisfied.
Replies now complete the RPC directly. rpcrdma_reply_handler() calls rpcrdma_complete_rqst() in place of kref_put on the non-LocalInv branch. The LocalInv branch already completes the RPC from frwr_unmap_async() and is unaffected.
Because Send-side references can now outlive RPC completion, connection teardown drains sendctx entries whose unsignaled Sends never had a later signaled completion to walk the ring. rpcrdma_sendctxs_destroy() walks the active range and runs rpcrdma_sendctx_unmap() on each entry with a non-NULL sc_req before the request buffers are reset, and is moved ahead of rpcrdma_reqs_reset() in rpcrdma_xprt_disconnect() so the reqs are still in their pre-reset state when the Send-side refs are released.
The drain creates a teardown-ordering hazard on the backchannel path. With the new lifetime, releasing a bc_prealloc req from rpcrdma_req_release() re-adds it to bc_pa_list. The disconnect in xprt_rdma_destroy() runs after xprt_destroy_backchannel() has already emptied bc_pa_list, so the drained reqs would otherwise leak. xprt_rdma_destroy() now runs xprt_rdma_bc_destroy(xprt, 0) a second time after the disconnect to reclaim them.
--- net/sunrpc/xprtrdma/backchannel.c | 5 ++- net/sunrpc/xprtrdma/rpc_rdma.c | 47 +++++++++++--------------- net/sunrpc/xprtrdma/transport.c | 55 ++++++++++++++++++++++++++++--- net/sunrpc/xprtrdma/verbs.c | 29 +++++++++++++--- net/sunrpc/xprtrdma/xprt_rdma.h | 2 +- 5 files changed, 97 insertions(+), 41 deletions(-)
net/sunrpc/xprtrdma/backchannel.c +2 -3
@@ -158,9 +158,7 @@ void xprt_rdma_bc_free_rqst(struct rpc_rqst *rqst)rpcrdma_rep_put (&r_xprt->rx_buf, rep); req->rl_reply =NULL ; -spin_lock (&xprt->bc_pa_lock); -list_add_tail (&rqst->rq_bc_pa_list, &xprt->bc_pa_list); -spin_unlock (&xprt->bc_pa_lock); +rpcrdma_req_put (req);xprt_put (xprt); }
@@ -202,6 +200,7 @@ static struct rpc_rqst *rpcrdma_bc_rqst_get(struct rpcrdma_xprt *r_xprt) rqst->rq_xprt = xprt;__set_bit (RPC_BC_PA_IN_USE , &rqst->rq_bc_pa_state);xdr_buf_init (&rqst->rq_snd_buf,rdmab_data (req->rl_sendbuf), size); +kref_init (&req->rl_kref);return rqst; }
net/sunrpc/xprtrdma/rpc_rdma.c +19 -28
105 lines not on this page · raw message
net/sunrpc/xprtrdma/transport.c +50 -5
91 lines not on this page · raw message
net/sunrpc/xprtrdma/verbs.c +25 -4
@@ -65,6 +65,8 @@static int rpcrdma_sendctxs_create (struct rpcrdma_xprt *r_xprt);static void rpcrdma_sendctxs_destroy (struct rpcrdma_xprt *r_xprt); +static unsigned long rpcrdma_sendctx_next (struct rpcrdma_buffer *buf, +unsigned long item);static void rpcrdma_sendctx_put_locked (struct rpcrdma_xprt *r_xprt,struct rpcrdma_sendctx *sc);static int rpcrdma_reqs_setup (struct rpcrdma_xprt *r_xprt);
@@ -566,9 +568,9 @@ void rpcrdma_xprt_disconnect(struct rpcrdma_xprt *r_xprt)rpcrdma_xprt_drain (r_xprt);rpcrdma_reps_unmap (r_xprt); +rpcrdma_sendctxs_destroy (r_xprt);rpcrdma_reqs_reset (r_xprt);rpcrdma_mrs_destroy (r_xprt); -rpcrdma_sendctxs_destroy (r_xprt);if (rpcrdma_ep_put (ep))rdma_destroy_id (id);
@@ -600,6 +602,20 @@ static void rpcrdma_sendctxs_destroy(struct rpcrdma_xprt *r_xprt)if (!buf->rb_sc_ctxs)return ; + +/* The QP is drained, but the final unsignaled Sends might not +* have been walked by a signaled Send completion. Release those +* Send owners before request buffers are reset. +*/ +for (i =rpcrdma_sendctx_next (buf, buf->rb_sc_tail); + i !=rpcrdma_sendctx_next (buf, buf->rb_sc_head); + i =rpcrdma_sendctx_next (buf, i)) { +struct rpcrdma_sendctx *sc = buf->rb_sc_ctxs[i]; + +if (sc && sc->sc_req) +rpcrdma_sendctx_unmap (sc); + } +for (i =0 ; i <= buf->rb_sc_last; i++)kfree (buf->rb_sc_ctxs[i]);kfree (buf->rb_sc_ctxs);
@@ -722,15 +738,20 @@ static void rpcrdma_sendctx_put_locked(struct rpcrdma_xprt *r_xprt,struct rpcrdma_buffer *buf = &r_xprt->rx_buf;unsigned long next_tail; -/* Unmap SGEs of previously completed but unsignaled -* Sends by walking up the queue until @sc is found. +/* Release previously completed but unsignaled Sends by walking +* up the queue until @sc is found. Entries left behind by a +* failed rpcrdma_prepare_send_sges() have sc_req cleared. */ next_tail = buf->rb_sc_tail;do { +struct rpcrdma_sendctx *cur; + next_tail =rpcrdma_sendctx_next (buf, next_tail);/* ORDER: item must be accessed _before_ tail is updated */ -rpcrdma_sendctx_unmap (buf->rb_sc_ctxs[next_tail]); + cur = buf->rb_sc_ctxs[next_tail]; +if (cur->sc_req) +rpcrdma_sendctx_unmap (cur); }while (buf->rb_sc_ctxs[next_tail] != sc);
net/sunrpc/xprtrdma/xprt_rdma.h +1 -1
@@ -408,7 +408,6 @@ struct rpcrdma_stats {/* accessed when receiving a reply */ unsigned long long total_rdma_reply;unsigned long long fixup_copy_count; -unsigned long reply_waits_for_send;unsigned long local_inv_needed;unsigned long nomsg_call_count;unsigned long bcall_count;
@@ -486,6 +485,7 @@ void rpcrdma_buffer_put(struct rpcrdma_buffer *buffers, struct rpcrdma_req *req);void rpcrdma_rep_put (struct rpcrdma_buffer *buf,struct rpcrdma_rep *rep);void rpcrdma_reply_put (struct rpcrdma_buffer *buffers,struct rpcrdma_req *req); +void rpcrdma_req_put (struct rpcrdma_req *req);bool rpcrdma_regbuf_realloc (struct rpcrdma_regbuf *rb,size_t size,gfp_t flags);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 656/1266 NFSv4/pnfs: defer return_range callbacks until after inode unlock
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dai Ngo <[email protected]>
[ Upstream commit 77b160b2d863d37f36b6c38e80a7d259ce939e69 ]
Sometimes unmounting an NFS filesystem mounted with pNFS SCSI layouts triggers the following warning:
BUG: scheduling while atomic: umount.nfs4/...
__schedule_bug+0xbd/0x100
schedule_debug.constprop.0+0x19f/0x220
__schedule+0x10d/0x10a0
schedule+0x74/0x190
schedule_timeout+0xf5/0x220
io_schedule_timeout+0xd5/0x160
__wait_for_common+0x186/0x4b0
blk_execute_rq+0x2ef/0x3a0
scsi_execute_cmd+0x1ff/0x700
sd_pr_out_command.isra.0+0x242/0x380 [sd_mod]
bl_unregister_scsi.constprop.0+0x109/0x3c0 [blocklayoutdriver]
bl_unregister_dev+0x175/0x1c0 [blocklayoutdriver]
bl_free_device+0x1f/0x1b0 [blocklayoutdriver]
bl_free_deviceid_node+0x12/0x30 [blocklayoutdriver]
nfs4_put_deviceid_node+0x171/0x360 [nfsv4]
ext_tree_remove+0x11c/0x1d0 [blocklayoutdriver]
_pnfs_return_layout+0x416/0x900 [nfsv4]
nfs4_evict_inode+0x108/0x130 [nfsv4]
evict+0x316/0x750
dispose_list+0xf1/0x1a0
evict_inodes+0x33f/0x440
generic_shutdown_super+0xc9/0x4e0
kill_anon_super+0x3a/0x90
nfs_kill_super+0x44/0x60 [nfs]
deactivate_locked_super+0xb8/0x1b0
cleanup_mnt+0x25a/0x380
task_work_run+0x13e/0x210
exit_to_user_mode_loop+0x169/0x400
do_syscall_64+0x467/0x1550
entry_SYSCALL_64_after_hwframe+0x76/0x7eThe warning occurs because the block layout driver unregisters the SCSI device while the inode lock is still held. Device unregistration issues a SCSI PR command, which may sleep, resulting in a "scheduling while atomic" warning.
During layout return, ext_tree_remove() invokes the layout driver's return_range callback while holding the inode lock. For block layouts, this callback eventually calls bl_unregister_scsi(), which may block in scsi_execute_cmd() while issuing PR commands to the device.
Fix this by deferring the return_range callbacks until after the inode lock has been released. The layout header reference count is incremented before invoking return_range(), ensuring that the layout header remains valid while the layout driver removes extents from the extent tree.
--- fs/nfs/callback_proc.c | 9 +++++---- fs/nfs/pnfs.c | 4 ++-- 2 files changed, 7 insertions(+), 6 deletions(-)
fs/nfs/callback_proc.c +5 -4
@@ -248,6 +248,7 @@ static u32 initiate_file_draining(struct nfs_client *clp,struct pnfs_layout_hdr *lo;u32 rv =NFS4ERR_NOMATCHING_LAYOUT ;LIST_HEAD (free_me_list); +bool return_range = false; ino =nfs_layout_find_inode (clp, &args->cbl_fh, &args->cbl_stateid);if (IS_ERR (ino)) {
@@ -292,13 +293,13 @@ static u32 initiate_file_draining(struct nfs_client *clp,/* Embrace your forgetfulness! */ rv =NFS4ERR_NOMATCHING_LAYOUT ; -if (NFS_SERVER (ino)->pnfs_curr_ld->return_range) { -NFS_SERVER (ino)->pnfs_curr_ld->return_range (lo, - &args->cbl_range); - } + return_range = true; } unlock:spin_unlock (&ino->i_lock); +if (return_range &&NFS_SERVER (ino)->pnfs_curr_ld->return_range) +NFS_SERVER (ino)->pnfs_curr_ld->return_range (lo, + &args->cbl_range);pnfs_free_lseg_list (&free_me_list);/* Free all lsegs that are attached to commit buckets */ nfs_commit_inode (ino,0 );
fs/nfs/pnfs.c +2 -2
@@ -1375,8 +1375,6 @@ _pnfs_return_layout(struct inode *ino)pnfs_clear_layoutcommit (ino, &tmp_list);pnfs_mark_matching_lsegs_return (lo, &tmp_list, &range,0 ); -if (NFS_SERVER (ino)->pnfs_curr_ld->return_range) -NFS_SERVER (ino)->pnfs_curr_ld->return_range (lo, &range);/* Don't send a LAYOUTRETURN if list was initially empty */ if (!test_bit(NFS_LAYOUT_RETURN_REQUESTED, &lo->plh_flags) ||
@@ -1388,6 +1386,8 @@ _pnfs_return_layout(struct inode *ino) send =pnfs_prepare_layoutreturn (lo, &stateid, &cred,NULL );spin_unlock (&ino->i_lock); +if (NFS_SERVER (ino)->pnfs_curr_ld->return_range) +NFS_SERVER (ino)->pnfs_curr_ld->return_range (lo, &range);if (send) status =pnfs_send_layoutreturn (lo, &stateid, &cred,IOMODE_ANY , true); out_wait_layoutreturn:
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 657/1266 nfs: keep PG_UPTODATE clear after read errors in page groups
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Clark Wang <[email protected]>
[ Upstream commit 3ff72e1cdf5c337b6acfcf3fcef748c5b9a5316b ]
When a read request is split into multiple subrequests, earlier completions may advance PG_UPTODATE state for the page group once their bytes fall within hdr->good_bytes. If a later subrequest in the same group then completes with NFS_IOHDR_ERROR, the read path needs to clear any accumulated PG_UPTODATE state and keep later completions from rebuilding it.
Otherwise, a subsequent successful subrequest can re-enter nfs_page_group_set_uptodate(), restore the page-group sync state, and leave stale PG_UPTODATE behind for nfs_page_group_destroy() to trip over in nfs_free_request().
Add a sticky page-group read-failed flag. Once any subrequest in the group is known to be bad, mark the group failed, clear any accumulated PG_UPTODATE state, and refuse further PG_UPTODATE synchronization for the rest of the completion walk.
--- fs/nfs/read.c | 25 ++++++++++++++++++++++++- include/linux/nfs_page.h | 1 + 2 files changed, 25 insertions(+), 1 deletion(-)
fs/nfs/read.c +24 -1
@@ -134,10 +134,32 @@ static void nfs_readpage_release(struct nfs_page *req, int error)static void nfs_page_group_set_uptodate (struct nfs_page *req) { -if (nfs_page_group_sync_on_bit (req,PG_UPTODATE )) +bool uptodate = false; + +nfs_page_group_lock (req); +if (!test_bit (PG_READ_FAILED , &req->wb_head->wb_flags) && +nfs_page_group_sync_on_bit_locked (req,PG_UPTODATE )) + uptodate = true; +nfs_page_group_unlock (req); + +if (uptodate)folio_mark_uptodate (nfs_page_to_folio (req)); } +static void nfs_page_group_mark_read_failed (struct nfs_page *req) +{ +struct nfs_page *tmp; + +nfs_page_group_lock (req); +set_bit (PG_READ_FAILED , &req->wb_head->wb_flags); + tmp = req; +do { +clear_bit (PG_UPTODATE , &tmp->wb_flags); + tmp = tmp->wb_this_page; + }while (tmp != req); +nfs_page_group_unlock (req); +} +static void nfs_read_completion (struct nfs_pgio_header *hdr) {unsigned long bytes =0 ;
@@ -174,6 +196,7 @@ static void nfs_read_completion(struct nfs_pgio_header *hdr)if (bytes <= hdr->good_bytes)nfs_page_group_set_uptodate (req);else { +nfs_page_group_mark_read_failed (req); error = hdr->error;xchg (&nfs_req_openctx (req)->error, error); }
include/linux/nfs_page.h +1 -0
@@ -33,6 +33,7 @@ enum {PG_TEARDOWN ,/* page group sync for destroy */ PG_UNLOCKPAGE ,/* page group sync bit in read path */ PG_UPTODATE ,/* page group sync bit in read path */ +PG_READ_FAILED ,/* page group saw a read error */ PG_WB_END ,/* page group sync bit in write path */ PG_REMOVE ,/* page group sync bit in write path */ PG_CONTENDED1, /* Is someone waiting for a lock? */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 658/1266 NFSv4/flexfiles: honor FF_FLAGS_NO_IO_THRU_MDS on fatal DS connect errors
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mike Snitzer <[email protected]>
[ Upstream commit 7a375cafc14ed151508f908ea5681caf0a9cc1d6 ]
Commit f06bedfa62d5 ("pNFS/flexfiles: don't attempt pnfs on fatal DS errors") teaches ff_layout_{read,write}_pagelist() to return PNFS_NOT_ATTEMPTED when nfs4_ff_layout_prepare_ds() fails with a nfs_error_is_fatal() errno (e.g. -ETIMEDOUT from a SOFTCONN connect deadline, -ENOMEM, -ERESTARTSYS), so that the client gives up instead of spinning. pnfs_do_{read,write}() then dispatches the I/O through pnfs_{read,write}_through_mds() → nfs_pageio_reset_{read,write}_mds().
That fallback is unconditional and silently violates FF_FLAGS_NO_IO_THRU_MDS:
when the layout segment carries the flag (typically single-mirror appliance layouts where MDS I/O is explicitly forbidden), theout_failed: path's \&& !ds_fatal_error\ clause overrides the flag's short-circuit through ff_layout_avoid_mds_available_ds() and routes the I/O to the MDS file handle anyway.
This is reachable in practice during a data-server restart: SOFTCONN exhaustion produces -ETIMEDOUT, which is fatal per nfs_error_is_fatal(), which triggers PNFS_NOT_ATTEMPTED, which silently goes to MDS.
Preserve the upstream "don't spin on fatal errors" intent for layouts that permit MDS fallback. For layouts with FF_FLAGS_NO_IO_THRU_MDS set, mark the layout for return and request PNFS_TRY_AGAIN instead; if the server cannot supply a usable layout the failure now surfaces cleanly via pnfs_update_layout(), rather than via silent MDS I/O that contradicts the flag.
--- fs/nfs/flexfilelayout/flexfilelayout.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+)
fs/nfs/flexfilelayout/flexfilelayout.c +16 -0
@@ -1902,6 +1902,14 @@ ff_layout_read_pagelist(struct nfs_pgio_header *hdr) out_failed:if (ff_layout_avoid_mds_available_ds (lseg) && !ds_fatal_error)return PNFS_TRY_AGAIN ; +if (ff_layout_no_fallback_to_mds (lseg)) { +/* +* FF_FLAGS_NO_IO_THRU_MDS: force fresh LAYOUTGET, +* never fall through to MDS I/O. +*/ +pnfs_error_mark_layout_for_return (hdr->inode, lseg); +return PNFS_TRY_AGAIN ; + }trace_pnfs_mds_fallback_read_pagelist (hdr->inode, hdr->args.offset, hdr->args.count,IOMODE_READ ,NFS_I (hdr->inode)->layout, lseg);
@@ -1973,6 +1981,14 @@ ff_layout_write_pagelist(struct nfs_pgio_header *hdr, int sync) out_failed:if (ff_layout_avoid_mds_available_ds (lseg) && !ds_fatal_error)return PNFS_TRY_AGAIN ; +if (ff_layout_no_fallback_to_mds (lseg)) { +/* +* FF_FLAGS_NO_IO_THRU_MDS: force fresh LAYOUTGET, +* never fall through to MDS I/O. +*/ +pnfs_error_mark_layout_for_return (hdr->inode, lseg); +return PNFS_TRY_AGAIN ; + }trace_pnfs_mds_fallback_write_pagelist (hdr->inode, hdr->args.offset, hdr->args.count,IOMODE_RW ,NFS_I (hdr->inode)->layout, lseg);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 659/1266 NFSv4/flexfiles: honor FF_FLAGS_NO_IO_THRU_MDS in pg_get_mirror_count_write
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mike Snitzer <[email protected]>
[ Upstream commit 1d62e659c0bf11649cf48e002c2a55d148f2610a ]
The FF_FLAGS_NO_IO_THRU_MDS flag lives on each lseg, so any fallback decision made when there is no current lseg (e.g. between LAYOUTRETURN and the next LAYOUTGET) cannot run the per-lseg check.
Introduce a sticky hdr-level ditto for FF_FLAGS_NO_IO_THRU_MDS in struct nfs4_flexfile_layout::flags (NFS4_FF_HDR_NO_IO_THRU_MDS bit), set whenever ff_layout_alloc_lseg() parses an lseg with the flag. The bit is never cleared for the lifetime of the layout hdr; the server is assumed to be consistent in its no-fallback policy per file. kzalloc() in ff_layout_alloc_layout_hdr() zero-initializes the field.
Use the new ff_layout_hdr_no_fallback_to_mds() helper to gate ff_layout_pg_get_mirror_count_write(): when pnfs_update_layout() returns NULL (e.g. NFS_LAYOUT_BULK_RECALL, pnfs_layout_io_test_failed, pnfs_layoutgets_blocked) the existing code unconditionally calls nfs_pageio_reset_write_mds(). This is a source of unwanted WRITE to MDS. Fix it by checking NFS4_FF_HDR_NO_IO_THRU_MDS bit, and if set surface -EAGAIN instead; the writepage-side caller (nfs_do_writepage() for buffered, nfs_direct_write_reschedule() for O_DIRECT) then redirties the request so writeback retries via pNFS.
--- fs/nfs/flexfilelayout/flexfilelayout.c | 13 +++++++++++++ fs/nfs/flexfilelayout/flexfilelayout.h | 16 ++++++++++++++++ 2 files changed, 29 insertions(+)
fs/nfs/flexfilelayout/flexfilelayout.c +13 -0
@@ -539,6 +539,9 @@ ff_layout_alloc_lseg(struct pnfs_layout_hdr *lh,if (!p) goto out_sort_mirrors; fls->flags =be32_to_cpup (p); +if (fls->flags &FF_FLAGS_NO_IO_THRU_MDS ) +set_bit (NFS4_FF_HDR_NO_IO_THRU_MDS , + &FF_LAYOUT_FROM_HDR (lh)->flags); p =xdr_inline_decode (&stream,4 );if (!p)
@@ -992,6 +995,16 @@ ff_layout_pg_get_mirror_count_write(struct nfs_pageio_descriptor *pgio,0 ,NFS4_MAX_UINT64 ,IOMODE_RW ,NFS_I (pgio->pg_inode)->layout, pgio->pg_lseg); +if (NFS_I (pgio->pg_inode)->layout && +ff_layout_hdr_no_fallback_to_mds (NFS_I (pgio->pg_inode)->layout)) { +/* +* FF_FLAGS_NO_IO_THRU_MDS: no current lseg but the server's +* policy forbids MDS fallback. Surface -EAGAIN so writeback +* retries rather than silently issuing the WRITE via MDS. +*/ + pgio->pg_error = -EAGAIN ; + goto out; + }/* no lseg means that pnfs is not in use, so no mirroring here */ nfs_pageio_reset_write_mds (pgio); out:
fs/nfs/flexfilelayout/flexfilelayout.h +16 -0
@@ -102,12 +102,16 @@ struct nfs4_ff_layout_segment {struct nfs4_ff_layout_mirror *mirror_array[]; }; +/* nfs4_flexfile_layout::flags bit indices */ +#define NFS4_FF_HDR_NO_IO_THRU_MDS 0/* any lseg has had FF_FLAGS_NO_IO_THRU_MDS */ +struct nfs4_flexfile_layout {struct pnfs_layout_hdr generic_hdr;struct pnfs_ds_commit_info commit_info;struct list_head mirrors;struct list_head error_list;/* nfs4_ff_layout_ds_err */ ktime_t last_report_time;/* Layoutstat report times */ +unsigned long flags; };struct nfs4_flexfile_layoutreturn_args {
@@ -174,6 +178,18 @@ ff_layout_no_fallback_to_mds(struct pnfs_layout_segment *lseg)return FF_LAYOUT_LSEG (lseg)->flags &FF_FLAGS_NO_IO_THRU_MDS ; } +/* +* Sticky hdr-level mirror of FF_FLAGS_NO_IO_THRU_MDS so callers that have +* no current lseg (e.g. between LAYOUTRETURN and the next LAYOUTGET) can +* still honor the no-MDS-fallback policy. +*/ +static inline bool +ff_layout_hdr_no_fallback_to_mds (struct pnfs_layout_hdr *lo) +{ +return test_bit (NFS4_FF_HDR_NO_IO_THRU_MDS , + &FF_LAYOUT_FROM_HDR (lo)->flags); +} +static inline bool ff_layout_no_read_on_rw (struct pnfs_layout_segment *lseg) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 660/1266 PCI: mediatek: Fix operator precedence in PCIE_FTS_NUM_L0 macro
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Li RongQing <[email protected]>
[ Upstream commit 282305d7e9c0e27fd8b4df34b7cd5506a1eccdd6 ]
The original PCIE_FTS_NUM_L0(x) macro was buggy due to improper operator precedence, where ((x) & 0xff << 8) was evaluated as ((x) & 0xff00).
Instead of just fixing the parentheses, use the standard FIELD_PREP() macro. This makes the code more robust by automatically handling masks and shifts, while also adding compile-time type and range checking to ensure the value fits within PCIE_FTS_NUM_MASK.
--- drivers/pci/controller/pcie-mediatek.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/pci/controller/pcie-mediatek.c +2 -1
@@ -7,6 +7,7 @@* Honghui Zhang <[email protected]> */ +#include <linux/bitfield.h> #include <linux/clk.h> #include <linux/delay.h> #include <linux/iopoll.h>
@@ -60,7 +61,7 @@/* MediaTek specific configuration registers */ #define PCIE_FTS_NUM 0x70c#define PCIE_FTS_NUM_MASK GENMASK(15, 8) -#define PCIE_FTS_NUM_L0 (x) ((x) & 0xff << 8) +#define PCIE_FTS_NUM_L0 (x) FIELD_PREP(PCIE_FTS_NUM_MASK, x)#define PCIE_FC_CREDIT 0x73c#define PCIE_FC_CREDIT_MASK (GENMASK(31, 31) | GENMASK(28, 16))
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 661/1266 PCI: meson: Propagate devm_add_action_or_reset() failure
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shuvam Pandey <[email protected]>
[ Upstream commit b12341b98d5ac52f48ca1390e1e371aed81346c8 ]
meson_pcie_probe_clock() enables a clock and then registers a devres action to disable it during teardown. If devm_add_action_or_reset() fails, it runs the action immediately, disabling the clock.
The return value is currently ignored, so on that failure path, meson_pcie_probe_clock() returns the disabled clock and probe continues. Return the error so the existing probe error path unwinds normally.
--- drivers/pci/controller/dwc/pci-meson.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/pci/controller/dwc/pci-meson.c +3 -1
@@ -194,7 +194,9 @@ static inline struct clk *meson_pcie_probe_clock(struct device *dev,return ERR_PTR (ret); } -devm_add_action_or_reset (dev, meson_pcie_disable_clock, clk); + ret =devm_add_action_or_reset (dev, meson_pcie_disable_clock, clk); +if (ret) +return ERR_PTR (ret);return clk; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 662/1266 fs/ntfs3: resize log->one_page_buf when adopting on-disk page size
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jamie Nguyen <[email protected]>
[ Upstream commit 5a35454179fe1041d9cd286f5d320ce0d448c12a ]
log_replay() allocates log->one_page_buf using the page size that was chosen from the host PAGE_SIZE:
log->one_page_buf = kmalloc(log->page_size, GFP_NOFS);
Later, when a restart area is found, the log page size recorded on disk is adopted:
t32 = le32_to_cpu(log->rst_info.r_page->sys_page_size);
if (log->page_size != t32) {
log->l_size = log->orig_file_size;
log->page_size = norm_file_page(t32, &log->l_size,
t32 == DefaultLogPageSize);
}If the on-disk page size is larger than the size used for the initial allocation, log->page_size grows but one_page_buf is left at its original, smaller size. A subsequent unaligned read_log_page() then reads log->page_size bytes into the undersized scratch buffer:
page_buf = page_off ? log->one_page_buf : *buffer; err = ntfs_read_run_nb_ra(ni->mi.sbi, &ni->file.run, page_vbo, page_buf, log->page_size, NULL, &log->read_ahead);
overflowing the allocation. This is reachable when mounting a dirty NTFS volume whose log was formatted with a page size larger than the buffer initially allocated on the mounting host (for example a 64K-log volume mounted on a host that allocated a 4K scratch buffer).
Grow one_page_buf when the adopted on-disk page size exceeds the size used for the initial allocation. On krealloc() failure the original buffer is left intact and freed by the existing error path.
--- fs/ntfs3/fslog.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+)
fs/ntfs3/fslog.c +19 -0
@@ -3938,9 +3938,28 @@ int log_replay(struct ntfs_inode *ni, bool *initialized)*/ t32 =le32_to_cpu (log->rst_info.r_page->sys_page_size);if (log->page_size != t32) { +u32 old_page_size = log->page_size; + log->l_size = log->orig_file_size; log->page_size =norm_file_page (t32, &log->l_size, t32 == DefaultLogPageSize); + +/* +* If the adopted on-disk page size is larger than the size used +* to allocate one_page_buf above, grow the scratch buffer so a +* later read_log_page() cannot overflow it. +*/ +if (log->page_size > old_page_size) { +void *buf; + + buf =krealloc (log->one_page_buf, log->page_size, +GFP_NOFS ); +if (!buf) { + err = -ENOMEM ; + goto out; + } + log->one_page_buf = buf; + } } if (log->page_size != t32 ||
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 663/1266 perf tools: Fix get_max_num() size_t underflow on empty sysfs file
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit 0a012113bb3a44482c163f16f4db03ccaa37a339 ]
get_max_num() reads a sysfs file (cpu/possible, cpu/present, or node/possible) and scans backward from the end to find the last number. If the file is empty, filename__read_str() returns num == 0. The loop while (--num) decrements the size_t from 0 to SIZE_MAX, reading backward across the heap until a comma or hyphen is found or unmapped memory is hit.
Add an early return for empty files before the backward scan.
--- tools/perf/util/cpumap.c | 6 ++++++ 1 file changed, 6 insertions(+)
tools/perf/util/cpumap.c +6 -0
@@ -378,6 +378,12 @@ static int get_max_num(char *path, int *max) buf[num] ='\0' ; +/* empty file — nothing to parse */ +if (num ==0 ) { + err =-1 ; + goto out; + } +/* start on the right, to find highest node num */ while (--num) {if ((buf[num] ==',' ) || (buf[num] =='-' )) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 664/1266 perf tools: Use scnprintf() in cpu_map__snprint() to prevent overflow
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit 7953a3a9b8e02e98c6e6958f291d0ae22393e46a ]
cpu_map__snprint() accumulates snprintf() return values in ret. snprintf() returns the number of characters that *would have been written* on truncation, not the actual count. When a fragmented CPU list exceeds the buffer, ret grows past size, causing size - ret to underflow (both are size_t), and subsequent snprintf() calls write past the end of the caller's stack buffer.
Switch to scnprintf() which returns the actual number of characters written, making ret accumulation safe by construction.
--- tools/perf/util/cpumap.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-)
tools/perf/util/cpumap.c +9 -9
@@ -601,21 +601,21 @@ size_t cpu_map__snprint(struct perf_cpu_map *map, char *buf, size_t size)if (start ==-1 ) { start = i;if (last) { - ret +=snprintf (buf + ret, size - ret, -"%s%d" ,COMMA , -perf_cpu_map__cpu (map, i).cpu); + ret +=scnprintf (buf + ret, size - ret, +"%s%d" ,COMMA , +perf_cpu_map__cpu (map, i).cpu); } }else if (((i - start) != (cpu.cpu -perf_cpu_map__cpu (map, start).cpu)) || last) {int end = i -1 ;if (start == end) { - ret +=snprintf (buf + ret, size - ret, -"%s%d" ,COMMA , -perf_cpu_map__cpu (map, start).cpu); + ret +=scnprintf (buf + ret, size - ret, +"%s%d" ,COMMA , +perf_cpu_map__cpu (map, start).cpu); }else { - ret +=snprintf (buf + ret, size - ret, -"%s%d-%d" ,COMMA , -perf_cpu_map__cpu (map, start).cpu,perf_cpu_map__cpu (map, end).cpu); + ret +=scnprintf (buf + ret, size - ret, +"%s%d-%d" ,COMMA , +perf_cpu_map__cpu (map, start).cpu,perf_cpu_map__cpu (map, end).cpu); } first = false; start = i;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 665/1266 perf tools: Use perf_env__get_cpu_topology() in machine__resolve()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit 5484b43a0ec8231c36fba6ead654cb72dbba8b8f ]
machine__resolve() accesses env->cpu[al->cpu].socket_id after checking al->cpu >= 0 and env->cpu != NULL, but without validating al->cpu against env->nr_cpus_avail. Since al->cpu comes from the untrusted perf.data sample, a crafted file with a large CPU index causes an out-of-bounds heap read.
Use perf_env__get_cpu_topology() which validates both NULL and bounds. Also bounds-check al->cpu before the cast to struct perf_cpu (int16_t):
without this, values like 65536 silently truncate to 0, bypassing the accessor's internal check and returning CPU 0's topology.
--- tools/perf/util/event.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-)
tools/perf/util/event.c +13 -2
@@ -12,6 +12,7 @@#include <linux/zalloc.h> #include "cpumap.h" #include "dso.h" +#include "env.h" #include "event.h" #include "debug.h" #include "hist.h"
@@ -743,8 +744,18 @@ int machine__resolve(struct machine *machine, struct addr_location *al,if (al->cpu >=0 ) {struct perf_env *env = machine->env; -if (env && env->cpu) - al->socket = env->cpu[al->cpu].socket_id; +/* +* Bounds-check al->cpu (s32) before casting to struct perf_cpu +* (int16_t): without this, e.g. 65536 truncates to 0 and silently +* returns CPU 0's topology. Can go once perf_cpu.cpu is widened. +*/ +if (env && al->cpu < env->nr_cpus_avail) { +struct cpu_topology_map *topo; + + topo =perf_env__get_cpu_topology (env, (struct perf_cpu ){ al->cpu }); +if (topo) + al->socket = topo->socket_id; + } }if (al->map) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 666/1266 PCI: rcar-host: Remove unused LIST_HEAD(res)
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lad Prabhakar <[email protected]>
[ Upstream commit 6ba90ce2069ae923b0ec787aebdf2d786e5d2a58 ]
Remove the unused LIST_HEAD(res) declaration from rcar_pcie_hw_enable().
The macro instantiation defines an unused 'struct list_head res' variable, which conflicts with a valid resource loop-local 'struct resource *res' declaration further down in the function, triggering a compiler variable shadowing warning:
drivers/pci/controller/pcie-rcar-host.c:357:34: warning: declaration of 'res' shadows a previous local [-Wshadow]
357 | struct resource *res = win->res;
--- drivers/pci/controller/pcie-rcar-host.c | 1 - 1 file changed, 1 deletion(-)
drivers/pci/controller/pcie-rcar-host.c +0 -1
@@ -344,7 +344,6 @@ static void rcar_pcie_hw_enable(struct rcar_pcie_host *host)struct rcar_pcie *pcie = &host->pcie;struct pci_host_bridge *bridge =pci_host_bridge_from_priv (host);struct resource_entry *win; -LIST_HEAD (res);int i =0 ;/* Try setting 5 GT/s link speed */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 667/1266 perf sched: Fix idle-hist callchain display using wrong rb_first variant
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit d9b99dc8148e0c1f5da3942131b47e0d21187a32 ]
timehist_print_idlehist_callchain() calls rb_first_cached() on sorted_root, but the sort function (callchain_param.sort) populates it via rb_insert_color() on the plain rb_root member — not the cached variant. This means rb_leftmost is never set, so rb_first_cached() always returns NULL and the entire callchain summary is silently dropped from --idle-hist output.
The original code in ba957ebb54893aca ("perf sched timehist: Show callchains for idle stat") was correct — it used struct rb_root and rb_first(). The bug was introduced when sorted_root was converted to rb_root_cached without converting the sort insertion path to use rb_insert_color_cached().
Use rb_first(&root->rb_root) to match how the tree was populated.
--- tools/perf/builtin-sched.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
tools/perf/builtin-sched.c +2 -1
@@ -2906,7 +2906,8 @@ static size_t timehist_print_idlehist_callchain(struct rb_root_cached *root)size_t ret =0 ;FILE *fp = stdout;struct callchain_node *chain; -struct rb_node *rb_node =rb_first_cached (root); +/* sort() uses rb_insert_color() on rb_root, not rb_root_cached */ +struct rb_node *rb_node =rb_first (&root->rb_root);printf (" %16s %8s %s\n" ,"Idle time (msec)" ,"Count" ,"Callchains" ); printf(" %.16s %.8s %.50s\n", graph_dotted_line, graph_dotted_line,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 668/1266 perf bpf: Use scnprintf() in snprintf_hex() and synthesize_bpf_prog_name()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit cab3a9331ed0b3f884dd61c8a25b3cf123705982 ]
Both functions accumulate formatted output via ret += snprintf(buf + ret, size - ret, ...). If the buffer is too small and snprintf() returns more than the remaining space, ret exceeds size and the next 'size - ret' underflows, causing snprintf() to write past the buffer end.
Switch to scnprintf() which returns the actual number of bytes written, making the accumulation safe.
--- tools/perf/util/bpf-event.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-)
tools/perf/util/bpf-event.c +6 -5
@@ -28,7 +28,7 @@ static int snprintf_hex(char *buf, size_t size, unsigned char *data, size_t len)size_t i;for (i =0 ; i < len; i++) - ret +=snprintf (buf + ret, size - ret,"%02x" , data[i]); + ret +=scnprintf (buf + ret, size - ret,"%02x" , data[i]);return ret; }
@@ -131,7 +131,7 @@ static int synthesize_bpf_prog_name(char *buf, int size,const struct btf_type *t;int name_len; - name_len =snprintf (buf, size,"bpf_prog_" ); + name_len =scnprintf (buf, size,"bpf_prog_" ); name_len +=snprintf_hex (buf + name_len, size - name_len, prog_tags[sub_id],BPF_TAG_SIZE );if (btf) {
@@ -144,9 +144,10 @@ static int synthesize_bpf_prog_name(char *buf, int size, short_name = info->name; }else short_name ="F" ; -if (short_name) - name_len +=snprintf (buf + name_len, size - name_len, -"_%s" , short_name); +if (short_name) { + name_len +=scnprintf (buf + name_len, size - name_len, +"_%s" , short_name); + }return name_len; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 669/1266 perf hists: Fix snprintf() in hists__scnprintf_title() UID filter path
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit 227a8748742f0263f1fe3131449b44563b77a209 ]
hists__scnprintf_title() accumulates formatted output into a buffer using scnprintf() for all filter clauses except the UID filter, which uses snprintf(). If the buffer fills up and snprintf() returns more than the remaining space, printed exceeds size and the next 'size - printed' underflows, causing later scnprintf() calls to write past the buffer.
Switch the UID filter clause to scnprintf() to match the rest of the function.
--- tools/perf/util/hist.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
tools/perf/util/hist.c +4 -3
@@ -2800,9 +2800,10 @@ int __hists__scnprintf_title(struct hists *hists, char *bf, size_t size, bool sh ev_name, sample_freq_str, enable_ref ? ref : " ", nr_events); -if (hists->uid_filter_str) - printed +=snprintf (bf + printed, size - printed, -", UID: %s" , hists->uid_filter_str); +if (hists->uid_filter_str) { + printed +=scnprintf (bf + printed, size - printed, +", UID: %s" , hists->uid_filter_str); + }if (thread) {if (hists__has (hists, thread)) { printed += scnprintf(bf + printed, size - printed,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 670/1266 xprtrdma: Check frwr_wp_create() during connect
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit 0f13fc7c7d2e0427517e63c739277a4cd338b0c5 ]
frwr_wp_create() creates the singleton Memory Region used to encode padding for Write chunks whose payload length is not XDR-aligned. Its failure paths return a negative errno and leave ep->re_write_pad_mr set to NULL.
rpcrdma_xprt_connect() currently ignores that return value. If frwr_wp_create() fails after the rest of the connection setup succeeds, xprt_rdma_connect_worker() treats the connection attempt as successful and sets XPRT_CONNECTED. A later NFS/RDMA read with a non-4-byte-aligned receive page length reaches rpcrdma_encode_write_list(), passes the NULL write-pad MR to encode_rdma_segment(), and dereferences it.
This is locally triggerable on an NFS/RDMA client after a connect or reconnect hits a local MR allocation, DMA-map, MR-map, or post-send failure; a remote peer alone cannot force the local MR setup failure.
Check the return value and fail the connect as -ENOTCONN, matching the adjacent setup failures. This keeps XPRT_CONNECTED clear and lets the normal reconnect path retry.
--- net/sunrpc/xprtrdma/verbs.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-)
net/sunrpc/xprtrdma/verbs.c +11 -1
@@ -536,7 +536,17 @@ int rpcrdma_xprt_connect(struct rpcrdma_xprt *r_xprt) goto out; }rpcrdma_mrs_create (r_xprt); -frwr_wp_create (r_xprt); + +/* +* rpcrdma_encode_write_list() dereferences the write-pad +* MR with no NULL check, so fail the connect rather than +* publish a transport whose write-pad MR is NULL. +*/ + rc =frwr_wp_create (r_xprt); +if (rc) { + rc = -ENOTCONN ; + goto out; + } out:trace_xprtrdma_connect (r_xprt, rc);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 671/1266 xprtrdma: Document and assert reply-handler invariants
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit 797943e8bd1ffcc63bfe79d24faad9a77054ec40 ]
The xprtrdma reply path has been the subject of recurring LLM-driven review claims that 'an RPC can complete while receive buffers are still DMA-mapped' or that 'the req can be freed while the HCA still owns the send buffer.' No runtime reproducer has surfaced, but the absence of a written-down invariant set lets each pass of automated review reach the same hypothetical conclusion. Subsequent fixes against ce2f9a4d9ccc ('xprtrdma: Decouple req recycling from RPC completion') closed the underlying races but did not document the closure where future readers will look for it.
State the invariants explicitly in a comment above rpcrdma_reply_handler() and back four of them with WARN_ON_ONCE() probes positioned where each invariant is locally checkable on the previous patch's cleaned-up ownership state:
- I1 (Receive WR ownership): WARN at rpcrdma_post_recvs() that a rep pulled from rb_free_reps carries rr_rqst == NULL.
- I2 (rep attachment): WARN at rpcrdma_reply_put() that req->rl_reply was NULLed before the matching rep_put.
- I3 (Registered-MR fence): WARN at rpcrdma_complete_rqst() that req->rl_registered is empty. Strong send-queue ordering of the LocalInv WR chain makes the last completion observe the ib_dma_unmap_sg() of every earlier MR, so 'list empty' implies 'all MRs unmapped'.
- I4 (Send-buffer release): WARN at rpcrdma_req_release() that req->rl_sendctx is NULL. Reaching the kref release callback requires both the RPC-layer and Send-side references to have dropped; the Send-side drop runs in rpcrdma_sendctx_unmap(), which clears rl_sendctx (previous patch). A non-NULL rl_sendctx here would mean the Send-side owner had not run -- a contradiction.
The XXX comment in xprt_rdma_free() about signal-driven release racing the Send completion described the pre-decouple state. Replace it with a one-line note pointing at the invariant set, since the kref scheme now holds the req across the in-flight Send regardless of which path released the rpc_task.
I5 (req lifecycle) is stated in the comment but not probed:
making it locally assertible would require moving kref_init out of rpcrdma_req_release(), which in turn requires adding kref_init to the bc_pa_list and backlog-wake reuse paths. That restructuring is deferred -- the invariant is unchanged either way.
Stable-dep-of: 234c0ff695ef ("xprtrdma: Resize reply buffers before reposting receives")
--- net/sunrpc/xprtrdma/rpc_rdma.c | 69 +++++++++++++++++++++++++++++++++ net/sunrpc/xprtrdma/transport.c | 13 +++++-- net/sunrpc/xprtrdma/verbs.c | 6 +++ 3 files changed, 84 insertions(+), 4 deletions(-)
net/sunrpc/xprtrdma/rpc_rdma.c +69 -0
@@ -1381,6 +1381,11 @@ void rpcrdma_complete_rqst(struct rpcrdma_rep *rep)struct rpc_rqst *rqst = rep->rr_rqst;int status; +/* I3: every registered MR has been invalidated and +* ib_dma_unmap_sg()'d before complete_rqst runs. +*/ +WARN_ON_ONCE (!list_empty (&rpcr_to_rdmar (rqst)->rl_registered)); +switch (rep->rr_proc) {case rdma_msg: status =rpcrdma_decode_msg (r_xprt, rep, rqst);
@@ -1412,6 +1417,70 @@ void rpcrdma_complete_rqst(struct rpcrdma_rep *rep) goto out; } +/* Reply-side ownership invariants +* +* I1 (Receive WR ownership). A struct rpcrdma_rep is owned by the +* HCA between ib_post_recv() and the matching Receive completion. +* After ib_dma_sync_single_for_cpu() in rpcrdma_wc_receive() it is +* owned by the CPU until rpcrdma_rep_put() returns it to +* rb_free_reps; a rep on rb_free_reps is not re-posted until +* rpcrdma_post_recvs() pulls it off. Asserted: rpcrdma_post_recvs() +* WARNs that a pulled rep has rr_rqst == NULL. +* +* I2 (rep attachment). While req->rl_reply == rep, the rep cannot be +* re-posted. rpcrdma_reply_put() NULLs req->rl_reply before handing +* the rep to rpcrdma_rep_put(). Asserted: rpcrdma_reply_put() WARNs +* that rl_reply is NULL after the put. +* +* I3 (Registered-MR fence). On entry to rpcrdma_complete_rqst() every +* MR that was on req->rl_registered has had its rkey invalidated +* (remotely via IB_WC_WITH_INVALIDATE or locally via IB_WR_LOCAL_INV) +* and its pages ib_dma_unmap_sg()'d. The LocalInv chain is posted +* on a single QP; strong send-queue ordering makes the last +* completion (frwr_wc_localinv_done) observe the +* ib_dma_unmap_sg() that ran from each earlier completion's +* frwr_mr_put() before complete_rqst is called. The inline +* frwr_reminv() path unmaps its one MR synchronously before +* rpcrdma_reply_handler() reaches complete_rqst. Asserted: +* rpcrdma_complete_rqst() WARNs that rl_registered is empty. +* +* I4 (Send-buffer release). req->rl_kref carries two unconditional +* owners while a Send is outstanding: the RPC-layer reference (set +* at xprt_rdma_alloc_slot / xprt_rdma_bc_rqst_get / rpcrdma_req_release +* pool-entry) and the Send-side reference (kref_get() in +* rpcrdma_prepare_send_sges()). rpcrdma_req_release() runs only +* after both have dropped, so the req does not return to its free +* pool until rpcrdma_sendctx_unmap() has fired -- the HCA has +* released the send buffer before the req can be reused. Asserted: +* rpcrdma_req_release() WARNs that rl_sendctx is NULL. +* +* I5 (req lifecycle). A req is owned by the RPC layer between slot +* acquisition and the matching xprt_rdma_free_slot() (or, for the +* backchannel, xprt_rdma_bc_free_rqst()). While owned, rl_kref >= 1. +* The pools (rb_send_bufs, bc_pa_list, backlog wake target) never +* contain a req with outstanding Send-side or Reply-side work. +* +* Non-hazards. The following claims have been raised by adversarial +* review and are each closed by the invariants above: +* +* * "Reply completes the RPC while the HCA still holds the send +* buffer" -- excluded by I4. The Send-side kref reference is held +* until rpcrdma_sendctx_unmap() runs from Send completion. +* +* * "Signal-driven release races the in-flight Send" -- same +* resolution. xprt_rdma_free() does not touch rl_kref; the +* Send-side reference keeps the req out of its pool until Send +* completion fires. +* +* * "Receive completion races rep reuse" -- excluded by I1. A rep +* is on rb_free_reps only after rpcrdma_rep_put() has been called +* and rpcrdma_post_recvs() owns the next transition back to the HCA. +* +* * "Pages still DMA-mapped when call_decode reads them" -- excluded +* by I3. The matching ib_dma_unmap_sg() for every MR has run on +* the same CPU thread that calls rpcrdma_complete_rqst(). +*/ +/** * rpcrdma_reply_handler - Process received RPC/RDMA messages * @rep: Incoming rpcrdma_rep object to process
net/sunrpc/xprtrdma/transport.c +9 -4
@@ -510,6 +510,11 @@ static void rpcrdma_req_release(struct kref *kref)struct rpc_xprt *xprt = rqst->rq_xprt;struct rpcrdma_xprt *r_xprt; +/* I4: both the RPC-layer and Send-side owners have dropped, +* so rpcrdma_sendctx_unmap() has cleared rl_sendctx. +*/ +WARN_ON_ONCE (req->rl_sendctx); +kref_init (&req->rl_kref);#if defined(CONFIG_SUNRPC_BACKCHANNEL )
@@ -653,10 +658,10 @@ xprt_rdma_free(struct rpc_task *task)frwr_unmap_sync (rpcx_to_rdmax (rqst->rq_xprt), req); } -/* XXX: If the RPC is completing because of a signal and -* not because a reply was received, we ought to ensure -* that the Send completion has fired, so that memory -* involved with the Send is not still visible to the NIC. +/* The Send-side rl_kref owner keeps req out of its free pool +* until rpcrdma_sendctx_unmap() has fired -- see I4 above +* rpcrdma_reply_handler() -- so signal-driven release here +* does not let the HCA touch a recycled send buffer. */ }
net/sunrpc/xprtrdma/verbs.c +6 -0
@@ -1222,6 +1222,10 @@ void rpcrdma_reply_put(struct rpcrdma_buffer *buffers, struct rpcrdma_req *req)rpcrdma_rep_put (buffers, req->rl_reply); req->rl_reply =NULL ; } +/* I2: rl_reply NULL after the put closes the +* 'rep on rb_free_reps still referenced by req' window. +*/ +WARN_ON_ONCE (req->rl_reply); }/**
@@ -1398,6 +1402,8 @@ void rpcrdma_post_recvs(struct rpcrdma_xprt *r_xprt, int needed) rep =rpcrdma_rep_create (r_xprt);if (!rep)break ; +/* I1: a rep on rb_free_reps must carry no rqst pointer. */ +WARN_ON_ONCE (rep->rr_rqst);if (!rpcrdma_regbuf_dma_map (r_xprt, rep->rr_rdmabuf)) {rpcrdma_rep_put (buf, rep);break ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 672/1266 xprtrdma: Resize reply buffers before reposting receives
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit 234c0ff695ef3ffb656931000e6b823d0c2f30fd ]
Commit 0e13dd9ea8be ("xprtrdma: Remove temp allocation of rpcrdma_rep objects") made rpcrdma_rep objects survive disconnects. That is normally fine, but it also means their receive regbufs keep the size they had when they were first allocated.
Each rep's receive buffer is sized to ep->re_inline_recv when the rep is created. rpcrdma_ep_create() resets that threshold to the rdma_max_inline_read ceiling for every new endpoint, and the connect handshake then shrinks it to the peer's advertised inline send size. A rep allocated under a smaller negotiated threshold keeps that size:
on disconnect, rpcrdma_xprt_disconnect() drains and DMA-unmaps the surviving reps but does not free or resize them.
The threshold can come back larger on the next connection. The first peer may supply no RPC-over-RDMA CM private data, defaulting its send size to 1024, while the reconnect target is an ordinary server offering 4096; or, with rdma_max_inline_read raised above its default, the reconnect target may advertise a larger svcrdma_max_req_size than the first. rpcrdma_post_recvs() then reposts a surviving rep whose SGE length is still the old, smaller value, and a larger inline Reply hits a receive length error and forces another disconnect.
The undersized rep returns to the free list when its failed Receive flushes, so the following reconnect reposts the same rep and fails the same way. The transport flaps without making forward progress for as long as the peer keeps advertising the larger inline size.
This is local/admin-triggerable rather than remote-triggerable: a local administrator must create and maintain the NFS/RDMA mount, while the server or reconnect target has to advertise a larger inline send size and return a reply that uses it.
Fix this by checking each rep before it is reposted. If the receive regbuf is smaller than the current endpoint's inline receive size, reallocate it on the current RDMA device's NUMA node and reinitialize the rep's xdr_buf before DMA-mapping and posting the Receive WR.
--- net/sunrpc/xprtrdma/verbs.c | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-)
net/sunrpc/xprtrdma/verbs.c +30 -1
@@ -81,6 +81,8 @@ rpcrdma_regbuf_alloc_node(size_t size, enum dma_data_direction direction, int node);static struct rpcrdma_regbuf *rpcrdma_regbuf_alloc (size_t size,enum dma_data_direction direction); +static bool rpcrdma_regbuf_realloc_node (struct rpcrdma_regbuf *rb, +size_t size,gfp_t flags,int node);static void rpcrdma_regbuf_dma_unmap (struct rpcrdma_regbuf *rb);static void rpcrdma_regbuf_free (struct rpcrdma_regbuf *rb);
@@ -1306,10 +1308,16 @@ rpcrdma_regbuf_alloc(size_t size, enum dma_data_direction direction)* returned, @rb is left untouched. */ bool rpcrdma_regbuf_realloc (struct rpcrdma_regbuf *rb,size_t size,gfp_t flags) +{ +return rpcrdma_regbuf_realloc_node (rb, size, flags,NUMA_NO_NODE ); +} + +static bool rpcrdma_regbuf_realloc_node (struct rpcrdma_regbuf *rb, +size_t size,gfp_t flags,int node) {void *buf; - buf =kmalloc (size, flags); + buf =kmalloc_node (size, flags, node);if (!buf)return false;
@@ -1321,6 +1329,23 @@ bool rpcrdma_regbuf_realloc(struct rpcrdma_regbuf *rb, size_t size, gfp_t flags)return true; } +static bool rpcrdma_rep_resize (struct rpcrdma_xprt *r_xprt, +struct rpcrdma_rep *rep) +{ +struct rpcrdma_regbuf *rb = rep->rr_rdmabuf; +struct rpcrdma_ep *ep = r_xprt->rx_ep; +size_t size = ep->re_inline_recv; + +if (likely (rdmab_length (rb) >= size)) +return true; +if (!rpcrdma_regbuf_realloc_node (rb, size,XPRTRDMA_GFP_FLAGS , +ibdev_to_node (ep->re_id->device))) +return false; + +xdr_buf_init (&rep->rr_hdrbuf,rdmab_data (rb),rdmab_length (rb)); +return true; +} +/** * __rpcrdma_regbuf_dma_map - DMA-map a regbuf * @r_xprt: controlling transport instance
@@ -1404,6 +1429,10 @@ void rpcrdma_post_recvs(struct rpcrdma_xprt *r_xprt, int needed)break ;/* I1: a rep on rb_free_reps must carry no rqst pointer. */ WARN_ON_ONCE (rep->rr_rqst); +if (!rpcrdma_rep_resize (r_xprt, rep)) { +rpcrdma_rep_put (buf, rep); +break ; + }if (!rpcrdma_regbuf_dma_map (r_xprt, rep->rr_rdmabuf)) {rpcrdma_rep_put (buf, rep);break ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 673/1266 xprtrdma: Fix bcall rep leak and unbounded peek
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chris Mason <[email protected]>
[ Upstream commit c7653d5cebc8492c77ec0415b5e9c0fb3e644bc6 ]
rpcrdma_is_bcall() decodes a reply's first words to decide whether the frame is a backchannel call. Two issues in that decode path let a short or malformed reply leak the receive buffer and drain the Receive queue.
First, the speculative peek
p = xdr_inline_decode(xdr, 0);
/* five p++ reads follow */asks xdr_inline_decode() for zero bytes, which returns xdr->p without consulting xdr->end. The five subsequent __be32 reads can then walk up to 20 bytes past the wire payload into stale regbuf contents and misclassify the reply as a backchannel call.
Second, after the post-peek
p = xdr_inline_decode(xdr, 3 * sizeof(*p));
if (unlikely(!p))
return true;the short-header arm returns true without calling rpcrdma_bc_receive_call(). The contract with the caller is that a true return transfers ownership of rep to the backchannel path:
rpcrdma_reply_handler()
if (rpcrdma_is_bcall(r_xprt, rep))
return; /* bare return, skips out_post */
...
out_post:
rpcrdma_post_recvs(r_xprt, credits + ...);
Because rpcrdma_bc_receive_call() never ran, no one took rep, but rpcrdma_reply_handler still bare-returns past rpcrdma_rep_put() and rpcrdma_post_recvs(). The rep, with its persistently DMA-mapped receive buffer, is orphaned on rb_all_reps and freed only at transport teardown. This completion reposts nothing, so its slot is reclaimed only when a later forward-channel reply reaches out_post and rpcrdma_post_recvs() allocates a fresh rep to backfill; absent that traffic the Receive queue drains and the peer's Sends draw RNR NAKs.
Fix by consulting xdr->end after the zero-length peek so the five __be32 reads cannot run unless 20 bytes of wire payload remain. A byte-precise comparison against xdr->end is required because a non-4-aligned receive rounds the stream's word count up past the true payload. Also return false from the short-header arm so the reply falls through the normal out_norqst cleanup chain (rpcrdma_rep_put() plus rpcrdma_post_recvs()).
--- net/sunrpc/xprtrdma/rpc_rdma.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
net/sunrpc/xprtrdma/rpc_rdma.c +3 -1
@@ -1133,6 +1133,8 @@ rpcrdma_is_bcall(struct rpcrdma_xprt *r_xprt, struct rpcrdma_rep *rep)/* Peek at stream contents without advancing. */ p =xdr_inline_decode (xdr,0 ); +if ((char *)xdr->end - (char *)p <5 *XDR_UNIT ) +return false;/* Chunk lists */ if (xdr_item_is_present (p++))
@@ -1157,7 +1159,7 @@ rpcrdma_is_bcall(struct rpcrdma_xprt *r_xprt, struct rpcrdma_rep *rep)*/ p =xdr_inline_decode (xdr,3 *sizeof (*p));if (unlikely (!p)) -return true; +return false;rpcrdma_bc_receive_call (r_xprt, rep);return true;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 674/1266 xprtrdma: Sanitize the reply credit grant after parsing
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit c3a628aab2dc8f5fd7bff86ceaeae64de590e60a ]
The out_norqst exit in rpcrdma_reply_handler() branches away before the credit clamp, so a reply that matches no pending request reaches out_post carrying the raw credit value parsed from the wire. rpcrdma_post_recvs() does not bound its @needed argument: the refill loop allocates and chains Receive WRs until the count is satisfied or allocation fails. A peer that sends a well-formed reply carrying an unknown XID and an inflated credit grant therefore drives rep allocation and Receive posting past re_max_requests on every such reply.
Move the clamp to immediately after the credit field is parsed, ahead of the first branch that can reach out_post, so every later consumer sees a sanitized value. The cwnd update stays on the matched-request path.
--- net/sunrpc/xprtrdma/rpc_rdma.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-)
net/sunrpc/xprtrdma/rpc_rdma.c +8 -4
@@ -1517,6 +1517,14 @@ void rpcrdma_reply_handler(struct rpcrdma_rep *rep) credits =be32_to_cpu (*p++); rep->rr_proc = *p++; +/* The credit grant from the wire is not trustworthy; +* sanitize it before any code path consumes it. +*/ +if (credits ==0 ) + credits =1 ;/* don't deadlock */ +else if (credits > r_xprt->rx_ep->re_max_requests) + credits = r_xprt->rx_ep->re_max_requests; +if (rep->rr_vers != rpcrdma_version) goto out_badversion;
@@ -1533,10 +1541,6 @@ void rpcrdma_reply_handler(struct rpcrdma_rep *rep)xprt_pin_rqst (rqst);spin_unlock (&xprt->queue_lock); -if (credits ==0 ) - credits =1 ;/* don't deadlock */ -else if (credits > r_xprt->rx_ep->re_max_requests) - credits = r_xprt->rx_ep->re_max_requests;if (buf->rb_credits != credits)rpcrdma_update_cwnd (r_xprt, credits);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 675/1266 xprtrdma: Repost Receive buffers for malformed replies
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit abc011ddaf1617e3e82d8a1e87daa7ddbfb9bac5 ]
rpcrdma_wc_receive() decrements the transport's Receive count for every completion before it dispatches a successful Receive to rpcrdma_reply_handler(). The handler must post a replacement Receive WR before returning unless ownership of the rep has moved elsewhere, as on the backchannel path.
Commit 2ae50ad68cd7 ("xprtrdma: Close window between waking RPC senders and posting Receives") moved the Receive refill out of rpcrdma_wc_receive(), where it had run ahead of every reply, into rpcrdma_reply_handler() so that the responder's credit grant could be parsed before reposting. The bad-version and short-reply exits never reach that refill: they recycle the rep and return without calling rpcrdma_post_recvs().
A remote peer can therefore drain the client's posted Receive queue by sending a sustained stream of replies that are shorter than the fixed transport header or that carry an unrecognized RPC/RDMA version. Each such reply consumes one posted Receive without replacing it. Once the queue empties, the peer's next Send finds no posted Receive and the transport stalls until reconnect.
Route both malformed-reply exits through the shared repost tail after recycling the rep, refilling against buf->rb_credits, the most recent accepted credit grant. Neither exit updates the congestion window, so RPCs admitted under the previous grant remain in flight awaiting replies. A smaller refill target would let a stream of malformed replies ratchet the posted Receive count down to the batch floor while the congestion window still admits rb_credits RPCs; a burst of valid replies to those RPCs could then overrun the posted Receives, and because the client connects with rnr_retry_count of zero, a single RNR NAK terminates the connection. Refilling against rb_credits also restores the target that applied to malformed replies before commit 2ae50ad68cd7 ("xprtrdma: Close window between waking RPC senders and posting Receives") when rpcrdma_post_recvs() computed it from rb_credits internally. rb_credits is at least one from connection establishment onward, so the repost path always keeps Receives posted.
--- net/sunrpc/xprtrdma/rpc_rdma.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
net/sunrpc/xprtrdma/rpc_rdma.c +5 -3
@@ -1573,11 +1573,13 @@ void rpcrdma_reply_handler(struct rpcrdma_rep *rep) out_badversion:trace_xprtrdma_reply_vers_err (rep); - goto out; +rpcrdma_rep_put (buf, rep); + credits = buf->rb_credits; + goto out_post; out_shortreply:trace_xprtrdma_reply_short_err (rep); - -out:rpcrdma_rep_put (buf, rep); + credits = buf->rb_credits; + goto out_post; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 676/1266 xprtrdma: Return sendctx slot after Send preparation failure
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
[ Upstream commit 60e7870052f417d83965db144f70ae21fcfcf37f ]
rpcrdma_prepare_send_sges() gets a sendctx before it maps the SGEs for the Send WR. If one of the mapping helpers fails, no Send WR is posted, so no Send completion is guaranteed to advance rb_sc_tail.
Current cleanup clears sc_req so a later completion can sweep over that slot, but a consecutive run of preparation failures can still advance rb_sc_head until the ring appears full. At that point rpcrdma_sendctx_get_locked() returns NULL and no Send can be posted to produce the completion needed to recover the ring.
The trigger requires CONFIG_SUNRPC_XPRT_RDMA and an NFS/RDMA mount. Mount setup and reliable DMA-map fault injection require local admin authority. Unprivileged I/O on an existing mount can exercise the send path, but a remote peer alone cannot force this local DMA-map failure.
Add rpcrdma_sendctx_unget_locked() for the single-consumer send path to rewind rb_sc_head when the just-acquired sendctx is canceled before ib_post_send(). Wake waiters after making the slot available again. After the rewind, every slot the completion sweep visits belongs to a posted Send, so rpcrdma_sendctx_put_locked() no longer needs to test sc_req before unmapping.
--- net/sunrpc/xprtrdma/rpc_rdma.c | 5 ++++- net/sunrpc/xprtrdma/verbs.c | 40 +++++++++++++++++++++++++++++---- net/sunrpc/xprtrdma/xprt_rdma.h | 2 ++ 3 files changed, 42 insertions(+), 5 deletions(-)
net/sunrpc/xprtrdma/rpc_rdma.c +4 -1
@@ -792,6 +792,7 @@ inline int rpcrdma_prepare_send_sges(struct rpcrdma_xprt *r_xprt,struct xdr_buf *xdr, enum rpcrdma_chunktype rtype) { + struct rpcrdma_sendctx *sc;int ret; ret = -EAGAIN ;
@@ -834,7 +835,9 @@ inline int rpcrdma_prepare_send_sges(struct rpcrdma_xprt *r_xprt,return 0 ; out_unmap: -rpcrdma_sendctx_cancel (req->rl_sendctx); + sc = req->rl_sendctx; +rpcrdma_sendctx_cancel (sc); +rpcrdma_sendctx_unget_locked (r_xprt, sc); out_nosc:trace_xprtrdma_prepsend_failed (&req->rl_slot, ret);return ret;
net/sunrpc/xprtrdma/verbs.c +36 -4
@@ -618,6 +618,11 @@ static void rpcrdma_sendctxs_destroy(struct rpcrdma_xprt *r_xprt)/* The QP is drained, but the final unsignaled Sends might not * have been walked by a signaled Send completion. Release those * Send owners before request buffers are reset. +* +* Unlike the completion sweep, this walk can visit slots with +* no Send posted: after a partial rpcrdma_sendctxs_create() +* failure on reconnect, rb_sc_head and rb_sc_tail are stale, +* and slots between them can be NULL or have sc_req clear. */ for (i = rpcrdma_sendctx_next(buf, buf->rb_sc_tail); i != rpcrdma_sendctx_next(buf, buf->rb_sc_head);
@@ -690,6 +695,12 @@ static unsigned long rpcrdma_sendctx_next(struct rpcrdma_buffer *buf,return likely (item < buf->rb_sc_last) ? item +1 :0 ; } +static unsigned long rpcrdma_sendctx_prev (struct rpcrdma_buffer *buf, +unsigned long item) +{ +return item >0 ? item -1 : buf->rb_sc_last; +} +/** * rpcrdma_sendctx_get_locked - Acquire a send context * @r_xprt: controlling transport instance
@@ -734,6 +745,29 @@ struct rpcrdma_sendctx *rpcrdma_sendctx_get_locked(struct rpcrdma_xprt *r_xprt)return NULL ; } +/** +* rpcrdma_sendctx_unget_locked - Release an unposted send context +* @r_xprt: controlling transport instance +* @sc: send context to release +* +* Usage: Called when no Send is posted for the sendctx most +* recently returned by rpcrdma_sendctx_get_locked(). +* +* The caller serializes calls to this function and to +* rpcrdma_sendctx_get_locked() (per transport). +*/ +void rpcrdma_sendctx_unget_locked (struct rpcrdma_xprt *r_xprt, +struct rpcrdma_sendctx *sc) +{ +struct rpcrdma_buffer *buf = &r_xprt->rx_buf; + +if (WARN_ON_ONCE (buf->rb_sc_ctxs[buf->rb_sc_head] != sc)) +return ; + + buf->rb_sc_head =rpcrdma_sendctx_prev (buf, buf->rb_sc_head); +xprt_write_space (&r_xprt->rx_xprt); +} +/** * rpcrdma_sendctx_put_locked - Release a send context * @r_xprt: controlling transport instance
@@ -751,8 +785,7 @@ static void rpcrdma_sendctx_put_locked(struct rpcrdma_xprt *r_xprt,unsigned long next_tail;/* Release previously completed but unsignaled Sends by walking -* up the queue until @sc is found. Entries left behind by a -* failed rpcrdma_prepare_send_sges() have sc_req cleared. +* up the queue until @sc is found. */ next_tail = buf->rb_sc_tail; do {
@@ -762,8 +795,7 @@ static void rpcrdma_sendctx_put_locked(struct rpcrdma_xprt *r_xprt,/* ORDER: item must be accessed _before_ tail is updated */ cur = buf->rb_sc_ctxs[next_tail]; -if (cur->sc_req) -rpcrdma_sendctx_unmap (cur); +rpcrdma_sendctx_unmap (cur); }while (buf->rb_sc_ctxs[next_tail] != sc);
net/sunrpc/xprtrdma/xprt_rdma.h +2 -0
@@ -476,6 +476,8 @@ void rpcrdma_req_destroy(struct rpcrdma_req *req);int rpcrdma_buffer_create (struct rpcrdma_xprt *);void rpcrdma_buffer_destroy (struct rpcrdma_buffer *);struct rpcrdma_sendctx *rpcrdma_sendctx_get_locked (struct rpcrdma_xprt *r_xprt); +void rpcrdma_sendctx_unget_locked (struct rpcrdma_xprt *r_xprt, +struct rpcrdma_sendctx *sc);struct rpcrdma_mr *rpcrdma_mr_get (struct rpcrdma_xprt *r_xprt);void rpcrdma_mrs_refresh (struct rpcrdma_xprt *r_xprt);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 677/1266 perf cs-etm: Fix incorrect or missing decoder for raw trace
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Besar Wicaksono <[email protected]>
[ Upstream commit a16afcc58a8c5ebc65c852faf001f8f61f05e4ef ]
The decoder creation for raw trace uses metadata from the first CPU. On per-cpu mode, this metadata is incorrectly used for every decoder. On per-process/per-thread traces, the first CPU is CPU0. If CPU0 trace is not enabled, its metadata will be marked unused and the decoder is not created. Perf report dump skips the decoding part because the decoder is missing.
To fix this, use metadata of the CPU associated with sample object.
Stable-dep-of: 68ca50bc0fa6 ("perf cs-etm: Queue context packets for frontend")
--- tools/perf/util/cs-etm.c | 106 ++++++++++++++++++++++++--------------- 1 file changed, 65 insertions(+), 41 deletions(-)
tools/perf/util/cs-etm.c +65 -41
@@ -283,22 +283,31 @@ static int cs_etm__metadata_set_trace_id(u8 trace_chan_id, u64 *cpu_metadata) }/* -* Get a metadata for a specific cpu from an array. +* Get a metadata index for a specific cpu from an array. * */ -static u64 *get_cpu_data (struct cs_etm_auxtrace *etm,int cpu) +static int get_cpu_data_idx (struct cs_etm_auxtrace *etm,int cpu) {int i; -u64 *metadata =NULL ;for (i =0 ; i < etm->num_cpu; i++) {if (etm->metadata[i][CS_ETM_CPU ] == (u64 )cpu) { - metadata = etm->metadata[i]; -break ; +return i; } } -return metadata; +return -1 ; +} + +/* +* Get a metadata for a specific cpu from an array. +* +*/ +static u64 *get_cpu_data (struct cs_etm_auxtrace *etm,int cpu) +{ +int idx =get_cpu_data_idx (etm, cpu); + +return (idx !=-1 ) ? etm->metadata[idx] :NULL ; }/*
@@ -641,66 +650,80 @@ static void cs_etm__packet_dump(const char *pkt_string) }static void cs_etm__set_trace_param_etmv3 (struct cs_etm_trace_params *t_params, -struct cs_etm_auxtrace *etm,int idx, -u32 etmidr) +struct cs_etm_auxtrace *etm,int t_idx, +int m_idx,u32 etmidr) {u64 **metadata = etm->metadata; - t_params[idx].protocol =cs_etm__get_v7_protocol_version (etmidr); - t_params[idx].etmv3.reg_ctrl = metadata[idx][CS_ETM_ETMCR ]; - t_params[idx].etmv3.reg_trc_id = metadata[idx][CS_ETM_ETMTRACEIDR ]; + t_params[t_idx].protocol =cs_etm__get_v7_protocol_version (etmidr); + t_params[t_idx].etmv3.reg_ctrl = metadata[m_idx][CS_ETM_ETMCR ]; + t_params[t_idx].etmv3.reg_trc_id = metadata[m_idx][CS_ETM_ETMTRACEIDR ]; }static void cs_etm__set_trace_param_etmv4 (struct cs_etm_trace_params *t_params, -struct cs_etm_auxtrace *etm,int idx) +struct cs_etm_auxtrace *etm,int t_idx, +int m_idx) {u64 **metadata = etm->metadata; - t_params[idx].protocol = CS_ETM_PROTO_ETMV4i; - t_params[idx].etmv4.reg_idr0 = metadata[idx][CS_ETMV4_TRCIDR0 ]; - t_params[idx].etmv4.reg_idr1 = metadata[idx][CS_ETMV4_TRCIDR1 ]; - t_params[idx].etmv4.reg_idr2 = metadata[idx][CS_ETMV4_TRCIDR2 ]; - t_params[idx].etmv4.reg_idr8 = metadata[idx][CS_ETMV4_TRCIDR8 ]; - t_params[idx].etmv4.reg_configr = metadata[idx][CS_ETMV4_TRCCONFIGR ]; - t_params[idx].etmv4.reg_traceidr = metadata[idx][CS_ETMV4_TRCTRACEIDR ]; + t_params[t_idx].protocol = CS_ETM_PROTO_ETMV4i; + t_params[t_idx].etmv4.reg_idr0 = metadata[m_idx][CS_ETMV4_TRCIDR0 ]; + t_params[t_idx].etmv4.reg_idr1 = metadata[m_idx][CS_ETMV4_TRCIDR1 ]; + t_params[t_idx].etmv4.reg_idr2 = metadata[m_idx][CS_ETMV4_TRCIDR2 ]; + t_params[t_idx].etmv4.reg_idr8 = metadata[m_idx][CS_ETMV4_TRCIDR8 ]; + t_params[t_idx].etmv4.reg_configr = metadata[m_idx][CS_ETMV4_TRCCONFIGR ]; + t_params[t_idx].etmv4.reg_traceidr = metadata[m_idx][CS_ETMV4_TRCTRACEIDR ]; }static void cs_etm__set_trace_param_ete (struct cs_etm_trace_params *t_params, -struct cs_etm_auxtrace *etm,int idx) +struct cs_etm_auxtrace *etm,int t_idx, +int m_idx) {u64 **metadata = etm->metadata; - t_params[idx].protocol =CS_ETM_PROTO_ETE ; - t_params[idx].ete.reg_idr0 = metadata[idx][CS_ETE_TRCIDR0 ]; - t_params[idx].ete.reg_idr1 = metadata[idx][CS_ETE_TRCIDR1 ]; - t_params[idx].ete.reg_idr2 = metadata[idx][CS_ETE_TRCIDR2 ]; - t_params[idx].ete.reg_idr8 = metadata[idx][CS_ETE_TRCIDR8 ]; - t_params[idx].ete.reg_configr = metadata[idx][CS_ETE_TRCCONFIGR ]; - t_params[idx].ete.reg_traceidr = metadata[idx][CS_ETE_TRCTRACEIDR ]; - t_params[idx].ete.reg_devarch = metadata[idx][CS_ETE_TRCDEVARCH ]; + t_params[t_idx].protocol =CS_ETM_PROTO_ETE ; + t_params[t_idx].ete.reg_idr0 = metadata[m_idx][CS_ETE_TRCIDR0 ]; + t_params[t_idx].ete.reg_idr1 = metadata[m_idx][CS_ETE_TRCIDR1 ]; + t_params[t_idx].ete.reg_idr2 = metadata[m_idx][CS_ETE_TRCIDR2 ]; + t_params[t_idx].ete.reg_idr8 = metadata[m_idx][CS_ETE_TRCIDR8 ]; + t_params[t_idx].ete.reg_configr = metadata[m_idx][CS_ETE_TRCCONFIGR ]; + t_params[t_idx].ete.reg_traceidr = metadata[m_idx][CS_ETE_TRCTRACEIDR ]; + t_params[t_idx].ete.reg_devarch = metadata[m_idx][CS_ETE_TRCDEVARCH ]; }static int cs_etm__init_trace_params (struct cs_etm_trace_params *t_params,struct cs_etm_auxtrace *etm, +bool formatted, +int sample_cpu,int decoders) { -int i; +int t_idx, m_idx;u32 etmidr;u64 architecture; -for (i =0 ; i < decoders; i++) { - architecture = etm->metadata[i][CS_ETM_MAGIC ]; +for (t_idx =0 ; t_idx < decoders; t_idx++) { +if (formatted) + m_idx = t_idx; +else { + m_idx =get_cpu_data_idx (etm, sample_cpu); +if (m_idx ==-1 ) { +pr_warning ("CS_ETM: unknown CPU, falling back to first metadata\n" ); + m_idx =0 ; + } + } + + architecture = etm->metadata[m_idx][CS_ETM_MAGIC ];switch (architecture) {case __perf_cs_etmv3_magic: - etmidr = etm->metadata[i][CS_ETM_ETMIDR ]; -cs_etm__set_trace_param_etmv3 (t_params, etm, i, etmidr); + etmidr = etm->metadata[m_idx][CS_ETM_ETMIDR ]; +cs_etm__set_trace_param_etmv3 (t_params, etm, t_idx, m_idx, etmidr);break ;case __perf_cs_etmv4_magic: -cs_etm__set_trace_param_etmv4 (t_params, etm, i); +cs_etm__set_trace_param_etmv4 (t_params, etm, t_idx, m_idx);break ;case __perf_cs_ete_magic: -cs_etm__set_trace_param_ete (t_params, etm, i); +cs_etm__set_trace_param_ete (t_params, etm, t_idx, m_idx);break ;default :return -EINVAL ;
@@ -1016,7 +1039,7 @@ static u32 cs_etm__mem_access(struct cs_etm_queue *etmq, u8 trace_chan_id, }static struct cs_etm_queue *cs_etm__alloc_queue (struct cs_etm_auxtrace *etm, -bool formatted) +bool formatted,int sample_cpu) {struct cs_etm_decoder_params d_params;struct cs_etm_trace_params *t_params =NULL ;
@@ -1041,7 +1064,7 @@ static struct cs_etm_queue *cs_etm__alloc_queue(struct cs_etm_auxtrace *etm,if (!t_params) goto out_free; -if (cs_etm__init_trace_params (t_params, etm, decoders)) +if (cs_etm__init_trace_params (t_params, etm, formatted, sample_cpu, decoders)) goto out_free;/* Set decoder parameters to decode trace packets */
@@ -1081,14 +1104,15 @@ static struct cs_etm_queue *cs_etm__alloc_queue(struct cs_etm_auxtrace *etm,static int cs_etm__setup_queue (struct cs_etm_auxtrace *etm,struct auxtrace_queue *queue,unsigned int queue_nr, -bool formatted) +bool formatted, +int sample_cpu) {struct cs_etm_queue *etmq = queue->priv;if (list_empty (&queue->head) || etmq)return 0 ; - etmq =cs_etm__alloc_queue (etm, formatted); + etmq =cs_etm__alloc_queue (etm, formatted, sample_cpu);if (!etmq)return -ENOMEM ;
@@ -2827,7 +2851,7 @@ static int cs_etm__process_auxtrace_event(struct perf_session *session,* formatted in piped mode (true). */ err =cs_etm__setup_queue (etm, &etm->queues.queue_array[idx], - idx, true); + idx, true,-1 );if (err)return err;
@@ -3033,7 +3057,7 @@ static int cs_etm__queue_aux_fragment(struct perf_session *session, off_t file_o idx = auxtrace_event->idx; formatted = !(aux_event->flags &PERF_AUX_FLAG_CORESIGHT_FORMAT_RAW );return cs_etm__setup_queue (etm, &etm->queues.queue_array[idx], - idx, formatted); + idx, formatted, sample->cpu); }/* Wasn't inside this buffer, but there were no parse errors. 1 == 'not found' */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 678/1266 perf cs-etm: Create decoders after both AUX and HW_ID search passes
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: James Clark <[email protected]>
[ Upstream commit b6aa0de9a53a231eb068ce1e62b5e7ec9e30e627 ]
Both of these passes gather information about how to create the decoders. AUX records determine formatted/unformatted, and the HW_IDs determine the traceID/metadata mappings.
Therefore it makes sense to cache the information and wait until both passes are over until creating the decoders, rather than creating them at the first HW_ID found.
This will allow a simplification of the creation process where cs_etm_queue->traceid_list will exclusively used to create the decoders, rather than the current two methods depending on whether the trace is formatted or not.
Previously the sample CPU from the AUX record was used to initialize the decoder CPU, but actually sample CPU == AUX queue index in per-CPU mode, so saving the sample CPU isn't required.
Similarly formatted/unformatted was used upfront to create the decoders, but now it's cached until later.
Stable-dep-of: 68ca50bc0fa6 ("perf cs-etm: Queue context packets for frontend")
--- tools/perf/util/cs-etm.c | 182 ++++++++++++++++++++++++--------------- 1 file changed, 113 insertions(+), 69 deletions(-)
tools/perf/util/cs-etm.c +113 -69
@@ -97,12 +97,19 @@ struct cs_etm_traceid_queue {struct cs_etm_packet_queue packet_queue; }; +enum cs_etm_format { +UNSET , +FORMATTED , +UNFORMATTED +}; +struct cs_etm_queue {struct cs_etm_auxtrace *etm;struct cs_etm_decoder *decoder;struct auxtrace_buffer *buffer;unsigned int queue_nr;u8 pending_timestamp_chan_id; +enum cs_etm_format format;u64 offset;const unsigned char *buf;size_t buf_len, buf_used;
@@ -693,7 +700,7 @@ static void cs_etm__set_trace_param_ete(struct cs_etm_trace_params *t_params,static int cs_etm__init_trace_params (struct cs_etm_trace_params *t_params,struct cs_etm_auxtrace *etm, -bool formatted, +enum cs_etm_format format,int sample_cpu,int decoders) {
@@ -702,7 +709,7 @@ static int cs_etm__init_trace_params(struct cs_etm_trace_params *t_params,u64 architecture;for (t_idx =0 ; t_idx < decoders; t_idx++) { -if (formatted) +if (format ==FORMATTED ) m_idx = t_idx;else { m_idx =get_cpu_data_idx (etm, sample_cpu);
@@ -735,8 +742,7 @@ static int cs_etm__init_trace_params(struct cs_etm_trace_params *t_params,static int cs_etm__init_decoder_params (struct cs_etm_decoder_params *d_params,struct cs_etm_queue *etmq, -enum cs_etm_decoder_operation mode, -bool formatted) +enum cs_etm_decoder_operation mode) {int ret = -EINVAL ;
@@ -746,7 +752,7 @@ static int cs_etm__init_decoder_params(struct cs_etm_decoder_params *d_params, d_params->packet_printer = cs_etm__packet_dump; d_params->operation = mode; d_params->data = etmq; - d_params->formatted = formatted; + d_params->formatted = etmq->format ==FORMATTED ; d_params->fsyncs = false; d_params->hsyncs = false; d_params->frame_aligned = true;
@@ -1038,81 +1044,34 @@ static u32 cs_etm__mem_access(struct cs_etm_queue *etmq, u8 trace_chan_id,return ret; } -static struct cs_etm_queue *cs_etm__alloc_queue (struct cs_etm_auxtrace *etm, -bool formatted,int sample_cpu) +static struct cs_etm_queue *cs_etm__alloc_queue (void ) { -struct cs_etm_decoder_params d_params; -struct cs_etm_trace_params *t_params =NULL ; -struct cs_etm_queue *etmq; -/* -* Each queue can only contain data from one CPU when unformatted, so only one decoder is -* needed. -*/ -int decoders = formatted ? etm->num_cpu :1 ; - - etmq =zalloc (sizeof (*etmq)); +struct cs_etm_queue *etmq =zalloc (sizeof (*etmq));if (!etmq)return NULL ; etmq->traceid_queues_list =intlist__new (NULL );if (!etmq->traceid_queues_list) - goto out_free; - -/* Use metadata to fill in trace parameters for trace decoder */ - t_params =zalloc (sizeof (*t_params) * decoders); - -if (!t_params) - goto out_free; - -if (cs_etm__init_trace_params (t_params, etm, formatted, sample_cpu, decoders)) - goto out_free; - -/* Set decoder parameters to decode trace packets */ -if (cs_etm__init_decoder_params (&d_params, etmq, - dump_trace ?CS_ETM_OPERATION_PRINT : -CS_ETM_OPERATION_DECODE , - formatted)) - goto out_free; - - etmq->decoder =cs_etm_decoder__new (decoders, &d_params, - t_params); - -if (!etmq->decoder) - goto out_free; - -/* -* Register a function to handle all memory accesses required by -* the trace decoder library. -*/ -if (cs_etm_decoder__add_mem_access_cb (etmq->decoder, -0x0L , ((u64) -1L ), - cs_etm__mem_access)) - goto out_free_decoder; +free (etmq); -zfree (&t_params);return etmq; - -out_free_decoder: -cs_etm_decoder__free (etmq->decoder); -out_free: -intlist__delete (etmq->traceid_queues_list); -free (etmq); - -return NULL ; }static int cs_etm__setup_queue (struct cs_etm_auxtrace *etm,struct auxtrace_queue *queue, -unsigned int queue_nr, -bool formatted, -int sample_cpu) +unsigned int queue_nr,enum cs_etm_format format) {struct cs_etm_queue *etmq = queue->priv; +if (etmq && format != etmq->format) { +pr_err ("CS_ETM: mixed formatted and unformatted trace not supported\n" ); +return -EINVAL ; + } +if (list_empty (&queue->head) || etmq)return 0 ; - etmq =cs_etm__alloc_queue (etm, formatted, sample_cpu); + etmq =cs_etm__alloc_queue ();if (!etmq)return -ENOMEM ;
@@ -1120,7 +1079,9 @@ static int cs_etm__setup_queue(struct cs_etm_auxtrace *etm, queue->priv = etmq; etmq->etm = etm; etmq->queue_nr = queue_nr; + queue->cpu = queue_nr;/* Placeholder, may be reset to -1 in per-thread mode */ etmq->offset =0 ; + etmq->format = format;return 0 ; }
@@ -2851,7 +2812,7 @@ static int cs_etm__process_auxtrace_event(struct perf_session *session,* formatted in piped mode (true). */ err =cs_etm__setup_queue (etm, &etm->queues.queue_array[idx], - idx, true,-1 ); + idx,FORMATTED );if (err)return err;
@@ -2972,7 +2933,7 @@ static int cs_etm__queue_aux_fragment(struct perf_session *session, off_t file_ounion perf_event auxtrace_fragment;__u64 aux_offset, aux_size;__u32 idx; -bool formatted; +enum cs_etm_format format; struct cs_etm_auxtrace *etm = container_of(session->auxtrace, struct cs_etm_auxtrace,
@@ -3055,9 +3016,10 @@ static int cs_etm__queue_aux_fragment(struct perf_session *session, off_t file_oreturn err; idx = auxtrace_event->idx; - formatted = !(aux_event->flags &PERF_AUX_FLAG_CORESIGHT_FORMAT_RAW ); -return cs_etm__setup_queue (etm, &etm->queues.queue_array[idx], - idx, formatted, sample->cpu); + format = (aux_event->flags &PERF_AUX_FLAG_CORESIGHT_FORMAT_RAW ) ? +UNFORMATTED :FORMATTED ; + +return cs_etm__setup_queue (etm, &etm->queues.queue_array[idx], idx, format); }/* Wasn't inside this buffer, but there were no parse errors. 1 == 'not found' */
@@ -3241,6 +3203,84 @@ static int cs_etm__clear_unused_trace_ids_metadata(int num_cpu, u64 **metadata)return 0 ; } +/* +* Use the data gathered by the peeks for HW_ID (trace ID mappings) and AUX +* (formatted or not) packets to create the decoders. +*/ +static int cs_etm__create_queue_decoders (struct cs_etm_queue *etmq) +{ +struct cs_etm_decoder_params d_params; + +/* +* Each queue can only contain data from one CPU when unformatted, so only one decoder is +* needed. +*/ +int decoders = etmq->format ==FORMATTED ? etmq->etm->num_cpu :1 ; + +/* Use metadata to fill in trace parameters for trace decoder */ +struct cs_etm_trace_params *t_params =zalloc (sizeof (*t_params) * decoders); + +if (!t_params) + goto out_free; + +if (cs_etm__init_trace_params (t_params, etmq->etm, etmq->format, + etmq->queue_nr, decoders)) + goto out_free; + +/* Set decoder parameters to decode trace packets */ +if (cs_etm__init_decoder_params (&d_params, etmq, + dump_trace ?CS_ETM_OPERATION_PRINT : +CS_ETM_OPERATION_DECODE )) + goto out_free; + + etmq->decoder =cs_etm_decoder__new (decoders, &d_params, + t_params); + +if (!etmq->decoder) + goto out_free; + +/* +* Register a function to handle all memory accesses required by +* the trace decoder library. +*/ +if (cs_etm_decoder__add_mem_access_cb (etmq->decoder, +0x0L , ((u64) -1L ), + cs_etm__mem_access)) + goto out_free_decoder; + +zfree (&t_params); +return 0 ; + +out_free_decoder: +cs_etm_decoder__free (etmq->decoder); +out_free: +zfree (&t_params); +return -EINVAL ; +} + +static int cs_etm__create_decoders (struct cs_etm_auxtrace *etm) +{ +struct auxtrace_queues *queues = &etm->queues; + +for (unsigned int i =0 ; i < queues->nr_queues; i++) { +bool empty =list_empty (&queues->queue_array[i].head); +struct cs_etm_queue *etmq = queues->queue_array[i].priv; +int ret; + +/* +* Don't create decoders for empty queues, mainly because +* etmq->format is unknown for empty queues. +*/ +if (empty) +continue ; + + ret =cs_etm__create_queue_decoders (etmq); +if (ret) +return ret; + } +return 0 ; +} +int cs_etm__process_auxtrace_info_full (union perf_event *event,struct perf_session *session) {
@@ -3389,6 +3429,10 @@ int cs_etm__process_auxtrace_info_full(union perf_event *event,if (err) goto err_free_queues; + err =cs_etm__queue_aux_records (session); +if (err) + goto err_free_queues; +/* * Map Trace ID values to CPU metadata. *
@@ -3411,7 +3455,7 @@ int cs_etm__process_auxtrace_info_full(union perf_event *event,* flags if present. */ -/* first scan for AUX_OUTPUT_HW_ID records to map trace ID values to CPU metadata */ +/* Scan for AUX_OUTPUT_HW_ID records to map trace ID values to CPU metadata */ aux_hw_id_found =0 ; err = perf_session__peek_events(session, session->header.data_offset, session->header.data_size,
@@ -3429,7 +3473,7 @@ int cs_etm__process_auxtrace_info_full(union perf_event *event,if (err) goto err_free_queues; - err =cs_etm__queue_aux_records (session); + err =cs_etm__create_decoders (etm);if (err) goto err_free_queues;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 679/1266 perf cs-etm: Queue context packets for frontend
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: James Clark <[email protected]>
[ Upstream commit 68ca50bc0fa64841cd73b8a1538df1d7f7eb4108 ]
PE_CONTEXT elements update the context ID and exception level, but the decoder may still have prior packets cached for frontend processing. Updating the context immediately in the decoder backend can make those cached packets get consumed with the wrong thread or EL state.
Add a CS_ETM_CONTEXT packet carrying the TID and EL to the frontend, this keeps context changes ordered with the rest of the packet stream and avoids mismatches when synthesizing samples from cached packets.
Separate the memory access function into one for the frontend and one for decoding. The frontend also needs memory access to attach the instruction to samples. Because the frontend does memory access for both previous and current packets, change all the frontend memory access function signatures to take both a tidq and packet. But backend always uses the current backend EL and thread from the tidq.
Treat context packets as a boundary for branch sample generation and remove tidq->prev_packet_thread because it's not possible to branch to a different thread, so only tracking the current thread is required for sample generation.
--- .../perf/util/cs-etm-decoder/cs-etm-decoder.c | 21 +- tools/perf/util/cs-etm.c | 236 +++++++++++------- tools/perf/util/cs-etm.h | 8 +- 3 files changed, 163 insertions(+), 102 deletions(-)
tools/perf/util/cs-etm-decoder/cs-etm-decoder.c +16 -5
@@ -398,6 +398,8 @@ cs_etm_decoder__buffer_packet(struct cs_etm_packet_queue *packet_queue, packet_queue->packet_buffer[et].flags =0 ; packet_queue->packet_buffer[et].exception_number =UINT32_MAX ; packet_queue->packet_buffer[et].trace_chan_id = trace_chan_id; + packet_queue->packet_buffer[et].el = ocsd_EL_unknown; + packet_queue->packet_buffer[et].tid =-1 ;if (packet_queue->packet_count ==CS_ETM_PACKET_MAX_BUFFER -1 )return OCSD_RESP_WAIT ;
@@ -445,6 +447,7 @@ cs_etm_decoder__buffer_range(struct cs_etm_queue *etmq, packet->last_instr_type = elem->last_i_type; packet->last_instr_subtype = elem->last_i_subtype; packet->last_instr_cond = elem->last_instr_cond; + packet->el = elem->context.exception_level;if (elem->last_i_type ==OCSD_INSTR_BR || elem->last_i_type ==OCSD_INSTR_BR_INDIRECT ) packet->last_instr_taken_branch = elem->last_instr_exec;
@@ -518,7 +521,9 @@ cs_etm_decoder__set_tid(struct cs_etm_queue *etmq,const ocsd_generic_trace_elem *elem, const uint8_t trace_chan_id) { + struct cs_etm_packet *packet;pid_t tid =-1 ; +int ret;/* * Process the PE_CONTEXT packets if we have a valid contextID or VMID.
@@ -539,12 +544,18 @@ cs_etm_decoder__set_tid(struct cs_etm_queue *etmq,break ; } -if (cs_etm__etmq_set_tid_el (etmq, tid, trace_chan_id, - elem->context.exception_level)) +if (cs_etm__etmq_update_decode_context (etmq, trace_chan_id, + elem->context.exception_level, tid))return OCSD_RESP_FATAL_SYS_ERR ; -if (tid ==-1 ) -return OCSD_RESP_CONT ; + ret =cs_etm_decoder__buffer_packet (etmq, packet_queue, trace_chan_id, +CS_ETM_CONTEXT ); +if (ret !=OCSD_RESP_CONT && ret !=OCSD_RESP_WAIT ) +return ret; + + packet = &packet_queue->packet_buffer[packet_queue->tail]; + packet->tid = tid; + packet->el = elem->context.exception_level;/* * A timestamp is generated after a PE_CONTEXT element so make sure
@@ -552,7 +563,7 @@ cs_etm_decoder__set_tid(struct cs_etm_queue *etmq,*/ cs_etm_decoder__reset_timestamp (packet_queue); -return OCSD_RESP_CONT ; +return ret; } static ocsd_datapath_resp_t cs_etm_decoder__gen_trace_elem_printer(
tools/perf/util/cs-etm.c +141 -95
533 lines not on this page · raw message
tools/perf/util/cs-etm.h +6 -2
@@ -158,6 +158,7 @@ enum cs_etm_sample_type {CS_ETM_DISCONTINUITY ,CS_ETM_EXCEPTION ,CS_ETM_EXCEPTION_RET , + CS_ETM_CONTEXT, }; enum cs_etm_isa {
@@ -184,6 +185,8 @@ struct cs_etm_packet {u8 last_instr_size;u8 trace_chan_id;int cpu; +int el; +pid_t tid; };#define CS_ETM_PACKET_MAX_BUFFER 1024
@@ -254,8 +257,9 @@ enum cs_etm_pid_fmt {#include <opencsd/ocsd_if_types.h> int cs_etm__get_cpu (u8 trace_chan_id,int *cpu);enum cs_etm_pid_fmt cs_etm__get_pid_fmt (struct cs_etm_queue *etmq); -int cs_etm__etmq_set_tid_el (struct cs_etm_queue *etmq,pid_t tid, -u8 trace_chan_id,ocsd_ex_level el); +int cs_etm__etmq_update_decode_context (struct cs_etm_queue *etmq, +u8 trace_chan_id,ocsd_ex_level el, +pid_t tid);bool cs_etm__etmq_is_timeless (struct cs_etm_queue *etmq);void cs_etm__etmq_set_traceid_queue_timestamp (struct cs_etm_queue *etmq,u8 trace_chan_id);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 680/1266 perf pmu: Fix pmu_id() heap underwrite on empty identifier file
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit 836455e6dbd34eb3d12eeab5e2d2b9a7f1512459 ]
pmu_id() calls filename__read_str() then strips the trailing newline via str[len - 1] = 0. If the PMU identifier file is empty, filename__read_str() succeeds with len = 0. len - 1 underflows size_t to SIZE_MAX, writing a null byte before the heap allocation.
Add a len == 0 check before the newline stripping.
--- tools/perf/util/pmu.c | 6 ++++++ 1 file changed, 6 insertions(+)
tools/perf/util/pmu.c +6 -0
@@ -774,6 +774,12 @@ static char *pmu_id(const char *name)if (filename__read_str (path, &str, &len) <0 )return NULL ; +/* empty identifier file — nothing useful */ +if (len ==0 ) { +free (str); +return NULL ; + } + str[len -1 ] =0 ;/* remove line feed */ return str;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 681/1266 perf pmu: Fix perf_pmu__parse_scale/unit() OOB access on empty sysfs file
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit 33035f7dd4e49f3f117e70c5e36c8c1ae88d37f2 ]
perf_pmu__parse_scale() reads a PMU scale file then accesses scale[sret - 1] to strip a trailing newline. Only sret < 0 is guarded, so an empty file (sret == 0) causes scale[-1] — a stack buffer underflow that reads and potentially writes out of bounds.
perf_pmu__parse_unit() has the same pattern: alias->unit[sret - 1] with sret == 0 accesses the byte before the struct member, which may corrupt the adjacent pmu_name pointer field.
Change both guards from sret < 0 to sret <= 0 so that empty files are treated as read errors.
--- tools/perf/util/pmu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
tools/perf/util/pmu.c +2 -2
@@ -318,7 +318,7 @@ static int perf_pmu__parse_scale(struct perf_pmu *pmu, struct perf_pmu_alias *al goto error; sret =read (fd, scale,sizeof (scale)-1 ); -if (sret <0 ) +if (sret <=0 ) goto error;if (scale[sret -1 ] =='\n' )
@@ -350,7 +350,7 @@ static int perf_pmu__parse_unit(struct perf_pmu *pmu, struct perf_pmu_alias *alireturn -1 ; sret =read (fd, alias->unit,UNIT_MAX_LEN ); -if (sret <0 ) +if (sret <=0 ) goto error;close (fd);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 682/1266 tools lib api: Fix missing null termination in filename__read_int/ull()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit 52b1f9678499b13b7aeb0186d9c6f486c043283f ]
filename__read_int() passes a stack buffer to read() using the full sizeof(line) and then hands it to atoi() without null-terminating. If a sysfs file fills the 64-byte buffer exactly, atoi() reads past the array into uninitialized stack memory.
filename__read_ull_base() has the same issue with strtoull().
Fix both by reading sizeof(line) - 1 bytes and explicitly null-terminating after a successful read.
--- tools/lib/api/fs/fs.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
tools/lib/api/fs/fs.c +8 -2
@@ -293,11 +293,14 @@ int filename__read_int(const char *filename, int *value) {char line[64 ];int fd =open (filename,O_RDONLY ), err =-1 ; +ssize_t n;if (fd <0 )return -1 ; -if (read (fd, line,sizeof (line)) >0 ) { + n =read (fd, line,sizeof (line) -1 ); +if (n >0 ) { + line[n] ='\0' ; *value =atoi (line); err =0 ; }
@@ -311,11 +314,14 @@ static int filename__read_ull_base(const char *filename, {char line[64 ];int fd =open (filename,O_RDONLY ), err =-1 ; +ssize_t n;if (fd <0 )return -1 ; -if (read (fd, line,sizeof (line)) >0 ) { + n =read (fd, line,sizeof (line) -1 ); +if (n >0 ) { + line[n] ='\0' ; *value =strtoull (line,NULL , base);if (*value !=ULLONG_MAX ) err =0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 683/1266 perf symbols: Fix signed overflow in sysfs__read_build_id() size check
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit 6eaa8ee3e2abe5112e80e94c27196bb175689469 ]
sysfs__read_build_id() reads ELF note headers from sysfs files. The note's namesz and descsz fields are used to compute the skip size:
int n = namesz + descsz;
if (n > (int)sizeof(bf))Both namesz and descsz are size_t from NOTE_ALIGN() of 32-bit note header fields. Their sum can exceed INT_MAX, overflowing the signed int n to a negative value. The check n > sizeof(bf) then evaluates false (negative < positive in signed comparison), and read(fd, bf, n) reinterprets the negative n as a huge size_t count — the kernel writes up to MAX_RW_COUNT bytes into the 8192-byte stack buffer.
In practice the overflow is bounded by the sysfs file's actual size, so a real sysfs notes file won't trigger it organically. But crafted input (e.g. via a mounted debugfs/sysfs image) could.
Fix by validating namesz and descsz individually against the buffer size before summing, and change n to size_t to avoid the signed overflow entirely.
--- tools/perf/util/symbol-elf.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
tools/perf/util/symbol-elf.c +6 -3
@@ -1062,14 +1062,17 @@ int sysfs__read_build_id(const char *filename, struct build_id *bid) }else if (read (fd, bf, descsz) != (ssize_t )descsz)break ; }else { -int n = namesz + descsz; +size_t n; -if (n > (int )sizeof (bf)) { +/* int sum of namesz+descsz can overflow negative, bypassing size check */ +if (namesz >sizeof (bf) || descsz >sizeof (bf) - namesz) { n =sizeof (bf);pr_debug ("%s: truncating reading of build id in sysfs file %s: n_namesz=%u, n_descsz=%u.\n" , __func__, filename, nhdr.n_namesz, nhdr.n_descsz); + }else { + n = namesz + descsz; } -if (read (fd, bf, n) != n) +if (read (fd, bf, n) != (ssize_t )n)break ; } }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 684/1266 perf symbols: Bounds-check .gnu_debuglink section data
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit 9c74f0aab398cb32ab250401f323c0fdc9a3a496 ]
filename__read_debuglink() copies .gnu_debuglink section data into a caller-provided buffer via:
strncpy(debuglink, data->d_buf, size);
where size is PATH_MAX. If the ELF section is smaller than size and lacks a null terminator, strncpy reads past data->d_buf into adjacent memory. A malformed ELF file can trigger this, potentially causing a segfault or leaking heap data.
Additionally, strncpy does not guarantee null termination when the source fills the buffer.
Replace with an explicit memcpy bounded by both the output buffer size and the actual section data size (data->d_size), followed by explicit null termination.
--- tools/perf/util/symbol-elf.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
tools/perf/util/symbol-elf.c +8 -1
@@ -1159,7 +1159,14 @@ int filename__read_debuglink(const char *filename, char *debuglink, goto out_elf_end;/* the start of this section is a zero-terminated string */ -strncpy (debuglink, data->d_buf, size); +if (data->d_size >0 ) { +size_t len =min (size -1 , data->d_size); + +memcpy (debuglink, data->d_buf, len); + debuglink[len] ='\0' ; + }else { + debuglink[0 ] ='\0' ; + } err =0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 685/1266 perf intel-pt: Fix snprintf size tracking bug in insn decoder
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit b6bb3b005dcdd960b8e0b7f9d6869132b3de08d5 ]
dump_insn() tracks remaining buffer space with a 'left' variable, but the loop subtracts the cumulative offset 'n' each iteration instead of just the per-iteration delta:
n += snprintf(x->out + n, left, "%02x ", inbuf[i]); left -= n; /* BUG: n is cumulative, not the delta */
After two iterations left goes massively negative, wrapping to a huge value when passed as size_t to snprintf(), disabling all bounds checking for the rest of the loop.
Switch to scnprintf() accumulation using sizeof(x->out) - n as the remaining space, which is always correct and eliminates the separate 'left' variable entirely.
--- .../util/intel-pt-decoder/intel-pt-insn-decoder.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-)
tools/perf/util/intel-pt-decoder/intel-pt-insn-decoder.c +3 -8
@@ -213,7 +213,6 @@ const char *dump_insn(struct perf_insn *x, uint64_t ip __maybe_unused, {struct insn insn;int n, i, ret; -int left; ret =insn_decode (&insn, inbuf, inlen, x->is64bit ?INSN_MODE_64 :INSN_MODE_32 );
@@ -222,13 +221,9 @@ const char *dump_insn(struct perf_insn *x, uint64_t ip __maybe_unused,return "<bad>" ;if (lenp) *lenp = insn.length; - left =sizeof (x->out); - n =snprintf (x->out, left,"insn: " ); - left -= n; -for (i =0 ; i < insn.length; i++) { - n +=snprintf (x->out + n, left,"%02x " , inbuf[i]); - left -= n; - } + n =scnprintf (x->out,sizeof (x->out),"insn: " ); +for (i =0 ; i < insn.length; i++) + n +=scnprintf (x->out + n,sizeof (x->out) - n,"%02x " , inbuf[i]);return x->out; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 686/1266 perf tools: Fix thread__set_comm_from_proc() on empty comm file
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit 31d596054550f793508abe7dd593853ece47d428 ]
thread__set_comm_from_proc() calls procfs__read_str() then strips the trailing newline via comm[sz - 1] = '\0'. procfs__read_str() allocates the buffer before reading, so on an empty /proc/pid/comm (reachable during late exit teardown) it returns success with sz = 0 and an unterminated heap buffer.
The sz - 1 underflow was the original sashiko finding: it writes a null byte before the allocation. But even with a sz > 0 guard on the newline strip, the unterminated buffer would still be passed to thread__set_comm() which calls strlen() — an unbounded heap read.
Fix by treating sz == 0 as failure: free the buffer and return -1. This is consistent with pmu.c's perf_pmu__parse_scale/unit which already treat len == 0 from filename__read_str as an error.
--- tools/perf/util/thread.c | 5 +++++ 1 file changed, 5 insertions(+)
tools/perf/util/thread.c +5 -0
@@ -273,6 +273,11 @@ int thread__set_comm_from_proc(struct thread *thread)if (!(snprintf (path,sizeof (path),"%d/task/%d/comm" ,thread__pid (thread),thread__tid (thread)) >= (int )sizeof (path)) &&procfs__read_str (path, &comm, &sz) ==0 ) { +/* sz==0: read got nothing, e.g. race during exit teardown */ +if (sz ==0 ) { +free (comm); +return -1 ; + } comm[sz -1 ] ='\0' ; err =thread__set_comm (thread, comm,0 ); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 687/1266 perf symbols: Bounds-check descsz in sysfs__read_build_id() GNU fallback
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit 1b4e9fbdeabc549965e70ac0cd8095d57ff6df06 ]
When sysfs__read_build_id() matches NT_GNU_BUILD_ID with the right namesz but the name content is not "GNU", it falls back to reading descsz bytes into the stack buffer bf[BUFSIZ]:
} else if (read(fd, bf, descsz) != (ssize_t)descsz)
Unlike the else branch which validates namesz + descsz against sizeof(bf), this path passes descsz directly to read() without any bounds check. A crafted sysfs file with a large n_descsz overflows the 8192-byte stack buffer.
Add a descsz > sizeof(bf) check before the read, breaking out of the loop on oversized values.
--- tools/perf/util/symbol-elf.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
tools/perf/util/symbol-elf.c +7 -2
@@ -1059,8 +1059,13 @@ int sysfs__read_build_id(const char *filename, struct build_id *bid) err =0 ;break ; } - }else if (read (fd, bf, descsz) != (ssize_t )descsz) -break ; + }else { +/* descsz from untrusted file — clamp to buffer */ +if (descsz >sizeof (bf)) +break ; +if (read (fd, bf, descsz) != (ssize_t )descsz) +break ; + } }else {size_t n;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 688/1266 tools lib api: Fix filename__write_int() writing uninitialized stack data
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit 438ece06185696e14c63c6113d5e2d34ec0a9680 ]
filename__write_int() formats an integer into a 64-byte buffer with sprintf() then passes sizeof(buf) (64) as the write length. This writes all 64 bytes including uninitialized stack data past the formatted string. Most sysfs files reject the oversized write, making the function always return -1.
Fix by capturing the sprintf() return value and using it as the write length.
--- tools/lib/api/fs/fs.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
tools/lib/api/fs/fs.c +3 -2
@@ -404,12 +404,13 @@ int filename__write_int(const char *filename, int value) {int fd =open (filename,O_WRONLY ), err =-1 ;char buf[64 ]; +int len;if (fd <0 )return err; -sprintf (buf,"%d" , value); -if (write (fd, buf,sizeof (buf)) ==sizeof (buf)) + len =sprintf (buf,"%d" , value); +if (write (fd, buf, len) == len) err =0 ;close (fd);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 689/1266 tools lib api: Fix mount_overload() snprintf truncation and toupper range
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit fd1f70776add263f8ef38a87ae593c75303f1dcd ]
mount_overload() builds an environment variable name like "PERF_SYSFS_ENVIRONMENT" from fs->name. Two bugs:
1) snprintf() uses name_len as the buffer size instead of sizeof(upper_name). For fs->name = "sysfs" (len=5), the output is truncated to "PERF" (4 chars + null), so getenv() never finds the intended variable.
2) mem_toupper() only uppercases name_len bytes, converting just the "PERF" prefix rather than the full string including the filesystem name portion.
Fix by using sizeof(upper_name) for snprintf and strlen(upper_name) for mem_toupper, so the full "PERF_SYSFS_ENVIRONMENT" string is correctly formatted and uppercased.
--- tools/lib/api/fs/fs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
tools/lib/api/fs/fs.c +2 -2
@@ -260,8 +260,8 @@ static const char *mount_overload(struct fs *fs)/* "PERF_" + name + "_ENVIRONMENT" + '\0' */ char upper_name[5 + name_len +12 +1 ]; -snprintf (upper_name, name_len,"PERF_%s_ENVIRONMENT" , fs->name); -mem_toupper (upper_name, name_len); +snprintf (upper_name,sizeof (upper_name),"PERF_%s_ENVIRONMENT" , fs->name); +mem_toupper (upper_name,strlen (upper_name));return getenv (upper_name) ?: *fs->mounts; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 690/1266 perf bpf: Add NULL check for btf__type_by_id() in synthesize_bpf_prog_name()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit 903b0526dcf86d030c5970b4b0a67f9c227368e2 ]
synthesize_bpf_prog_name() calls btf__type_by_id() and immediately dereferences the result via t->name_off without checking for NULL. btf__type_by_id() returns NULL when the type_id is invalid or out of range. When processing perf.data files, finfo->type_id comes from untrusted input, so an invalid ID causes a NULL pointer dereference.
Fix by checking t for NULL before dereferencing.
--- tools/perf/util/bpf-event.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
tools/perf/util/bpf-event.c +2 -1
@@ -137,7 +137,8 @@ static int synthesize_bpf_prog_name(char *buf, int size,if (btf) { finfo = func_infos + sub_id * info->func_info_rec_size; t =btf__type_by_id (btf, finfo->type_id); - short_name =btf__name_by_offset (btf, t->name_off); +if (t) + short_name =btf__name_by_offset (btf, t->name_off); }else if (sub_id ==0 && sub_prog_cnt ==1 ) {/* no subprog */ if (info->name[0 ])
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 691/1266 perf symbols: Add bounds checks to elf_read_build_id() note iteration
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit acc56d3941fc2997a5a21ea9233a8ac3d87c4f2f ]
elf_read_build_id() iterates ELF notes using pointer arithmetic driven by n_namesz and n_descsz from the note headers. Neither the note header read nor the subsequent name/desc advances are checked against the section boundary. A malformed ELF file with oversized note sizes causes out-of-bounds reads past the section data buffer.
Add two bounds checks: verify the note header fits within the remaining section data, and verify that namesz + descsz (after alignment) fits before advancing the pointer.
--- tools/perf/util/symbol-elf.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-)
tools/perf/util/symbol-elf.c +16 -2
@@ -908,10 +908,24 @@ static int elf_read_build_id(Elf *elf, void *bf, size_t size) ptr = data->d_buf;while (ptr < (data->d_buf + data->d_size)) {GElf_Nhdr *nhdr = ptr; -size_t namesz =NOTE_ALIGN (nhdr->n_namesz), - descsz =NOTE_ALIGN (nhdr->n_descsz); +size_t namesz, descsz, remaining;const char *name; +/* ensure the note header fits within the section */ +if (ptr +sizeof (*nhdr) > data->d_buf + data->d_size) +break ; + + namesz =NOTE_ALIGN (nhdr->n_namesz); + descsz =NOTE_ALIGN (nhdr->n_descsz); + +/* validate individually to avoid size_t overflow on 32-bit */ + remaining = data->d_buf + data->d_size - ptr -sizeof (*nhdr); +if (namesz > remaining || descsz > remaining - namesz) { +pr_warning ("%s: oversized note: n_namesz=%u, n_descsz=%u\n" , + __func__, nhdr->n_namesz, nhdr->n_descsz); +break ; + } + ptr +=sizeof (*nhdr); name = ptr; ptr += namesz;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 692/1266 perf symbols: Add bounds checks to read_build_id() note iteration in minimal build
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arnaldo Carvalho de Melo <[email protected]>
[ Upstream commit 52e582e316c48c53bb3082c29f7862ebc554087e ]
symbol-minimal.c's read_build_id() iterates ELF notes with the same pattern as symbol-elf.c's elf_read_build_id(): pointer arithmetic driven by n_namesz and n_descsz from 32-bit note header fields, without validating that the name and desc fit within the note section data. A malformed ELF file with oversized note sizes causes out-of-bounds reads past the section data buffer.
Add the same bounds check as the libelf path: validate namesz and descsz individually against remaining data before advancing the pointer, avoiding size_t overflow on 32-bit.
--- tools/perf/util/symbol-minimal.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-)
tools/perf/util/symbol-minimal.c +10 -1
@@ -1,3 +1,4 @@ +#include "debug.h" #include "dso.h" #include "symbol.h" #include "symsrc.h"
@@ -45,7 +46,7 @@ static int read_build_id(void *note_data, size_t note_len, struct build_id *bid, ptr = note_data;while (ptr < (note_data + note_len)) {const char *name; -size_t namesz, descsz; +size_t namesz, descsz, remaining; nhdr = ptr;if (need_swap) {
@@ -57,6 +58,14 @@ static int read_build_id(void *note_data, size_t note_len, struct build_id *bid, namesz =NOTE_ALIGN (nhdr->n_namesz); descsz =NOTE_ALIGN (nhdr->n_descsz); +/* validate individually to avoid size_t overflow on 32-bit */ + remaining = note_data + note_len - ptr -sizeof (*nhdr); +if (namesz > remaining || descsz > remaining - namesz) { +pr_warning ("%s: oversized note: n_namesz=%u, n_descsz=%u\n" , + __func__, nhdr->n_namesz, nhdr->n_descsz); +break ; + } + ptr +=sizeof (*nhdr); name = ptr; ptr += namesz;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 693/1266 PCI: mediatek: Fix possible truncation in mtk_pcie_parse_port()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ryder Lee <[email protected]>
[ Upstream commit ab4a4043db1fcc4fd4c5745c5be8caf053502e29 ]
As reported by the W=1 warning below, content of the 'name' variable might get truncated with the existing size of 10 bytes. Though it is not practically possible to exceed the 10 bytes size, increase it to 20 to silence the warning for a clean W=1 build:
$ make W=1 drivers/pci/controller/pcie-mediatek.o
CALL scripts/checksyscalls.sh
DESCEND objtool
INSTALL libsubcmd_headers
CC drivers/pci/controller/pcie-mediatek.o
drivers/pci/controller/pcie-mediatek.c: In function ‘mtk_pcie_parse_port’:
drivers/pci/controller/pcie-mediatek.c:963:43: error: ‘%d’ directive output may be truncated writing between 1 and 10 bytes into a region of size 6 [-Werror=format-truncation=]
963 | snprintf(name, sizeof(name), "port%d", slot);
| ^~
drivers/pci/controller/pcie-mediatek.c:963:38: note: directive argument in the range [0, 2147483647]
963 | snprintf(name, sizeof(name), "port%d", slot);
| ^~~~~~~~
drivers/pci/controller/pcie-mediatek.c:963:9: note: ‘snprintf’ output between 6 and 15 bytes into a destination of size 10
963 | snprintf(name, sizeof(name), "port%d", slot);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~Stable-dep-of: ebc1d9906894 ("PCI: mediatek: Use actual physical address instead of virt_to_phys()")
--- drivers/pci/controller/pcie-mediatek.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/pci/controller/pcie-mediatek.c +1 -1
@@ -924,7 +924,7 @@ static int mtk_pcie_parse_port(struct mtk_pcie *pcie,struct mtk_pcie_port *port;struct device *dev = pcie->dev;struct platform_device *pdev =to_platform_device (dev); -char name[10 ]; +char name[20 ];int err; port =devm_kzalloc (dev,sizeof (*port),GFP_KERNEL );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 694/1266 PCI: mediatek: Use actual physical address instead of virt_to_phys()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Manivannan Sadhasivam <[email protected]>
[ Upstream commit ebc1d9906894703286d12306a6f242d90cfb49e8 ]
The driver previously used virt_to_phys() on the ioremapped register base (port->base) to compute the MSI message address. Using virt_to_phys() on an IO mapped address is incorrect because it expects a kernel virtual address.
To fix it, store the physical start of the I/O register region in mtk_pcie_port->phys_base and use it to build the MSI address. This replaces the incorrect virt_to_phys() usage and ensures MSI addresses are generated correctly.
--- drivers/pci/controller/pcie-mediatek.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-)
drivers/pci/controller/pcie-mediatek.c +13 -3
@@ -165,6 +165,7 @@ struct mtk_pcie_soc {/** * struct mtk_pcie_port - PCIe port information * @base: IO mapped register base +* @phys_base: Physical address of the I/O register base region * @list: port list * @pcie: pointer to PCIe host info * @reset: pointer to port reset control
@@ -187,6 +188,7 @@ struct mtk_pcie_soc {*/ struct mtk_pcie_port {void __iomem *base; +phys_addr_t phys_base;struct list_head list;struct mtk_pcie *pcie;struct reset_control *reset;
@@ -398,7 +400,7 @@ static void mtk_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)phys_addr_t addr;/* MT2712/MT7622 only support 32-bit MSI addresses */ - addr =virt_to_phys (port->base +PCIE_MSI_VECTOR ); + addr = port->phys_base +PCIE_MSI_VECTOR ; msg->address_hi =0 ; msg->address_lo =lower_32_bits (addr);
@@ -521,7 +523,7 @@ static void mtk_pcie_enable_msi(struct mtk_pcie_port *port)u32 val;phys_addr_t msg_addr; - msg_addr =virt_to_phys (port->base +PCIE_MSI_VECTOR ); + msg_addr = port->phys_base +PCIE_MSI_VECTOR ; val =lower_32_bits (msg_addr);writel (val, port->base +PCIE_IMSI_ADDR );
@@ -924,6 +926,7 @@ static int mtk_pcie_parse_port(struct mtk_pcie *pcie,struct mtk_pcie_port *port;struct device *dev = pcie->dev;struct platform_device *pdev =to_platform_device (dev); +struct resource *res;char name[20 ];int err;
@@ -932,7 +935,14 @@ static int mtk_pcie_parse_port(struct mtk_pcie *pcie,return -ENOMEM ;snprintf (name,sizeof (name),"port%d" , slot); - port->base =devm_platform_ioremap_resource_byname (pdev, name); + res =platform_get_resource_byname (pdev,IORESOURCE_MEM , name); +if (!res) { +dev_err (dev,"failed to get port%d base\n" , slot); +return -EINVAL ; + } + + port->phys_base = res->start; + port->base =devm_ioremap_resource (&pdev->dev, res);if (IS_ERR (port->base)) {dev_err (dev,"failed to map port%d base\n" , slot);return PTR_ERR (port->base);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 695/1266 Revert "PCI/MSI: Unmap MSI-X region on error"
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yuanhe Shu <[email protected]>
[ Upstream commit f64e03da0d83cb173743888bff4a7e61476a8fc2 ]
This reverts commit 1a8d4c6ecb4c81261bcdf13556abd4a958eca202.
Commit 1a8d4c6ecb4c ("PCI/MSI: Unmap MSI-X region on error") added an iounmap(dev->msix_base) on the error path of msix_capability_init() to release the MSI-X region when msix_setup_interrupts() fails.
When msix_setup_interrupts() fails, the call chain is:
msix_setup_interrupts()
-> __msix_setup_interrupts()
struct pci_dev *dev __free(free_msi_irqs) = __dev;
...
return ret; // __free cleanup fires on errorThe __free(free_msi_irqs) cleanup calls pci_free_msi_irqs(), which already handles the unmap:
void pci_free_msi_irqs(struct pci_dev *dev)
{
pci_msi_teardown_msi_irqs(dev);
if (dev->msix_base) {
iounmap(dev->msix_base); // already unmapped here
dev->msix_base = NULL; // and set to NULL
}
}So dev->msix_base is unmapped and set to NULL before msix_setup_interrupts() returns to msix_capability_init(). The "goto out_unmap" introduced by commit 1a8d4c6ecb4c ("PCI/MSI: Unmap MSI-X region on error") then calls iounmap() a second time on a NULL pointer.
This was reproduced on Intel Emerald Rapids (192 CPUs) while running tools/testing/selftests/kexec/test_kexec_jump.sh:
WARNING: CPU#44 at iounmap+0x2a/0xe0
RIP: 0010:iounmap+0x2a/0xe0 RDI: 0000000000000000 Call Trace: msix_capability_init+0x317/0x3f0 __pci_enable_msix_range+0x21d/0x2c0 pci_alloc_irq_vectors_affinity+0xa9/0x130 nvme_setup_io_queues+0x2a8/0x420 [nvme] nvme_reset_work+0x151/0x340 [nvme] ...
RDI=0 confirms iounmap() is called with NULL.
Restore the original "goto out_disable" and leave the unmap to the existing __free(free_msi_irqs) cleanup.
--- drivers/pci/msi/msi.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-)
drivers/pci/msi/msi.c +1 -3
@@ -737,7 +737,7 @@ static int msix_capability_init(struct pci_dev *dev, struct msix_entry *entries, ret =msix_setup_interrupts (dev, entries, nvec, affd);if (ret) - goto out_unmap; + goto out_disable;/* Disable INTX */ pci_intx_for_msi (dev,0 );
@@ -756,8 +756,6 @@ static int msix_capability_init(struct pci_dev *dev, struct msix_entry *entries,pcibios_free_irq (dev);return 0 ; -out_unmap: -iounmap (dev->msix_base); out_disable: dev->msix_enabled =0 ;pci_msix_clear_and_set_ctrl (dev,PCI_MSIX_FLAGS_MASKALL |PCI_MSIX_FLAGS_ENABLE ,0 );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 696/1266 security/apparmor/apparmorfs.c: conditionally compile get_loaddata_common_ref()
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Andrew Morton <[email protected]>
[ Upstream commit d62d9bfe050f44f772d05a32079dba3e3523ab2a ]
Some config did this:
security/apparmor/apparmorfs.c:177:28: warning: 'get_loaddata_common_ref' defined but not used [-Wunused-function]
177 | static struct aa_loaddata *get_loaddata_common_ref(struct aa_common_ref *ref)
get_loaddata_common_ref() is only used ifCONFIG_SECURITY_APPARMOR_EXPORT_BINARY=y.
(Or of course move the function into that block if maintainers perfer)
--- security/apparmor/apparmorfs.c | 2 ++ 1 file changed, 2 insertions(+)
security/apparmor/apparmorfs.c +2 -0
@@ -174,6 +174,7 @@ static struct aa_proxy *get_proxy_common_ref(struct aa_common_ref *ref)return NULL ; } +#ifdef CONFIG_SECURITY_APPARMOR_EXPORT_BINARY static struct aa_loaddata *get_loaddata_common_ref (struct aa_common_ref *ref) {if (ref)
@@ -181,6 +182,7 @@ static struct aa_loaddata *get_loaddata_common_ref(struct aa_common_ref *ref) count)); return NULL; } +#endif static void aa_put_common_ref (struct aa_common_ref *ref) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 697/1266 apparmor: check label build before no_new_privs test
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ruoyu Wang <[email protected]>
[ Upstream commit a58cafd38b46fb1a2220e2fbbcfe291ea75fa147 ]
aa_change_profile() builds a replacement label with fn_label_build_in_scope() before the no_new_privs subset check. The build helper can fail and return NULL or an ERR_PTR, but the result was passed to aa_label_is_unconfined_subset() before the existing IS_ERR_OR_NULL() check.
Reuse the existing target-label build failure handling immediately after the build. This preserves the current audit handling while preventing the subset helper from dereferencing an invalid label.
--- security/apparmor/domain.c | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-)
security/apparmor/domain.c +15 -10
@@ -1440,6 +1440,8 @@ int aa_change_profile(const char *fqname, int flags) new =fn_label_build_in_ns (label, profile,GFP_KERNEL ,aa_get_label (target),aa_get_label (&profile->label)); +if (IS_ERR_OR_NULL (new)) + goto build_fail;/* * no new privs prevents domain transitions that would * reduce restrictions.
@@ -1457,16 +1459,8 @@ int aa_change_profile(const char *fqname, int flags)/* only transition profiles in the current ns */ if (stack) new =aa_label_merge (label, target,GFP_KERNEL ); -if (IS_ERR_OR_NULL (new)) { - info ="failed to build target label" ; -if (!new) - error = -ENOMEM ; -else - error =PTR_ERR (new); - new =NULL ; - perms.allow =0 ; - goto audit; - } +if (IS_ERR_OR_NULL (new)) + goto build_fail; error =aa_replace_current_label (new); }else {if (new) {
@@ -1478,6 +1472,17 @@ int aa_change_profile(const char *fqname, int flags) error =aa_set_current_onexec (target, stack); } + goto audit; + +build_fail: + info ="failed to build target label" ; +if (!new) + error = -ENOMEM ; +else + error =PTR_ERR (new); + new =NULL ; + perms.allow =0 ; + audit: error = fn_for_each_in_ns(label, profile, aa_audit_file(subj_cred,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 698/1266 apparmor: aa_label_alloc use aa_label_free on alloc failure
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zygmunt Krynicki <[email protected]>
[ Upstream commit 654fe7505dc6889724d4094fa64f89991afabfc3 ]
aa_label_alloc() allocates a secid before allocating or taking the label proxy. If the later proxy step fails, the error path only freed the label memory, leaking any resources initialized by aa_label_init().
Use aa_label_free() on the failure path so partially initialized labels release their secid and other label resources before the backing memory is freed.
--- security/apparmor/label.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
security/apparmor/label.c +1 -1
@@ -452,7 +452,7 @@ struct aa_label *aa_label_alloc(int size, struct aa_proxy *proxy, gfp_t gfp)return new; fail: -kfree (new); +aa_label_free (new);return NULL ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 699/1266 apparmor: fix rawdata_f_data implicit flex array
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: John Johansen <[email protected]>
[ Upstream commit ad213bbbc0e3e270ce7df2d9d80d4ce3826993d7 ]
rawdata_f_data has a blob of data that is allocated at its end but not explicitly declared. Makes sure it is correctly declared as a flex_rray.
--- security/apparmor/apparmorfs.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-)
security/apparmor/apparmorfs.c +3 -4
@@ -71,10 +71,10 @@struct rawdata_f_data {struct aa_loaddata *loaddata; + DECLARE_FLEX_ARRAY(char, data); };#ifdef CONFIG_SECURITY_APPARMOR_EXPORT_BINARY -#define RAWDATA_F_DATA_BUF (p) (char *)(p + 1)static void rawdata_f_data_free (struct rawdata_f_data *private) {
@@ -1436,7 +1436,7 @@ static ssize_t rawdata_read(struct file *file, char __user *buf, size_t size,struct rawdata_f_data *private = file->private_data;return simple_read_from_buffer (buf, size, ppos, -RAWDATA_F_DATA_BUF (private), + private->data, private->loaddata->size); }
@@ -1469,8 +1469,7 @@ static int rawdata_open(struct inode *inode, struct file *file) private->loaddata = loaddata; error =decompress_zstd (loaddata->data, loaddata->compressed_size, -RAWDATA_F_DATA_BUF (private), - loaddata->size); + private->data, loaddata->size);if (error) goto fail_decompress;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 700/1266 apparmor: grab ns lock and refresh when looking up changehat child profiles
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ryan Lee <[email protected]>
[ Upstream commit 32e92764d6f8d251c1bca62be33793287b453a81 ]
There was a race condition involving change_hat and profile replacement in which replacement of the parent profile during a changehat operation could result in the list of children becoming empty and the changehat operation failing. To prevent this:
- grab the namespace lock until we've built the hat transition, and
- use aa_get_newest_profile to avoid using stale profile objects.
--- security/apparmor/domain.c | 33 +++++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-)
security/apparmor/domain.c +31 -2
@@ -13,6 +13,7 @@#include <linux/fs.h> #include <linux/file.h> #include <linux/mount.h> +#include <linux/mutex.h> #include <linux/syscalls.h> #include <linux/personality.h> #include <linux/xattr.h>
@@ -1061,6 +1062,7 @@ static struct aa_label *change_hat(const struct cred *subj_cred, int count, int flags) {struct aa_profile *profile, *root, *hat =NULL ; +struct aa_ns *ns, *new_ns;struct aa_label *new;struct label_it it;bool sibling = false;
@@ -1071,6 +1073,32 @@ static struct aa_label *change_hat(const struct cred *subj_cred,AA_BUG (!hats);AA_BUG (count <1 ); +/* +* Acquire the newest label and then hold the lock until we choose a +* hat, so that profile replacement doesn't atomically truncate the +* list of potential hats. Because we are getting the namespaces from +* the profiles and label, we can rely on the namespaces being live +* and avoid incrementing their refcounts while grabbing the lock. +*/ + label =aa_get_label (label); + ns =labels_ns (label); + +retry: +mutex_lock_nested (&ns->lock, ns->level); +if (label_is_stale (label)) { + new =aa_get_newest_label (label); + new_ns =labels_ns (new); +if (new_ns != ns) { +aa_put_label (new); +mutex_unlock (&ns->lock); + ns = new_ns; + label = new; + goto retry; + } +aa_put_label (label); + label = new; + } +if (PROFILE_IS_HAT (labels_profile (label))) sibling = true;
@@ -1079,7 +1107,7 @@ static struct aa_label *change_hat(const struct cred *subj_cred, name = hats[i];label_for_each_in_ns (it,labels_ns (label), label, profile) {if (sibling &&PROFILE_IS_HAT (profile)) { - root =aa_get_profile_rcu (&profile->parent); + root =aa_get_profile (profile->parent); }else if (!sibling && !PROFILE_IS_HAT (profile)) { root =aa_get_profile (profile); }else {/* conflicting change type */
@@ -1139,6 +1167,7 @@ static struct aa_label *change_hat(const struct cred *subj_cred, GLOBAL_ROOT_UID, info, error); } } +mutex_unlock (&ns->lock);return ERR_PTR (error); build:
@@ -1151,7 +1180,7 @@ static struct aa_label *change_hat(const struct cred *subj_cred, error = -ENOMEM ; goto fail; }/* else if (IS_ERR) build_change_hat has logged error so return new */ - +mutex_unlock (&ns->lock);return new; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 701/1266 apparmor: fix potential UAF in aa_replace_profiles
In reply to Greg Kroah-Hartman6.6-stable review patch. If anyone has any objections, please let me know.
------------------
From: Maxime Bélair <[email protected]>
[ Upstream commit 7b42f95813dc9ceb6bda35afcf914630909a19f9 ]
The function aa_replace_profiles was accessing udata->size after calling aa_put_loaddata(udata), causing a potential UAF.
Fixed this by saving the size to a local variable before dropping the reference.
--- security/apparmor/policy.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
security/apparmor/policy.c +3 -1
@@ -1324,13 +1324,15 @@ ssize_t aa_replace_profiles(struct aa_ns *policy_ns, struct aa_label *label,mutex_unlock (&ns->lock); out: +ssize_t udata_sz = udata->size; +aa_put_ns (ns);aa_put_profile_loaddata (udata);kfree (ns_name);if (error)return error; -return udata->size; +return udata_sz; fail_lock:mutex_unlock (&ns->lock);
Signature · 1 line
2.53.0