From: Greg Kroah-Hartman Date: Thu, 19 Mar 2026 12:01:18 +0000 (+0100) Subject: 6.6-stable patches X-Git-Tag: v6.18.19~6 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=0882a682571c5f03bc1ebb2146e0638a4772cbf9;p=thirdparty%2Fkernel%2Fstable-queue.git 6.6-stable patches added patches: binfmt_misc-restore-write-access-before-closing-files-opened-by-open_exec.patch bpf-forget-ranges-when-refining-tnum-after-jset.patch drm-amd-display-add-pixel_clock-to-amd_pp_display_configuration.patch drm-amd-pm-use-pm_display_cfg-in-legacy-dpm-v2.patch drm-amdgpu-add-basic-validation-for-ras-header.patch drm-exynos-vidi-fix-to-avoid-directly-dereferencing-user-pointer.patch drm-exynos-vidi-use-ctx-lock-to-protect-struct-vidi_context-member-variables-related-to-memory-alloc-free.patch drm-exynos-vidi-use-priv-vidi_dev-for-ctx-lookup-in-vidi_connection_ioctl.patch f2fs-zone-fix-to-avoid-inconsistence-in-between-sit-and-ssa.patch l2tp-do-not-use-sock_hold-in-pppol2tp_session_get_sock.patch mptcp-pm-in-kernel-always-set-id-as-avail-when-rm-endp.patch net-dsa-properly-keep-track-of-conduit-reference.patch net-dst-add-four-helpers-to-annotate-data-races-around-dst-dev.patch net-dst-introduce-dst-dev_rcu.patch net-stmmac-remove-support-for-lpi_intr_o.patch net-use-dst_dev_rcu-in-sk_setup_caps.patch platform-x86-amd-pmc-add-support-for-van-gogh-soc.patch rcu-nocb-fix-possible-invalid-rdp-s-nocb_cb_kthread-pointer-access.patch sched-fair-fix-pelt-clock-sync-when-entering-idle.patch x86-uprobes-fix-xol-allocation-failure-for-32-bit-tasks.patch --- diff --git a/queue-6.6/binfmt_misc-restore-write-access-before-closing-files-opened-by-open_exec.patch b/queue-6.6/binfmt_misc-restore-write-access-before-closing-files-opened-by-open_exec.patch new file mode 100644 index 0000000000..71fd0c141b --- /dev/null +++ b/queue-6.6/binfmt_misc-restore-write-access-before-closing-files-opened-by-open_exec.patch @@ -0,0 +1,50 @@ +From stable+bounces-223166-greg=kroah.com@vger.kernel.org Thu Mar 5 03:35:55 2026 +From: Robert Garcia +Date: Thu, 5 Mar 2026 10:35:01 +0800 +Subject: binfmt_misc: restore write access before closing files opened by open_exec() +To: stable@vger.kernel.org, Zilin Guan +Cc: Christian Brauner , Alexander Viro , Robert Garcia , Jan Kara , Eric Biederman , Kees Cook , Andrew Morton , Helge Deller , Lior Ribak , linux-fsdevel@vger.kernel.org, linux-mm@kvack.org, linux-kernel@vger.kernel.org +Message-ID: <20260305023501.4003943-1-rob_garcia@163.com> + +From: Zilin Guan + +[ Upstream commit 90f601b497d76f40fa66795c3ecf625b6aced9fd ] + +bm_register_write() opens an executable file using open_exec(), which +internally calls do_open_execat() and denies write access on the file to +avoid modification while it is being executed. + +However, when an error occurs, bm_register_write() closes the file using +filp_close() directly. This does not restore the write permission, which +may cause subsequent write operations on the same file to fail. + +Fix this by calling exe_file_allow_write_access() before filp_close() to +restore the write permission properly. + +Fixes: e7850f4d844e ("binfmt_misc: fix possible deadlock in bm_register_write") +Signed-off-by: Zilin Guan +Link: https://patch.msgid.link/20251105022923.1813587-1-zilin@seu.edu.cn +Signed-off-by: Christian Brauner +[ Use allow_write_access() instead of exe_file_allow_write_access() +according to commit 0357ef03c94ef +("fs: don't block write during exec on pre-content watched files"). ] +Signed-off-by: Robert Garcia +Signed-off-by: Greg Kroah-Hartman +--- + fs/binfmt_misc.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +--- a/fs/binfmt_misc.c ++++ b/fs/binfmt_misc.c +@@ -815,8 +815,10 @@ out: + inode_unlock(d_inode(root)); + + if (err) { +- if (f) ++ if (f) { ++ allow_write_access(f); + filp_close(f, NULL); ++ } + kfree(e); + return err; + } diff --git a/queue-6.6/bpf-forget-ranges-when-refining-tnum-after-jset.patch b/queue-6.6/bpf-forget-ranges-when-refining-tnum-after-jset.patch new file mode 100644 index 0000000000..3964af31dc --- /dev/null +++ b/queue-6.6/bpf-forget-ranges-when-refining-tnum-after-jset.patch @@ -0,0 +1,68 @@ +From 6279846b9b2532e1b04559ef8bd0dec049f29383 Mon Sep 17 00:00:00 2001 +From: Paul Chaignon +Date: Thu, 10 Jul 2025 20:20:53 +0200 +Subject: bpf: Forget ranges when refining tnum after JSET + +From: Paul Chaignon + +commit 6279846b9b2532e1b04559ef8bd0dec049f29383 upstream. + +Syzbot reported a kernel warning due to a range invariant violation on +the following BPF program. + + 0: call bpf_get_netns_cookie + 1: if r0 == 0 goto + 2: if r0 & Oxffffffff goto + +The issue is on the path where we fall through both jumps. + +That path is unreachable at runtime: after insn 1, we know r0 != 0, but +with the sign extension on the jset, we would only fallthrough insn 2 +if r0 == 0. Unfortunately, is_branch_taken() isn't currently able to +figure this out, so the verifier walks all branches. The verifier then +refines the register bounds using the second condition and we end +up with inconsistent bounds on this unreachable path: + + 1: if r0 == 0 goto + r0: u64=[0x1, 0xffffffffffffffff] var_off=(0, 0xffffffffffffffff) + 2: if r0 & 0xffffffff goto + r0 before reg_bounds_sync: u64=[0x1, 0xffffffffffffffff] var_off=(0, 0) + r0 after reg_bounds_sync: u64=[0x1, 0] var_off=(0, 0) + +Improving the range refinement for JSET to cover all cases is tricky. We +also don't expect many users to rely on JSET given LLVM doesn't generate +those instructions. So instead of improving the range refinement for +JSETs, Eduard suggested we forget the ranges whenever we're narrowing +tnums after a JSET. This patch implements that approach. + +Reported-by: syzbot+c711ce17dd78e5d4fdcf@syzkaller.appspotmail.com +Suggested-by: Eduard Zingerman +Acked-by: Yonghong Song +Acked-by: Eduard Zingerman +Signed-off-by: Paul Chaignon +Link: https://lore.kernel.org/r/9d4fd6432a095d281f815770608fdcd16028ce0b.1752171365.git.paul.chaignon@gmail.com +Signed-off-by: Alexei Starovoitov +[ shung-hsi.yu: no detection or kernel warning for invariant violation before + 6.8, but the same umin=1,umax=0 state can occur when jset is preceed by r0 < 1. + Changes were made to adapt to older range refinement logic before commit + 67420501e868 ("bpf: generalize reg_set_min_max() to handle non-const register + comparisons"). ] +Signed-off-by: Shung-Hsi Yu +Signed-off-by: Greg Kroah-Hartman +--- + kernel/bpf/verifier.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/kernel/bpf/verifier.c ++++ b/kernel/bpf/verifier.c +@@ -14158,6 +14158,10 @@ static void reg_set_min_max(struct bpf_r + } + break; + case BPF_JSET: ++ /* Forget the ranges before narrowing tnums, to avoid invariant ++ * violations if we're on a dead branch. ++ */ ++ __mark_reg_unbounded(false_reg); + if (is_jmp32) { + false_32off = tnum_and(false_32off, tnum_const(~val32)); + if (is_power_of_2(val32)) diff --git a/queue-6.6/drm-amd-display-add-pixel_clock-to-amd_pp_display_configuration.patch b/queue-6.6/drm-amd-display-add-pixel_clock-to-amd_pp_display_configuration.patch new file mode 100644 index 0000000000..c4dd22c224 --- /dev/null +++ b/queue-6.6/drm-amd-display-add-pixel_clock-to-amd_pp_display_configuration.patch @@ -0,0 +1,77 @@ +From b515dcb0dc4e85d8254f5459cfb32fce88dacbfb Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Timur=20Krist=C3=B3f?= +Date: Tue, 9 Sep 2025 16:17:50 +0200 +Subject: drm/amd/display: Add pixel_clock to amd_pp_display_configuration +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +commit b515dcb0dc4e85d8254f5459cfb32fce88dacbfb upstream. + +This commit adds the pixel_clock field to the display config +struct so that power management (DPM) can use it. + +We currently don't have a proper bandwidth calculation on old +GPUs with DCE 6-10 because dce_calcs only supports DCE 11+. +So the power management (DPM) on these GPUs may need to make +ad-hoc decisions for display based on the pixel clock. + +Also rename sym_clock to pixel_clock in dm_pp_single_disp_config +to avoid confusion with other code where the sym_clock refers to +the DisplayPort symbol clock. + +Signed-off-by: Timur Kristóf +Signed-off-by: Alex Deucher +Signed-off-by: Rosen Penev +Signed-off-by: Greg Kroah-Hartman +--- + drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c | 1 + + drivers/gpu/drm/amd/display/dc/clk_mgr/dce110/dce110_clk_mgr.c | 2 +- + drivers/gpu/drm/amd/display/dc/dm_services_types.h | 2 +- + drivers/gpu/drm/amd/include/dm_pp_interface.h | 1 + + 4 files changed, 4 insertions(+), 2 deletions(-) + +--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c ++++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_pp_smu.c +@@ -97,6 +97,7 @@ bool dm_pp_apply_display_requirements( + const struct dm_pp_single_disp_config *dc_cfg = + &pp_display_cfg->disp_configs[i]; + adev->pm.pm_display_cfg.displays[i].controller_id = dc_cfg->pipe_idx + 1; ++ adev->pm.pm_display_cfg.displays[i].pixel_clock = dc_cfg->pixel_clock; + } + + amdgpu_dpm_display_configuration_change(adev, &adev->pm.pm_display_cfg); +--- a/drivers/gpu/drm/amd/display/dc/clk_mgr/dce110/dce110_clk_mgr.c ++++ b/drivers/gpu/drm/amd/display/dc/clk_mgr/dce110/dce110_clk_mgr.c +@@ -164,7 +164,7 @@ void dce110_fill_display_configs( + stream->link->cur_link_settings.link_rate; + cfg->link_settings.link_spread = + stream->link->cur_link_settings.link_spread; +- cfg->sym_clock = stream->phy_pix_clk; ++ cfg->pixel_clock = stream->phy_pix_clk; + /* Round v_refresh*/ + cfg->v_refresh = stream->timing.pix_clk_100hz * 100; + cfg->v_refresh /= stream->timing.h_total; +--- a/drivers/gpu/drm/amd/display/dc/dm_services_types.h ++++ b/drivers/gpu/drm/amd/display/dc/dm_services_types.h +@@ -127,7 +127,7 @@ struct dm_pp_single_disp_config { + uint32_t src_height; + uint32_t src_width; + uint32_t v_refresh; +- uint32_t sym_clock; /* HDMI only */ ++ uint32_t pixel_clock; /* Pixel clock in KHz (for HDMI only: normalized) */ + struct dc_link_settings link_settings; /* DP only */ + }; + +--- a/drivers/gpu/drm/amd/include/dm_pp_interface.h ++++ b/drivers/gpu/drm/amd/include/dm_pp_interface.h +@@ -66,6 +66,7 @@ struct single_display_configuration + uint32_t view_resolution_cy; + enum amd_pp_display_config_type displayconfigtype; + uint32_t vertical_refresh; /* for active display */ ++ uint32_t pixel_clock; /* Pixel clock in KHz (for HDMI only: normalized) */ + }; + + #define MAX_NUM_DISPLAY 32 diff --git a/queue-6.6/drm-amd-pm-use-pm_display_cfg-in-legacy-dpm-v2.patch b/queue-6.6/drm-amd-pm-use-pm_display_cfg-in-legacy-dpm-v2.patch new file mode 100644 index 0000000000..5bf9b66c1f --- /dev/null +++ b/queue-6.6/drm-amd-pm-use-pm_display_cfg-in-legacy-dpm-v2.patch @@ -0,0 +1,351 @@ +From 9d73b107a61b73e7101d4b728ddac3d2c77db111 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Timur=20Krist=C3=B3f?= +Date: Tue, 9 Sep 2025 16:17:51 +0200 +Subject: drm/amd/pm: Use pm_display_cfg in legacy DPM (v2) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +From: Timur Kristóf + +commit 9d73b107a61b73e7101d4b728ddac3d2c77db111 upstream. + +This commit is necessary for DC to function well with chips +that use the legacy power management code, ie. SI and KV. +Communicate display information from DC to the legacy PM code. + +Currently DC uses pm_display_cfg to communicate power management +requirements from the display code to the DPM code. +However, the legacy (non-DC) code path used different fields +and therefore could not take into account anything from DC. + +Change the legacy display code to fill the same pm_display_cfg +struct as DC and use the same in the legacy DPM code. + +To ease review and reduce churn, this commit does not yet +delete the now unneeded code, that is done in the next commit. + +v2: +Rebase. +Fix single_display in amdgpu_dpm_pick_power_state. + +Signed-off-by: Timur Kristóf +Signed-off-by: Alex Deucher +Signed-off-by: Rosen Penev +Signed-off-by: Greg Kroah-Hartman +--- + drivers/gpu/drm/amd/pm/amdgpu_dpm_internal.c | 67 +++++++++++++++++++++++ + drivers/gpu/drm/amd/pm/inc/amdgpu_dpm_internal.h | 2 + drivers/gpu/drm/amd/pm/legacy-dpm/kv_dpm.c | 4 - + drivers/gpu/drm/amd/pm/legacy-dpm/legacy_dpm.c | 6 +- + drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c | 65 +++++++--------------- + drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c | 11 --- + 6 files changed, 97 insertions(+), 58 deletions(-) + +--- a/drivers/gpu/drm/amd/pm/amdgpu_dpm_internal.c ++++ b/drivers/gpu/drm/amd/pm/amdgpu_dpm_internal.c +@@ -100,3 +100,70 @@ u32 amdgpu_dpm_get_vrefresh(struct amdgp + + return vrefresh; + } ++ ++void amdgpu_dpm_get_display_cfg(struct amdgpu_device *adev) ++{ ++ struct drm_device *ddev = adev_to_drm(adev); ++ struct amd_pp_display_configuration *cfg = &adev->pm.pm_display_cfg; ++ struct single_display_configuration *display_cfg; ++ struct drm_crtc *crtc; ++ struct amdgpu_crtc *amdgpu_crtc; ++ struct amdgpu_connector *conn; ++ int num_crtcs = 0; ++ int vrefresh; ++ u32 vblank_in_pixels, vblank_time_us; ++ ++ cfg->min_vblank_time = 0xffffffff; /* if the displays are off, vblank time is max */ ++ ++ if (adev->mode_info.num_crtc && adev->mode_info.mode_config_initialized) { ++ list_for_each_entry(crtc, &ddev->mode_config.crtc_list, head) { ++ amdgpu_crtc = to_amdgpu_crtc(crtc); ++ ++ /* The array should only contain active displays. */ ++ if (!amdgpu_crtc->enabled) ++ continue; ++ ++ conn = to_amdgpu_connector(amdgpu_crtc->connector); ++ display_cfg = &adev->pm.pm_display_cfg.displays[num_crtcs++]; ++ ++ if (amdgpu_crtc->hw_mode.clock) { ++ vrefresh = drm_mode_vrefresh(&amdgpu_crtc->hw_mode); ++ ++ vblank_in_pixels = ++ amdgpu_crtc->hw_mode.crtc_htotal * ++ (amdgpu_crtc->hw_mode.crtc_vblank_end - ++ amdgpu_crtc->hw_mode.crtc_vdisplay + ++ (amdgpu_crtc->v_border * 2)); ++ ++ vblank_time_us = ++ vblank_in_pixels * 1000 / amdgpu_crtc->hw_mode.clock; ++ ++ /* The legacy (non-DC) code has issues with mclk switching ++ * with refresh rates over 120 Hz. Disable mclk switching. ++ */ ++ if (vrefresh > 120) ++ vblank_time_us = 0; ++ ++ /* Find minimum vblank time. */ ++ if (vblank_time_us < cfg->min_vblank_time) ++ cfg->min_vblank_time = vblank_time_us; ++ ++ /* Find vertical refresh rate of first active display. */ ++ if (!cfg->vrefresh) ++ cfg->vrefresh = vrefresh; ++ } ++ ++ if (amdgpu_crtc->crtc_id < cfg->crtc_index) { ++ /* Find first active CRTC and its line time. */ ++ cfg->crtc_index = amdgpu_crtc->crtc_id; ++ cfg->line_time_in_us = amdgpu_crtc->line_time; ++ } ++ ++ display_cfg->controller_id = amdgpu_crtc->crtc_id; ++ display_cfg->pixel_clock = conn->pixelclock_for_modeset; ++ } ++ } ++ ++ cfg->display_clk = adev->clock.default_dispclk; ++ cfg->num_display = num_crtcs; ++} +--- a/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm_internal.h ++++ b/drivers/gpu/drm/amd/pm/inc/amdgpu_dpm_internal.h +@@ -29,4 +29,6 @@ u32 amdgpu_dpm_get_vblank_time(struct am + + u32 amdgpu_dpm_get_vrefresh(struct amdgpu_device *adev); + ++void amdgpu_dpm_get_display_cfg(struct amdgpu_device *adev); ++ + #endif +--- a/drivers/gpu/drm/amd/pm/legacy-dpm/kv_dpm.c ++++ b/drivers/gpu/drm/amd/pm/legacy-dpm/kv_dpm.c +@@ -2299,7 +2299,7 @@ static void kv_apply_state_adjust_rules( + + if (pi->sys_info.nb_dpm_enable) { + force_high = (mclk >= pi->sys_info.nbp_memory_clock[3]) || +- pi->video_start || (adev->pm.dpm.new_active_crtc_count >= 3) || ++ pi->video_start || (adev->pm.pm_display_cfg.num_display >= 3) || + pi->disable_nb_ps3_in_battery; + ps->dpm0_pg_nb_ps_lo = force_high ? 0x2 : 0x3; + ps->dpm0_pg_nb_ps_hi = 0x2; +@@ -2358,7 +2358,7 @@ static int kv_calculate_nbps_level_setti + return 0; + + force_high = ((mclk >= pi->sys_info.nbp_memory_clock[3]) || +- (adev->pm.dpm.new_active_crtc_count >= 3) || pi->video_start); ++ (adev->pm.pm_display_cfg.num_display >= 3) || pi->video_start); + + if (force_high) { + for (i = pi->lowest_valid; i <= pi->highest_valid; i++) +--- a/drivers/gpu/drm/amd/pm/legacy-dpm/legacy_dpm.c ++++ b/drivers/gpu/drm/amd/pm/legacy-dpm/legacy_dpm.c +@@ -797,8 +797,7 @@ static struct amdgpu_ps *amdgpu_dpm_pick + int i; + struct amdgpu_ps *ps; + u32 ui_class; +- bool single_display = (adev->pm.dpm.new_active_crtc_count < 2) ? +- true : false; ++ bool single_display = adev->pm.pm_display_cfg.num_display < 2; + + /* check if the vblank period is too short to adjust the mclk */ + if (single_display && adev->powerplay.pp_funcs->vblank_too_short) { +@@ -1003,7 +1002,8 @@ void amdgpu_legacy_dpm_compute_clocks(vo + { + struct amdgpu_device *adev = (struct amdgpu_device *)handle; + +- amdgpu_dpm_get_active_displays(adev); ++ if (!adev->dc_enabled) ++ amdgpu_dpm_get_display_cfg(adev); + + amdgpu_dpm_change_power_state_locked(adev); + } +--- a/drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c ++++ b/drivers/gpu/drm/amd/pm/legacy-dpm/si_dpm.c +@@ -3058,7 +3058,7 @@ static int si_get_vce_clock_voltage(stru + static bool si_dpm_vblank_too_short(void *handle) + { + struct amdgpu_device *adev = (struct amdgpu_device *)handle; +- u32 vblank_time = amdgpu_dpm_get_vblank_time(adev); ++ u32 vblank_time = adev->pm.pm_display_cfg.min_vblank_time; + /* we never hit the non-gddr5 limit so disable it */ + u32 switch_limit = adev->gmc.vram_type == AMDGPU_VRAM_TYPE_GDDR5 ? 450 : 0; + +@@ -3424,9 +3424,10 @@ static void rv770_get_engine_memory_ss(s + static void si_apply_state_adjust_rules(struct amdgpu_device *adev, + struct amdgpu_ps *rps) + { ++ const struct amd_pp_display_configuration *display_cfg = ++ &adev->pm.pm_display_cfg; + struct si_ps *ps = si_get_ps(rps); + struct amdgpu_clock_and_voltage_limits *max_limits; +- struct amdgpu_connector *conn; + bool disable_mclk_switching = false; + bool disable_sclk_switching = false; + u32 mclk, sclk; +@@ -3475,14 +3476,9 @@ static void si_apply_state_adjust_rules( + * For example, 4K 60Hz and 1080p 144Hz fall into this category. + * Find number of such displays connected. + */ +- for (i = 0; i < adev->mode_info.num_crtc; i++) { +- if (!(adev->pm.dpm.new_active_crtcs & (1 << i)) || +- !adev->mode_info.crtcs[i]->enabled) +- continue; +- +- conn = to_amdgpu_connector(adev->mode_info.crtcs[i]->connector); +- +- if (conn->pixelclock_for_modeset > 297000) ++ for (i = 0; i < display_cfg->num_display; i++) { ++ /* The array only contains active displays. */ ++ if (display_cfg->displays[i].pixel_clock > 297000) + high_pixelclock_count++; + } + +@@ -3515,7 +3511,7 @@ static void si_apply_state_adjust_rules( + rps->ecclk = 0; + } + +- if ((adev->pm.dpm.new_active_crtc_count > 1) || ++ if ((adev->pm.pm_display_cfg.num_display > 1) || + si_dpm_vblank_too_short(adev)) + disable_mclk_switching = true; + +@@ -3663,7 +3659,7 @@ static void si_apply_state_adjust_rules( + ps->performance_levels[i].mclk, + max_limits->vddc, &ps->performance_levels[i].vddc); + btc_apply_voltage_dependency_rules(&adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk, +- adev->clock.current_dispclk, ++ display_cfg->display_clk, + max_limits->vddc, &ps->performance_levels[i].vddc); + } + +@@ -4188,16 +4184,16 @@ static void si_program_ds_registers(stru + + static void si_program_display_gap(struct amdgpu_device *adev) + { ++ const struct amd_pp_display_configuration *cfg = &adev->pm.pm_display_cfg; + u32 tmp, pipe; +- int i; + + tmp = RREG32(CG_DISPLAY_GAP_CNTL) & ~(DISP1_GAP_MASK | DISP2_GAP_MASK); +- if (adev->pm.dpm.new_active_crtc_count > 0) ++ if (cfg->num_display > 0) + tmp |= DISP1_GAP(R600_PM_DISPLAY_GAP_VBLANK_OR_WM); + else + tmp |= DISP1_GAP(R600_PM_DISPLAY_GAP_IGNORE); + +- if (adev->pm.dpm.new_active_crtc_count > 1) ++ if (cfg->num_display > 1) + tmp |= DISP2_GAP(R600_PM_DISPLAY_GAP_VBLANK_OR_WM); + else + tmp |= DISP2_GAP(R600_PM_DISPLAY_GAP_IGNORE); +@@ -4207,17 +4203,8 @@ static void si_program_display_gap(struc + tmp = RREG32(DCCG_DISP_SLOW_SELECT_REG); + pipe = (tmp & DCCG_DISP1_SLOW_SELECT_MASK) >> DCCG_DISP1_SLOW_SELECT_SHIFT; + +- if ((adev->pm.dpm.new_active_crtc_count > 0) && +- (!(adev->pm.dpm.new_active_crtcs & (1 << pipe)))) { +- /* find the first active crtc */ +- for (i = 0; i < adev->mode_info.num_crtc; i++) { +- if (adev->pm.dpm.new_active_crtcs & (1 << i)) +- break; +- } +- if (i == adev->mode_info.num_crtc) +- pipe = 0; +- else +- pipe = i; ++ if (cfg->num_display > 0 && pipe != cfg->crtc_index) { ++ pipe = cfg->crtc_index; + + tmp &= ~DCCG_DISP1_SLOW_SELECT_MASK; + tmp |= DCCG_DISP1_SLOW_SELECT(pipe); +@@ -4228,7 +4215,7 @@ static void si_program_display_gap(struc + * This can be a problem on PowerXpress systems or if you want to use the card + * for offscreen rendering or compute if there are no crtcs enabled. + */ +- si_notify_smc_display_change(adev, adev->pm.dpm.new_active_crtc_count > 0); ++ si_notify_smc_display_change(adev, cfg->num_display > 0); + } + + static void si_enable_spread_spectrum(struct amdgpu_device *adev, bool enable) +@@ -5533,7 +5520,7 @@ static int si_convert_power_level_to_smc + (pl->mclk <= pi->mclk_stutter_mode_threshold) && + !eg_pi->uvd_enabled && + (RREG32(DPG_PIPE_STUTTER_CONTROL) & STUTTER_ENABLE) && +- (adev->pm.dpm.new_active_crtc_count <= 2)) { ++ (adev->pm.pm_display_cfg.num_display <= 2)) { + level->mcFlags |= SISLANDS_SMC_MC_STUTTER_EN; + + if (gmc_pg) +@@ -5685,7 +5672,7 @@ static bool si_is_state_ulv_compatible(s + /* XXX validate against display requirements! */ + + for (i = 0; i < adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.count; i++) { +- if (adev->clock.current_dispclk <= ++ if (adev->pm.pm_display_cfg.display_clk <= + adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[i].clk) { + if (ulv->pl.vddc < + adev->pm.dpm.dyn_state.vddc_dependency_on_dispclk.entries[i].v) +@@ -5839,30 +5826,22 @@ static int si_upload_ulv_state(struct am + + static int si_upload_smc_data(struct amdgpu_device *adev) + { +- struct amdgpu_crtc *amdgpu_crtc = NULL; +- int i; ++ const struct amd_pp_display_configuration *cfg = &adev->pm.pm_display_cfg; + u32 crtc_index = 0; + u32 mclk_change_block_cp_min = 0; + u32 mclk_change_block_cp_max = 0; + +- for (i = 0; i < adev->mode_info.num_crtc; i++) { +- if (adev->pm.dpm.new_active_crtcs & (1 << i)) { +- amdgpu_crtc = adev->mode_info.crtcs[i]; +- break; +- } +- } +- + /* When a display is plugged in, program these so that the SMC + * performs MCLK switching when it doesn't cause flickering. + * When no display is plugged in, there is no need to restrict + * MCLK switching, so program them to zero. + */ +- if (adev->pm.dpm.new_active_crtc_count && amdgpu_crtc) { +- crtc_index = amdgpu_crtc->crtc_id; ++ if (cfg->num_display) { ++ crtc_index = cfg->crtc_index; + +- if (amdgpu_crtc->line_time) { +- mclk_change_block_cp_min = 200 / amdgpu_crtc->line_time; +- mclk_change_block_cp_max = 100 / amdgpu_crtc->line_time; ++ if (cfg->line_time_in_us) { ++ mclk_change_block_cp_min = 200 / cfg->line_time_in_us; ++ mclk_change_block_cp_max = 100 / cfg->line_time_in_us; + } + } + +--- a/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c ++++ b/drivers/gpu/drm/amd/pm/powerplay/amd_powerplay.c +@@ -1567,16 +1567,7 @@ static void pp_pm_compute_clocks(void *h + struct amdgpu_device *adev = hwmgr->adev; + + if (!adev->dc_enabled) { +- amdgpu_dpm_get_active_displays(adev); +- adev->pm.pm_display_cfg.num_display = adev->pm.dpm.new_active_crtc_count; +- adev->pm.pm_display_cfg.vrefresh = amdgpu_dpm_get_vrefresh(adev); +- adev->pm.pm_display_cfg.min_vblank_time = amdgpu_dpm_get_vblank_time(adev); +- /* we have issues with mclk switching with +- * refresh rates over 120 hz on the non-DC code. +- */ +- if (adev->pm.pm_display_cfg.vrefresh > 120) +- adev->pm.pm_display_cfg.min_vblank_time = 0; +- ++ amdgpu_dpm_get_display_cfg(adev); + pp_display_configuration_change(handle, + &adev->pm.pm_display_cfg); + } diff --git a/queue-6.6/drm-amdgpu-add-basic-validation-for-ras-header.patch b/queue-6.6/drm-amdgpu-add-basic-validation-for-ras-header.patch new file mode 100644 index 0000000000..e511b557bc --- /dev/null +++ b/queue-6.6/drm-amdgpu-add-basic-validation-for-ras-header.patch @@ -0,0 +1,59 @@ +From 5df0d6addb7e9b6f71f7162d1253762a5be9138e Mon Sep 17 00:00:00 2001 +From: Lijo Lazar +Date: Wed, 26 Mar 2025 13:28:38 +0530 +Subject: drm/amdgpu: Add basic validation for RAS header + +From: Lijo Lazar + +commit 5df0d6addb7e9b6f71f7162d1253762a5be9138e upstream. + +If RAS header read from EEPROM is corrupted, it could result in trying +to allocate huge memory for reading the records. Add some validation to +header fields. + +Signed-off-by: Lijo Lazar +Reviewed-by: Hawking Zhang +Signed-off-by: Alex Deucher +[ RAS_TABLE_VER_V3 is not supported in v6.6.y. ] +Signed-off-by: Alva Lan +Signed-off-by: Greg Kroah-Hartman +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c | 20 ++++++++++++++++++-- + 1 file changed, 18 insertions(+), 2 deletions(-) + +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ras_eeprom.c +@@ -1338,15 +1338,31 @@ int amdgpu_ras_eeprom_init(struct amdgpu + + __decode_table_header_from_buf(hdr, buf); + +- if (hdr->version == RAS_TABLE_VER_V2_1) { ++ switch (hdr->version) { ++ case RAS_TABLE_VER_V2_1: + control->ras_num_recs = RAS_NUM_RECS_V2_1(hdr); + control->ras_record_offset = RAS_RECORD_START_V2_1; + control->ras_max_record_count = RAS_MAX_RECORD_COUNT_V2_1; +- } else { ++ break; ++ case RAS_TABLE_VER_V1: + control->ras_num_recs = RAS_NUM_RECS(hdr); + control->ras_record_offset = RAS_RECORD_START; + control->ras_max_record_count = RAS_MAX_RECORD_COUNT; ++ break; ++ default: ++ dev_err(adev->dev, ++ "RAS header invalid, unsupported version: %u", ++ hdr->version); ++ return -EINVAL; + } ++ ++ if (control->ras_num_recs > control->ras_max_record_count) { ++ dev_err(adev->dev, ++ "RAS header invalid, records in header: %u max allowed :%u", ++ control->ras_num_recs, control->ras_max_record_count); ++ return -EINVAL; ++ } ++ + control->ras_fri = RAS_OFFSET_TO_INDEX(control, hdr->first_rec_offset); + + if (hdr->header == RAS_TABLE_HDR_VAL) { diff --git a/queue-6.6/drm-exynos-vidi-fix-to-avoid-directly-dereferencing-user-pointer.patch b/queue-6.6/drm-exynos-vidi-fix-to-avoid-directly-dereferencing-user-pointer.patch new file mode 100644 index 0000000000..c10f67b3e3 --- /dev/null +++ b/queue-6.6/drm-exynos-vidi-fix-to-avoid-directly-dereferencing-user-pointer.patch @@ -0,0 +1,60 @@ +From stable+bounces-219910-greg=kroah.com@vger.kernel.org Fri Feb 27 06:00:25 2026 +From: Jeongjun Park +Date: Fri, 27 Feb 2026 13:59:52 +0900 +Subject: drm/exynos: vidi: fix to avoid directly dereferencing user pointer +To: stable@vger.kernel.org +Cc: Greg Kroah-Hartman , Inki Dae , Seung-Woo Kim , Kyungmin Park , David Airlie , Simona Vetter , Krzysztof Kozlowski , Alim Akhtar , dri-devel@lists.freedesktop.org, linux-arm-kernel@lists.infradead.org, linux-samsung-soc@vger.kernel.org, linux-kernel@vger.kernel.org, Jeongjun Park +Message-ID: <20260227045953.165751-3-aha310510@gmail.com> + +From: Jeongjun Park + +[ Upstream commit d4c98c077c7fb2dfdece7d605e694b5ea2665085 ] + +In vidi_connection_ioctl(), vidi->edid(user pointer) is directly +dereferenced in the kernel. + +This allows arbitrary kernel memory access from the user space, so instead +of directly accessing the user pointer in the kernel, we should modify it +to copy edid to kernel memory using copy_from_user() and use it. + +Cc: +Signed-off-by: Jeongjun Park +Signed-off-by: Inki Dae +Signed-off-by: Greg Kroah-Hartman +--- + drivers/gpu/drm/exynos/exynos_drm_vidi.c | 15 +++++++++++---- + 1 file changed, 11 insertions(+), 4 deletions(-) + +--- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c ++++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c +@@ -252,19 +252,26 @@ int vidi_connection_ioctl(struct drm_dev + + if (vidi->connection) { + struct edid *raw_edid; ++ struct edid edid_buf; ++ void *edid_userptr = u64_to_user_ptr(vidi->edid); + +- raw_edid = (struct edid *)(unsigned long)vidi->edid; +- if (!drm_edid_is_valid(raw_edid)) { ++ if (copy_from_user(&edid_buf, edid_userptr, sizeof(struct edid))) ++ return -EFAULT; ++ ++ if (!drm_edid_is_valid(&edid_buf)) { + DRM_DEV_DEBUG_KMS(ctx->dev, + "edid data is invalid.\n"); + return -EINVAL; + } +- ctx->raw_edid = drm_edid_duplicate(raw_edid); +- if (!ctx->raw_edid) { ++ ++ raw_edid = drm_edid_duplicate(&edid_buf); ++ ++ if (!raw_edid) { + DRM_DEV_DEBUG_KMS(ctx->dev, + "failed to allocate raw_edid.\n"); + return -ENOMEM; + } ++ ctx->raw_edid = raw_edid; + } else { + /* + * with connection = 0, free raw_edid diff --git a/queue-6.6/drm-exynos-vidi-use-ctx-lock-to-protect-struct-vidi_context-member-variables-related-to-memory-alloc-free.patch b/queue-6.6/drm-exynos-vidi-use-ctx-lock-to-protect-struct-vidi_context-member-variables-related-to-memory-alloc-free.patch new file mode 100644 index 0000000000..7bf4601176 --- /dev/null +++ b/queue-6.6/drm-exynos-vidi-use-ctx-lock-to-protect-struct-vidi_context-member-variables-related-to-memory-alloc-free.patch @@ -0,0 +1,202 @@ +From stable+bounces-219911-greg=kroah.com@vger.kernel.org Fri Feb 27 06:01:30 2026 +From: Jeongjun Park +Date: Fri, 27 Feb 2026 13:59:53 +0900 +Subject: drm/exynos: vidi: use ctx->lock to protect struct vidi_context member variables related to memory alloc/free +To: stable@vger.kernel.org +Cc: Greg Kroah-Hartman , Inki Dae , Seung-Woo Kim , Kyungmin Park , David Airlie , Simona Vetter , Krzysztof Kozlowski , Alim Akhtar , dri-devel@lists.freedesktop.org, linux-arm-kernel@lists.infradead.org, linux-samsung-soc@vger.kernel.org, linux-kernel@vger.kernel.org, Jeongjun Park +Message-ID: <20260227045953.165751-4-aha310510@gmail.com> + +From: Jeongjun Park + +[ Upstream commit 52b330799e2d6f825ae2bb74662ec1b10eb954bb ] + +Exynos Virtual Display driver performs memory alloc/free operations +without lock protection, which easily causes concurrency problem. + +For example, use-after-free can occur in race scenario like this: +``` + CPU0 CPU1 CPU2 + ---- ---- ---- + vidi_connection_ioctl() + if (vidi->connection) // true + drm_edid = drm_edid_alloc(); // alloc drm_edid + ... + ctx->raw_edid = drm_edid; + ... + drm_mode_getconnector() + drm_helper_probe_single_connector_modes() + vidi_get_modes() + if (ctx->raw_edid) // true + drm_edid_dup(ctx->raw_edid); + if (!drm_edid) // false + ... + vidi_connection_ioctl() + if (vidi->connection) // false + drm_edid_free(ctx->raw_edid); // free drm_edid + ... + drm_edid_alloc(drm_edid->edid) + kmemdup(edid); // UAF!! + ... +``` + +To prevent these vulns, at least in vidi_context, member variables related +to memory alloc/free should be protected with ctx->lock. + +Cc: +Signed-off-by: Jeongjun Park +Signed-off-by: Greg Kroah-Hartman +--- + drivers/gpu/drm/exynos/exynos_drm_vidi.c | 43 +++++++++++++++++++++++++------ + 1 file changed, 35 insertions(+), 8 deletions(-) + +--- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c ++++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c +@@ -186,15 +186,17 @@ static ssize_t vidi_store_connection(str + const char *buf, size_t len) + { + struct vidi_context *ctx = dev_get_drvdata(dev); +- int ret; ++ int ret, new_connected; + +- ret = kstrtoint(buf, 0, &ctx->connected); ++ ret = kstrtoint(buf, 0, &new_connected); + if (ret) + return ret; + +- if (ctx->connected > 1) ++ if (new_connected > 1) + return -EINVAL; + ++ mutex_lock(&ctx->lock); ++ + /* use fake edid data for test. */ + if (!ctx->raw_edid) + ctx->raw_edid = (struct edid *)fake_edid_info; +@@ -202,14 +204,21 @@ static ssize_t vidi_store_connection(str + /* if raw_edid isn't same as fake data then it can't be tested. */ + if (ctx->raw_edid != (struct edid *)fake_edid_info) { + DRM_DEV_DEBUG_KMS(dev, "edid data is not fake data.\n"); +- return -EINVAL; ++ ret = -EINVAL; ++ goto fail; + } + ++ ctx->connected = new_connected; ++ mutex_unlock(&ctx->lock); ++ + DRM_DEV_DEBUG_KMS(dev, "requested connection.\n"); + + drm_helper_hpd_irq_event(ctx->drm_dev); + + return len; ++fail: ++ mutex_unlock(&ctx->lock); ++ return ret; + } + + static DEVICE_ATTR(connection, 0644, vidi_show_connection, +@@ -244,11 +253,14 @@ int vidi_connection_ioctl(struct drm_dev + return -EINVAL; + } + ++ mutex_lock(&ctx->lock); + if (ctx->connected == vidi->connection) { ++ mutex_unlock(&ctx->lock); + DRM_DEV_DEBUG_KMS(ctx->dev, + "same connection request.\n"); + return -EINVAL; + } ++ mutex_unlock(&ctx->lock); + + if (vidi->connection) { + struct edid *raw_edid; +@@ -271,20 +283,27 @@ int vidi_connection_ioctl(struct drm_dev + "failed to allocate raw_edid.\n"); + return -ENOMEM; + } ++ mutex_lock(&ctx->lock); + ctx->raw_edid = raw_edid; ++ mutex_unlock(&ctx->lock); + } else { + /* + * with connection = 0, free raw_edid + * only if raw edid data isn't same as fake data. + */ ++ mutex_lock(&ctx->lock); + if (ctx->raw_edid && ctx->raw_edid != + (struct edid *)fake_edid_info) { + kfree(ctx->raw_edid); + ctx->raw_edid = NULL; + } ++ mutex_unlock(&ctx->lock); + } + ++ mutex_lock(&ctx->lock); + ctx->connected = vidi->connection; ++ mutex_unlock(&ctx->lock); ++ + drm_helper_hpd_irq_event(ctx->drm_dev); + + return 0; +@@ -299,7 +318,7 @@ static enum drm_connector_status vidi_de + * connection request would come from user side + * to do hotplug through specific ioctl. + */ +- return ctx->connected ? connector_status_connected : ++ return READ_ONCE(ctx->connected) ? connector_status_connected : + connector_status_disconnected; + } + +@@ -321,22 +340,24 @@ static int vidi_get_modes(struct drm_con + struct vidi_context *ctx = ctx_from_connector(connector); + struct edid *edid; + int edid_len; +- int count; ++ int count = 0; + + /* + * the edid data comes from user side and it would be set + * to ctx->raw_edid through specific ioctl. + */ ++ ++ mutex_lock(&ctx->lock); + if (!ctx->raw_edid) { + DRM_DEV_DEBUG_KMS(ctx->dev, "raw_edid is null.\n"); +- return 0; ++ goto fail; + } + + edid_len = (1 + ctx->raw_edid->extensions) * EDID_LENGTH; + edid = kmemdup(ctx->raw_edid, edid_len, GFP_KERNEL); + if (!edid) { + DRM_DEV_DEBUG_KMS(ctx->dev, "failed to allocate edid\n"); +- return 0; ++ goto fail; + } + + drm_connector_update_edid_property(connector, edid); +@@ -345,6 +366,8 @@ static int vidi_get_modes(struct drm_con + + kfree(edid); + ++fail: ++ mutex_unlock(&ctx->lock); + return count; + } + +@@ -490,11 +513,15 @@ static int vidi_remove(struct platform_d + { + struct vidi_context *ctx = platform_get_drvdata(pdev); + ++ mutex_lock(&ctx->lock); ++ + if (ctx->raw_edid != (struct edid *)fake_edid_info) { + kfree(ctx->raw_edid); + ctx->raw_edid = NULL; + } + ++ mutex_unlock(&ctx->lock); ++ + component_del(&pdev->dev, &vidi_component_ops); + + return 0; diff --git a/queue-6.6/drm-exynos-vidi-use-priv-vidi_dev-for-ctx-lookup-in-vidi_connection_ioctl.patch b/queue-6.6/drm-exynos-vidi-use-priv-vidi_dev-for-ctx-lookup-in-vidi_connection_ioctl.patch new file mode 100644 index 0000000000..397903e488 --- /dev/null +++ b/queue-6.6/drm-exynos-vidi-use-priv-vidi_dev-for-ctx-lookup-in-vidi_connection_ioctl.patch @@ -0,0 +1,93 @@ +From stable+bounces-219909-greg=kroah.com@vger.kernel.org Fri Feb 27 06:00:30 2026 +From: Jeongjun Park +Date: Fri, 27 Feb 2026 13:59:51 +0900 +Subject: drm/exynos: vidi: use priv->vidi_dev for ctx lookup in vidi_connection_ioctl() +To: stable@vger.kernel.org +Cc: Greg Kroah-Hartman , Inki Dae , Seung-Woo Kim , Kyungmin Park , David Airlie , Simona Vetter , Krzysztof Kozlowski , Alim Akhtar , dri-devel@lists.freedesktop.org, linux-arm-kernel@lists.infradead.org, linux-samsung-soc@vger.kernel.org, linux-kernel@vger.kernel.org, Jeongjun Park +Message-ID: <20260227045953.165751-2-aha310510@gmail.com> + +From: Jeongjun Park + +[ Upstream commit d3968a0d85b211e197f2f4f06268a7031079e0d0 ] + +vidi_connection_ioctl() retrieves the driver_data from drm_dev->dev to +obtain a struct vidi_context pointer. However, drm_dev->dev is the +exynos-drm master device, and the driver_data contained therein is not +the vidi component device, but a completely different device. + +This can lead to various bugs, ranging from null pointer dereferences and +garbage value accesses to, in unlucky cases, out-of-bounds errors, +use-after-free errors, and more. + +To resolve this issue, we need to store/delete the vidi device pointer in +exynos_drm_private->vidi_dev during bind/unbind, and then read this +exynos_drm_private->vidi_dev within ioctl() to obtain the correct +struct vidi_context pointer. + +Cc: +Signed-off-by: Jeongjun Park +Signed-off-by: Inki Dae +Signed-off-by: Greg Kroah-Hartman +--- + drivers/gpu/drm/exynos/exynos_drm_drv.h | 1 + + drivers/gpu/drm/exynos/exynos_drm_vidi.c | 14 +++++++++++++- + 2 files changed, 14 insertions(+), 1 deletion(-) + +--- a/drivers/gpu/drm/exynos/exynos_drm_drv.h ++++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h +@@ -199,6 +199,7 @@ struct drm_exynos_file_private { + struct exynos_drm_private { + struct device *g2d_dev; + struct device *dma_dev; ++ struct device *vidi_dev; + void *mapping; + + /* for atomic commit */ +--- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c ++++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c +@@ -224,9 +224,14 @@ ATTRIBUTE_GROUPS(vidi); + int vidi_connection_ioctl(struct drm_device *drm_dev, void *data, + struct drm_file *file_priv) + { +- struct vidi_context *ctx = dev_get_drvdata(drm_dev->dev); ++ struct exynos_drm_private *priv = drm_dev->dev_private; ++ struct device *dev = priv ? priv->vidi_dev : NULL; ++ struct vidi_context *ctx = dev ? dev_get_drvdata(dev) : NULL; + struct drm_exynos_vidi_connection *vidi = data; + ++ if (!ctx) ++ return -ENODEV; ++ + if (!vidi) { + DRM_DEV_DEBUG_KMS(ctx->dev, + "user data for vidi is null.\n"); +@@ -386,6 +391,7 @@ static int vidi_bind(struct device *dev, + { + struct vidi_context *ctx = dev_get_drvdata(dev); + struct drm_device *drm_dev = data; ++ struct exynos_drm_private *priv = drm_dev->dev_private; + struct drm_encoder *encoder = &ctx->encoder; + struct exynos_drm_plane *exynos_plane; + struct exynos_drm_plane_config plane_config = { 0 }; +@@ -393,6 +399,8 @@ static int vidi_bind(struct device *dev, + int ret; + + ctx->drm_dev = drm_dev; ++ if (priv) ++ priv->vidi_dev = dev; + + plane_config.pixel_formats = formats; + plane_config.num_pixel_formats = ARRAY_SIZE(formats); +@@ -438,8 +446,12 @@ static int vidi_bind(struct device *dev, + static void vidi_unbind(struct device *dev, struct device *master, void *data) + { + struct vidi_context *ctx = dev_get_drvdata(dev); ++ struct drm_device *drm_dev = data; ++ struct exynos_drm_private *priv = drm_dev->dev_private; + + del_timer_sync(&ctx->timer); ++ if (priv) ++ priv->vidi_dev = NULL; + } + + static const struct component_ops vidi_component_ops = { diff --git a/queue-6.6/f2fs-zone-fix-to-avoid-inconsistence-in-between-sit-and-ssa.patch b/queue-6.6/f2fs-zone-fix-to-avoid-inconsistence-in-between-sit-and-ssa.patch new file mode 100644 index 0000000000..155ea747d0 --- /dev/null +++ b/queue-6.6/f2fs-zone-fix-to-avoid-inconsistence-in-between-sit-and-ssa.patch @@ -0,0 +1,75 @@ +From stable+bounces-222982-greg=kroah.com@vger.kernel.org Wed Mar 4 06:56:20 2026 +From: Li hongliang <1468888505@139.com> +Date: Wed, 4 Mar 2026 13:55:56 +0800 +Subject: f2fs: zone: fix to avoid inconsistence in between SIT and SSA +To: gregkh@linuxfoundation.org, stable@vger.kernel.org, chao@kernel.org +Cc: patches@lists.linux.dev, linux-kernel@vger.kernel.org, jaegeuk@kernel.org, daehojeong@google.com, linux-f2fs-devel@lists.sourceforge.net +Message-ID: <20260304055556.2595295-1-1468888505@139.com> + +From: Chao Yu + +[ Upstream commit 773704c1ef96a8b70d0d186ab725f50548de82c4 ] + +w/ below testcase, it will cause inconsistence in between SIT and SSA. + +create_null_blk 512 2 1024 1024 +mkfs.f2fs -m /dev/nullb0 +mount /dev/nullb0 /mnt/f2fs/ +touch /mnt/f2fs/file +f2fs_io pinfile set /mnt/f2fs/file +fallocate -l 4GiB /mnt/f2fs/file + +F2FS-fs (nullb0): Inconsistent segment (0) type [1, 0] in SSA and SIT +CPU: 5 UID: 0 PID: 2398 Comm: fallocate Tainted: G O 6.13.0-rc1 #84 +Tainted: [O]=OOT_MODULE +Hardware name: innotek GmbH VirtualBox/VirtualBox, BIOS VirtualBox 12/01/2006 +Call Trace: + + dump_stack_lvl+0xb3/0xd0 + dump_stack+0x14/0x20 + f2fs_handle_critical_error+0x18c/0x220 [f2fs] + f2fs_stop_checkpoint+0x38/0x50 [f2fs] + do_garbage_collect+0x674/0x6e0 [f2fs] + f2fs_gc_range+0x12b/0x230 [f2fs] + f2fs_allocate_pinning_section+0x5c/0x150 [f2fs] + f2fs_expand_inode_data+0x1cc/0x3c0 [f2fs] + f2fs_fallocate+0x3c3/0x410 [f2fs] + vfs_fallocate+0x15f/0x4b0 + __x64_sys_fallocate+0x4a/0x80 + x64_sys_call+0x15e8/0x1b80 + do_syscall_64+0x68/0x130 + entry_SYSCALL_64_after_hwframe+0x67/0x6f +RIP: 0033:0x7f9dba5197ca +F2FS-fs (nullb0): Stopped filesystem due to reason: 4 + +The reason is f2fs_gc_range() may try to migrate block in curseg, however, +its SSA block is not uptodate due to the last summary block data is still +in cache of curseg. + +In this patch, we add a condition in f2fs_gc_range() to check whether +section is opened or not, and skip block migration for opened section. + +Fixes: 9703d69d9d15 ("f2fs: support file pinning for zoned devices") +Reviewed-by: Daeho Jeong +Cc: Daeho Jeong +Signed-off-by: Chao Yu +Signed-off-by: Jaegeuk Kim +[ Minor conflict resolved. ] +Signed-off-by: Li hongliang <1468888505@139.com> +Signed-off-by: Greg Kroah-Hartman +--- + fs/f2fs/gc.c | 3 +++ + 1 file changed, 3 insertions(+) + +--- a/fs/f2fs/gc.c ++++ b/fs/f2fs/gc.c +@@ -2019,6 +2019,9 @@ int f2fs_gc_range(struct f2fs_sb_info *s + if (!get_valid_blocks(sbi, segno, true)) + continue; + ++ if (IS_CURSEC(sbi, GET_SEC_FROM_SEG(sbi, segno))) ++ continue; ++ + do_garbage_collect(sbi, segno, &gc_list, FG_GC, + dry_run_sections == 0); + put_gc_inode(&gc_list); diff --git a/queue-6.6/l2tp-do-not-use-sock_hold-in-pppol2tp_session_get_sock.patch b/queue-6.6/l2tp-do-not-use-sock_hold-in-pppol2tp_session_get_sock.patch new file mode 100644 index 0000000000..fa18d675d5 --- /dev/null +++ b/queue-6.6/l2tp-do-not-use-sock_hold-in-pppol2tp_session_get_sock.patch @@ -0,0 +1,108 @@ +From 9b8c88f875c04d4cb9111bd5dd9291c7e9691bf5 Mon Sep 17 00:00:00 2001 +From: Eric Dumazet +Date: Tue, 26 Aug 2025 13:44:35 +0000 +Subject: l2tp: do not use sock_hold() in pppol2tp_session_get_sock() + +From: Eric Dumazet + +commit 9b8c88f875c04d4cb9111bd5dd9291c7e9691bf5 upstream. + +pppol2tp_session_get_sock() is using RCU, it must be ready +for sk_refcnt being zero. + +Commit ee40fb2e1eb5 ("l2tp: protect sock pointer of +struct pppol2tp_session with RCU") was correct because it +had a call_rcu(..., pppol2tp_put_sk) which was later removed in blamed commit. + +pppol2tp_recv() can use pppol2tp_session_get_sock() as well. + +Fixes: c5cbaef992d6 ("l2tp: refactor ppp socket/session relationship") +Signed-off-by: Eric Dumazet +Cc: James Chapman +Reviewed-by: Guillaume Nault +Link: https://patch.msgid.link/20250826134435.1683435-1-edumazet@google.com +Signed-off-by: Jakub Kicinski +Signed-off-by: Qingfang Deng +Signed-off-by: Greg Kroah-Hartman +--- + net/l2tp/l2tp_ppp.c | 25 ++++++++----------------- + 1 file changed, 8 insertions(+), 17 deletions(-) + +--- a/net/l2tp/l2tp_ppp.c ++++ b/net/l2tp/l2tp_ppp.c +@@ -130,22 +130,12 @@ static const struct ppp_channel_ops pppo + + static const struct proto_ops pppol2tp_ops; + +-/* Retrieves the pppol2tp socket associated to a session. +- * A reference is held on the returned socket, so this function must be paired +- * with sock_put(). +- */ ++/* Retrieves the pppol2tp socket associated to a session. */ + static struct sock *pppol2tp_session_get_sock(struct l2tp_session *session) + { + struct pppol2tp_session *ps = l2tp_session_priv(session); +- struct sock *sk; + +- rcu_read_lock(); +- sk = rcu_dereference(ps->sk); +- if (sk) +- sock_hold(sk); +- rcu_read_unlock(); +- +- return sk; ++ return rcu_dereference(ps->sk); + } + + /* Helpers to obtain tunnel/session contexts from sockets. +@@ -211,14 +201,13 @@ end: + + static void pppol2tp_recv(struct l2tp_session *session, struct sk_buff *skb, int data_len) + { +- struct pppol2tp_session *ps = l2tp_session_priv(session); +- struct sock *sk = NULL; ++ struct sock *sk; + + /* If the socket is bound, send it in to PPP's input queue. Otherwise + * queue it on the session socket. + */ + rcu_read_lock(); +- sk = rcu_dereference(ps->sk); ++ sk = pppol2tp_session_get_sock(session); + if (!sk) + goto no_sock; + +@@ -528,13 +517,14 @@ static void pppol2tp_show(struct seq_fil + struct l2tp_session *session = arg; + struct sock *sk; + ++ rcu_read_lock(); + sk = pppol2tp_session_get_sock(session); + if (sk) { + struct pppox_sock *po = pppox_sk(sk); + + seq_printf(m, " interface %s\n", ppp_dev_name(&po->chan)); +- sock_put(sk); + } ++ rcu_read_unlock(); + } + + static void pppol2tp_session_init(struct l2tp_session *session) +@@ -1540,6 +1530,7 @@ static void pppol2tp_seq_session_show(st + port = ntohs(inet->inet_sport); + } + ++ rcu_read_lock(); + sk = pppol2tp_session_get_sock(session); + if (sk) { + state = sk->sk_state; +@@ -1575,8 +1566,8 @@ static void pppol2tp_seq_session_show(st + struct pppox_sock *po = pppox_sk(sk); + + seq_printf(m, " interface %s\n", ppp_dev_name(&po->chan)); +- sock_put(sk); + } ++ rcu_read_unlock(); + } + + static int pppol2tp_seq_show(struct seq_file *m, void *v) diff --git a/queue-6.6/mptcp-pm-in-kernel-always-set-id-as-avail-when-rm-endp.patch b/queue-6.6/mptcp-pm-in-kernel-always-set-id-as-avail-when-rm-endp.patch new file mode 100644 index 0000000000..d5dcba2624 --- /dev/null +++ b/queue-6.6/mptcp-pm-in-kernel-always-set-id-as-avail-when-rm-endp.patch @@ -0,0 +1,169 @@ +From matttbe@kernel.org Fri Mar 6 18:49:49 2026 +From: "Matthieu Baerts (NGI0)" +Date: Fri, 6 Mar 2026 18:49:08 +0100 +Subject: mptcp: pm: in-kernel: always set ID as avail when rm endp +To: stable@vger.kernel.org, gregkh@linuxfoundation.org, sashal@kernel.org +Cc: MPTCP Upstream , "Matthieu Baerts (NGI0)" , syzbot+f56f7d56e2c6e11a01b6@syzkaller.appspotmail.com, Mat Martineau , Jakub Kicinski +Message-ID: <20260306174907.2519153-2-matttbe@kernel.org> + +From: "Matthieu Baerts (NGI0)" + +commit d191101dee25567c2af3b28565f45346c33d65f5 upstream. + +Syzkaller managed to find a combination of actions that was generating +this warning: + + WARNING: net/mptcp/pm_kernel.c:1074 at __mark_subflow_endp_available net/mptcp/pm_kernel.c:1074 [inline], CPU#1: syz.7.48/2535 + WARNING: net/mptcp/pm_kernel.c:1074 at mptcp_pm_nl_fullmesh net/mptcp/pm_kernel.c:1446 [inline], CPU#1: syz.7.48/2535 + WARNING: net/mptcp/pm_kernel.c:1074 at mptcp_pm_nl_set_flags_all net/mptcp/pm_kernel.c:1474 [inline], CPU#1: syz.7.48/2535 + WARNING: net/mptcp/pm_kernel.c:1074 at mptcp_pm_nl_set_flags+0x5de/0x640 net/mptcp/pm_kernel.c:1538, CPU#1: syz.7.48/2535 + Modules linked in: + CPU: 1 UID: 0 PID: 2535 Comm: syz.7.48 Not tainted 6.18.0-03987-gea5f5e676cf5 #17 PREEMPT(voluntary) + Hardware name: QEMU Ubuntu 25.10 PC (i440FX + PIIX, 1996), BIOS 1.17.0-debian-1.17.0-1 04/01/2014 + RIP: 0010:__mark_subflow_endp_available net/mptcp/pm_kernel.c:1074 [inline] + RIP: 0010:mptcp_pm_nl_fullmesh net/mptcp/pm_kernel.c:1446 [inline] + RIP: 0010:mptcp_pm_nl_set_flags_all net/mptcp/pm_kernel.c:1474 [inline] + RIP: 0010:mptcp_pm_nl_set_flags+0x5de/0x640 net/mptcp/pm_kernel.c:1538 + Code: 89 c7 e8 c5 8c 73 fe e9 f7 fd ff ff 49 83 ef 80 e8 b7 8c 73 fe 4c 89 ff be 03 00 00 00 e8 4a 29 e3 fe eb ac e8 a3 8c 73 fe 90 <0f> 0b 90 e9 3d ff ff ff e8 95 8c 73 fe b8 a1 ff ff ff eb 1a e8 89 + RSP: 0018:ffffc9001535b820 EFLAGS: 00010287 + netdevsim0: tun_chr_ioctl cmd 1074025677 + RAX: ffffffff82da294d RBX: 0000000000000001 RCX: 0000000000080000 + RDX: ffffc900096d0000 RSI: 00000000000006d6 RDI: 00000000000006d7 + netdevsim0: linktype set to 823 + RBP: ffff88802cdb2240 R08: 00000000000104ae R09: ffffffffffffffff + R10: ffffffff82da27d4 R11: 0000000000000000 R12: 0000000000000000 + R13: ffff88801246d8c0 R14: ffffc9001535b8b8 R15: ffff88802cdb1800 + FS: 00007fc6ac5a76c0(0000) GS:ffff8880f90c8000(0000) knlGS:0000000000000000 + netlink: 'syz.3.50': attribute type 5 has an invalid length. + CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 + netlink: 1232 bytes leftover after parsing attributes in process `syz.3.50'. + CR2: 0000200000010000 CR3: 0000000025b1a000 CR4: 0000000000350ef0 + Call Trace: + + mptcp_pm_set_flags net/mptcp/pm_netlink.c:277 [inline] + mptcp_pm_nl_set_flags_doit+0x1d7/0x210 net/mptcp/pm_netlink.c:282 + genl_family_rcv_msg_doit+0x117/0x180 net/netlink/genetlink.c:1115 + genl_family_rcv_msg net/netlink/genetlink.c:1195 [inline] + genl_rcv_msg+0x3a8/0x3f0 net/netlink/genetlink.c:1210 + netlink_rcv_skb+0x16d/0x240 net/netlink/af_netlink.c:2550 + genl_rcv+0x28/0x40 net/netlink/genetlink.c:1219 + netlink_unicast_kernel net/netlink/af_netlink.c:1318 [inline] + netlink_unicast+0x3e9/0x4c0 net/netlink/af_netlink.c:1344 + netlink_sendmsg+0x4ab/0x5b0 net/netlink/af_netlink.c:1894 + sock_sendmsg_nosec net/socket.c:718 [inline] + __sock_sendmsg+0xc9/0xf0 net/socket.c:733 + ____sys_sendmsg+0x272/0x3b0 net/socket.c:2608 + ___sys_sendmsg+0x2de/0x320 net/socket.c:2662 + __sys_sendmsg net/socket.c:2694 [inline] + __do_sys_sendmsg net/socket.c:2699 [inline] + __se_sys_sendmsg net/socket.c:2697 [inline] + __x64_sys_sendmsg+0x110/0x1a0 net/socket.c:2697 + do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline] + do_syscall_64+0xed/0x360 arch/x86/entry/syscall_64.c:94 + entry_SYSCALL_64_after_hwframe+0x77/0x7f + RIP: 0033:0x7fc6adb66f6d + Code: ff c3 66 2e 0f 1f 84 00 00 00 00 00 90 f3 0f 1e fa 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 e8 ff ff ff f7 d8 64 89 01 48 + RSP: 002b:00007fc6ac5a6ff8 EFLAGS: 00000246 ORIG_RAX: 000000000000002e + RAX: ffffffffffffffda RBX: 00007fc6addf5fa0 RCX: 00007fc6adb66f6d + RDX: 0000000000048084 RSI: 00002000000002c0 RDI: 000000000000000e + RBP: 0000000000000000 R08: 0000000000000000 R09: 0000000000000000 + R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000 + netlink: 'syz.5.51': attribute type 2 has an invalid length. + R13: 00007fff25e91fe0 R14: 00007fc6ac5a7ce4 R15: 00007fff25e920d7 + + +The actions that caused that seem to be: + + - Create an MPTCP endpoint for address A without any flags + - Create a new MPTCP connection from address A + - Remove the MPTCP endpoint: the corresponding subflows will be removed + - Recreate the endpoint with the same ID, but with the subflow flag + - Change the same endpoint to add the fullmesh flag + +In this case, msk->pm.local_addr_used has been kept to 0 as expected, +but the corresponding bit in msk->pm.id_avail_bitmap was still unset +after having removed the endpoint, causing the splat later on. + +When removing an endpoint, the corresponding endpoint ID was only marked +as available for "signal" types with an announced address, plus all +"subflow" types, but not the other types like an endpoint corresponding +to the initial subflow. In these cases, re-creating an endpoint with the +same ID didn't signal/create anything. Here, adding the fullmesh flag +was creating the splat when calling __mark_subflow_endp_available() from +mptcp_pm_nl_fullmesh(), because msk->pm.local_addr_used was set to 0 +while the ID was marked as used. + +To fix this issue, the corresponding bit in msk->pm.id_avail_bitmap can +always be set as available when removing an MPTCP in-kernel endpoint. In +other words, moving the call to __set_bit() to do it in all cases, +except for "subflow" types where this bit is handled in a dedicated +helper. + +Note: instead of adding a new spin_(un)lock_bh that would be taken in +all cases, do all the actions requiring the spin lock under the same +block. + +This modification potentially fixes another issue reported by syzbot, +see [1]. But without a reproducer or more details about what exactly +happened before, it is hard to confirm. + +Fixes: e255683c06df ("mptcp: pm: re-using ID of unused removed ADD_ADDR") +Cc: stable@vger.kernel.org +Closes: https://github.com/multipath-tcp/mptcp_net-next/issues/606 +Reported-by: syzbot+f56f7d56e2c6e11a01b6@syzkaller.appspotmail.com +Closes: https://lore.kernel.org/68fcfc4a.050a0220.346f24.02fb.GAE@google.com [1] +Reviewed-by: Mat Martineau +Signed-off-by: Matthieu Baerts (NGI0) +Link: https://patch.msgid.link/20260205-net-mptcp-misc-fixes-6-19-rc8-v2-1-c2720ce75c34@kernel.org +Signed-off-by: Jakub Kicinski +[ Conflict in pm_netlink.c, because commit 8617e85e04bd ("mptcp: pm: + split in-kernel PM specific code") is not in this version, and move + code from pm_netlink.c to pm_kernel.c. Also, commit 636113918508 + ("mptcp: pm: remove '_nl' from mptcp_pm_nl_rm_addr_received") renamed + mptcp_pm_nl_rm_subflow_received() to mptcp_pm_rm_subflow(). Apart from + that, the same patch can be applied in pm_netlink.c. ] +Signed-off-by: Matthieu Baerts (NGI0) +Signed-off-by: Greg Kroah-Hartman +--- + net/mptcp/pm_netlink.c | 20 ++++++++------------ + 1 file changed, 8 insertions(+), 12 deletions(-) + +--- a/net/mptcp/pm_netlink.c ++++ b/net/mptcp/pm_netlink.c +@@ -1647,10 +1647,8 @@ static bool mptcp_pm_remove_anno_addr(st + ret = remove_anno_list_by_saddr(msk, addr); + if (ret || force) { + spin_lock_bh(&msk->pm.lock); +- if (ret) { +- __set_bit(addr->id, msk->pm.id_avail_bitmap); ++ if (ret) + msk->pm.add_addr_signaled--; +- } + mptcp_pm_remove_addr(msk, &list); + spin_unlock_bh(&msk->pm.lock); + } +@@ -1688,17 +1686,15 @@ static int mptcp_nl_remove_subflow_and_s + !(entry->flags & MPTCP_PM_ADDR_FLAG_IMPLICIT)); + + list.ids[0] = mptcp_endp_get_local_id(msk, addr); +- if (remove_subflow) { +- spin_lock_bh(&msk->pm.lock); +- mptcp_pm_nl_rm_subflow_received(msk, &list); +- spin_unlock_bh(&msk->pm.lock); +- } + +- if (entry->flags & MPTCP_PM_ADDR_FLAG_SUBFLOW) { +- spin_lock_bh(&msk->pm.lock); ++ spin_lock_bh(&msk->pm.lock); ++ if (remove_subflow) ++ mptcp_pm_nl_rm_subflow_received(msk, &list); ++ if (entry->flags & MPTCP_PM_ADDR_FLAG_SUBFLOW) + __mark_subflow_endp_available(msk, list.ids[0]); +- spin_unlock_bh(&msk->pm.lock); +- } ++ else /* mark endp ID as available, e.g. Signal or MPC endp */ ++ __set_bit(addr->id, msk->pm.id_avail_bitmap); ++ spin_unlock_bh(&msk->pm.lock); + + if (msk->mpc_endpoint_id == entry->addr.id) + msk->mpc_endpoint_id = 0; diff --git a/queue-6.6/net-dsa-properly-keep-track-of-conduit-reference.patch b/queue-6.6/net-dsa-properly-keep-track-of-conduit-reference.patch new file mode 100644 index 0000000000..8b9abcb8c3 --- /dev/null +++ b/queue-6.6/net-dsa-properly-keep-track-of-conduit-reference.patch @@ -0,0 +1,290 @@ +From 06e219f6a706c367c93051f408ac61417643d2f9 Mon Sep 17 00:00:00 2001 +From: Vladimir Oltean +Date: Mon, 15 Dec 2025 17:02:35 +0200 +Subject: net: dsa: properly keep track of conduit reference + +From: Vladimir Oltean + +commit 06e219f6a706c367c93051f408ac61417643d2f9 upstream. + +Problem description +------------------- + +DSA has a mumbo-jumbo of reference handling of the conduit net device +and its kobject which, sadly, is just wrong and doesn't make sense. + +There are two distinct problems. + +1. The OF path, which uses of_find_net_device_by_node(), never releases + the elevated refcount on the conduit's kobject. Nominally, the OF and + non-OF paths should result in objects having identical reference + counts taken, and it is already suspicious that + dsa_dev_to_net_device() has a put_device() call which is missing in + dsa_port_parse_of(), but we can actually even verify that an issue + exists. With CONFIG_DEBUG_KOBJECT_RELEASE=y, if we run this command + "before" and "after" applying this patch: + +(unbind the conduit driver for net device eno2) +echo 0000:00:00.2 > /sys/bus/pci/drivers/fsl_enetc/unbind + +we see these lines in the output diff which appear only with the patch +applied: + +kobject: 'eno2' (ffff002009a3a6b8): kobject_release, parent 0000000000000000 (delayed 1000) +kobject: '109' (ffff0020099d59a0): kobject_release, parent 0000000000000000 (delayed 1000) + +2. After we find the conduit interface one way (OF) or another (non-OF), + it can get unregistered at any time, and DSA remains with a long-lived, + but in this case stale, cpu_dp->conduit pointer. Holding the net + device's underlying kobject isn't actually of much help, it just + prevents it from being freed (but we never need that kobject + directly). What helps us to prevent the net device from being + unregistered is the parallel netdev reference mechanism (dev_hold() + and dev_put()). + +Actually we actually use that netdev tracker mechanism implicitly on +user ports since commit 2f1e8ea726e9 ("net: dsa: link interfaces with +the DSA master to get rid of lockdep warnings"), via netdev_upper_dev_link(). +But time still passes at DSA switch probe time between the initial +of_find_net_device_by_node() code and the user port creation time, time +during which the conduit could unregister itself and DSA wouldn't know +about it. + +So we have to run of_find_net_device_by_node() under rtnl_lock() to +prevent that from happening, and release the lock only with the netdev +tracker having acquired the reference. + +Do we need to keep the reference until dsa_unregister_switch() / +dsa_switch_shutdown()? +1: Maybe yes. A switch device will still be registered even if all user + ports failed to probe, see commit 86f8b1c01a0a ("net: dsa: Do not + make user port errors fatal"), and the cpu_dp->conduit pointers + remain valid. I haven't audited all call paths to see whether they + will actually use the conduit in lack of any user port, but if they + do, it seems safer to not rely on user ports for that reference. +2. Definitely yes. We support changing the conduit which a user port is + associated to, and we can get into a situation where we've moved all + user ports away from a conduit, thus no longer hold any reference to + it via the net device tracker. But we shouldn't let it go nonetheless + - see the next change in relation to dsa_tree_find_first_conduit() + and LAG conduits which disappear. + We have to be prepared to return to the physical conduit, so the CPU + port must explicitly keep another reference to it. This is also to + say: the user ports and their CPU ports may not always keep a + reference to the same conduit net device, and both are needed. + +As for the conduit's kobject for the /sys/class/net/ entry, we don't +care about it, we can release it as soon as we hold the net device +object itself. + +History and blame attribution +----------------------------- + +The code has been refactored so many times, it is very difficult to +follow and properly attribute a blame, but I'll try to make a short +history which I hope to be correct. + +We have two distinct probing paths: +- one for OF, introduced in 2016 in commit 83c0afaec7b7 ("net: dsa: Add + new binding implementation") +- one for non-OF, introduced in 2017 in commit 71e0bbde0d88 ("net: dsa: + Add support for platform data") + +These are both complete rewrites of the original probing paths (which +used struct dsa_switch_driver and other weird stuff, instead of regular +devices on their respective buses for register access, like MDIO, SPI, +I2C etc): +- one for OF, introduced in 2013 in commit 5e95329b701c ("dsa: add + device tree bindings to register DSA switches") +- one for non-OF, introduced in 2008 in commit 91da11f870f0 ("net: + Distributed Switch Architecture protocol support") + +except for tiny bits and pieces like dsa_dev_to_net_device() which were +seemingly carried over since the original commit, and used to this day. + +The point is that the original probing paths received a fix in 2015 in +the form of commit 679fb46c5785 ("net: dsa: Add missing master netdev +dev_put() calls"), but the fix never made it into the "new" (dsa2) +probing paths that can still be traced to today, and the fixed probing +path was later deleted in 2019 in commit 93e86b3bc842 ("net: dsa: Remove +legacy probing support"). + +That is to say, the new probing paths were never quite correct in this +area. + +The existence of the legacy probing support which was deleted in 2019 +explains why dsa_dev_to_net_device() returns a conduit with elevated +refcount (because it was supposed to be released during +dsa_remove_dst()). After the removal of the legacy code, the only user +of dsa_dev_to_net_device() calls dev_put(conduit) immediately after this +function returns. This pattern makes no sense today, and can only be +interpreted historically to understand why dev_hold() was there in the +first place. + +Change details +-------------- + +Today we have a better netdev tracking infrastructure which we should +use. Logically netdev_hold() belongs in common code +(dsa_port_parse_cpu(), where dp->conduit is assigned), but there is a +tradeoff to be made with the rtnl_lock() section which would become a +bit too long if we did that - dsa_port_parse_cpu() also calls +request_module(). So we duplicate a bit of logic in order for the +callers of dsa_port_parse_cpu() to be the ones responsible of holding +the conduit reference and releasing it on error. This shortens the +rtnl_lock() section significantly. + +In the dsa_switch_probe() error path, dsa_switch_release_ports() will be +called in a number of situations, one being where dsa_port_parse_cpu() +maybe didn't get the chance to run at all (a different port failed +earlier, etc). So we have to test for the conduit being NULL prior to +calling netdev_put(). + +There have still been so many transformations to the code since the +blamed commits (rename master -> conduit, commit 0650bf52b31f ("net: +dsa: be compatible with masters which unregister on shutdown")), that it +only makes sense to fix the code using the best methods available today +and see how it can be backported to stable later. I suspect the fix +cannot even be backported to kernels which lack dsa_switch_shutdown(), +and I suspect this is also maybe why the long-lived conduit reference +didn't make it into the new DSA probing paths at the time (problems +during shutdown). + +Because dsa_dev_to_net_device() has a single call site and has to be +changed anyway, the logic was just absorbed into the non-OF +dsa_port_parse(). + +Tested on the ocelot/felix switch and on dsa_loop, both on the NXP +LS1028A with CONFIG_DEBUG_KOBJECT_RELEASE=y. + +Reported-by: Ma Ke +Closes: https://lore.kernel.org/netdev/20251214131204.4684-1-make24@iscas.ac.cn/ +Fixes: 83c0afaec7b7 ("net: dsa: Add new binding implementation") +Fixes: 71e0bbde0d88 ("net: dsa: Add support for platform data") +Reviewed-by: Jonas Gorski +Signed-off-by: Vladimir Oltean +Link: https://patch.msgid.link/20251215150236.3931670-1-vladimir.oltean@nxp.com +Signed-off-by: Paolo Abeni +[ backport: "conduit" -> "master" in code, kept original commit message ] +Signed-off-by: Vladimir Oltean +Signed-off-by: Greg Kroah-Hartman +--- + include/net/dsa.h | 1 + net/dsa/dsa.c | 59 +++++++++++++++++++++++++++++++----------------------- + 2 files changed, 35 insertions(+), 25 deletions(-) + +--- a/include/net/dsa.h ++++ b/include/net/dsa.h +@@ -297,6 +297,7 @@ struct dsa_port { + struct devlink_port devlink_port; + struct phylink *pl; + struct phylink_config pl_config; ++ netdevice_tracker master_tracker; + struct dsa_lag *lag; + struct net_device *hsr_dev; + +--- a/net/dsa/dsa.c ++++ b/net/dsa/dsa.c +@@ -1257,14 +1257,25 @@ static int dsa_port_parse_of(struct dsa_ + if (ethernet) { + struct net_device *master; + const char *user_protocol; ++ int err; + ++ rtnl_lock(); + master = of_find_net_device_by_node(ethernet); + of_node_put(ethernet); +- if (!master) ++ if (!master) { ++ rtnl_unlock(); + return -EPROBE_DEFER; ++ } ++ ++ netdev_hold(master, &dp->master_tracker, GFP_KERNEL); ++ put_device(&master->dev); ++ rtnl_unlock(); + + user_protocol = of_get_property(dn, "dsa-tag-protocol", NULL); +- return dsa_port_parse_cpu(dp, master, user_protocol); ++ err = dsa_port_parse_cpu(dp, master, user_protocol); ++ if (err) ++ netdev_put(master, &dp->master_tracker); ++ return err; + } + + if (link) +@@ -1397,37 +1408,30 @@ static struct device *dev_find_class(str + return device_find_child(parent, class, dev_is_class); + } + +-static struct net_device *dsa_dev_to_net_device(struct device *dev) +-{ +- struct device *d; +- +- d = dev_find_class(dev, "net"); +- if (d != NULL) { +- struct net_device *nd; +- +- nd = to_net_dev(d); +- dev_hold(nd); +- put_device(d); +- +- return nd; +- } +- +- return NULL; +-} +- + static int dsa_port_parse(struct dsa_port *dp, const char *name, + struct device *dev) + { + if (!strcmp(name, "cpu")) { + struct net_device *master; ++ struct device *d; ++ int err; + +- master = dsa_dev_to_net_device(dev); +- if (!master) ++ rtnl_lock(); ++ d = dev_find_class(dev, "net"); ++ if (!d) { ++ rtnl_unlock(); + return -EPROBE_DEFER; ++ } + +- dev_put(master); ++ master = to_net_dev(d); ++ netdev_hold(master, &dp->master_tracker, GFP_KERNEL); ++ put_device(d); ++ rtnl_unlock(); + +- return dsa_port_parse_cpu(dp, master, NULL); ++ err = dsa_port_parse_cpu(dp, master, NULL); ++ if (err) ++ netdev_put(master, &dp->master_tracker); ++ return err; + } + + if (!strcmp(name, "dsa")) +@@ -1495,6 +1499,9 @@ static void dsa_switch_release_ports(str + struct dsa_vlan *v, *n; + + dsa_switch_for_each_port_safe(dp, next, ds) { ++ if (dsa_port_is_cpu(dp) && dp->master) ++ netdev_put(dp->master, &dp->master_tracker); ++ + /* These are either entries that upper layers lost track of + * (probably due to bugs), or installed through interfaces + * where one does not necessarily have to remove them, like +@@ -1639,8 +1646,10 @@ void dsa_switch_shutdown(struct dsa_swit + /* Disconnect from further netdevice notifiers on the master, + * since netdev_uses_dsa() will now return false. + */ +- dsa_switch_for_each_cpu_port(dp, ds) ++ dsa_switch_for_each_cpu_port(dp, ds) { + dp->master->dsa_ptr = NULL; ++ netdev_put(dp->master, &dp->master_tracker); ++ } + + rtnl_unlock(); + out: diff --git a/queue-6.6/net-dst-add-four-helpers-to-annotate-data-races-around-dst-dev.patch b/queue-6.6/net-dst-add-four-helpers-to-annotate-data-races-around-dst-dev.patch new file mode 100644 index 0000000000..ed77ef29bd --- /dev/null +++ b/queue-6.6/net-dst-add-four-helpers-to-annotate-data-races-around-dst-dev.patch @@ -0,0 +1,135 @@ +From ruohanlan@aliyun.com Mon Mar 2 08:37:18 2026 +From: Ruohan Lan +Date: Mon, 2 Mar 2026 15:36:28 +0800 +Subject: net: dst: add four helpers to annotate data-races around dst->dev +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: edumazet@google.com, kuniyu@google.com, kuba@kernel.org, dsahern@kernel.org, netdev@vger.kernel.org, Ruohan Lan +Message-ID: <20260302073630.988982-2-ruohanlan@aliyun.com> + +From: Eric Dumazet + +[ Upstream commit 88fe14253e181878c2ddb51a298ae8c468a63010 ] + +dst->dev is read locklessly in many contexts, +and written in dst_dev_put(). + +Fixing all the races is going to need many changes. + +We probably will have to add full RCU protection. + +Add three helpers to ease this painful process. + +static inline struct net_device *dst_dev(const struct dst_entry *dst) +{ + return READ_ONCE(dst->dev); +} + +static inline struct net_device *skb_dst_dev(const struct sk_buff *skb) +{ + return dst_dev(skb_dst(skb)); +} + +static inline struct net *skb_dst_dev_net(const struct sk_buff *skb) +{ + return dev_net(skb_dst_dev(skb)); +} + +static inline struct net *skb_dst_dev_net_rcu(const struct sk_buff *skb) +{ + return dev_net_rcu(skb_dst_dev(skb)); +} + +Fixes: 4a6ce2b6f2ec ("net: introduce a new function dst_dev_put()") +Signed-off-by: Eric Dumazet +Reviewed-by: Kuniyuki Iwashima +Link: https://patch.msgid.link/20250630121934.3399505-7-edumazet@google.com +Signed-off-by: Jakub Kicinski +[ Minor context conflict resolved. ] +Signed-off-by: Ruohan Lan +Signed-off-by: Greg Kroah-Hartman +--- + include/net/dst.h | 20 ++++++++++++++++++++ + net/core/dst.c | 4 ++-- + net/core/sock.c | 8 ++++---- + 3 files changed, 26 insertions(+), 6 deletions(-) + +--- a/include/net/dst.h ++++ b/include/net/dst.h +@@ -581,6 +581,26 @@ static inline struct net_device *skb_dst + return dst_dev_rcu(skb_dst(skb)); + } + ++static inline struct net_device *dst_dev(const struct dst_entry *dst) ++{ ++ return READ_ONCE(dst->dev); ++} ++ ++static inline struct net_device *skb_dst_dev(const struct sk_buff *skb) ++{ ++ return dst_dev(skb_dst(skb)); ++} ++ ++static inline struct net *skb_dst_dev_net(const struct sk_buff *skb) ++{ ++ return dev_net(skb_dst_dev(skb)); ++} ++ ++static inline struct net *skb_dst_dev_net_rcu(const struct sk_buff *skb) ++{ ++ return dev_net_rcu(skb_dst_dev(skb)); ++} ++ + struct dst_entry *dst_blackhole_check(struct dst_entry *dst, u32 cookie); + void dst_blackhole_update_pmtu(struct dst_entry *dst, struct sock *sk, + struct sk_buff *skb, u32 mtu, bool confirm_neigh); +--- a/net/core/dst.c ++++ b/net/core/dst.c +@@ -153,7 +153,7 @@ void dst_dev_put(struct dst_entry *dst) + dst->ops->ifdown(dst, dev); + WRITE_ONCE(dst->input, dst_discard); + WRITE_ONCE(dst->output, dst_discard_out); +- dst->dev = blackhole_netdev; ++ WRITE_ONCE(dst->dev, blackhole_netdev); + netdev_ref_replace(dev, blackhole_netdev, &dst->dev_tracker, + GFP_ATOMIC); + } +@@ -266,7 +266,7 @@ unsigned int dst_blackhole_mtu(const str + { + unsigned int mtu = dst_metric_raw(dst, RTAX_MTU); + +- return mtu ? : dst->dev->mtu; ++ return mtu ? : dst_dev(dst)->mtu; + } + EXPORT_SYMBOL_GPL(dst_blackhole_mtu); + +--- a/net/core/sock.c ++++ b/net/core/sock.c +@@ -2450,8 +2450,8 @@ static u32 sk_dst_gso_max_size(struct so + !ipv6_addr_v4mapped(&sk->sk_v6_rcv_saddr)); + #endif + /* pairs with the WRITE_ONCE() in netif_set_gso(_ipv4)_max_size() */ +- max_size = is_ipv6 ? READ_ONCE(dst->dev->gso_max_size) : +- READ_ONCE(dst->dev->gso_ipv4_max_size); ++ max_size = is_ipv6 ? READ_ONCE(dst_dev(dst)->gso_max_size) : ++ READ_ONCE(dst_dev(dst)->gso_ipv4_max_size); + if (max_size > GSO_LEGACY_MAX_SIZE && !sk_is_tcp(sk)) + max_size = GSO_LEGACY_MAX_SIZE; + +@@ -2462,7 +2462,7 @@ void sk_setup_caps(struct sock *sk, stru + { + u32 max_segs = 1; + +- sk->sk_route_caps = dst->dev->features; ++ sk->sk_route_caps = dst_dev(dst)->features; + if (sk_is_tcp(sk)) + sk->sk_route_caps |= NETIF_F_GSO; + if (sk->sk_route_caps & NETIF_F_GSO) +@@ -2476,7 +2476,7 @@ void sk_setup_caps(struct sock *sk, stru + sk->sk_route_caps |= NETIF_F_SG | NETIF_F_HW_CSUM; + sk->sk_gso_max_size = sk_dst_gso_max_size(sk, dst); + /* pairs with the WRITE_ONCE() in netif_set_gso_max_segs() */ +- max_segs = max_t(u32, READ_ONCE(dst->dev->gso_max_segs), 1); ++ max_segs = max_t(u32, READ_ONCE(dst_dev(dst)->gso_max_segs), 1); + } + } + sk->sk_gso_max_segs = max_segs; diff --git a/queue-6.6/net-dst-introduce-dst-dev_rcu.patch b/queue-6.6/net-dst-introduce-dst-dev_rcu.patch new file mode 100644 index 0000000000..2fb9faf67e --- /dev/null +++ b/queue-6.6/net-dst-introduce-dst-dev_rcu.patch @@ -0,0 +1,106 @@ +From ruohanlan@aliyun.com Mon Mar 2 08:37:19 2026 +From: Ruohan Lan +Date: Mon, 2 Mar 2026 15:36:29 +0800 +Subject: net: dst: introduce dst->dev_rcu +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: edumazet@google.com, kuniyu@google.com, kuba@kernel.org, dsahern@kernel.org, netdev@vger.kernel.org, Ruohan Lan +Message-ID: <20260302073630.988982-3-ruohanlan@aliyun.com> + +From: Eric Dumazet + +[ Upstream commit caedcc5b6df1b2e2b5f39079e3369c1d4d5c5f50 ] + +Followup of commit 88fe14253e18 ("net: dst: add four helpers +to annotate data-races around dst->dev"). + +We want to gradually add explicit RCU protection to dst->dev, +including lockdep support. + +Add an union to alias dst->dev_rcu and dst->dev. + +Add dst_dev_net_rcu() helper. + +Fixes: 4a6ce2b6f2ec ("net: introduce a new function dst_dev_put()") +Signed-off-by: Eric Dumazet +Reviewed-by: David Ahern +Link: https://patch.msgid.link/20250828195823.3958522-2-edumazet@google.com +Signed-off-by: Jakub Kicinski +[ Minor context conflict resolved. ] +Signed-off-by: Ruohan Lan +Signed-off-by: Greg Kroah-Hartman +--- + include/net/dst.h | 16 +++++++++++----- + net/core/dst.c | 2 +- + net/ipv4/route.c | 4 ++-- + 3 files changed, 14 insertions(+), 8 deletions(-) + +--- a/include/net/dst.h ++++ b/include/net/dst.h +@@ -24,7 +24,10 @@ + struct sk_buff; + + struct dst_entry { +- struct net_device *dev; ++ union { ++ struct net_device *dev; ++ struct net_device __rcu *dev_rcu; ++ }; + struct dst_ops *ops; + unsigned long _metrics; + unsigned long expires; +@@ -571,9 +574,12 @@ static inline void skb_dst_update_pmtu_n + + static inline struct net_device *dst_dev_rcu(const struct dst_entry *dst) + { +- /* In the future, use rcu_dereference(dst->dev) */ +- WARN_ON_ONCE(!rcu_read_lock_held()); +- return READ_ONCE(dst->dev); ++ return rcu_dereference(dst->dev_rcu); ++} ++ ++static inline struct net *dst_dev_net_rcu(const struct dst_entry *dst) ++{ ++ return dev_net_rcu(dst_dev_rcu(dst)); + } + + static inline struct net_device *skb_dst_dev_rcu(const struct sk_buff *skb) +@@ -598,7 +604,7 @@ static inline struct net *skb_dst_dev_ne + + static inline struct net *skb_dst_dev_net_rcu(const struct sk_buff *skb) + { +- return dev_net_rcu(skb_dst_dev(skb)); ++ return dev_net_rcu(skb_dst_dev_rcu(skb)); + } + + struct dst_entry *dst_blackhole_check(struct dst_entry *dst, u32 cookie); +--- a/net/core/dst.c ++++ b/net/core/dst.c +@@ -153,7 +153,7 @@ void dst_dev_put(struct dst_entry *dst) + dst->ops->ifdown(dst, dev); + WRITE_ONCE(dst->input, dst_discard); + WRITE_ONCE(dst->output, dst_discard_out); +- WRITE_ONCE(dst->dev, blackhole_netdev); ++ rcu_assign_pointer(dst->dev_rcu, blackhole_netdev); + netdev_ref_replace(dev, blackhole_netdev, &dst->dev_tracker, + GFP_ATOMIC); + } +--- a/net/ipv4/route.c ++++ b/net/ipv4/route.c +@@ -1042,7 +1042,7 @@ static void __ip_rt_update_pmtu(struct r + return; + + rcu_read_lock(); +- net = dev_net_rcu(dst->dev); ++ net = dst_dev_net_rcu(dst); + if (mtu < net->ipv4.ip_rt_min_pmtu) { + lock = true; + mtu = min(old_mtu, net->ipv4.ip_rt_min_pmtu); +@@ -1340,7 +1340,7 @@ static unsigned int ipv4_default_advmss( + struct net *net; + + rcu_read_lock(); +- net = dev_net_rcu(dst->dev); ++ net = dst_dev_net_rcu(dst); + advmss = max_t(unsigned int, ipv4_mtu(dst) - header_size, + net->ipv4.ip_rt_min_advmss); + rcu_read_unlock(); diff --git a/queue-6.6/net-stmmac-remove-support-for-lpi_intr_o.patch b/queue-6.6/net-stmmac-remove-support-for-lpi_intr_o.patch new file mode 100644 index 0000000000..f08ec31172 --- /dev/null +++ b/queue-6.6/net-stmmac-remove-support-for-lpi_intr_o.patch @@ -0,0 +1,214 @@ +From stable+bounces-223355-greg=kroah.com@vger.kernel.org Fri Mar 6 16:12:28 2026 +From: Ovidiu Panait +Date: Fri, 6 Mar 2026 15:06:56 +0000 +Subject: net: stmmac: remove support for lpi_intr_o +To: stable@vger.kernel.org +Cc: "Russell King (Oracle)" , Ovidiu Panait , Jakub Kicinski +Message-ID: <20260306150656.23781-2-ovidiu.panait.rb@renesas.com> + +From: "Russell King (Oracle)" + +commit 14eb64db8ff07b58a35b98375f446d9e20765674 upstream. + +The dwmac databook for v3.74a states that lpi_intr_o is a sideband +signal which should be used to ungate the application clock, and this +signal is synchronous to the receive clock. The receive clock can run +at 2.5, 25 or 125MHz depending on the media speed, and can stop under +the control of the link partner. This means that the time it takes to +clear is dependent on the negotiated media speed, and thus can be 8, +40, or 400ns after reading the LPI control and status register. + +It has been observed with some aggressive link partners, this clock +can stop while lpi_intr_o is still asserted, meaning that the signal +remains asserted for an indefinite period that the local system has +no direct control over. + +The LPI interrupts will still be signalled through the main interrupt +path in any case, and this path is not dependent on the receive clock. + +This, since we do not gate the application clock, and the chances of +adding clock gating in the future are slim due to the clocks being +ill-defined, lpi_intr_o serves no useful purpose. Remove the code which +requests the interrupt, and all associated code. + +Reported-by: Ovidiu Panait +Tested-by: Ovidiu Panait # Renesas RZ/V2H board +Signed-off-by: Russell King (Oracle) +Link: https://patch.msgid.link/E1vnJbt-00000007YYN-28nm@rmk-PC.armlinux.org.uk +Signed-off-by: Jakub Kicinski +Signed-off-by: Ovidiu Panait +Signed-off-by: Greg Kroah-Hartman +--- + drivers/net/ethernet/stmicro/stmmac/common.h | 1 + drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c | 4 -- + drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c | 7 --- + drivers/net/ethernet/stmicro/stmmac/stmmac.h | 2 - + drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 36 ------------------ + drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c | 8 ---- + include/linux/stmmac.h | 1 + 7 files changed, 59 deletions(-) + +--- a/drivers/net/ethernet/stmicro/stmmac/common.h ++++ b/drivers/net/ethernet/stmicro/stmmac/common.h +@@ -371,7 +371,6 @@ enum request_irq_err { + REQ_IRQ_ERR_RX, + REQ_IRQ_ERR_SFTY_UE, + REQ_IRQ_ERR_SFTY_CE, +- REQ_IRQ_ERR_LPI, + REQ_IRQ_ERR_WOL, + REQ_IRQ_ERR_MAC, + REQ_IRQ_ERR_NO, +--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c ++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-intel.c +@@ -612,7 +612,6 @@ static int intel_mgbe_common_data(struct + + /* Setup MSI vector offset specific to Intel mGbE controller */ + plat->msi_mac_vec = 29; +- plat->msi_lpi_vec = 28; + plat->msi_sfty_ce_vec = 27; + plat->msi_sfty_ue_vec = 26; + plat->msi_rx_base_vec = 0; +@@ -998,8 +997,6 @@ static int stmmac_config_multi_msi(struc + res->irq = pci_irq_vector(pdev, plat->msi_mac_vec); + if (plat->msi_wol_vec < STMMAC_MSI_VEC_MAX) + res->wol_irq = pci_irq_vector(pdev, plat->msi_wol_vec); +- if (plat->msi_lpi_vec < STMMAC_MSI_VEC_MAX) +- res->lpi_irq = pci_irq_vector(pdev, plat->msi_lpi_vec); + if (plat->msi_sfty_ce_vec < STMMAC_MSI_VEC_MAX) + res->sfty_ce_irq = pci_irq_vector(pdev, plat->msi_sfty_ce_vec); + if (plat->msi_sfty_ue_vec < STMMAC_MSI_VEC_MAX) +@@ -1081,7 +1078,6 @@ static int intel_eth_pci_probe(struct pc + */ + plat->msi_mac_vec = STMMAC_MSI_VEC_MAX; + plat->msi_wol_vec = STMMAC_MSI_VEC_MAX; +- plat->msi_lpi_vec = STMMAC_MSI_VEC_MAX; + plat->msi_sfty_ce_vec = STMMAC_MSI_VEC_MAX; + plat->msi_sfty_ue_vec = STMMAC_MSI_VEC_MAX; + plat->msi_rx_base_vec = STMMAC_MSI_VEC_MAX; +--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c ++++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-loongson.c +@@ -138,13 +138,6 @@ static int loongson_dwmac_probe(struct p + res.wol_irq = res.irq; + } + +- res.lpi_irq = of_irq_get_byname(np, "eth_lpi"); +- if (res.lpi_irq < 0) { +- dev_err(&pdev->dev, "IRQ eth_lpi not found\n"); +- ret = -ENODEV; +- goto err_disable_msi; +- } +- + ret = stmmac_dvr_probe(&pdev->dev, plat, &res); + if (ret) + goto err_disable_msi; +--- a/drivers/net/ethernet/stmicro/stmmac/stmmac.h ++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac.h +@@ -29,7 +29,6 @@ struct stmmac_resources { + void __iomem *addr; + u8 mac[ETH_ALEN]; + int wol_irq; +- int lpi_irq; + int irq; + int sfty_ce_irq; + int sfty_ue_irq; +@@ -260,7 +259,6 @@ struct stmmac_priv { + bool wol_irq_disabled; + int clk_csr; + struct timer_list eee_ctrl_timer; +- int lpi_irq; + int eee_enabled; + int eee_active; + int tx_lpi_timer; +--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c ++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +@@ -3496,10 +3496,6 @@ static void stmmac_free_irq(struct net_d + free_irq(priv->sfty_ce_irq, dev); + fallthrough; + case REQ_IRQ_ERR_SFTY_CE: +- if (priv->lpi_irq > 0 && priv->lpi_irq != dev->irq) +- free_irq(priv->lpi_irq, dev); +- fallthrough; +- case REQ_IRQ_ERR_LPI: + if (priv->wol_irq > 0 && priv->wol_irq != dev->irq) + free_irq(priv->wol_irq, dev); + fallthrough; +@@ -3554,24 +3550,6 @@ static int stmmac_request_irq_multi_msi( + } + } + +- /* Request the LPI IRQ in case of another line +- * is used for LPI +- */ +- if (priv->lpi_irq > 0 && priv->lpi_irq != dev->irq) { +- int_name = priv->int_name_lpi; +- sprintf(int_name, "%s:%s", dev->name, "lpi"); +- ret = request_irq(priv->lpi_irq, +- stmmac_mac_interrupt, +- 0, int_name, dev); +- if (unlikely(ret < 0)) { +- netdev_err(priv->dev, +- "%s: alloc lpi MSI %d (error: %d)\n", +- __func__, priv->lpi_irq, ret); +- irq_err = REQ_IRQ_ERR_LPI; +- goto irq_error; +- } +- } +- + /* Request the Safety Feature Correctible Error line in + * case of another line is used + */ +@@ -3695,19 +3673,6 @@ static int stmmac_request_irq_single(str + } + } + +- /* Request the IRQ lines */ +- if (priv->lpi_irq > 0 && priv->lpi_irq != dev->irq) { +- ret = request_irq(priv->lpi_irq, stmmac_interrupt, +- IRQF_SHARED, dev->name, dev); +- if (unlikely(ret < 0)) { +- netdev_err(priv->dev, +- "%s: ERROR: allocating the LPI IRQ %d (%d)\n", +- __func__, priv->lpi_irq, ret); +- irq_err = REQ_IRQ_ERR_LPI; +- goto irq_error; +- } +- } +- + return 0; + + irq_error: +@@ -7436,7 +7401,6 @@ int stmmac_dvr_probe(struct device *devi + + priv->dev->irq = res->irq; + priv->wol_irq = res->wol_irq; +- priv->lpi_irq = res->lpi_irq; + priv->sfty_ce_irq = res->sfty_ce_irq; + priv->sfty_ue_irq = res->sfty_ue_irq; + for (i = 0; i < MTL_MAX_RX_QUEUES; i++) +--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c ++++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c +@@ -762,14 +762,6 @@ int stmmac_get_platform_resources(struct + stmmac_res->wol_irq = stmmac_res->irq; + } + +- stmmac_res->lpi_irq = +- platform_get_irq_byname_optional(pdev, "eth_lpi"); +- if (stmmac_res->lpi_irq < 0) { +- if (stmmac_res->lpi_irq == -EPROBE_DEFER) +- return -EPROBE_DEFER; +- dev_info(&pdev->dev, "IRQ eth_lpi not found\n"); +- } +- + stmmac_res->addr = devm_platform_ioremap_resource(pdev, 0); + + return PTR_ERR_OR_ZERO(stmmac_res->addr); +--- a/include/linux/stmmac.h ++++ b/include/linux/stmmac.h +@@ -306,7 +306,6 @@ struct plat_stmmacenet_data { + int ext_snapshot_num; + int msi_mac_vec; + int msi_wol_vec; +- int msi_lpi_vec; + int msi_sfty_ce_vec; + int msi_sfty_ue_vec; + int msi_rx_base_vec; diff --git a/queue-6.6/net-use-dst_dev_rcu-in-sk_setup_caps.patch b/queue-6.6/net-use-dst_dev_rcu-in-sk_setup_caps.patch new file mode 100644 index 0000000000..f8dccf1654 --- /dev/null +++ b/queue-6.6/net-use-dst_dev_rcu-in-sk_setup_caps.patch @@ -0,0 +1,135 @@ +From ruohanlan@aliyun.com Mon Mar 2 08:37:21 2026 +From: Ruohan Lan +Date: Mon, 2 Mar 2026 15:36:30 +0800 +Subject: net: use dst_dev_rcu() in sk_setup_caps() +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: edumazet@google.com, kuniyu@google.com, kuba@kernel.org, dsahern@kernel.org, netdev@vger.kernel.org, Ruohan Lan +Message-ID: <20260302073630.988982-4-ruohanlan@aliyun.com> + +From: Eric Dumazet + +[ Upstream commit 99a2ace61b211b0be861b07fbaa062fca4b58879 ] + +Use RCU to protect accesses to dst->dev from sk_setup_caps() +and sk_dst_gso_max_size(). + +Also use dst_dev_rcu() in ip6_dst_mtu_maybe_forward(), +and ip_dst_mtu_maybe_forward(). + +ip4_dst_hoplimit() can use dst_dev_net_rcu(). + +Fixes: 4a6ce2b6f2ec ("net: introduce a new function dst_dev_put()") +Signed-off-by: Eric Dumazet +Reviewed-by: David Ahern +Link: https://patch.msgid.link/20250828195823.3958522-6-edumazet@google.com +Signed-off-by: Jakub Kicinski +[ Adjust context ] +Signed-off-by: Ruohan Lan +Signed-off-by: Greg Kroah-Hartman +--- + include/net/ip.h | 7 +++++-- + include/net/ip6_route.h | 2 +- + include/net/route.h | 2 +- + net/core/sock.c | 16 ++++++++++------ + 4 files changed, 17 insertions(+), 10 deletions(-) + +--- a/include/net/ip.h ++++ b/include/net/ip.h +@@ -458,9 +458,12 @@ static inline unsigned int ip_dst_mtu_ma + bool forwarding) + { + const struct rtable *rt = container_of(dst, struct rtable, dst); +- struct net *net = dev_net(dst->dev); ++ struct net *net; ++ const struct net_device *dev; + unsigned int mtu; + ++ dev = dst_dev_rcu(dst); ++ net = dev_net_rcu(dev); + if (READ_ONCE(net->ipv4.sysctl_ip_fwd_use_pmtu) || + ip_mtu_locked(dst) || + !forwarding) { +@@ -474,7 +477,7 @@ static inline unsigned int ip_dst_mtu_ma + if (mtu) + goto out; + +- mtu = READ_ONCE(dst->dev->mtu); ++ mtu = READ_ONCE(dev->mtu); + + if (unlikely(ip_mtu_locked(dst))) { + if (rt->rt_uses_gateway && mtu > 576) +--- a/include/net/ip6_route.h ++++ b/include/net/ip6_route.h +@@ -333,7 +333,7 @@ static inline unsigned int ip6_dst_mtu_m + + mtu = IPV6_MIN_MTU; + rcu_read_lock(); +- idev = __in6_dev_get(dst->dev); ++ idev = __in6_dev_get(dst_dev_rcu(dst)); + if (idev) + mtu = idev->cnf.mtu6; + rcu_read_unlock(); +--- a/include/net/route.h ++++ b/include/net/route.h +@@ -363,7 +363,7 @@ static inline int ip4_dst_hoplimit(const + const struct net *net; + + rcu_read_lock(); +- net = dev_net_rcu(dst->dev); ++ net = dst_dev_net_rcu(dst); + hoplimit = READ_ONCE(net->ipv4.sysctl_ip_default_ttl); + rcu_read_unlock(); + } +--- a/net/core/sock.c ++++ b/net/core/sock.c +@@ -2440,7 +2440,7 @@ void sk_free_unlock_clone(struct sock *s + } + EXPORT_SYMBOL_GPL(sk_free_unlock_clone); + +-static u32 sk_dst_gso_max_size(struct sock *sk, struct dst_entry *dst) ++static u32 sk_dst_gso_max_size(struct sock *sk, const struct net_device *dev) + { + bool is_ipv6 = false; + u32 max_size; +@@ -2450,8 +2450,8 @@ static u32 sk_dst_gso_max_size(struct so + !ipv6_addr_v4mapped(&sk->sk_v6_rcv_saddr)); + #endif + /* pairs with the WRITE_ONCE() in netif_set_gso(_ipv4)_max_size() */ +- max_size = is_ipv6 ? READ_ONCE(dst_dev(dst)->gso_max_size) : +- READ_ONCE(dst_dev(dst)->gso_ipv4_max_size); ++ max_size = is_ipv6 ? READ_ONCE(dev->gso_max_size) : ++ READ_ONCE(dev->gso_ipv4_max_size); + if (max_size > GSO_LEGACY_MAX_SIZE && !sk_is_tcp(sk)) + max_size = GSO_LEGACY_MAX_SIZE; + +@@ -2460,9 +2460,12 @@ static u32 sk_dst_gso_max_size(struct so + + void sk_setup_caps(struct sock *sk, struct dst_entry *dst) + { ++ const struct net_device *dev; + u32 max_segs = 1; + +- sk->sk_route_caps = dst_dev(dst)->features; ++ rcu_read_lock(); ++ dev = dst_dev_rcu(dst); ++ sk->sk_route_caps = dev->features; + if (sk_is_tcp(sk)) + sk->sk_route_caps |= NETIF_F_GSO; + if (sk->sk_route_caps & NETIF_F_GSO) +@@ -2474,13 +2477,14 @@ void sk_setup_caps(struct sock *sk, stru + sk->sk_route_caps &= ~NETIF_F_GSO_MASK; + } else { + sk->sk_route_caps |= NETIF_F_SG | NETIF_F_HW_CSUM; +- sk->sk_gso_max_size = sk_dst_gso_max_size(sk, dst); ++ sk->sk_gso_max_size = sk_dst_gso_max_size(sk, dev); + /* pairs with the WRITE_ONCE() in netif_set_gso_max_segs() */ +- max_segs = max_t(u32, READ_ONCE(dst_dev(dst)->gso_max_segs), 1); ++ max_segs = max_t(u32, READ_ONCE(dev->gso_max_segs), 1); + } + } + sk->sk_gso_max_segs = max_segs; + sk_dst_set(sk, dst); ++ rcu_read_unlock(); + } + EXPORT_SYMBOL_GPL(sk_setup_caps); + diff --git a/queue-6.6/platform-x86-amd-pmc-add-support-for-van-gogh-soc.patch b/queue-6.6/platform-x86-amd-pmc-add-support-for-van-gogh-soc.patch new file mode 100644 index 0000000000..205f4023d0 --- /dev/null +++ b/queue-6.6/platform-x86-amd-pmc-add-support-for-van-gogh-soc.patch @@ -0,0 +1,71 @@ +From stable+bounces-222799-greg=kroah.com@vger.kernel.org Tue Mar 3 07:32:46 2026 +From: Alva Lan +Date: Tue, 3 Mar 2026 14:31:51 +0800 +Subject: platform/x86/amd/pmc: Add support for Van Gogh SoC +To: gregkh@linuxfoundation.org, stable@vger.kernel.org +Cc: platform-driver-x86@vger.kernel.org, "Antheas Kapenekakis" , "Mario Limonciello" , "Shyam Sundar S K" , "Ilpo Järvinen" , "Alva Lan" +Message-ID: + +From: Antheas Kapenekakis + +[ Upstream commit db4a3f0fbedb0398f77b9047e8b8bb2b49f355bb ] + +The ROG Xbox Ally (non-X) SoC features a similar architecture to the +Steam Deck. While the Steam Deck supports S3 (s2idle causes a crash), +this support was dropped by the Xbox Ally which only S0ix suspend. + +Since the handler is missing here, this causes the device to not suspend +and the AMD GPU driver to crash while trying to resume afterwards due to +a power hang. + +Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/4659 +Signed-off-by: Antheas Kapenekakis +Reviewed-by: Mario Limonciello (AMD) +Acked-by: Shyam Sundar S K +Link: https://patch.msgid.link/20251024152152.3981721-2-lkml@antheas.dev +Reviewed-by: Ilpo Järvinen +Signed-off-by: Ilpo Järvinen +[ Adjust context ] +Signed-off-by: Alva Lan +Signed-off-by: Greg Kroah-Hartman +--- + drivers/platform/x86/amd/pmc/pmc.c | 3 +++ + drivers/platform/x86/amd/pmc/pmc.h | 1 + + 2 files changed, 4 insertions(+) + +--- a/drivers/platform/x86/amd/pmc/pmc.c ++++ b/drivers/platform/x86/amd/pmc/pmc.c +@@ -294,6 +294,7 @@ static void amd_pmc_get_ip_info(struct a + switch (dev->cpu_id) { + case AMD_CPU_ID_PCO: + case AMD_CPU_ID_RN: ++ case AMD_CPU_ID_VG: + case AMD_CPU_ID_YC: + case AMD_CPU_ID_CB: + dev->num_ips = 12; +@@ -698,6 +699,7 @@ static int amd_pmc_get_os_hint(struct am + case AMD_CPU_ID_PCO: + return MSG_OS_HINT_PCO; + case AMD_CPU_ID_RN: ++ case AMD_CPU_ID_VG: + case AMD_CPU_ID_YC: + case AMD_CPU_ID_CB: + case AMD_CPU_ID_PS: +@@ -908,6 +910,7 @@ static const struct pci_device_id pmc_pc + { PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_PCO) }, + { PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_RV) }, + { PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_SP) }, ++ { PCI_DEVICE(PCI_VENDOR_ID_AMD, AMD_CPU_ID_VG) }, + { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_1AH_M20H_ROOT) }, + { } + }; +--- a/drivers/platform/x86/amd/pmc/pmc.h ++++ b/drivers/platform/x86/amd/pmc/pmc.h +@@ -47,6 +47,7 @@ void amd_pmc_quirks_init(struct amd_pmc_ + #define AMD_CPU_ID_RN 0x1630 + #define AMD_CPU_ID_PCO AMD_CPU_ID_RV + #define AMD_CPU_ID_CZN AMD_CPU_ID_RN ++#define AMD_CPU_ID_VG 0x1645 + #define AMD_CPU_ID_YC 0x14B5 + #define AMD_CPU_ID_CB 0x14D8 + #define AMD_CPU_ID_PS 0x14E8 diff --git a/queue-6.6/rcu-nocb-fix-possible-invalid-rdp-s-nocb_cb_kthread-pointer-access.patch b/queue-6.6/rcu-nocb-fix-possible-invalid-rdp-s-nocb_cb_kthread-pointer-access.patch new file mode 100644 index 0000000000..6caf329d4b --- /dev/null +++ b/queue-6.6/rcu-nocb-fix-possible-invalid-rdp-s-nocb_cb_kthread-pointer-access.patch @@ -0,0 +1,64 @@ +From stable+bounces-222973-greg=kroah.com@vger.kernel.org Wed Mar 4 03:59:38 2026 +From: Jianqiang kang +Date: Wed, 4 Mar 2026 10:57:24 +0800 +Subject: rcu/nocb: Fix possible invalid rdp's->nocb_cb_kthread pointer access +To: gregkh@linuxfoundation.org, stable@vger.kernel.org, qiang.zhang1211@gmail.com +Cc: patches@lists.linux.dev, linux-kernel@vger.kernel.org, paulmck@kernel.org, frederic@kernel.org, quic_neeraju@quicinc.com, josh@joshtriplett.org, rostedt@goodmis.org, mathieu.desnoyers@efficios.com, jiangshanlai@gmail.com, joel@joelfernandes.org, rcu@vger.kernel.org, neeraj.upadhyay@kernel.org +Message-ID: <20260304025724.2365669-1-jianqkang@sina.cn> + +From: Zqiang + +[ Upstream commit 1bba3900ca18bdae28d1b9fa10f16a8f8cb2ada1 ] + +In the preparation stage of CPU online, if the corresponding +the rdp's->nocb_cb_kthread does not exist, will be created, +there is a situation where the rdp's rcuop kthreads creation fails, +and then de-offload this CPU's rdp, does not assign this CPU's +rdp->nocb_cb_kthread pointer, but this rdp's->nocb_gp_rdp and +rdp's->rdp_gp->nocb_gp_kthread is still valid. + +This will cause the subsequent re-offload operation of this offline +CPU, which will pass the conditional check and the kthread_unpark() +will access invalid rdp's->nocb_cb_kthread pointer. + +This commit therefore use rdp's->nocb_gp_kthread instead of +rdp_gp's->nocb_gp_kthread for safety check. + +Signed-off-by: Zqiang +Reviewed-by: Frederic Weisbecker +Signed-off-by: Neeraj Upadhyay (AMD) +[ Minor conflict resolved. ] +Signed-off-by: Jianqiang kang +Signed-off-by: Greg Kroah-Hartman +--- + kernel/rcu/tree_nocb.h | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +--- a/kernel/rcu/tree_nocb.h ++++ b/kernel/rcu/tree_nocb.h +@@ -1221,7 +1221,6 @@ static long rcu_nocb_rdp_offload(void *a + struct rcu_segcblist *cblist = &rdp->cblist; + unsigned long flags; + int wake_gp; +- struct rcu_data *rdp_gp = rdp->nocb_gp_rdp; + + WARN_ON_ONCE(rdp->cpu != raw_smp_processor_id()); + /* +@@ -1231,7 +1230,7 @@ static long rcu_nocb_rdp_offload(void *a + if (!rdp->nocb_gp_rdp) + return -EINVAL; + +- if (WARN_ON_ONCE(!rdp_gp->nocb_gp_kthread)) ++ if (WARN_ON_ONCE(!rdp->nocb_gp_kthread)) + return -EINVAL; + + pr_info("Offloading %d\n", rdp->cpu); +@@ -1260,7 +1259,7 @@ static long rcu_nocb_rdp_offload(void *a + */ + wake_gp = rdp_offload_toggle(rdp, true, flags); + if (wake_gp) +- wake_up_process(rdp_gp->nocb_gp_kthread); ++ wake_up_process(rdp->nocb_gp_kthread); + swait_event_exclusive(rdp->nocb_state_wq, + rcu_segcblist_test_flags(cblist, SEGCBLIST_KTHREAD_CB) && + rcu_segcblist_test_flags(cblist, SEGCBLIST_KTHREAD_GP)); diff --git a/queue-6.6/sched-fair-fix-pelt-clock-sync-when-entering-idle.patch b/queue-6.6/sched-fair-fix-pelt-clock-sync-when-entering-idle.patch new file mode 100644 index 0000000000..f62e58362e --- /dev/null +++ b/queue-6.6/sched-fair-fix-pelt-clock-sync-when-entering-idle.patch @@ -0,0 +1,71 @@ +From stable+bounces-223134-greg=kroah.com@vger.kernel.org Wed Mar 4 21:26:05 2026 +From: Samuel Wu +Date: Wed, 4 Mar 2026 12:25:52 -0800 +Subject: sched/fair: Fix pelt clock sync when entering idle +To: stable@vger.kernel.org +Cc: gregkh@linuxfoundation.org, sashal@kernel.org, jstultz@google.com, qyousef@google.com, vincent.guittot@linaro.com, Vincent Guittot , Samuel Wu , Alex Hoh , "Peter Zijlstra (Intel)" +Message-ID: <20260304202553.422006-1-wusamuel@google.com> + +From: Vincent Guittot + +[ Upstream commit 98c88dc8a1ace642d9021b103b28cba7b51e3abc ] + +Samuel and Alex reported regressions of the util_avg of RT rq with +commit 17e3e88ed0b6 ("sched/fair: Fix pelt lost idle time detection"). +It happens that fair is updating and syncing the pelt clock with task one +when pick_next_task_fair() fails to pick a task but before the prev +scheduling class got a chance to update its pelt signals. + +Move update_idle_rq_clock_pelt() in set_next_task_idle() which is called +after prev class has been called. + +Fixes: 17e3e88ed0b6 ("sched/fair: Fix pelt lost idle time detection") +Reported-by: Samuel Wu +Closes: https://lore.kernel.org/all/CAG2KctpO6VKS6GN4QWDji0t92_gNBJ7HjjXrE+6H+RwRXt=iLg@mail.gmail.com/ +Reported-by: Alex Hoh +Closes: https://lore.kernel.org/all/8cf19bf0e0054dcfed70e9935029201694f1bb5a.camel@mediatek.com/ +Signed-off-by: Vincent Guittot +Signed-off-by: Peter Zijlstra (Intel) +Tested-by: Samuel Wu +Tested-by: Alex Hoh +Link: https://patch.msgid.link/20260121163317.505635-1-vincent.guittot@linaro.org +(cherry picked from commit 98c88dc8a1ace642d9021b103b28cba7b51e3abc) +[ wusamuel: Did not include line 'exec_start = rq_clock_task()', which +is not present in 6.6.y but found in mainline ] +Signed-off-by: Samuel Wu +Signed-off-by: Greg Kroah-Hartman +--- + kernel/sched/fair.c | 6 ------ + kernel/sched/idle.c | 6 ++++++ + 2 files changed, 6 insertions(+), 6 deletions(-) + +--- a/kernel/sched/fair.c ++++ b/kernel/sched/fair.c +@@ -8557,12 +8557,6 @@ idle: + goto again; + } + +- /* +- * rq is about to be idle, check if we need to update the +- * lost_idle_time of clock_pelt +- */ +- update_idle_rq_clock_pelt(rq); +- + return NULL; + } + +--- a/kernel/sched/idle.c ++++ b/kernel/sched/idle.c +@@ -423,6 +423,12 @@ static void set_next_task_idle(struct rq + { + update_idle_core(rq); + schedstat_inc(rq->sched_goidle); ++ ++ /* ++ * rq is about to be idle, check if we need to update the ++ * lost_idle_time of clock_pelt ++ */ ++ update_idle_rq_clock_pelt(rq); + } + + #ifdef CONFIG_SMP diff --git a/queue-6.6/series b/queue-6.6/series index 8fc15a3346..892235626d 100644 --- a/queue-6.6/series +++ b/queue-6.6/series @@ -424,3 +424,23 @@ tracing-add-recursion-protection-in-kernel-stack-trace-recording.patch net-add-support-for-segmenting-tcp-fraglist-gso-packets.patch net-gso-fix-tcp-fraglist-segmentation-after-pull-from-frag_list.patch net-fix-segmentation-of-forwarding-fraglist-gro.patch +bpf-forget-ranges-when-refining-tnum-after-jset.patch +net-dsa-properly-keep-track-of-conduit-reference.patch +drm-amd-display-add-pixel_clock-to-amd_pp_display_configuration.patch +drm-amd-pm-use-pm_display_cfg-in-legacy-dpm-v2.patch +l2tp-do-not-use-sock_hold-in-pppol2tp_session_get_sock.patch +drm-amdgpu-add-basic-validation-for-ras-header.patch +drm-exynos-vidi-use-priv-vidi_dev-for-ctx-lookup-in-vidi_connection_ioctl.patch +drm-exynos-vidi-fix-to-avoid-directly-dereferencing-user-pointer.patch +drm-exynos-vidi-use-ctx-lock-to-protect-struct-vidi_context-member-variables-related-to-memory-alloc-free.patch +net-dst-add-four-helpers-to-annotate-data-races-around-dst-dev.patch +net-dst-introduce-dst-dev_rcu.patch +net-use-dst_dev_rcu-in-sk_setup_caps.patch +x86-uprobes-fix-xol-allocation-failure-for-32-bit-tasks.patch +platform-x86-amd-pmc-add-support-for-van-gogh-soc.patch +rcu-nocb-fix-possible-invalid-rdp-s-nocb_cb_kthread-pointer-access.patch +f2fs-zone-fix-to-avoid-inconsistence-in-between-sit-and-ssa.patch +sched-fair-fix-pelt-clock-sync-when-entering-idle.patch +binfmt_misc-restore-write-access-before-closing-files-opened-by-open_exec.patch +net-stmmac-remove-support-for-lpi_intr_o.patch +mptcp-pm-in-kernel-always-set-id-as-avail-when-rm-endp.patch diff --git a/queue-6.6/x86-uprobes-fix-xol-allocation-failure-for-32-bit-tasks.patch b/queue-6.6/x86-uprobes-fix-xol-allocation-failure-for-32-bit-tasks.patch new file mode 100644 index 0000000000..933475c29a --- /dev/null +++ b/queue-6.6/x86-uprobes-fix-xol-allocation-failure-for-32-bit-tasks.patch @@ -0,0 +1,130 @@ +From stable+bounces-222629-greg=kroah.com@vger.kernel.org Mon Mar 2 16:45:15 2026 +From: Oleg Nesterov +Date: Mon, 2 Mar 2026 16:29:27 +0100 +Subject: x86/uprobes: Fix XOL allocation failure for 32-bit tasks +To: Sasha Levin +Cc: stable@vger.kernel.org, Paulo Andrade , "Peter Zijlstra (Intel)" , linux-trace-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org +Message-ID: +Content-Disposition: inline + +From: Oleg Nesterov + +[ Upstream commit d55c571e4333fac71826e8db3b9753fadfbead6a ] + +This script + + #!/usr/bin/bash + + echo 0 > /proc/sys/kernel/randomize_va_space + + echo 'void main(void) {}' > TEST.c + + # -fcf-protection to ensure that the 1st endbr32 insn can't be emulated + gcc -m32 -fcf-protection=branch TEST.c -o test + + bpftrace -e 'uprobe:./test:main {}' -c ./test + +"hangs", the probed ./test task enters an endless loop. + +The problem is that with randomize_va_space == 0 +get_unmapped_area(TASK_SIZE - PAGE_SIZE) called by xol_add_vma() can not +just return the "addr == TASK_SIZE - PAGE_SIZE" hint, this addr is used +by the stack vma. + +arch_get_unmapped_area_topdown() doesn't take TIF_ADDR32 into account and +in_32bit_syscall() is false, this leads to info.high_limit > TASK_SIZE. +vm_unmapped_area() happily returns the high address > TASK_SIZE and then +get_unmapped_area() returns -ENOMEM after the "if (addr > TASK_SIZE - len)" +check. + +handle_swbp() doesn't report this failure (probably it should) and silently +restarts the probed insn. Endless loop. + +I think that the right fix should change the x86 get_unmapped_area() paths +to rely on TIF_ADDR32 rather than in_32bit_syscall(). Note also that if +CONFIG_X86_X32_ABI=y, in_x32_syscall() falsely returns true in this case +because ->orig_ax = -1. + +But we need a simple fix for -stable, so this patch just sets TS_COMPAT if +the probed task is 32-bit to make in_ia32_syscall() true. + +Fixes: 1b028f784e8c ("x86/mm: Introduce mmap_compat_base() for 32-bit mmap()") +Reported-by: Paulo Andrade +Signed-off-by: Oleg Nesterov +Signed-off-by: Peter Zijlstra (Intel) +Link: https://lore.kernel.org/all/aV5uldEvV7pb4RA8@redhat.com/ +Cc: stable@vger.kernel.org +Link: https://patch.msgid.link/aWO7Fdxn39piQnxu@redhat.com +Signed-off-by: Greg Kroah-Hartman +--- + arch/x86/kernel/uprobes.c | 24 ++++++++++++++++++++++++ + include/linux/uprobes.h | 1 + + kernel/events/uprobes.c | 10 +++++++--- + 3 files changed, 32 insertions(+), 3 deletions(-) + +--- a/arch/x86/kernel/uprobes.c ++++ b/arch/x86/kernel/uprobes.c +@@ -1102,3 +1102,27 @@ bool arch_uretprobe_is_alive(struct retu + else + return regs->sp <= ret->stack; + } ++ ++#ifdef CONFIG_IA32_EMULATION ++unsigned long arch_uprobe_get_xol_area(void) ++{ ++ struct thread_info *ti = current_thread_info(); ++ unsigned long vaddr; ++ ++ /* ++ * HACK: we are not in a syscall, but x86 get_unmapped_area() paths ++ * ignore TIF_ADDR32 and rely on in_32bit_syscall() to calculate ++ * vm_unmapped_area_info.high_limit. ++ * ++ * The #ifdef above doesn't cover the CONFIG_X86_X32_ABI=y case, ++ * but in this case in_32bit_syscall() -> in_x32_syscall() always ++ * (falsely) returns true because ->orig_ax == -1. ++ */ ++ if (test_thread_flag(TIF_ADDR32)) ++ ti->status |= TS_COMPAT; ++ vaddr = get_unmapped_area(NULL, TASK_SIZE - PAGE_SIZE, PAGE_SIZE, 0, 0); ++ ti->status &= ~TS_COMPAT; ++ ++ return vaddr; ++} ++#endif +--- a/include/linux/uprobes.h ++++ b/include/linux/uprobes.h +@@ -140,6 +140,7 @@ extern bool arch_uretprobe_is_alive(stru + extern bool arch_uprobe_ignore(struct arch_uprobe *aup, struct pt_regs *regs); + extern void arch_uprobe_copy_ixol(struct page *page, unsigned long vaddr, + void *src, unsigned long len); ++extern unsigned long arch_uprobe_get_xol_area(void); + #else /* !CONFIG_UPROBES */ + struct uprobes_state { + }; +--- a/kernel/events/uprobes.c ++++ b/kernel/events/uprobes.c +@@ -1449,6 +1449,12 @@ void uprobe_munmap(struct vm_area_struct + set_bit(MMF_RECALC_UPROBES, &vma->vm_mm->flags); + } + ++unsigned long __weak arch_uprobe_get_xol_area(void) ++{ ++ /* Try to map as high as possible, this is only a hint. */ ++ return get_unmapped_area(NULL, TASK_SIZE - PAGE_SIZE, PAGE_SIZE, 0, 0); ++} ++ + /* Slot allocation for XOL */ + static int xol_add_vma(struct mm_struct *mm, struct xol_area *area) + { +@@ -1464,9 +1470,7 @@ static int xol_add_vma(struct mm_struct + } + + if (!area->vaddr) { +- /* Try to map as high as possible, this is only a hint. */ +- area->vaddr = get_unmapped_area(NULL, TASK_SIZE - PAGE_SIZE, +- PAGE_SIZE, 0, 0); ++ area->vaddr = arch_uprobe_get_xol_area(); + if (IS_ERR_VALUE(area->vaddr)) { + ret = area->vaddr; + goto fail;