mailweb.openeuler.org
Manage this list

Keyboard Shortcuts

Thread View

  • j: Next unread message
  • k: Previous unread message
  • j a: Jump to all threads
  • j l: Jump to MailingList overview

Kernel

Threads by month
  • ----- 2026 -----
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2025 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2024 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2023 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2022 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2021 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2020 -----
  • December
  • November
  • October
  • September
  • August
  • July
  • June
  • May
  • April
  • March
  • February
  • January
  • ----- 2019 -----
  • December
kernel@openeuler.org

  • 46 participants
  • 24995 discussions
[PATCH OLK-5.10] net: openvswitch: fix flow mask use-after-free on flow deletion
by Gaosheng Cui 28 Sep '26

28 Sep '26
From: Ilya Maximets <i.maximets(a)ovn.org> stable inclusion from stable-v5.10.270 commit ea5f7b45b582665541ddfb77dce98611354af4ab category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/18828 CVE: CVE-2026-80994 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id… -------------------------------- commit 4e30317ff67a2eb12b4d890d39f72fd7e7117d48 upstream. The commit in the Fixes tag below made so flow->mask free is scheduled via RCU right after it is removed from the flow table. The pointer stays in the flow structure and it can be accessible while in the same RCU critical section. This is done to avoid requiring ovs_mutex for the ovs_flow_free(). However, while removing the flow during processing of CMD_DEL, we do not take RCU read lock before the removal, and ovs_flow_cmd_fill_info() uses the flow->mask pointer afterwards. The RCU read lock is taken, but it's already late at that point. The comment on that line acknowledges that the lock is cosmetic and doesn't serve a real purpose. This leads to use-after-free if the RCU grace period passes between removal and the filling. It is a short race window, but it is there and can lead to a real crash in case memory allocation for the info takes a bit longer: BUG: KASAN: slab-use-after-free in __ovs_nla_put_key net/openvswitch/flow_netlink.c:1996 BUG: KASAN: slab-use-after-free in ovs_nla_put_key+0x2463/0x2e30 net/openvswitch/flow_netlink.c:2250 Read of size 4 at addr ffff88801ee89970 by task ovs_flow_del_ec/9487 Call Trace: <TASK> __ovs_nla_put_key net/openvswitch/flow_netlink.c:1996 ovs_nla_put_key+0x2463/0x2e30 net/openvswitch/flow_netlink.c:2250 ovs_flow_cmd_fill_info+0x420/0x9c0 net/openvswitch/datapath.c:930 ovs_flow_cmd_del+0x53a/0x970 net/openvswitch/datapath.c:1467 ... netlink_rcv_skb+0x156/0x420 net/netlink/af_netlink.c:2556 </TASK> Allocated by task 9487: mask_alloc net/openvswitch/flow_table.c:967 flow_mask_insert net/openvswitch/flow_table.c:1012 ovs_flow_tbl_insert+0xea2/0x1a90 net/openvswitch/flow_table.c:1084 ovs_flow_cmd_new+0x7e3/0xd90 net/openvswitch/datapath.c:1086 ... netlink_rcv_skb+0x156/0x420 net/netlink/af_netlink.c:2556 Freed by task 9485: rcu_free_sheaf+0x1e/0x100 mm/slub.c:5978 rcu_do_batch kernel/rcu/tree.c:2645 rcu_core+0x59c/0x10c0 kernel/rcu/tree.c:2897 handle_softirqs+0x1e4/0x9a0 kernel/softirq.c:622 ... instr_sysvec_apic_timer_interrupt arch/x86/kernel/apic/apic.c:1062 ovs_flow_tbl_remove() must be called after the ovs_flow_cmd_fill_info() to avoid this race. This also helps with cleaning up the forced cast and the cosmetic RCU read lock. Before the commit in the Fixes tag the order did not matter as long as the flow object itself was not freed. A wider RCU critical section could be another option, but we have a GFP_KERNEL allocation in the way. Reported by Trend Micro's Zero Day Initiative as ZDI-CAN-32042. Fixes: 56c19868e115 ("openvswitch: Make flow mask removal symmetric.") Cc: stable(a)vger.kernel.org Signed-off-by: Ilya Maximets <i.maximets(a)ovn.org> Reviewed-by: Aaron Conole <aconole(a)redhat.com> Link: https://patch.msgid.link/20260815005915.1097270-1-i.maximets@ovn.org Signed-off-by: Jakub Kicinski <kuba(a)kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh(a)linuxfoundation.org> Signed-off-by: Gaosheng Cui <cuigaosheng1(a)huawei.com> --- net/openvswitch/datapath.c | 45 +++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/net/openvswitch/datapath.c b/net/openvswitch/datapath.c index 529eb9d6acab..b6d5dddaf35d 100644 --- a/net/openvswitch/datapath.c +++ b/net/openvswitch/datapath.c @@ -1381,33 +1381,34 @@ static int ovs_flow_cmd_del(struct sk_buff *skb, struct genl_info *info) goto unlock; } - ovs_flow_tbl_remove(&dp->table, flow); - ovs_unlock(); - - reply = ovs_flow_cmd_alloc_info((const struct sw_flow_actions __force *) flow->sf_acts, + reply = ovs_flow_cmd_alloc_info(ovsl_dereference(flow->sf_acts), &flow->id, info, false, ufid_flags); - if (likely(reply)) { - if (!IS_ERR(reply)) { - rcu_read_lock(); /*To keep RCU checker happy. */ - err = ovs_flow_cmd_fill_info(flow, ovs_header->dp_ifindex, - reply, info->snd_portid, - info->snd_seq, 0, - OVS_FLOW_CMD_DEL, - ufid_flags); - rcu_read_unlock(); - if (WARN_ON_ONCE(err < 0)) { - kfree_skb(reply); - goto out_free; - } + if (IS_ERR(reply)) { + netlink_set_err(sock_net(skb->sk)->genl_sock, 0, 0, + PTR_ERR(reply)); + reply = NULL; + } - ovs_notify(&dp_flow_genl_family, reply, info); - } else { - netlink_set_err(sock_net(skb->sk)->genl_sock, 0, 0, - PTR_ERR(reply)); + if (likely(reply)) { + err = ovs_flow_cmd_fill_info(flow, ovs_header->dp_ifindex, + reply, info->snd_portid, + info->snd_seq, 0, + OVS_FLOW_CMD_DEL, ufid_flags); + if (WARN_ON_ONCE(err < 0)) { + kfree_skb(reply); + reply = NULL; } } + /* Removal has to happen after ovs_flow_cmd_fill_info(), as it uses + * the flow->mask that can be scheduled to be freed by the + * ovs_flow_tbl_remove() and we're not holding the RCU read lock. + */ + ovs_flow_tbl_remove(&dp->table, flow); + ovs_unlock(); + + if (likely(reply)) + ovs_notify(&dp_flow_genl_family, reply, info); -out_free: ovs_flow_free(flow, true); return 0; unlock: -- 2.43.0
1 0
0 0
[PATCH OLK-6.6] md/raid5: round bitmap stripes with sector division
by Lu Jialin 28 Sep '26

