7.0.7-rc1 review
Greg Kroah-Hartman
maintainerPATCH 298/307 hfsplus: fix uninit-value by validating catalog record size
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Deepanshu Kartikey <[email protected]>
[ Upstream commit b6b592275aeff184aa82fcf6abccd833fb71b393 ]
Syzbot reported a KMSAN uninit-value issue in hfsplus_strcasecmp(). The root cause is that hfs_brec_read() doesn't validate that the on-disk record size matches the expected size for the record type being read.
When mounting a corrupted filesystem, hfs_brec_read() may read less data than expected. For example, when reading a catalog thread record, the debug output showed:
HFSPLUS_BREC_READ: rec_len=520, fd->entrylength=26
HFSPLUS_BREC_READ: WARNING - entrylength (26) < rec_len (520) - PARTIAL READ!
hfs_brec_read() only validates that entrylength is not greater than the buffer size, but doesn't check if it's less than expected. It successfully reads 26 bytes into a 520-byte structure and returns success, leaving 494 bytes uninitialized.
This uninitialized data in tmp.thread.nodeName then gets copied by hfsplus_cat_build_key_uni() and used by hfsplus_strcasecmp(), triggering the KMSAN warning when the uninitialized bytes are used as array indices in case_fold().
Fix by introducing hfsplus_brec_read_cat() wrapper that:
1. Calls hfs_brec_read() to read the data
2. Validates the record size based on the type field:
- Fixed size for folder and file records
- Variable size for thread records (depends on string length)
3. Returns -EIO if size doesn't match expected
For thread records, check against HFSPLUS_MIN_THREAD_SZ before reading nodeName.length to avoid reading uninitialized data at call sites that don't zero-initialize the entry structure.
Also initialize the tmp variable in hfsplus_find_cat() as defensive programming to ensure no uninitialized data even if validation is bypassed.
Stable-dep-of: 90c500e4fd83 ("hfsplus: fix held lock freed on hfsplus_fill_super()")
--- fs/hfsplus/bfind.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++++ fs/hfsplus/catalog.c | 4 +-- fs/hfsplus/dir.c | 2 - fs/hfsplus/hfsplus_fs.h | 9 ++++++++ fs/hfsplus/super.c | 2 - 5 files changed, 64 insertions(+), 4 deletions(-)
fs/hfsplus/bfind.c +51 -0
@@ -287,3 +287,54 @@ out: fd->bnode = bnode;return res; } + +/** +* hfsplus_brec_read_cat - read and validate a catalog record +* @fd: find data structure +* @entry: pointer to catalog entry to read into +* +* Reads a catalog record and validates its size matches the expected +* size based on the record type. +* +* Returns 0 on success, or negative error code on failure. +*/ +int hfsplus_brec_read_cat (struct hfs_find_data *fd,hfsplus_cat_entry *entry) +{ +int res; +u32 expected_size; + + res =hfs_brec_read (fd, entry,sizeof (hfsplus_cat_entry)); +if (res) +return res; + +/* Validate catalog record size based on type */ +switch (be16_to_cpu (entry->type)) { +case HFSPLUS_FOLDER : + expected_size =sizeof (struct hfsplus_cat_folder ); +break ; +case HFSPLUS_FILE : + expected_size =sizeof (struct hfsplus_cat_file ); +break ; +case HFSPLUS_FOLDER_THREAD : +case HFSPLUS_FILE_THREAD : +/* Ensure we have at least the fixed fields before reading nodeName.length */ +if (fd->entrylength <HFSPLUS_MIN_THREAD_SZ ) { +pr_err ("thread record too short (got %u)\n" , fd->entrylength); +return -EIO ; + } + expected_size =hfsplus_cat_thread_size (&entry->thread); +break ; +default : +pr_err ("unknown catalog record type %d\n" , +be16_to_cpu (entry->type)); +return -EIO ; + } + +if (fd->entrylength != expected_size) { +pr_err ("catalog record size mismatch (type %d, got %u, expected %u)\n" , +be16_to_cpu (entry->type), fd->entrylength, expected_size); +return -EIO ; + } + +return 0 ; +}
fs/hfsplus/catalog.c +2 -2
@@ -194,12 +194,12 @@ static int hfsplus_fill_cat_thread(strucint hfsplus_find_cat (struct super_block *sb,u32 cnid,struct hfs_find_data *fd) { -hfsplus_cat_entry tmp; +hfsplus_cat_entry tmp = {0 };int err;u16 type;hfsplus_cat_build_key_with_cnid (sb, fd->search_key, cnid); - err =hfs_brec_read (fd, &tmp,sizeof (hfsplus_cat_entry)); + err =hfsplus_brec_read_cat (fd, &tmp);if (err)return err;
fs/hfsplus/dir.c +1 -1
@@ -49,7 +49,7 @@ static struct dentry *hfsplus_lookup(strif (unlikely (err <0 )) goto fail; again: - err =hfs_brec_read (&fd, &entry,sizeof (entry)); + err =hfsplus_brec_read_cat (&fd, &entry);if (err) {if (err == -ENOENT ) {hfs_find_exit (&fd);
fs/hfsplus/hfsplus_fs.h +9 -0
@@ -509,6 +509,15 @@ int hfsplus_submit_bio(struct super_bloc void **data, blk_opf_t opf);int hfsplus_read_wrapper (struct super_block *sb); +static inline u32 hfsplus_cat_thread_size (const struct hfsplus_cat_thread *thread) +{ +return offsetof(struct hfsplus_cat_thread , nodeName) + + offsetof(struct hfsplus_unistr , unicode) + +be16_to_cpu (thread->nodeName.length) *sizeof (hfsplus_unichr); +} + +int hfsplus_brec_read_cat (struct hfs_find_data *fd,hfsplus_cat_entry *entry); +/* * time helpers: convert between 1904-base and 1970-base timestamps *
fs/hfsplus/super.c +1 -1
@@ -571,7 +571,7 @@ static int hfsplus_fill_super(struct sup err =hfsplus_cat_build_key (sb, fd.search_key,HFSPLUS_ROOT_CNID , &str);if (unlikely (err <0 )) goto out_put_root; -if (!hfs_brec_read (&fd, &entry,sizeof (entry))) { +if (!hfsplus_brec_read_cat (&fd, &entry)) {hfs_find_exit (&fd);if (entry.type !=cpu_to_be16 (HFSPLUS_FOLDER )) { err = -EIO ;
Greg Kroah-Hartman
maintainerPATCH 299/307 hfsplus: fix held lock freed on hfsplus_fill_super()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zilin Guan <[email protected]>
[ Upstream commit 90c500e4fd83fa33c09bc7ee23b6d9cc487ac733 ]
hfsplus_fill_super() calls hfs_find_init() to initialize a search structure, which acquires tree->tree_lock. If the subsequent call to hfsplus_cat_build_key() fails, the function jumps to the out_put_root error label without releasing the lock. The later cleanup path then frees the tree data structure with the lock still held, triggering a held lock freed warning.
Fix this by adding the missing hfs_find_exit(&fd) call before jumping to the out_put_root error label. This ensures that tree->tree_lock is properly released on the error path.
The bug was originally detected on v6.13-rc1 using an experimental static analysis tool we are developing, and we have verified that the issue persists in the latest mainline kernel. The tool is specifically designed to detect memory management issues. It is currently under active development and not yet publicly available.
We confirmed the bug by runtime testing under QEMU with x86_64 defconfig, lockdep enabled, and CONFIG_HFSPLUS_FS=y. To trigger the error path, we used GDB to dynamically shrink the max_unistr_len parameter to 1 before hfsplus_asc2uni() is called. This forces hfsplus_asc2uni() to naturally return -ENAMETOOLONG, which propagates to hfsplus_cat_build_key() and exercises the faulty error path. The following warning was observed during mount:
=========================
WARNING: held lock freed!
7.0.0-rc3-00016-gb4f0dd314b39 #4 Not tainted
-------------------------
mount/174 is freeing memory ffff888103f92000-ffff888103f92fff, with a lock still held there!
ffff888103f920b0 (&tree->tree_lock){+.+.}-{4:4}, at: hfsplus_find_init+0x154/0x1e0
2 locks held by mount/174:
#0: ffff888103f960e0 (&type->s_umount_key#42/1){+.+.}-{4:4}, at: alloc_super.constprop.0+0x167/0xa40
#1: ffff888103f920b0 (&tree->tree_lock){+.+.}-{4:4}, at: hfsplus_find_init+0x154/0x1e0
stack backtrace:
CPU: 2 UID: 0 PID: 174 Comm: mount Not tainted 7.0.0-rc3-00016-gb4f0dd314b39 #4 PREEMPT(lazy)
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.15.0-1 04/01/2014
Call Trace:
<TASK>
dump_stack_lvl+0x82/0xd0
debug_check_no_locks_freed+0x13a/0x180
kfree+0x16b/0x510
? hfsplus_fill_super+0xcb4/0x18a0
hfsplus_fill_super+0xcb4/0x18a0
? __pfx_hfsplus_fill_super+0x10/0x10
? srso_return_thunk+0x5/0x5f
? bdev_open+0x65f/0xc30
? srso_return_thunk+0x5/0x5f
? pointer+0x4ce/0xbf0
? trace_contention_end+0x11c/0x150
? __pfx_pointer+0x10/0x10
? srso_return_thunk+0x5/0x5f
? bdev_open+0x79b/0xc30
? srso_return_thunk+0x5/0x5f
? srso_return_thunk+0x5/0x5f
? vsnprintf+0x6da/0x1270
? srso_return_thunk+0x5/0x5f
? __mutex_unlock_slowpath+0x157/0x740
? __pfx_vsnprintf+0x10/0x10
? srso_return_thunk+0x5/0x5f
? srso_return_thunk+0x5/0x5f
? mark_held_locks+0x49/0x80
? srso_return_thunk+0x5/0x5f
? srso_return_thunk+0x5/0x5f
? irqentry_exit+0x17b/0x5e0
? trace_irq_disable.constprop.0+0x116/0x150
? __pfx_hfsplus_fill_super+0x10/0x10
? __pfx_hfsplus_fill_super+0x10/0x10
get_tree_bdev_flags+0x302/0x580
? __pfx_get_tree_bdev_flags+0x10/0x10
? vfs_parse_fs_qstr+0x129/0x1a0
? __pfx_vfs_parse_fs_qstr+0x3/0x10
vfs_get_tree+0x89/0x320
fc_mount+0x10/0x1d0
path_mount+0x5c5/0x21c0
? __pfx_path_mount+0x10/0x10
? trace_irq_enable.constprop.0+0x116/0x150
? trace_irq_enable.constprop.0+0x116/0x150
? srso_return_thunk+0x5/0x5f
? srso_return_thunk+0x5/0x5f
? kmem_cache_free+0x307/0x540
? user_path_at+0x51/0x60
? __x64_sys_mount+0x212/0x280
? srso_return_thunk+0x5/0x5f
__x64_sys_mount+0x212/0x280
? __pfx___x64_sys_mount+0x10/0x10
? srso_return_thunk+0x5/0x5f
? trace_irq_enable.constprop.0+0x116/0x150
? srso_return_thunk+0x5/0x5f
do_syscall_64+0x111/0x680
entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x7ffacad55eae
Code: 48 8b 0d 85 1f 0f 00 f7 d8 64 89 01 48 83 c8 ff c3 66 2e 0f 1f 84 00 00 00 00 00 90 f3 0f 1e fa 49 89 ca b8 a5 00 00 8
RSP: 002b:00007fff1ab55718 EFLAGS: 00000246 ORIG_RAX: 00000000000000a5
RAX: ffffffffffffffda RBX: 0000000000000000 RCX: 00007ffacad55eae
RDX: 000055740c64e5b0 RSI: 000055740c64e630 RDI: 000055740c651ab0
RBP: 000055740c64e380 R08: 0000000000000000 R09: 0000000000000001
R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000
R13: 000055740c64e5b0 R14: 000055740c651ab0 R15: 000055740c64e380
</TASK>After applying this patch, the warning no longer appears.
--- fs/hfsplus/super.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
fs/hfsplus/super.c +3 -1
@@ -569,8 +569,10 @@ static int hfsplus_fill_super(struct supif (err) goto out_put_root; err =hfsplus_cat_build_key (sb, fd.search_key,HFSPLUS_ROOT_CNID , &str); -if (unlikely (err <0 )) +if (unlikely (err <0 )) { +hfs_find_exit (&fd); goto out_put_root; + }if (!hfsplus_brec_read_cat (&fd, &entry)) {hfs_find_exit (&fd);if (entry.type !=cpu_to_be16 (HFSPLUS_FOLDER )) {
Greg Kroah-Hartman
maintainerPATCH 300/307 8021q: use RCU for egress QoS mappings
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Longxuan Yu <[email protected]>
[ Upstream commit fc69decc811b155a0ed8eef17ee940f28c4f6dbc ]
The TX fast path and reporting paths walk egress QoS mappings without RTNL. Convert the mapping lists to RCU-protected pointers, use RCU reader annotations in readers, and defer freeing mapping nodes with an embedded rcu_head.
This prepares the egress QoS mapping code for safe removal of mapping nodes in a follow-up change while preserving the current behavior.
Stable-dep-of: 7dddc74af369 ("8021q: delete cleared egress QoS mappings")
--- include/linux/if_vlan.h | 25 ++++++++++++++++--------- net/8021q/vlan_dev.c | 31 ++++++++++++++++--------------- net/8021q/vlan_netlink.c | 10 ++++++---- net/8021q/vlanproc.c | 12 ++++++++---- 4 files changed, 46 insertions(+), 32 deletions(-)
include/linux/if_vlan.h +16 -9
@@ -147,11 +147,13 @@ extern __be16 vlan_dev_vlan_proto(const* @priority: skb priority * @vlan_qos: vlan priority: (skb->priority << 13) & 0xE000 * @next: pointer to next struct +* @rcu: used for deferred freeing of mapping nodes */ struct vlan_priority_tci_mapping {u32 priority;u16 vlan_qos; -struct vlan_priority_tci_mapping *next; +struct vlan_priority_tci_mapping __rcu *next; +struct rcu_head rcu; };struct proc_dir_entry ;
@@ -177,7 +179,7 @@ struct vlan_dev_priv {unsigned int nr_ingress_mappings;u32 ingress_priority_map[8 ];unsigned int nr_egress_mappings; -struct vlan_priority_tci_mapping *egress_priority_map[16 ]; +struct vlan_priority_tci_mapping __rcu *egress_priority_map[16 ];__be16 vlan_proto;u16 vlan_id;
@@ -209,19 +211,24 @@ static inline u16 vlan_dev_get_egress_qos_mask(struct net_device *dev, u32 skprio) {struct vlan_priority_tci_mapping *mp; +u16 vlan_qos =0 ; -smp_rmb ();/* coupled with smp_wmb() in vlan_dev_set_egress_priority() */ +rcu_read_lock (); - mp =vlan_dev_priv (dev)->egress_priority_map[(skprio &0xF )]; + mp =rcu_dereference (vlan_dev_priv (dev)->egress_priority_map[skprio &0xF ]);while (mp) {if (mp->priority == skprio) { -return mp->vlan_qos;/* This should already be shifted -* to mask correctly with the -* VLAN's TCI */ + vlan_qos =READ_ONCE (mp->vlan_qos); +break ; } - mp = mp->next; + mp =rcu_dereference (mp->next); } -return 0 ; +rcu_read_unlock (); + +/* This should already be shifted to mask correctly with +* the VLAN's TCI. +*/ +return vlan_qos; }extern bool vlan_do_receive (struct sk_buff **skb);
net/8021q/vlan_dev.c +16 -15
@@ -172,39 +172,34 @@ int vlan_dev_set_egress_priority(const s u32 skb_prio, u16 vlan_prio) {struct vlan_dev_priv *vlan =vlan_dev_priv (dev); -struct vlan_priority_tci_mapping *mp =NULL ; +struct vlan_priority_tci_mapping *mp;struct vlan_priority_tci_mapping *np; +u32 bucket = skb_prio &0xF ;u32 vlan_qos = (vlan_prio <<VLAN_PRIO_SHIFT ) &VLAN_PRIO_MASK ;/* See if a priority mapping exists.. */ - mp = vlan->egress_priority_map[skb_prio &0xF ]; + mp =rtnl_dereference (vlan->egress_priority_map[bucket]);while (mp) {if (mp->priority == skb_prio) {if (mp->vlan_qos && !vlan_qos) vlan->nr_egress_mappings--;else if (!mp->vlan_qos && vlan_qos) vlan->nr_egress_mappings++; - mp->vlan_qos = vlan_qos; +WRITE_ONCE (mp->vlan_qos, vlan_qos);return 0 ; } - mp = mp->next; + mp =rtnl_dereference (mp->next); }/* Create a new mapping then. */ - mp = vlan->egress_priority_map[skb_prio &0xF ]; np = kmalloc_obj(struct vlan_priority_tci_mapping);if (!np)return -ENOBUFS ; - np->next = mp; np->priority = skb_prio; np->vlan_qos = vlan_qos; -/* Before inserting this element in hash table, make sure all its fields -* are committed to memory. -* coupled with smp_rmb() in vlan_dev_get_egress_qos_mask() -*/ -smp_wmb (); - vlan->egress_priority_map[skb_prio &0xF ] = np; +RCU_INIT_POINTER (np->next,rtnl_dereference (vlan->egress_priority_map[bucket])); +rcu_assign_pointer (vlan->egress_priority_map[bucket], np);if (vlan_qos) vlan->nr_egress_mappings++;return 0 ;
@@ -604,11 +599,17 @@ void vlan_dev_free_egress_priority(constint i;for (i =0 ; i <ARRAY_SIZE (vlan->egress_priority_map); i++) { -while ((pm = vlan->egress_priority_map[i]) !=NULL ) { - vlan->egress_priority_map[i] = pm->next; -kfree (pm); + pm =rtnl_dereference (vlan->egress_priority_map[i]); +RCU_INIT_POINTER (vlan->egress_priority_map[i],NULL ); +while (pm) { +struct vlan_priority_tci_mapping *next; + + next =rtnl_dereference (pm->next); +kfree_rcu (pm, rcu); + pm = next; } } + vlan->nr_egress_mappings =0 ; }static void vlan_dev_uninit (struct net_device *dev)
net/8021q/vlan_netlink.c +6 -4
@@ -260,13 +260,15 @@ static int vlan_fill_info(struct sk_buff goto nla_put_failure;for (i =0 ; i <ARRAY_SIZE (vlan->egress_priority_map); i++) { -for (pm = vlan->egress_priority_map[i]; pm; - pm = pm->next) { -if (!pm->vlan_qos) +for (pm =rcu_dereference_rtnl (vlan->egress_priority_map[i]); pm; + pm =rcu_dereference_rtnl (pm->next)) { +u16 vlan_qos =READ_ONCE (pm->vlan_qos); + +if (!vlan_qos)continue ; m.from = pm->priority; - m.to = (pm->vlan_qos >>13 ) &0x7 ; + m.to = (vlan_qos >>13 ) &0x7 ;if (nla_put (skb,IFLA_VLAN_QOS_MAPPING ,sizeof (m), &m)) goto nla_put_failure;
net/8021q/vlanproc.c +8 -4
@@ -262,15 +262,19 @@ static int vlandev_seq_show(struct seq_f vlan->ingress_priority_map[7]);seq_printf (seq," EGRESS priority mappings: " ); +rcu_read_lock ();for (i =0 ; i <16 ; i++) { -const struct vlan_priority_tci_mapping *mp - = vlan->egress_priority_map[i]; +const struct vlan_priority_tci_mapping *mp = +rcu_dereference (vlan->egress_priority_map[i]);while (mp) { +u16 vlan_qos =READ_ONCE (mp->vlan_qos); +seq_printf (seq,"%u:%d " , - mp->priority, ((mp->vlan_qos >>13 ) &0x7 )); - mp = mp->next; + mp->priority, ((vlan_qos >>13 ) &0x7 )); + mp =rcu_dereference (mp->next); } } +rcu_read_unlock ();seq_puts (seq,"\n" );return 0 ;
Greg Kroah-Hartman
maintainerPATCH 301/307 8021q: delete cleared egress QoS mappings
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Longxuan Yu <[email protected]>
[ Upstream commit 7dddc74af369478ba7f9bc136d0fc1dc4570cb66 ]
vlan_dev_set_egress_priority() currently keeps cleared egress priority mappings in the hash as tombstones. Repeated set/clear cycles with distinct skb priorities therefore accumulate mapping nodes until device teardown and leak memory.
Delete mappings when vlan_prio is cleared instead of keeping tombstones. Now that the egress mapping lists are RCU protected, the node can be unlinked safely and freed after a grace period.
--- net/8021q/vlan_dev.c | 20 ++++++++++++++------ net/8021q/vlan_netlink.c | 4 ---- 2 files changed, 14 insertions(+), 10 deletions(-)
net/8021q/vlan_dev.c +14 -6
@@ -172,26 +172,34 @@ int vlan_dev_set_egress_priority(const s u32 skb_prio, u16 vlan_prio) {struct vlan_dev_priv *vlan =vlan_dev_priv (dev); +struct vlan_priority_tci_mapping __rcu **mpp;struct vlan_priority_tci_mapping *mp;struct vlan_priority_tci_mapping *np;u32 bucket = skb_prio &0xF ;u32 vlan_qos = (vlan_prio <<VLAN_PRIO_SHIFT ) &VLAN_PRIO_MASK ;/* See if a priority mapping exists.. */ - mp =rtnl_dereference (vlan->egress_priority_map[bucket]); + mpp = &vlan->egress_priority_map[bucket]; + mp =rtnl_dereference (*mpp);while (mp) {if (mp->priority == skb_prio) { -if (mp->vlan_qos && !vlan_qos) +if (!vlan_qos) { +rcu_assign_pointer (*mpp,rtnl_dereference (mp->next)); vlan->nr_egress_mappings--; -else if (!mp->vlan_qos && vlan_qos) - vlan->nr_egress_mappings++; -WRITE_ONCE (mp->vlan_qos, vlan_qos); +kfree_rcu (mp, rcu); + }else { +WRITE_ONCE (mp->vlan_qos, vlan_qos); + }return 0 ; } - mp =rtnl_dereference (mp->next); + mpp = &mp->next; + mp =rtnl_dereference (*mpp); }/* Create a new mapping then. */ +if (!vlan_qos) +return 0 ; + np = kmalloc_obj(struct vlan_priority_tci_mapping);if (!np)return -ENOBUFS ;
net/8021q/vlan_netlink.c +0 -4
@@ -263,10 +263,6 @@ static int vlan_fill_info(struct sk_bufffor (pm =rcu_dereference_rtnl (vlan->egress_priority_map[i]); pm; pm =rcu_dereference_rtnl (pm->next)) {u16 vlan_qos =READ_ONCE (pm->vlan_qos); - -if (!vlan_qos) -continue ; - m.from = pm->priority; m.to = (vlan_qos >>13 ) &0x7 ; if (nla_put(skb, IFLA_VLAN_QOS_MAPPING,
Greg Kroah-Hartman
maintainerPATCH 302/307 printk: add print_hex_dump_devel()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thorsten Blum <[email protected]>
[ Upstream commit d134feeb5df33fbf77f482f52a366a44642dba09 ]
Add print_hex_dump_devel() as the hex dump equivalent of pr_devel(), which emits output only when DEBUG is enabled, but keeps call sites compiled otherwise.
Stable-dep-of: 177730a273b1 ("crypto: caam - guard HMAC key hex dumps in hash_digest_key")
--- include/linux/printk.h | 13 +++++++++++++ 1 file changed, 13 insertions(+)
include/linux/printk.h +13 -0
@@ -801,6 +801,19 @@ static inline void print_hex_dump_debug( }#endif +#if defined(DEBUG ) +#define print_hex_dump_devel (prefix_str, prefix_type, rowsize, \ + groupsize, buf, len, ascii) \ + print_hex_dump(KERN_DEBUG, prefix_str, prefix_type, rowsize, \ + groupsize, buf, len, ascii) +#else +static inline void print_hex_dump_devel (const char *prefix_str,int prefix_type, +int rowsize,int groupsize, +const void *buf,size_t len,bool ascii) +{ +} +#endif +/** * print_hex_dump_bytes - shorthand form of print_hex_dump() with default params * @prefix_str: string to prefix each line with;
Greg Kroah-Hartman
maintainerPATCH 303/307 crypto: caam - guard HMAC key hex dumps in hash_digest_key
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thorsten Blum <[email protected]>
[ Upstream commit 177730a273b18e195263ed953853273e901b5064 ]
Use print_hex_dump_devel() for dumping sensitive HMAC key bytes in hash_digest_key() to avoid leaking secrets at runtime when CONFIG_DYNAMIC_DEBUG is enabled.
--- drivers/crypto/caam/caamalg_qi2.c | 4 ++-- drivers/crypto/caam/caamhash.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-)
drivers/crypto/caam/caamalg_qi2.c +2 -2
@@ -3269,7 +3269,7 @@ static int hash_digest_key(struct caam_hdpaa2_fl_set_addr (out_fle, key_dma);dpaa2_fl_set_len (out_fle, digestsize); - print_hex_dump_debug("key_in@" __stringify(__LINE__)": ", + print_hex_dump_devel("key_in@" __stringify(__LINE__)": ",DUMP_PREFIX_ADDRESS ,16 ,4 , key, *keylen,1 ); print_hex_dump_debug("shdesc@" __stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc),
@@ -3289,7 +3289,7 @@ static int hash_digest_key(struct caam_h/* in progress */ wait_for_completion (&result.completion); ret = result.err; - print_hex_dump_debug("digested key@" __stringify(__LINE__)": ", + print_hex_dump_devel("digested key@" __stringify(__LINE__)": ",DUMP_PREFIX_ADDRESS ,16 ,4 , key, digestsize,1 ); }
drivers/crypto/caam/caamhash.c +2 -2
@@ -393,7 +393,7 @@ static int hash_digest_key(struct caam_happend_seq_store (desc, digestsize,LDST_CLASS_2_CCB |LDST_SRCDST_BYTE_CONTEXT ); - print_hex_dump_debug("key_in@"__stringify(__LINE__)": ", + print_hex_dump_devel("key_in@"__stringify(__LINE__)": ",DUMP_PREFIX_ADDRESS ,16 ,4 , key, *keylen,1 ); print_hex_dump_debug("jobdesc@"__stringify(__LINE__)": ", DUMP_PREFIX_ADDRESS, 16, 4, desc, desc_bytes(desc),
@@ -408,7 +408,7 @@ static int hash_digest_key(struct caam_hwait_for_completion (&result.completion); ret = result.err; - print_hex_dump_debug("digested key@"__stringify(__LINE__)": ", + print_hex_dump_devel("digested key@"__stringify(__LINE__)": ",DUMP_PREFIX_ADDRESS ,16 ,4 , key, digestsize,1 ); }
Greg Kroah-Hartman
maintainerPATCH 304/307 net: stmmac: rename STMMAC_GET_ENTRY() -> STMMAC_NEXT_ENTRY()
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: "Russell King (Oracle)" <[email protected]>
[ Upstream commit 6b4286e0550814cdc4b897f881ec1fa8b0313227 ]
STMMAC_GET_ENTRY() doesn't describe what this macro is doing - it is incrementing the provided index for the circular array of descriptors. Replace "GET" with "NEXT" as this better describes the action here.
Stable-dep-of: 0bb05e6adfa9 ("net: stmmac: Prevent NULL deref when RX memory exhausted")
--- drivers/net/ethernet/stmicro/stmmac/chain_mode.c | 2 - drivers/net/ethernet/stmicro/stmmac/common.h | 2 - drivers/net/ethernet/stmicro/stmmac/ring_mode.c | 2 - drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 26 +++++++++++----------- 4 files changed, 16 insertions(+), 16 deletions(-)
drivers/net/ethernet/stmicro/stmmac/chain_mode.c +1 -1
@@ -47,7 +47,7 @@ static int jumbo_frm(struct stmmac_tx_quwhile (len !=0 ) { tx_q->tx_skbuff[entry] =NULL ; - entry =STMMAC_GET_ENTRY (entry, priv->dma_conf.dma_tx_size); + entry =STMMAC_NEXT_ENTRY (entry, priv->dma_conf.dma_tx_size); desc = tx_q->dma_tx + entry;if (len > bmax) {
drivers/net/ethernet/stmicro/stmmac/common.h +1 -1
@@ -63,7 +63,7 @@ static inline bool dwmac_is_xmac(enum dw#define DMA_MIN_RX_SIZE 64#define DMA_MAX_RX_SIZE 1024#define DMA_DEFAULT_RX_SIZE 512 -#define STMMAC_GET_ENTRY (x, size) ((x + 1) & (size - 1)) +#define STMMAC_NEXT_ENTRY (x, size) ((x + 1) & (size - 1))#undef FRAME_FILTER_DEBUG/* #define FRAME_FILTER_DEBUG */
drivers/net/ethernet/stmicro/stmmac/ring_mode.c +1 -1
@@ -51,7 +51,7 @@ static int jumbo_frm(struct stmmac_tx_qustmmac_prepare_tx_desc (priv, desc,1 , bmax, csum,STMMAC_RING_MODE ,0 , false, skb->len); tx_q->tx_skbuff[entry] =NULL ; - entry =STMMAC_GET_ENTRY (entry, priv->dma_conf.dma_tx_size); + entry =STMMAC_NEXT_ENTRY (entry, priv->dma_conf.dma_tx_size);if (priv->extend_desc) desc = (struct dma_desc *)(tx_q->dma_etx + entry);
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +13 -13
@@ -2744,7 +2744,7 @@ static bool stmmac_xdp_xmit_zc(struct stxsk_tx_metadata_to_compl (meta, &tx_q->tx_skbuff_dma[entry].xsk_meta); - tx_q->cur_tx =STMMAC_GET_ENTRY (tx_q->cur_tx, priv->dma_conf.dma_tx_size); + tx_q->cur_tx =STMMAC_NEXT_ENTRY (tx_q->cur_tx, priv->dma_conf.dma_tx_size); entry = tx_q->cur_tx; }u64_stats_update_begin (&txq_stats->napi_syncp);
@@ -2915,7 +2915,7 @@ static int stmmac_tx_clean(struct stmmacstmmac_release_tx_desc (priv, p, priv->mode); - entry =STMMAC_GET_ENTRY (entry, priv->dma_conf.dma_tx_size); + entry =STMMAC_NEXT_ENTRY (entry, priv->dma_conf.dma_tx_size); } tx_q->dirty_tx = entry;
@@ -4258,7 +4258,7 @@ static bool stmmac_vlan_insert(struct streturn false;stmmac_set_tx_owner (priv, p); - tx_q->cur_tx =STMMAC_GET_ENTRY (tx_q->cur_tx, priv->dma_conf.dma_tx_size); + tx_q->cur_tx =STMMAC_NEXT_ENTRY (tx_q->cur_tx, priv->dma_conf.dma_tx_size);return true; }
@@ -4286,7 +4286,7 @@ static void stmmac_tso_allocator(structwhile (tmp_len >0 ) {dma_addr_t curr_addr; - tx_q->cur_tx =STMMAC_GET_ENTRY (tx_q->cur_tx, + tx_q->cur_tx =STMMAC_NEXT_ENTRY (tx_q->cur_tx, priv->dma_conf.dma_tx_size);WARN_ON (tx_q->tx_skbuff[tx_q->cur_tx]);
@@ -4437,7 +4437,7 @@ static netdev_tx_t stmmac_tso_xmit(strucstmmac_set_mss (priv, mss_desc, mss); tx_q->mss = mss; - tx_q->cur_tx =STMMAC_GET_ENTRY (tx_q->cur_tx, + tx_q->cur_tx =STMMAC_NEXT_ENTRY (tx_q->cur_tx, priv->dma_conf.dma_tx_size);WARN_ON (tx_q->tx_skbuff[tx_q->cur_tx]); }
@@ -4541,7 +4541,7 @@ static netdev_tx_t stmmac_tso_xmit(struc* ndo_start_xmit will fill this descriptor the next time it's * called and stmmac_tx_clean may clean up to this descriptor. */ - tx_q->cur_tx =STMMAC_GET_ENTRY (tx_q->cur_tx, priv->dma_conf.dma_tx_size); + tx_q->cur_tx =STMMAC_NEXT_ENTRY (tx_q->cur_tx, priv->dma_conf.dma_tx_size);if (unlikely (stmmac_tx_avail (priv, queue) <= (MAX_SKB_FRAGS +1 ))) { netif_dbg(priv, hw, priv->dev, "%s: stop transmitted packets\n",
@@ -4751,7 +4751,7 @@ static netdev_tx_t stmmac_xmit(struct skint len =skb_frag_size (frag);bool last_segment = (i == (nfrags -1 )); - entry =STMMAC_GET_ENTRY (entry, priv->dma_conf.dma_tx_size); + entry =STMMAC_NEXT_ENTRY (entry, priv->dma_conf.dma_tx_size);WARN_ON (tx_q->tx_skbuff[entry]);if (likely (priv->extend_desc))
@@ -4821,7 +4821,7 @@ static netdev_tx_t stmmac_xmit(struct sk* ndo_start_xmit will fill this descriptor the next time it's * called and stmmac_tx_clean may clean up to this descriptor. */ - entry =STMMAC_GET_ENTRY (entry, priv->dma_conf.dma_tx_size); + entry =STMMAC_NEXT_ENTRY (entry, priv->dma_conf.dma_tx_size); tx_q->cur_tx = entry;if (netif_msg_pktdata (priv)) {
@@ -4990,7 +4990,7 @@ static inline void stmmac_rx_refill(strudma_wmb ();stmmac_set_rx_owner (priv, p, use_rx_wd); - entry =STMMAC_GET_ENTRY (entry, priv->dma_conf.dma_rx_size); + entry =STMMAC_NEXT_ENTRY (entry, priv->dma_conf.dma_rx_size); } rx_q->dirty_rx = entry; rx_q->rx_tail_addr = rx_q->dma_rx_phy +
@@ -5140,7 +5140,7 @@ static int stmmac_xdp_xmit_xdpf(struct sstmmac_enable_dma_transmission (priv, priv->ioaddr, queue); - entry =STMMAC_GET_ENTRY (entry, priv->dma_conf.dma_tx_size); + entry =STMMAC_NEXT_ENTRY (entry, priv->dma_conf.dma_tx_size); tx_q->cur_tx = entry;return STMMAC_XDP_TX ;
@@ -5374,7 +5374,7 @@ static bool stmmac_rx_refill_zc(struct sdma_wmb ();stmmac_set_rx_owner (priv, rx_desc, use_rx_wd); - entry =STMMAC_GET_ENTRY (entry, priv->dma_conf.dma_rx_size); + entry =STMMAC_NEXT_ENTRY (entry, priv->dma_conf.dma_rx_size); }if (rx_desc) {
@@ -5469,7 +5469,7 @@ read_again:break ;/* Prefetch the next RX descriptor */ - rx_q->cur_rx =STMMAC_GET_ENTRY (rx_q->cur_rx, + rx_q->cur_rx =STMMAC_NEXT_ENTRY (rx_q->cur_rx, priv->dma_conf.dma_rx_size); next_entry = rx_q->cur_rx;
@@ -5665,7 +5665,7 @@ read_again:if (unlikely (status & dma_own))break ; - rx_q->cur_rx =STMMAC_GET_ENTRY (rx_q->cur_rx, + rx_q->cur_rx =STMMAC_NEXT_ENTRY (rx_q->cur_rx, priv->dma_conf.dma_rx_size); next_entry = rx_q->cur_rx;
Greg Kroah-Hartman
maintainerPATCH 305/307 net: stmmac: Prevent NULL deref when RX memory exhausted
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sam Edwards <[email protected]>
[ Upstream commit 0bb05e6adfa99a2ea1fee1125cc0953409f83ed8 ]
The CPU receives frames from the MAC through conventional DMA: the CPU allocates buffers for the MAC, then the MAC fills them and returns ownership to the CPU. For each hardware RX queue, the CPU and MAC coordinate through a shared ring array of DMA descriptors: one descriptor per DMA buffer. Each descriptor includes the buffer's physical address and a status flag ("OWN") indicating which side owns the buffer: OWN=0 for CPU, OWN=1 for MAC. The CPU is only allowed to set the flag and the MAC is only allowed to clear it, and both must move through the ring in sequence: thus the ring is used for both "submissions" and "completions."
In the stmmac driver, stmmac_rx() bookmarks its position in the ring with the cur_rx index. The main receive loop in that function checks for rx_descs[cur_rx].own=0, gives the corresponding buffer to the network stack (NULLing the pointer), and increments cur_rx modulo the ring size. After the loop exits, stmmac_rx_refill(), which bookmarks its position with dirty_rx, allocates fresh buffers and rearms the descriptors (setting OWN=1). If it fails any allocation, it simply stops early (leaving OWN=0) and will retry where it left off when next called.
This means descriptors have a three-stage lifecycle (terms my own):
- empty (OWN=1, buffer valid)
- full (OWN=0, buffer valid and populated)
- dirty (OWN=0, buffer NULL)
But because stmmac_rx() only checks OWN, it confuses full/dirty. In the past (see 'Fixes:'), there was a bug where the loop could cycle cur_rx all the way back to the first descriptor it dirtied, resulting in a NULL dereference when mistaken for full. The aforementioned commit resolved that *specific* failure by capping the loop's iteration limit at dma_rx_size - 1, but this is only a partial fix: if the previous stmmac_rx_refill() didn't complete, then there are leftover dirty descriptors that the loop might encounter without needing to cycle fully around. The current code therefore panics (see 'Closes:') when stmmac_rx_refill() is memory-starved long enough for cur_rx to catch up to dirty_rx.
Fix this by explicitly checking, before advancing cur_rx, if the next entry is dirty; exit the loop if so. This prevents processing of the final, used descriptor until stmmac_rx_refill() succeeds, but fully prevents the cur_rx == dirty_rx ambiguity as the previous bugfix
intended: so remove the clamp as well. Since stmmac_rx_zc() is a copy-paste-and-tweak of stmmac_rx() and the code structure is identical, any fix to stmmac_rx() will also need a corresponding fix for stmmac_rx_zc(). Therefore, apply the same check there.
In stmmac_rx() (not stmmac_rx_zc()), a related bug remains: after the MAC sets OWN=0 on the final descriptor, it will be unable to send any further DMA-complete IRQs until it's given more empty descriptors. Currently, the driver simply *hopes* that the next stmmac_rx_refill() succeeds, risking an indefinite stall of the receive process if not. But this is not a regression, so it can be addressed in a future change.
--- drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-)
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +12 -7
@@ -5469,9 +5469,12 @@ read_again:break ;/* Prefetch the next RX descriptor */ - rx_q->cur_rx =STMMAC_NEXT_ENTRY (rx_q->cur_rx, - priv->dma_conf.dma_rx_size); - next_entry = rx_q->cur_rx; + next_entry =STMMAC_NEXT_ENTRY (rx_q->cur_rx, + priv->dma_conf.dma_rx_size); +if (unlikely (next_entry == rx_q->dirty_rx)) +break ; + + rx_q->cur_rx = next_entry;if (priv->extend_desc) np = (struct dma_desc *)(rx_q->dma_erx + next_entry);
@@ -5609,7 +5612,6 @@ static int stmmac_rx(struct stmmac_priv dma_dir =page_pool_get_dma_dir (rx_q->page_pool); bufsz =DIV_ROUND_UP (priv->dma_conf.dma_buf_sz,PAGE_SIZE ) *PAGE_SIZE ; - limit =min (priv->dma_conf.dma_rx_size -1 , (unsigned int )limit);if (netif_msg_rx_status (priv)) {void *rx_head;
@@ -5665,9 +5667,12 @@ read_again:if (unlikely (status & dma_own))break ; - rx_q->cur_rx =STMMAC_NEXT_ENTRY (rx_q->cur_rx, - priv->dma_conf.dma_rx_size); - next_entry = rx_q->cur_rx; + next_entry =STMMAC_NEXT_ENTRY (rx_q->cur_rx, + priv->dma_conf.dma_rx_size); +if (unlikely (next_entry == rx_q->dirty_rx)) +break ; + + rx_q->cur_rx = next_entry;if (priv->extend_desc) np = (struct dma_desc *)(rx_q->dma_erx + next_entry);
Greg Kroah-Hartman
maintainerPATCH 306/307 rust: pin-init: fix incorrect accessor reference lifetime
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Gary Guo <[email protected]>
commit 68bf102226cf2199dc609b67c1e847cad4de4b57 upstream
When a field has been initialized, init!/pin_init! create a reference or pinned reference to the field so it can be accessed later during the initialization of other fields. However, the reference it created is incorrectly &'static rather than just the scope of the initializer.
This means that you can do
init!(Foo {
a: 1,
_: {
let b: &'static u32 = a;
}
})which is unsound.
This is caused by &mut (*#slot).#ident, which actually allows arbitrary lifetime, so this is effectively 'static. Somewhat ironically, the safety justification of creating the accessor is.. "SAFETY: TODO".
Fix it by adding let_binding method on DropGuard to shorten lifetime. This results exactly what we want for these accessors. The safety and invariant comments of DropGuard have been reworked; instead of reasoning about what caller can do with the guard, express it in a way that the ownership is transferred to the guard and forget takes it back, so the unsafe operations within the DropGuard can be more easily justified.
--- rust/pin-init/internal/src/init.rs | 106 ++++++++++++++++--------------------- rust/pin-init/src/__internal.rs | 28 ++++++--- 2 files changed, 66 insertions(+), 68 deletions(-)
rust/pin-init/internal/src/init.rs +47 -59
@@ -243,18 +243,6 @@ fn init_fields( });// Again span for better diagnostics let write =quote_spanned! (ident.span ()=> ::core::ptr::write); -let accessor =if pinned { -let project_ident =format_ident! ("__project_{ident}" ); -quote! { -// SAFETY: TODO -unsafe { #data.#project_ident (&mut (*#slot).#ident) } - } - }else { -quote! { -// SAFETY: TODO -unsafe { &mut (*#slot).#ident } - } - };quote! { #(#attrs)* {
@@ -262,51 +250,31 @@ fn init_fields(// SAFETY: TODO unsafe { #write(::core::ptr::addr_of_mut!((*#slot).#ident), #value_ident) }; } - #(#cfgs)* -#[allow(unused_variables)] - let #ident = #accessor; } } InitializerKind::Init { ident, value, .. } => { // Again span for better diagnostics let init = format_ident!("init", span = value.span()); - // NOTE: the field accessor ensures that the initialized field is properly aligned. - // Unaligned fields will cause the compiler to emit E0793. We do not support - // unaligned fields since `Init::__init` requires an aligned pointer; the call to - // `ptr::write` below has the same requirement. - let (value_init, accessor) = if pinned { - let project_ident = format_ident!("__project_{ident}"); - ( - quote! { - // SAFETY: - // - `slot` is valid, because we are inside of an initializer closure, we - // return when an error/panic occurs. - // - We also use `#data` to require the correct trait (`Init` or `PinInit`) - // for `#ident`. - unsafe { #data.#ident(::core::ptr::addr_of_mut!((*#slot).#ident), #init)? }; - }, - quote! { - // SAFETY: TODO - unsafe { #data.#project_ident(&mut (*#slot).#ident) } - }, - ) + let value_init = if pinned { + quote! { + // SAFETY: + // - `slot` is valid, because we are inside of an initializer closure, we + // return when an error/panic occurs. + // - We also use `#data` to require the correct trait (`Init` or `PinInit`) + // for `#ident`. + unsafe { #data.#ident(::core::ptr::addr_of_mut!((*#slot).#ident), #init)? }; + } } else { - ( - quote! { - // SAFETY: `slot` is valid, because we are inside of an initializer - // closure, we return when an error/panic occurs. - unsafe { - ::pin_init::Init::__init( - #init, - ::core::ptr::addr_of_mut!((*#slot).#ident), - )? - }; - }, - quote! { - // SAFETY: TODO - unsafe { &mut (*#slot).#ident } - }, - ) + quote! { + // SAFETY: `slot` is valid, because we are inside of an initializer + // closure, we return when an error/panic occurs. + unsafe { + ::pin_init::Init::__init( + #init, + ::core::ptr::addr_of_mut!((*#slot).#ident), + )? + }; + } }; quote! { #(#attrs)*
@@ -314,9 +282,6 @@ fn init_fields( let #init = #value; #value_init } - #(#cfgs)* -#[allow(unused_variables)] - let #ident = #accessor; } } InitializerKind::Code { block: value, .. } => quote! {
@@ -329,18 +294,41 @@ fn init_fields(if let Some (ident) = kind.ident () {// `mixed_site` ensures that the guard is not accessible to the user-controlled code. let guard =format_ident! ("__{ident}_guard" , span =Span ::mixed_site ()); + +// NOTE: The reference is derived from the guard so that it only lives as long as the +// guard does and cannot escape the scope. If it's created via `&mut (*#slot).#ident` +// like the unaligned field guard, it will become effectively `'static`. +let accessor =if pinned { +let project_ident =format_ident! ("__project_{ident}" ); +quote! { +// SAFETY: the initialization is pinned. +unsafe { #data.#project_ident (#guard.let_binding ()) } + } + }else { +quote! { + #guard.let_binding () + } + }; + res.extend (quote! { #(#cfgs)* -// Create the drop guard: +// Create the drop guard. // -// We rely on macro hygiene to make it impossible for users to access this local -// variable. -// SAFETY: We forget the guard later when initialization has succeeded. -let #guard =unsafe { +// SAFETY: +// - `&raw mut (*slot).#ident` is valid. +// - `make_field_check` checks that `&raw mut (*slot).#ident` is properly aligned. +// - `(*slot).#ident` has been initialized above. +// - We only need the ownership to the pointee back when initialization has +// succeeded, where we `forget` the guard. +let mut #guard =unsafe { ::pin_init::__internal::DropGuard ::new ( ::core::ptr::addr_of_mut!((*slot).#ident) ) }; + + #(#cfgs)* +#[allow(unused_variables)] +let #ident = #accessor; }); guards.push (guard); guard_attrs.push (cfgs);
rust/pin-init/src/__internal.rs +19 -9
@@ -238,32 +238,42 @@ fn stack_init_reuse() {/// When a value of this type is dropped, it drops a `T`. /// /// Can be forgotten to prevent the drop. +/// +/// # Invariants +/// +/// - `ptr` is valid and properly aligned. +/// - `*ptr` is initialized and owned by this guard. pub struct DropGuard <T : ?Sized > { ptr: *mut T , }impl <T : ?Sized >DropGuard <T > { -/// Creates a new [`DropGuard<T>`]. It will [`ptr::drop_in_place`] `ptr` when it gets dropped. +/// Creates a drop guard and transfer the ownership of the pointer content. /// -/// # Safety +/// The ownership is only relinguished if the guard is forgotten via [`core::mem::forget`]. /// -/// `ptr` must be a valid pointer. +/// # Safety /// -/// It is the callers responsibility that `self` will only get dropped if the pointee of `ptr`: -/// - has not been dropped, -/// - is not accessible by any other means, -/// - will not be dropped by any other means. +/// - `ptr` is valid and properly aligned. +/// - `*ptr` is initialized, and the ownership is transferred to this guard. #[inline] pub unsafe fn new (ptr: *mut T ) ->Self { +// INVARIANT: By safety requirement. Self { ptr } } + +/// Create a let binding for accessor use. +#[inline] +pub fn let_binding (&mut self) -> &mut T { +// SAFETY: Per type invariant. +unsafe { &mut *self.ptr } + } }impl <T : ?Sized >Drop for DropGuard <T > {#[inline] fn drop (&mut self) { -// SAFETY: A `DropGuard` can only be constructed using the unsafe `new` function -// ensuring that this operation is safe. +// SAFETY: `self.ptr` is valid, properly aligned and `*self.ptr` is owned by this guard. unsafe { ptr::drop_in_place (self.ptr) } } }
Greg Kroah-Hartman
maintainerPATCH 307/307 x86/CPU/AMD: Prevent improper isolation of shared resources in Zen2s op cache
In reply to Greg Kroah-Hartman7.0-stable review patch. If anyone has any objections, please let me know.
------------------
From: Prathyushi Nangia <[email protected]>
commit c21b90f77687075115d989e53a8ec5e2bb427ab1 upstream.
Make sure resources are not improperly shared in the op cache and cause instruction corruption this way.
--- arch/x86/include/asm/msr-index.h | 3 ++- arch/x86/kernel/cpu/amd.c | 3 +++ tools/arch/x86/include/asm/msr-index.h | 3 ++- 3 files changed, 7 insertions(+), 2 deletions(-)
arch/x86/include/asm/msr-index.h +2 -1
@@ -796,9 +796,10 @@#define MSR_AMD64_LBR_SELECT 0xc000010e/* Zen4 */ -#define MSR_ZEN4_BP_CFG 0xc001102e +#define MSR_ZEN4_BP_CFG 0xc001102e#define MSR_ZEN4_BP_CFG_BP_SPEC_REDUCE_BIT 4#define MSR_ZEN4_BP_CFG_SHARED_BTB_FIX_BIT 5 +#define MSR_ZEN2_BP_CFG_BUG_FIX_BIT 33/* Fam 19h MSRs */ #define MSR_F19H_UMC_PERF_CTL 0xc0010800
arch/x86/kernel/cpu/amd.c +3 -0
@@ -988,6 +988,9 @@ static void init_amd_zen2(struct cpuinfo/* Correct misconfigured CPUID on some clients. */ clear_cpu_cap (c,X86_FEATURE_INVLPGB ); + +if (!cpu_has (c,X86_FEATURE_HYPERVISOR )) +msr_set_bit (MSR_ZEN4_BP_CFG ,MSR_ZEN2_BP_CFG_BUG_FIX_BIT ); }static void init_amd_zen3 (struct cpuinfo_x86 *c)
tools/arch/x86/include/asm/msr-index.h +2 -1
@@ -793,9 +793,10 @@#define MSR_AMD64_LBR_SELECT 0xc000010e/* Zen4 */ -#define MSR_ZEN4_BP_CFG 0xc001102e +#define MSR_ZEN4_BP_CFG 0xc001102e#define MSR_ZEN4_BP_CFG_BP_SPEC_REDUCE_BIT 4#define MSR_ZEN4_BP_CFG_SHARED_BTB_FIX_BIT 5 +#define MSR_ZEN2_BP_CFG_BUG_FIX_BIT 33/* Fam 19h MSRs */ #define MSR_F19H_UMC_PERF_CTL 0xc0010800
Hi
7.0.7-rc1 does not compile !
=======
error:
In file included from kernel/sched/build_policy.c:62:kernel/sched/ext.c: In function ‘bypass_lb_cpu’:kernel/sched/ext.c:4019:35: error: ‘donor_rq’ undeclared (first use in this function); did you mean ‘donee_rq’?
4019 | if (task_rq(p) != donor_rq)
| ^~~~~~~~
| donee_rqkernel/sched/ext.c:4019:35: note: each undeclared identifier is reported only once for each function it appears in make[4]: *** [scripts/Makefile.build:289: kernel/sched/build_policy.o] Error 1
make[3]: *** [scripts/Makefile.build:548: kernel/sched] Error 2
make[2]: *** [scripts/Makefile.build:548: kernel] Error 2
make[2]: *** Waiting for unfinished jobs....
========
if I do
git revert eb5b997dadc51746b5db031be1e9e7c19646c317 --no-edit
(NOT bisected just reading through the patches !)
I find no regressions here on x86_64 (Intel 11th Gen. CPU)
Thanks
Hi Greg
Quoted 10 lines · Greg Kroah-Hartman
This is the start of the stable review cycle for the 7.0.7 release. There are 307 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Thu, 14 May 2026 17:38:03 +0000. Anything received after that time might be too late.
The whole patch series can be found in one patch at:
Quoted 9 lines
https://www.kernel.org/pub/linux/kernel/v7.x/stable-review/patch-7.0.7-rc1.gzor in the git tree and branch at:
git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.gitlinux-7.0.y
and the diffstat can be found below.thanks,
greg k-h
Linux version 7.0.7-rc1 tested.
Build error.
Error log (some output is in the native language (Japanese))
CC kernel/sched/build_policy.o
In file included from kernel/sched/build_policy.c:62:kernel/sched/ext.c: 関数 ‘bypass_lb_cpu’ 内:kernel/sched/ext.c:4019:35: error: ‘donor_rq’ undeclared (first use in this function); did you mean ‘donee_rq’?
4019 | if (task_rq(p) != donor_rq)
| ^~~~~~~~
| donee_rqkernel/sched/ext.c:4019:35: note: 未宣言の識別子は出現した各関数内で一回のみ報告されます make[4]: *** [scripts/Makefile.build:289: kernel/sched/build_policy.o] エラー 1 make[3]: *** [scripts/Makefile.build:548: kernel/sched] エラー 2 make[2]: *** [scripts/Makefile.build:548: kernel] エラー 2
make[1]: *** [/home/takeshi/kernelbuild/linux-stable-rc/Makefile:2108: .] エラー 2
make: *** [Makefile:248: __sub-make] エラー 2
Following the error log, I corrected line 4019 and tried building again, and this time the build was successful.
We successfully booted and tested the modified kernel.
Due to time constraints, I omitted the investigation using git bisect, but the suspected commits are presumed to be the following. eb5b997dadc51746b5db031be1e9e7c19646c317
Thanks
Hi Greg,
Am 12.05.2026 um 19:36 schrieb Greg Kroah-Hartman:
Quoted 4 lines
This is the start of the stable review cycle for the 7.0.7 release. There are 307 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Trying to build 7.0.7-rc1, I get this build error.
In file included from kernel/sched/build_policy.c:62:kernel/sched/ext.c: In function ‘bypass_lb_cpu’:kernel/sched/ext.c:4019:35: error: ‘donor_rq’ undeclared (first use in this function); did you mean ‘donee_rq’?
4019 | if (task_rq(p) != donor_rq)
| ^~~~~~~~
| donee_rqkernel/sched/ext.c:4019:35: note: each undeclared identifier is reported only once for each function it appears in make[4]: *** [scripts/Makefile.build:289: kernel/sched/build_policy.o] Fehler 1
make[3]: *** [scripts/Makefile.build:548: kernel/sched] Fehler 2
make[2]: *** [scripts/Makefile.build:548: kernel] Fehler 2
make[1]: *** [/usr/src/linux-stable-rc/Makefile:2108: .] Fehler 2
make: *** [Makefile:248: __sub-make] Fehler 2
root@linus:/usr/src/linux-stable-rc#
The offending line seems to be part of eb5b997dadc517 (sched_ext: Skip tasks with stale task_rq in bypass_lb_cpu()) Adding Tejun and Andrea to CC.
Beste Grüße,
Peter Schneider
Signature · 8 lines
Climb the mountain not to plant your flag, but to embrace the challenge, enjoy the air and behold the view. Climb it so you can see the world, not so the world can see you. -- David McCullough Jr. OpenPGP: 0xA3828BD796CCE11A8CADE8866E3A92C92C3FF244 Download: https://www.peters-netzplatz.de/download/pschneider1968_pub.asc https://keys.mailvelope.com/pks/lookup?op=get&[email protected] https://keys.mailvelope.com/pks/lookup?op=get&[email protected]
Hello,
Quoted 24 lines · Peter Schneider
Hi Greg,
Am 12.05.2026 um 19:36 schrieb Greg Kroah-Hartman:
Quoted 4 lines
This is the start of the stable review cycle for the 7.0.7 release. There are 307 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Trying to build 7.0.7-rc1, I get this build error.
In file included from
kernel/sched/build_policy.c:62:kernel/sched/ext.c: In function ‘bypass_lb_cpu’:kernel/sched/ext.c:4019:35: error: ‘donor_rq’ undeclared (first use in this function); did you mean ‘donee_rq’?4019 | if (task_rq(p) != donor_rq) | ^~~~~~~~ | donee_rq
kernel/sched/ext.c:4019:35: note: each undeclared identifier is reported only once for each function it appears in make[4]: *** [scripts/Makefile.build:289:kernel/sched/build_policy.o] Fehler 1
make[3]: *** [scripts/Makefile.build:548: kernel/sched] Fehler 2
make[2]: *** [scripts/Makefile.build:548: kernel] Fehler 2
make[1]: *** [/usr/src/linux-stable-rc/Makefile:2108: .] Fehler 2
make: *** [Makefile:248: __sub-make] Fehler 2
root@linus:/usr/src/linux-stable-rc#
Quoted 2 lines
The offending line seems to be part of
eb5b997dadc517(sched_ext: Skip tasks with staletask_rqinbypass_lb_cpu()) Adding Tejun and Andrea to CC.
The upstream commit (da2d81b4118a) was written on top of ff06f727a941 ("sched_ext: Move bypass_dsq into scx_sched_pcpu"), which renamed @rq to @donor_rq (among other things). That refactor is not in 7.0.y and it's not stable material.
I think The minimal fix is to rename donor_rq -> rq in the backported hunk, in 7.0.y the function still takes struct rq *rq directly, and that is the donor rq.
Greg, can you fold the following into the queued patch? Do you prefer a separate/updated patch?
Thanks,
-Andrea
kernel/sched/ext.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
kernel/sched/ext.c +2 -2
@@ -4013,10 +4013,10 @@ static u32 bypass_lb_cpu(struct scx_sched *sch, struct rq *rq,/* * If an earlier pass placed @p on @donor_dsq from a different * CPU and the donee hasn't consumed it yet, @p is still on the -* previous CPU and task_rq(@p) != @donor_rq. @p can't be moved +* previous CPU and task_rq(@p) != @rq. @p can't be moved * without its rq locked. Skip. */ -if (task_rq (p) != donor_rq) +if (task_rq (p) != rq)continue ; donee =cpumask_any_and_distribute (donee_mask, p->cpus_ptr);
Greg Kroah-Hartman
maintainerQuoted 55 lines · Andrea Righi
Hello,
Quoted 24 lines · Peter Schneider
Hi Greg,
Am 12.05.2026 um 19:36 schrieb Greg Kroah-Hartman:
Quoted 4 lines
This is the start of the stable review cycle for the 7.0.7 release. There are 307 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Trying to build 7.0.7-rc1, I get this build error.
In file included from
kernel/sched/build_policy.c:62:kernel/sched/ext.c: In function ‘bypass_lb_cpu’:kernel/sched/ext.c:4019:35: error: ‘donor_rq’ undeclared (first use in this function); did you mean ‘donee_rq’?4019 | if (task_rq(p) != donor_rq) | ^~~~~~~~ | donee_rq
kernel/sched/ext.c:4019:35: note: each undeclared identifier is reported only once for each function it appears in make[4]: *** [scripts/Makefile.build:289:kernel/sched/build_policy.o] Fehler 1
make[3]: *** [scripts/Makefile.build:548: kernel/sched] Fehler 2
make[2]: *** [scripts/Makefile.build:548: kernel] Fehler 2
make[1]: *** [/usr/src/linux-stable-rc/Makefile:2108: .] Fehler 2
make: *** [Makefile:248: __sub-make] Fehler 2
root@linus:/usr/src/linux-stable-rc#Quoted 2 lines
The offending line seems to be part of
eb5b997dadc517(sched_ext: Skip tasks with staletask_rqinbypass_lb_cpu()) Adding Tejun and Andrea to CC.The upstream commit (
da2d81b4118a) was written on top offf06f727a941("sched_ext: Movebypass_dsqintoscx_sched_pcpu"), which renamed @rq to @donor_rq (among other things). That refactor is not in 7.0.y and it's not stable material.I think The minimal fix is to rename
donor_rq-> rq in the backported hunk, in 7.0.y the function still takes struct rq *rq directly, and that is the donor rq.Greg, can you fold the following into the queued patch? Do you prefer a separate/updated patch?
Thanks,
(quoted diff) +0
-1-Andrea kernel/sched/ext.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)kernel/sched/ext.c +0
-0@@ -4013,10 +4013,10 @@ static u32 bypass_lb_cpu(struct scx_sched *sch, struct rq *rq,/* * If an earlier pass placed @p on @donor_dsq from a different
kernel/sched/ext.c static u32 bypass_lb_cpu(struct scx_sched *sch, struct rq *rq, · line 4022
Quoted 10 lines
kernel/sched/ext.c +2
-2* CPU and the donee hasn't consumed it yet, @p is still on the -* previous CPU and task_rq(@p) != @donor_rq. @p can't be moved +* previous CPU and task_rq(@p) != @rq. @p can't be moved * without its rq locked. Skip. */ -if (task_rq (p) != donor_rq) +if (task_rq (p) != rq)continue ; donee =cpumask_any_and_distribute (donee_mask, p->cpus_ptr);
A whole new patch please.
thanks,
greg k-h
PATCH 1/1 usb: typec: tcpm: reset internal port states on soft reset AMS
In reply to Greg Kroah-HartmanReset internal port states (such as vdm_sm_running and explicit_contract) on soft reset AMS as the port needs to negotiate a new contract. The consequence of leaving the states in as-is cond are as follows:
* port is in SRC power role and an explicit contract is negotiated with the port partner (in sink role)
* port partner sends a Soft Reset AMS while VDM State Machine is running
* port accepts the Soft Reset request and the port advertises src caps
* port partner sends a Request message but since the explicit_contract and vdm_sm_running are true from previous negotiation, the port ends up sending Soft Reset instead of Accept msg.
Stub Log:
[ 203.653942] AMS DISCOVER_IDENTITY start [ 203.653947] PD TX, header: 0x176f [ 203.655901] PD TX complete, status: 0 [ 203.657470] PD RX, header: 0x124f [1] [ 203.657477] Rx VDM cmd 0xff008081 type 2 cmd 1 len 1 [ 203.657482] AMS DISCOVER_IDENTITY finished [ 203.657484] cc:=4 [ 204.155698] PD RX, header: 0x144f [1] [ 204.155718] Rx VDM cmd 0xeeee8001 type 0 cmd 1 len 1 [ 204.155741] PD TX, header: 0x196f [ 204.157622] PD TX complete, status: 0 [ 204.160060] PD RX, header: 0x4d [1] [ 204.160066] state change SRC_READY -> SOFT_RESET [rev2 SOFT_RESET_AMS] [ 204.160076] PD TX, header: 0x163 [ 204.162486] PD TX complete, status: 0 [ 204.162832] AMS SOFT_RESET_AMS finished [ 204.162840] cc:=4 [ 204.162891] AMS POWER_NEGOTIATION start [ 204.162896] state change SOFT_RESET -> AMS_START [rev2 POWER_NEGOTIATION] [ 204.162908] state change AMS_START -> SRC_SEND_CAPABILITIES [rev2 POWER_NEGOTIATION] [ 204.162913] PD TX, header: 0x1361 [ 204.165529] PD TX complete, status: 0 [ 204.165571] pending state change SRC_SEND_CAPABILITIES -> SRC_SEND_CAPABILITIES_TIMEOUT @ 60 ms [rev2 POWER_NEGOTIATION] [ 204.166996] PD RX, header: 0x1242 [1] [ 204.167009] state change SRC_SEND_CAPABILITIES -> SRC_SOFT_RESET_WAIT_SNK_TX [rev2 POWER_NEGOTIATION] [ 204.167019] AMS POWER_NEGOTIATION finished [ 204.167020] cc:=4 [ 204.167083] AMS SOFT_RESET_AMS start [ 204.167086] state change SRC_SOFT_RESET_WAIT_SNK_TX -> SOFT_RESET_SEND [rev2 SOFT_RESET_AMS] [ 204.167092] PD TX, header: 0x16d [ 204.168824] PD TX complete, status: 0 [ 204.168854] pending state change SOFT_RESET_SEND -> HARD_RESET_SEND @ 60 ms [rev2 SOFT_RESET_AMS] [ 204.171876] PD RX, header: 0x43 [1] [ 204.171879] AMS SOFT_RESET_AMS finished
This causes COMMON.PROC.PD.11.2 check failure for TEST.PD.VDM.SRC.2_Rev2Src test on the PD compliance tester.
--- drivers/usb/typec/tcpm/tcpm.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/usb/typec/tcpm/tcpm.c +2 -0
@@ -5534,6 +5534,8 @@ static void run_state_machine(struct tcpm_port *port)usb_power_delivery_unregister_capabilities (port->partner_source_caps); port->partner_source_caps =NULL ;tcpm_pd_send_control (port,PD_CTRL_ACCEPT ,TCPC_TX_SOP ); + port->vdm_sm_running = false; + port->explicit_contract = false;tcpm_ams_finish (port);if (port->pwr_role ==TYPEC_SOURCE ) { port->upcoming_state =SRC_SEND_CAPABILITIES ;
Signature · 1 line
2.54.0.563.g4f69b47b94-goog
# Librecast Test Results
020/020 [ OK ] liblcrq
010/010 [ OK ] libmld
120/120 [ OK ] liblibrecast
CPU/kernel: Linux auntie 7.0.7-rc1-g9fd19ccdb6f2 #1 SMP PREEMPT_DYNAMIC Wed May 13 07:11:13 -00 2026 x86_64 AMD Ryzen 9 9950X 16-Core Processor AuthenticAMD GNU/Linux
Quoted 4 lines · Greg Kroah-Hartman
This is the start of the stable review cycle for the 7.0.7 release. There are 307 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Quoted 9 lines · Greg Kroah-Hartman
This is the start of the stable review cycle for the 7.0.7 release. There are 307 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Thu, 14 May 2026 17:38:03 +0000. Anything received after that time might be too late.
The whole patch series can be found in one patch at:
Quoted 9 lines
https://www.kernel.org/pub/linux/kernel/v7.x/stable-review/patch-7.0.7-rc1.gzor in the git tree and branch at:
git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.gitlinux-7.0.y
and the diffstat can be found below.thanks,
greg k-h
Compiled and booted on my test system. No dmesg regressions.
thanks,
-- Shuah