28 Sep '26
From: Yu Kuai <yukuai(a)fygo.io> stable inclusion from stable-v6.6.157 commit 9d7490007707f90691911385365bd1d691d99225 category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/19461 CVE: CVE-2026-90279 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id… -------------------------------- [ Upstream commit 17ea021ae74987d6064c8195c4922fa025753892 ] raid5_bitmap_sector_map() aligns the array range to full RAID5 stripe widths before converting it to component sectors. That width is chunk_sectors multiplied by the number of data disks, and it is not always a power of two. Reproduce with a 4-disk RAID5, 1024-sector chunks, and three data disks. The full-stripe width is 3072 sectors. For a one-sector write at array sector 3072, correct rounding gives array range [3072, 6144), which maps to component range [1024, 2048). The old round_down()/round_up() logic instead gives [1024, 4096), which maps to [0, 1024). Use sector_div() based arithmetic so the rounded range is aligned to the actual RAID5 stripe width. The deterministic mapper test now reports the fixed component range as [1024, 2048), while the old mask-based range was [0, 1024). Fixes: 9c89f604476c ("md/raid5: implement pers->bitmap_sector()") Reported-by: Mykola Marzhan <mykola(a)meshstor.io> Link: https://lore.kernel.org/all/20260726185916.2223460-1-mykola@meshstor.io/ Tested-by: Mykola Marzhan <mykola(a)meshstor.io> Link: https://patch.msgid.link/20260802195038.164272-6-yukuai@kernel.org Signed-off-by: Yu Kuai <yukuai(a)fygo.io> Signed-off-by: Sasha Levin <sashal(a)kernel.org> Signed-off-by: Lu Jialin <lujialin4(a)huawei.com> --- drivers/md/raid5.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 6ec8e1b3d8b2..435612b60c53 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -5899,8 +5899,11 @@ static void raid5_bitmap_sector(struct mddev *mddev, sector_t *offset, sectors_per_chunk = conf->chunk_sectors * (conf->raid_disks - conf->max_degraded); - start = round_down(start, sectors_per_chunk); - end = round_up(end, sectors_per_chunk); + sector_div(start, sectors_per_chunk); + start *= sectors_per_chunk; + if (sector_div(end, sectors_per_chunk)) + end++; + end *= sectors_per_chunk; start = raid5_compute_sector(conf, start, 0, &dd_idx, NULL); end = raid5_compute_sector(conf, end, 0, &dd_idx, NULL); @@ -5918,8 +5921,10 @@ static void raid5_bitmap_sector(struct mddev *mddev, sector_t *offset, sectors_per_chunk = conf->prev_chunk_sectors * (conf->previous_raid_disks - conf->max_degraded); - prev_start = round_down(prev_start, sectors_per_chunk); - prev_end = round_down(prev_end, sectors_per_chunk); + sector_div(prev_start, sectors_per_chunk); + prev_start *= sectors_per_chunk; + sector_div(prev_end, sectors_per_chunk); + prev_end *= sectors_per_chunk; prev_start = raid5_compute_sector(conf, prev_start, 1, &dd_idx, NULL); prev_end = raid5_compute_sector(conf, prev_end, 1, &dd_idx, NULL); -- 2.34.1
2 1
0 0
[PATCH OLK-6.6] mtd: rawnand: validate ONFI extended parameter page sections
by Lu Jialin 28 Sep '26

28 Sep '26
From: Pengpeng Hou <pengpeng(a)iscas.ac.cn> stable inclusion from stable-v6.6.157 commit ddb6ddf5be7429bb98b3368c883be51f00b31678 category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/19270 CVE: CVE-2026-89952 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id… -------------------------------- commit e5e415262330bd70f983e091d8919d9dcd99e475 upstream. nand_flash_detect_ext_param_page() allocates the length declared by the ONFI parameter page, then treats the data as a fixed header followed by variable-length sections. It reads that header and advances over sections without first proving that the fixed page and each current section fit in the allocation. Reject pages shorter than the fixed header, track the remaining variable area while walking sections, and require the ECC section to contain every field read from struct onfi_ext_ecc_info. Use device-scoped diagnostics that identify the malformed ONFI section. Fixes: 6dcbe0cdd83f ("mtd: get the ECC info from the Extended Parameter Page") Cc: stable(a)vger.kernel.org Signed-off-by: Pengpeng Hou <pengpeng(a)iscas.ac.cn> Signed-off-by: Miquel Raynal <miquel.raynal(a)bootlin.com> Signed-off-by: Greg Kroah-Hartman <gregkh(a)linuxfoundation.org> Signed-off-by: Lu Jialin <lujialin4(a)huawei.com> --- drivers/mtd/nand/raw/nand_onfi.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/nand/raw/nand_onfi.c b/drivers/mtd/nand/raw/nand_onfi.c index 861975e44b55..f03553eb1324 100644 --- a/drivers/mtd/nand/raw/nand_onfi.c +++ b/drivers/mtd/nand/raw/nand_onfi.c @@ -35,16 +35,21 @@ static int nand_flash_detect_ext_param_page(struct nand_chip *chip, struct nand_onfi_params *p) { struct nand_device *base = &chip->base; + struct mtd_info *mtd = nand_to_mtd(chip); struct nand_ecc_props requirements; struct onfi_ext_param_page *ep; struct onfi_ext_section *s; struct onfi_ext_ecc_info *ecc; + size_t remaining, section_len; uint8_t *cursor; int ret; int len; int i; len = le16_to_cpu(p->ext_param_page_length) * 16; + if (len < sizeof(*ep)) + return -EINVAL; + ep = kmalloc(len, GFP_KERNEL); if (!ep) return -ENOMEM; @@ -77,11 +82,29 @@ static int nand_flash_detect_ext_param_page(struct nand_chip *chip, /* find the ECC section. */ cursor = (uint8_t *)(ep + 1); + remaining = len - sizeof(*ep); for (i = 0; i < ONFI_EXT_SECTION_MAX; i++) { s = ep->sections + i; - if (s->type == ONFI_SECTION_TYPE_2) + section_len = s->length * 16; + if (section_len > remaining) { + dev_dbg(&mtd->dev, + "ONFI extended parameter section %d exceeds page\n", + i); + goto ext_out; + } + + if (s->type == ONFI_SECTION_TYPE_2) { + if (section_len < sizeof(*ecc)) { + dev_dbg(&mtd->dev, + "ONFI extended parameter ECC section %d is too short\n", + i); + goto ext_out; + } break; - cursor += s->length * 16; + } + + cursor += section_len; + remaining -= section_len; } if (i == ONFI_EXT_SECTION_MAX) { pr_debug("We can not find the ECC section.\n"); -- 2.34.1
2 1
0 0
[PATCH OLK-6.6] ubi: Fix rollback for explicit UBI device numbers
by Lu Jialin 28 Sep '26

28 Sep '26
From: Yuho Choi <dbgh9129(a)gmail.com> stable inclusion from stable-v6.6.157 commit 552e565ed8846e7db143e4a6bdf3f5677453c686 category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/19443 CVE: CVE-2026-90216 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id… -------------------------------- [ Upstream commit 5b0a6b554e12a97f9771a9a9f4ea1f5457373c73 ] ubi_init_attach() rolls back module initialization failures by scanning ubi_devices[0..i-1], where i is the mtd= parameter index. That assumes the parameter index matches the UBI device number. That assumption is not true when mtd= specifies an explicit ubi_num. A successfully attached device can be stored at a higher ubi_devices[] slot, and a later failure can miss it during rollback. Scan the full ubi_devices[] array and detach by the actual array index, matching the way UBI devices are stored. Fixes: 83ff59a06663 ("UBI: support ubi_num on mtd.ubi command line") Signed-off-by: Yuho Choi <dbgh9129(a)gmail.com> Reviewed-by: Zhihao Cheng <chengzhihao1(a)huawei.com> Signed-off-by: Richard Weinberger <richard(a)nod.at> Signed-off-by: Sasha Levin <sashal(a)kernel.org> Signed-off-by: Lu Jialin <lujialin4(a)huawei.com> --- drivers/mtd/ubi/build.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c index 1a227c3b08b5..8c74020c8ce2 100644 --- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -1316,10 +1316,10 @@ static int __init ubi_init(void) return 0; out_detach: - for (k = 0; k < i; k++) + for (k = 0; k < UBI_MAX_DEVICES; k++) if (ubi_devices[k]) { mutex_lock(&ubi_devices_mutex); - ubi_detach_mtd_dev(ubi_devices[k]->ubi_num, 1); + ubi_detach_mtd_dev(k, 1); mutex_unlock(&ubi_devices_mutex); } ubi_debugfs_exit(); -- 2.34.1
1 0
0 0
[PATCH OLK-6.6] nvdimm/btt: reject an arena whose nfree is below the lane count
by Lu Jialin 28 Sep '26

28 Sep '26
From: Bryam Vargas <hexlabsecurity(a)proton.me> stable inclusion from stable-v6.6.157 commit f9bf05c63b77d000e9c01f3e47af36973887d350 category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/19097 CVE: CVE-2026-89965 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id… -------------------------------- commit 6a1f2e5ed9267ca19187038ac635393c165213ac upstream. The BTT info block's nfree field, the number of reserve free blocks, is read from the medium without validation. btt_freelist_init() and btt_rtt_init() size the per-lane freelist[] and rtt[] arrays by nfree, but the I/O path indexes them by the lane from nd_region_acquire_lane(), which is bounded by nd_region->num_lanes (ND_MAX_LANES), not by nfree. A crafted or foreign arena whose nfree is below the lane count makes freelist[lane]/rtt[lane] run past the allocation: an out-of-bounds write. btt.rst documents the nlanes = min(nfree, num_cpus) invariant, which the code does not currently honor: num_lanes is ND_MAX_LANES regardless of nfree. Reject an arena whose nfree is below num_lanes at discovery, before the per-lane arrays are allocated, enforcing that invariant. Fixes: 5212e11fde4d ("nd_btt: atomic sector updates") Cc: stable(a)vger.kernel.org Signed-off-by: Bryam Vargas <hexlabsecurity(a)proton.me> Reviewed-by: Alison Schofield <alison.schofield(a)intel.com> Tested-by: Alison Schofield <alison.schofield(a)intel.com> Link: https://patch.msgid.link/20260620-b4-disp-88b2514b-v1-1-3834e707d232@proton… Signed-off-by: Alison Schofield <alison.schofield(a)intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh(a)linuxfoundation.org> Signed-off-by: Lu Jialin <lujialin4(a)huawei.com> --- drivers/nvdimm/btt.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/nvdimm/btt.c b/drivers/nvdimm/btt.c index 9e54083505f3..4cfed0a3d142 100644 --- a/drivers/nvdimm/btt.c +++ b/drivers/nvdimm/btt.c @@ -886,6 +886,14 @@ static int discover_arenas(struct btt *btt) arena->external_lba_start = cur_nlba; parse_arena_meta(arena, super, cur_off); + if (arena->nfree < btt->nd_region->num_lanes) { + dev_err(to_dev(arena), + "nfree %u smaller than lane count %d\n", + arena->nfree, btt->nd_region->num_lanes); + ret = -ENODEV; + goto out; + } + ret = log_set_indices(arena); if (ret) { dev_err(to_dev(arena), -- 2.34.1
2 1
0 0
[PATCH OLK-5.10] nvdimm/btt: reject an arena whose nfree is below the lane count
by Lu Jialin 28 Sep '26

28 Sep '26
From: Bryam Vargas <hexlabsecurity(a)proton.me> stable inclusion from stable-v5.10.270 commit eb491343d2d1784121ad9af91c25b338c28913c3 category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/19097 CVE: CVE-2026-89965 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id… -------------------------------- commit 6a1f2e5ed9267ca19187038ac635393c165213ac upstream. The BTT info block's nfree field, the number of reserve free blocks, is read from the medium without validation. btt_freelist_init() and btt_rtt_init() size the per-lane freelist[] and rtt[] arrays by nfree, but the I/O path indexes them by the lane from nd_region_acquire_lane(), which is bounded by nd_region->num_lanes (ND_MAX_LANES), not by nfree. A crafted or foreign arena whose nfree is below the lane count makes freelist[lane]/rtt[lane] run past the allocation: an out-of-bounds write. btt.rst documents the nlanes = min(nfree, num_cpus) invariant, which the code does not currently honor: num_lanes is ND_MAX_LANES regardless of nfree. Reject an arena whose nfree is below num_lanes at discovery, before the per-lane arrays are allocated, enforcing that invariant. Fixes: 5212e11fde4d ("nd_btt: atomic sector updates") Cc: stable(a)vger.kernel.org Signed-off-by: Bryam Vargas <hexlabsecurity(a)proton.me> Reviewed-by: Alison Schofield <alison.schofield(a)intel.com> Tested-by: Alison Schofield <alison.schofield(a)intel.com> Link: https://patch.msgid.link/20260620-b4-disp-88b2514b-v1-1-3834e707d232@proton… Signed-off-by: Alison Schofield <alison.schofield(a)intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh(a)linuxfoundation.org> Signed-off-by: Lu Jialin <lujialin4(a)huawei.com> --- drivers/nvdimm/btt.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/nvdimm/btt.c b/drivers/nvdimm/btt.c index 12ff6f8784ac..45208cdd536a 100644 --- a/drivers/nvdimm/btt.c +++ b/drivers/nvdimm/btt.c @@ -886,6 +886,14 @@ static int discover_arenas(struct btt *btt) arena->external_lba_start = cur_nlba; parse_arena_meta(arena, super, cur_off); + if (arena->nfree < btt->nd_region->num_lanes) { + dev_err(to_dev(arena), + "nfree %u smaller than lane count %d\n", + arena->nfree, btt->nd_region->num_lanes); + ret = -ENODEV; + goto out; + } + ret = log_set_indices(arena); if (ret) { dev_err(to_dev(arena), -- 2.34.1
1 0
0 0
[PATCH OLK-6.6] mm/rmap: fix missing barrier between anon_vma init and vma->anon_vma publish
by Jinjiang Tu 28 Sep '26

28 Sep '26
mainline inclusion from mainline-v7.3-rc5 commit b6ac0b3f6013c168f22cad97e79967accacb08e1 category: bugfix bugzilla: https://atomgit.com/openeuler/kernel/issues/10048 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?… -------------------------------- On arm64 server, we find that a task trying to grab the anon_vma lock triggers hungtask. INFO: task main:2354726 blocked for more than 120 seconds. Tainted: G E 5.10.0-0021.aarch64 #1 "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message. task:main state:D stack: 0 pid:2354726 ppid:2350673 flags:0x00000a01 Call trace: __switch_to+0x7c/0xbc __schedule+0x3b4/0x8a0 schedule+0x50/0xe0 rwsem_down_write_slowpath+0x3cc/0x6cc down_write+0x60/0x260 __anon_vma_prepare+0x6c/0x210 do_anonymous_page+0x258/0x660 handle_pte_fault+0x188/0x214 __handle_mm_fault+0x1b0/0x380 handle_mm_fault+0xf4/0x284 do_page_fault+0x19c/0x494 do_translation_fault+0xcc/0xf8 do_mem_abort+0x48/0xac el0_da+0x44/0x80 el0_sync_handler+0x88/0xb4 el0_sync+0x160/0x180 After analyzing the vmcore, we found the anon_vma->root->rwsem.count is -1. There is another anon_vma whose anon_vma->root->rwsem.count is 1, the anon_vma->root->rwsem.owner shows the lock is held, but the stack of the task shows the task doesn't hold the anon_vma lock. After adding more debugging info, we found __anon_vma_prepare() reuses anon_vma and triggers the UAF of anon_vma->root due to missing memory barrier, leading to locking and unlocking two different anon_vma->root, thus leading to an anon_vma will never be unlocked, and another anon_vma couldn't be locked anymore. This race requires two adjacent VMAs that are not merged but are anon_vma-compatible (e.g., they differ in VMA_ACCESS_FLAGS that can be changed by mprotect()). Two threads fault on each VMA concurrently, both calling __anon_vma_prepare() with only mmap_lock held for reading. THREAD A THREAD B __anon_vma_prepare __anon_vma_prepare find_mergeable_anon_vma() -> NULL anon_vma = anon_vma_alloc(); anon_vma->root = anon_vma; // the two stores may be reordered vma->anon_vma = anon_vma; // finds A's anon_vma anon_vma = find_mergeable_anon_vma(vma); anon_vma_lock_write(anon_vma); // may still see the old root down_write(&anon_vma->root->rwsem); anon_vma_unlock_write(anon_vma); // see the new root, never unlock old up_write(&anon_vma->root->rwsem); thread A triggers page fault and calls __anon_vma_prepare() to prepare anon_vma for the faulting vma. __anon_vma_prepare() allocates and initializes a new anon_vma, and then publishes it to the vma with a plain store. anon_vma_prepare() only requires the mmap_lock to be held for reading, so two threads can fault on adjacent VMAs at the same time. While thread A publishes a new anon_vma, thread B could find the anon_vma via find_mergeable_anon_vma() and then locks anon_vma->root->rwsem. The store to anon_vma->root in anon_vma_alloc() and the store to vma->anon_vma can be reordered. The anon_vma_lock_write() and spin_lock() only provide acquire semantics, which do not prevent prior stores from being reordered after them. The release semantics of the corresponding spin_unlock() and anon_vma_unlock_write() come too late, the store to vma->anon_vma is already published before they take effect. As a result, thread B can observe the following order: vma->anon_vma = anon_vma; anon_vma->root = anon_vma; The anon_vma slab is SLAB_TYPESAFE_BY_RCU, so a newly allocated anon_vma may reuse memory from a previously freed one. The constructor (anon_vma_ctor) does not reset anon_vma->root, and __put_anon_vma() doesn't clear it either, so the old root value persists until anon_vma_alloc() overwrites it. If that store isn't visible, thread B reads a root that points to the old anon_vma and locks it. As a result, thread B can call anon_vma_lock_write() with the old root, and call anon_vma_unlock_write() with the new root, leading to an anon_vma will never be unlocked, and another anon_vma couldn't be locked anymore (its count is dropped from 0 to -1 due to wrong unlock). To fix it, change the plain store `vma->anon_vma = anon_vma` to store release, so that the fields of anon_vma are visible before anon_vma is published to vma->anon_vma. At read side, the load of anon_vma and anon_vma->root have address dependency. According to Documentation/memory-barriers.txt and some investigations, only Alpha needs address-dependency barriers and it has been handled by READ_ONCE() in reusable_anon_vma(). We reproduced this issue in v5.10 with KSM enabled. The kernel doesn't merge commit cf7e7a3503df ("mm: prevent KSM from breaking VMA merging for new VMAs"), so there are many adjacent VMAs that aren't merged but are compatible for anon_vma. Without this fix, our production environment could reproduce this issue about 2-5 times each month. After adding a smp_mb() before anon_vma_lock_write(anon_vma) in __anon_vma_prepare(), which is different to this patch, this issue hasn't been reproduced for one month. Link: https://lore.kernel.org/20260908122924.554373-1-tujinjiang@huawei.com Fixes: 5c341ee1dfc8 ("mm: track the root (oldest) anon_vma") Signed-off-by: Jinjiang Tu <tujinjiang(a)huawei.com> Signed-off-by: Andrew Morton <akpm(a)linux-foundation.org> Reviewed-by: Lance Yang <lance.yang(a)linux.dev> Reviewed-by: Lorenzo Stoakes (ARM) <ljs(a)kernel.org> Acked-by: David Hildenbrand (Arm) <david(a)kernel.org> Acked-by: Vlastimil Babka (SUSE) <vbabka(a)kernel.org> Cc: Minchan Kim <minchan(a)kernel.org> Cc: Harry Yoo <harry(a)kernel.org> Cc: Hiroyouki Kamezawa <kamezawa.hiroyu(a)jp.fujitsu.com> Cc: Jann Horn <jannh(a)google.com> Cc: Jinjiang Tu <tujinjiang(a)huawei.com> Cc: Kefeng Wang <wangkefeng.wang(a)huawei.com> Cc: Larry Woodman <lwoodman(a)redhat.com> Cc: Liam R. Howlett <liam(a)infradead.org> Cc: Nanyong Sun <sunnanyong(a)huawei.com> Cc: Rik van Riel <riel(a)surriel.com> Cc: <stable(a)vger.kernel.org> Conflicts: mm/rmap.c mm/mmap.c mm/vma.c [Context conflicts.] Signed-off-by: Jinjiang Tu <tujinjiang(a)huawei.com> --- mm/mmap.c | 7 +++++++ mm/rmap.c | 6 +++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/mm/mmap.c b/mm/mmap.c index 669bc1b74b35..7b0ba4395441 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -1170,6 +1170,13 @@ static int anon_vma_compatible(struct vm_area_struct *a, struct vm_area_struct * * acceptable for merging, so we can do all of this optimistically. But * we do that READ_ONCE() to make sure that we never re-load the pointer. * + * The READ_ONCE() establishes an address dependency between anon_vma and + * any access to its fields, which pairs with the assignment to + * vma->anon_vma performed with release semantics in __anon_vma_prepare(). + * + * This is especially important as anon_vma's are SLAB_TYPESAFE_BY_RCU so + * accessing an uninitialised anon_vma's fields may result in a UAF. + * * IOW: that the "list_is_singular()" test on the anon_vma_chain only * matters for the 'stable anon_vma' case (ie the thing we want to avoid * is to return an anon_vma that is "complex" due to having gone through diff --git a/mm/rmap.c b/mm/rmap.c index ad0213898dcd..12718f5ed9d2 100644 --- a/mm/rmap.c +++ b/mm/rmap.c @@ -210,7 +210,11 @@ int __anon_vma_prepare(struct vm_area_struct *vma) /* page_table_lock to protect against threads */ spin_lock(&mm->page_table_lock); if (likely(!vma->anon_vma)) { - vma->anon_vma = anon_vma; + /* + * Make anon_vma fields visible before anon_vma is published. + * Paired with an address dependency in reusable_anon_vma(). + */ + smp_store_release(&vma->anon_vma, anon_vma); anon_vma_chain_link(vma, avc, anon_vma); anon_vma->num_active_vmas++; allocated = NULL; -- 2.43.0
2 1
0 0
[PATCH openEuler-1.0-LTS] sctp: validate cookie AUTH state before use
by Jinjiang Tu 28 Sep '26

28 Sep '26
From: Jérémy Jean <Jeremy.Jean(a)oss.cyber.gouv.fr> mainline inclusion from mainline-v7.2 commit 3dbb44d88b1e94dd31fe43588af7437b34b44d56 category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/18398 CVE: CVE-2026-74752 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id… -------------------------------- When cookie authentication is disabled, COOKIE_ECHO restores fixed-size AUTH fields directly from peer-controlled cookie bytes. A forged RANDOM length, HMAC list, or CHUNKS list can then reach association consumers with lengths or identifiers that were never validated against the local backing arrays. A forged RANDOM length can cause out-of-bounds reads during key-vector construction. A forged HMAC identifier also caused a 32-byte write past a zero-length AUTH chunk, providing a primitive for a local privilege escalation chain. Validate the cookie's RANDOM, HMACS, and CHUNKS parameters at the cookie trust boundary before copying them into the association. Reject invalid types, malformed lengths, unsupported HMAC identifiers, HMAC lists without SHA1, and forbidden chunk ids. Fixes: bbd0d59809f9 ("[SCTP]: Implement the receive and verification of AUTH chunk") Fixes: 1f485649f529 ("[SCTP]: Implement SCTP-AUTH internals") Signed-off-by: Jérémy Jean <Jeremy.Jean(a)oss.cyber.gouv.fr> Acked-by: Xin Long <lucien.xin(a)gmail.com> Link: https://patch.msgid.link/20260804200042.2412009-1-Jeremy.Jean@oss.cyber.gou… Signed-off-by: Jakub Kicinski <kuba(a)kernel.org> Conflicts: include/net/sctp/auth.h net/sctp/auth.c [Backport of upstream 3dbb44d88b1e adding sctp_auth_verify_cookie_params() to validate the cookie's RANDOM/HMACS/CHUNKS parameters before they are restored into an association. Two helpers used by the new function are provided by later mainline refactors absent on this tree and are replaced with in-tree equivalents: - sctp_sk(ep->base.sk)->cookie_auth_enable (from 2f3dd6ec901f2, which replaces sp->hmac with a bool) becomes sctp_sk(ep->base.sk)->hmac, whose non-NULL value keeps the same "cookie HMAC auth enabled" meaning already used by sctp_pack_cookie()/sctp_unpack_cookie(); - sctp_hmac_supported(hmac_id) (from bf40785fa437c) becomes the equivalent "hmac_id >= SCTP_AUTH_NUM_HMACS || !sctp_hmac_list[hmac_id].hmac_name" check matching auth.c style. In auth.h the new declaration and the struct sctp_cookie forward declaration are added while the downstream crypto_shash, init_hmacs, destroy_hmacs declarations and the non-const sctp_auth_get_hmac()/ sctp_auth_asoc_get_hmac() signatures (predating the const qualifiers of the upstream refactors) are preserved. The full validation logic is retained and is semantically equivalent to upstream.] Signed-off-by: Hulk Robot <hulkrobot(a)huawei.com> Signed-off-by: Zhang Xiaoxu <zhangxiaoxu5(a)huawei.com> Signed-off-by: Jinjiang Tu <tujinjiang(a)huawei.com> --- include/net/sctp/auth.h | 3 ++ net/sctp/auth.c | 76 ++++++++++++++++++++++++++++++++++++++++ net/sctp/sm_make_chunk.c | 3 ++ 3 files changed, 82 insertions(+) diff --git a/include/net/sctp/auth.h b/include/net/sctp/auth.h index 687e7f80037d..3c375bf0050b 100644 --- a/include/net/sctp/auth.h +++ b/include/net/sctp/auth.h @@ -38,6 +38,7 @@ struct sctp_association; struct sctp_authkey; struct sctp_hmacalgo; struct crypto_shash; +struct sctp_cookie; /* * Define a generic struct that will hold all the info @@ -92,6 +93,8 @@ struct sctp_shared_key *sctp_auth_get_shkey( int sctp_auth_asoc_copy_shkeys(const struct sctp_endpoint *ep, struct sctp_association *asoc, gfp_t gfp); +bool sctp_auth_verify_cookie_params(const struct sctp_endpoint *ep, + const struct sctp_cookie *cookie); int sctp_auth_init_hmacs(struct sctp_endpoint *ep, gfp_t gfp); void sctp_auth_destroy_hmacs(struct crypto_shash *auth_hmacs[]); struct sctp_hmac *sctp_auth_get_hmac(__u16 hmac_id); diff --git a/net/sctp/auth.c b/net/sctp/auth.c index 9cf61a18098a..a5e9eee937e0 100644 --- a/net/sctp/auth.c +++ b/net/sctp/auth.c @@ -391,6 +391,82 @@ int sctp_auth_asoc_copy_shkeys(const struct sctp_endpoint *ep, return -ENOMEM; } +static bool sctp_auth_chunk_id_forbidden(__u8 chunk_id) +{ + switch (chunk_id) { + case SCTP_CID_INIT: + case SCTP_CID_INIT_ACK: + case SCTP_CID_SHUTDOWN_COMPLETE: + case SCTP_CID_AUTH: + return true; + default: + return false; + } +} + +/* Verify AUTH parameters copied from a state cookie before they are restored + * into an association. When cookie authentication is disabled these fields + * are peer-controlled, so they must satisfy the same constraints as locally + * generated AUTH parameters. + */ +bool sctp_auth_verify_cookie_params(const struct sctp_endpoint *ep, + const struct sctp_cookie *cookie) +{ + const struct sctp_paramhdr *random; + const struct sctp_hmac_algo_param *hmacs; + const struct sctp_chunks_param *chunks; + u16 hmacs_len, chunks_len; + u16 n_hmacs, n_chunks, i; + bool has_sha1 = false; + + if (sctp_sk(ep->base.sk)->hmac || !ep->auth_enable) + return true; + + random = (const struct sctp_paramhdr *)cookie->auth_random; + if (random->type != SCTP_PARAM_RANDOM || + ntohs(random->length) != sizeof(*random) + SCTP_AUTH_RANDOM_LENGTH) + return false; + + hmacs = (const struct sctp_hmac_algo_param *)cookie->auth_hmacs; + hmacs_len = ntohs(hmacs->param_hdr.length); + if (hmacs->param_hdr.type != SCTP_PARAM_HMAC_ALGO || + hmacs_len < sizeof(struct sctp_paramhdr) + + sizeof(hmacs->hmac_ids[0]) || + hmacs_len > sizeof(cookie->auth_hmacs) || + (hmacs_len - sizeof(struct sctp_paramhdr)) % + sizeof(hmacs->hmac_ids[0])) + return false; + + n_hmacs = (hmacs_len - sizeof(struct sctp_paramhdr)) / + sizeof(hmacs->hmac_ids[0]); + for (i = 0; i < n_hmacs; i++) { + u16 hmac_id = ntohs(hmacs->hmac_ids[i]); + + if (hmac_id >= SCTP_AUTH_NUM_HMACS || + !sctp_hmac_list[hmac_id].hmac_name) + return false; + if (hmac_id == SCTP_AUTH_HMAC_ID_SHA1) + has_sha1 = true; + } + if (!has_sha1) + return false; + + chunks = (const struct sctp_chunks_param *)cookie->auth_chunks; + chunks_len = ntohs(chunks->param_hdr.length); + if (chunks->param_hdr.type != SCTP_PARAM_CHUNKS || + chunks_len < sizeof(struct sctp_paramhdr) || + chunks_len > sizeof(cookie->auth_chunks)) + return false; + + n_chunks = chunks_len - sizeof(struct sctp_paramhdr); + for (i = 0; i < n_chunks; i++) { + if (sctp_auth_chunk_id_forbidden(chunks->chunks[i])) + return false; + } + + return true; +} + /* Public interface to create the association shared key. * See code above for the algorithm. diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index caa41c90e537..0ed35b2a62f4 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -1849,6 +1849,9 @@ struct sctp_association *sctp_unpack_cookie( /* Set up our peer's port number. */ retval->peer.port = ntohs(chunk->sctp_hdr->source); + if (!sctp_auth_verify_cookie_params(ep, bear_cookie)) + goto malformed; + /* Populate the association from the cookie. */ memcpy(&retval->c, bear_cookie, sizeof(*bear_cookie)); -- 2.43.0
2 1
0 0
[PATCH OLK-6.6] [Backport] RDMA/erdma: Hold QP references for AE and CM processing
by Tang Hui 24 Sep '26

24 Sep '26
From: Cheng Xu <chengyou(a)linux.alibaba.com> mainline inclusion from mainline-v7.3-rc1 commit a52eeff32024f190b3bdc99088c7becccd4fa60b category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/19471 CVE: CVE-2026-90308 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id… -------------------------------- AE QP fatal events and iWARP CM paths load QPs from dev->qp_xa and then use or reference them outside the xarray lock. erdma_destroy_qp() can drop the destroy-path reference and free QP resources while such a lookup is in flight. Add erdma_qp_get_by_qpn() to acquire a kref under the xarray lock with kref_get_unless_zero(). Remove the QP from the xarray before dropping the destroy-path reference so no new lookup can acquire it while destruction waits for existing users. Fixes: 155055771704 ("RDMA/erdma: Add verbs implementation") Signed-off-by: Cheng Xu <chengyou(a)linux.alibaba.com> Link: https://patch.msgid.link/20260730124357.12976-2-chengyou@linux.alibaba.com Signed-off-by: Leon Romanovsky <leon(a)kernel.org> Conflicts: drivers/infiniband/hw/erdma/erdma_verbs.c [In erdma_destroy_qp() the downstream tree keeps its own local declaration order (struct erdma_qp_attrs qp_attrs plus a later struct erdma_cmdq_destroy_qp_req req) and its own internal modify-qp helper, so the only adaptation is adding the new unsigned long flags declaration; the xa_erase change is applied unchanged.] Co-authored-by: BackportAgent(a)deepseek-v4.1-flash Signed-off-by: Hulk Robot <hulkrobot(a)huawei.com> Signed-off-by: Tang Hui <tanghui20(a)huawei.com> --- drivers/infiniband/hw/erdma/erdma_cm.c | 6 ++---- drivers/infiniband/hw/erdma/erdma_eq.c | 3 ++- drivers/infiniband/hw/erdma/erdma_verbs.c | 6 +++++- drivers/infiniband/hw/erdma/erdma_verbs.h | 15 +++++++++++++++ 4 files changed, 24 insertions(+), 6 deletions(-) diff --git a/drivers/infiniband/hw/erdma/erdma_cm.c b/drivers/infiniband/hw/erdma/erdma_cm.c index e349e8d2fb50a..c747f77c1bdbd 100644 --- a/drivers/infiniband/hw/erdma/erdma_cm.c +++ b/drivers/infiniband/hw/erdma/erdma_cm.c @@ -1017,10 +1017,9 @@ int erdma_connect(struct iw_cm_id *id, struct iw_cm_conn_param *params) if (laddr->sa_family != AF_INET || raddr->sa_family != AF_INET) return -EAFNOSUPPORT; - qp = find_qp_by_qpn(dev, params->qpn); + qp = erdma_qp_get_by_qpn(dev, params->qpn); if (!qp) return -ENOENT; - erdma_qp_get(qp); ret = sock_create(AF_INET, SOCK_STREAM, IPPROTO_TCP, &s); if (ret < 0) @@ -1149,10 +1148,9 @@ int erdma_accept(struct iw_cm_id *id, struct iw_cm_conn_param *params) return -ECONNRESET; } - qp = find_qp_by_qpn(dev, params->qpn); + qp = erdma_qp_get_by_qpn(dev, params->qpn); if (!qp) return -ENOENT; - erdma_qp_get(qp); down_write(&qp->state_lock); if (qp->attrs.state > ERDMA_QP_STATE_RTR) { diff --git a/drivers/infiniband/hw/erdma/erdma_eq.c b/drivers/infiniband/hw/erdma/erdma_eq.c index d59e2de4e4e10..eb695f10ea395 100644 --- a/drivers/infiniband/hw/erdma/erdma_eq.c +++ b/drivers/infiniband/hw/erdma/erdma_eq.c @@ -65,7 +65,7 @@ void erdma_aeq_event_handler(struct erdma_dev *dev) erdma_cq_put(cq); } else { qpn = le32_to_cpu(aeqe->event_data0); - qp = find_qp_by_qpn(dev, qpn); + qp = erdma_qp_get_by_qpn(dev, qpn); if (!qp) continue; @@ -75,6 +75,7 @@ void erdma_aeq_event_handler(struct erdma_dev *dev) if (qp->ibqp.event_handler) qp->ibqp.event_handler(&event, qp->ibqp.qp_context); + erdma_qp_put(qp); } } diff --git a/drivers/infiniband/hw/erdma/erdma_verbs.c b/drivers/infiniband/hw/erdma/erdma_verbs.c index 0c66d2bed569b..8aa830aee88bd 100644 --- a/drivers/infiniband/hw/erdma/erdma_verbs.c +++ b/drivers/infiniband/hw/erdma/erdma_verbs.c @@ -1266,6 +1266,7 @@ int erdma_destroy_qp(struct ib_qp *ibqp, struct ib_udata *udata) struct erdma_ucontext *ctx = rdma_udata_to_drv_context( udata, struct erdma_ucontext, ibucontext); struct erdma_qp_attrs qp_attrs; + unsigned long flags; int err; struct erdma_cmdq_destroy_qp_req req; @@ -1284,6 +1285,10 @@ int erdma_destroy_qp(struct ib_qp *ibqp, struct ib_udata *udata) if (err) return err; + xa_lock_irqsave(&dev->qp_xa, flags); + __xa_erase(&dev->qp_xa, QP_ID(qp)); + xa_unlock_irqrestore(&dev->qp_xa, flags); + erdma_qp_put(qp); wait_for_completion(&qp->safe_free); @@ -1306,7 +1311,6 @@ int erdma_destroy_qp(struct ib_qp *ibqp, struct ib_udata *udata) if (qp->cep) erdma_cep_put(qp->cep); - xa_erase(&dev->qp_xa, QP_ID(qp)); return 0; } diff --git a/drivers/infiniband/hw/erdma/erdma_verbs.h b/drivers/infiniband/hw/erdma/erdma_verbs.h index 10b9b8a5f6a8b..687017531b958 100644 --- a/drivers/infiniband/hw/erdma/erdma_verbs.h +++ b/drivers/infiniband/hw/erdma/erdma_verbs.h @@ -280,6 +280,21 @@ static inline struct erdma_qp *find_qp_by_qpn(struct erdma_dev *dev, int id) return (struct erdma_qp *)xa_load(&dev->qp_xa, id); } +static inline struct erdma_qp *erdma_qp_get_by_qpn(struct erdma_dev *dev, + int id) +{ + struct erdma_qp *qp; + unsigned long flags; + + xa_lock_irqsave(&dev->qp_xa, flags); + qp = xa_load(&dev->qp_xa, id); + if (qp && !kref_get_unless_zero(&qp->ref)) + qp = NULL; + xa_unlock_irqrestore(&dev->qp_xa, flags); + + return qp; +} + static inline struct erdma_cq *erdma_cq_get_by_cqn(struct erdma_dev *dev, int id) { -- 2.34.1
2 1
0 0
[PATCH OLK-5.10] NFSD: check truncate permission under inode lock
by Yang Erkun 24 Sep '26

24 Sep '26
From: Chuck Lever <chuck.lever(a)oracle.com> mainline inclusion from mainline-v7.3-rc1 commit b778e0e0a16759f22a70579c3cf8d254a40d4a7f category: bugfix bugzilla: https://atomgit.com/src-openeuler/kernel/issues/18761 Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id… -------------------------------- nfsd_setattr() checks whether a size update needs NFSD_MAY_TRUNC before it takes inode_lock(). The comparison uses the file size sampled by that unlocked read, but the actual ATTR_SIZE update is applied later under inode_lock() by notify_change(). This leaves a TOCTOU window for append-only files. If a client sends a SETATTR that does not shrink the file at the time of the unlocked sample, a concurrent append can extend the file before nfsd_setattr() takes inode_lock(). notify_change() then applies a real truncation without the NFSD_MAY_TRUNC check that rejects IS_APPEND(inode). The VFS truncate syscall paths perform their own append-only checks before calling notify_change(), so NFSD must make this decision against the locked size it is about to change. Split the write-count acquisition from the truncation permission check. Keep get_write_access() before the locked setattr work, then recheck whether the requested size is below i_size_read(inode) after inode_lock() has been acquired and before notify_change(ATTR_SIZE). This also avoids the plain unlocked inode->i_size load. Fixes: 783112f7401f ("nfsd: special case truncates some more") Cc: stable(a)vger.kernel.org Assisted-by: kres:claude-opus-4-7 Reported-by: Chris Mason <clm(a)meta.com> Signed-off-by: Jeff Layton <jlayton(a)kernel.org> Link: https://patch.msgid.link/20260530-nfsd-fixes-v2-6-f27e8eb4d974@kernel.org Signed-off-by: Chuck Lever <chuck.lever(a)oracle.com> Conflicts: fs/nfsd/vfs.c [v5.10 has no fh_fill_pre_attrs()/inode_lock() in nfsd_setattr(), so keep fh_lock() with the existing size_attr and place the nfsd_may_truncate() check inside that locked block. Keep @iap in nfsd_get_write_access() to retain the v5.10 locks_verify_truncate() call, and return the __be32 permission error from out_unlock by making err take precedence.] Signed-off-by: Yang Erkun <yangerkun(a)huawei.com> --- fs/nfsd/vfs.c | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 7820945e2d07..bac671ac36dd 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -329,20 +329,23 @@ nfsd_sanitize_attrs(struct inode *inode, struct iattr *iap) } static __be32 -nfsd_get_write_access(struct svc_rqst *rqstp, struct svc_fh *fhp, - struct iattr *iap) +nfsd_may_truncate(struct svc_rqst *rqstp, struct svc_fh *fhp, + struct iattr *iap) { struct inode *inode = d_inode(fhp->fh_dentry); - int host_err; - if (iap->ia_size < inode->i_size) { - __be32 err; + if (iap->ia_size >= i_size_read(inode)) + return nfs_ok; - err = nfsd_permission(rqstp, fhp->fh_export, fhp->fh_dentry, - NFSD_MAY_TRUNC | NFSD_MAY_OWNER_OVERRIDE); - if (err) - return err; - } + return nfsd_permission(rqstp, fhp->fh_export, fhp->fh_dentry, + NFSD_MAY_TRUNC | NFSD_MAY_OWNER_OVERRIDE); +} + +static __be32 +nfsd_get_write_access(struct svc_fh *fhp, struct iattr *iap) +{ + struct inode *inode = d_inode(fhp->fh_dentry); + int host_err; host_err = get_write_access(inode); if (host_err) @@ -429,7 +432,7 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, * setattr call. */ if (size_change) { - err = nfsd_get_write_access(rqstp, fhp, iap); + err = nfsd_get_write_access(fhp, iap); if (err) return err; } @@ -452,6 +455,10 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, if (iap->ia_size < 0) goto out_unlock; + err = nfsd_may_truncate(rqstp, fhp, iap); + if (err) + goto out_unlock; + host_err = notify_change(dentry, &size_attr, NULL); if (host_err) goto out_unlock; @@ -476,7 +483,7 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap, out: if (!host_err) host_err = commit_metadata(fhp); - return nfserrno(host_err); + return err ? err : nfserrno(host_err); } #if defined(CONFIG_NFSD_V4) -- 2.52.0
2 1
0 0
  • ← Newer
  • 1
  • 2
  • 3
  • 4
  • ...
  • 2500
  • Older →

HyperKitty Powered by HyperKitty