Skip to contentSkip to conversation

6.19.4-rc1 review

PATCH In review Greg Kroah-Hartman 12 participants 799 messages Feb 25 – Feb 28 Page 6 of 7

Subsystems (4)
lore
Share & tools
lore
author maintainer
#626 lore raw

PATCH 623/781 powercap: intel_rapl: Remove incorrect CPU check in PMU context

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Kuppuswamy Sathyanarayanan <[email protected]>

[ Upstream commit 7537bae8b6eb635583e0e6260f61d13ddbd52087 ]

The RAPL MSR read path incorrectly validates CPU context when called from the PMU subsystem:

    if (atomic) {
        if (unlikely(smp_processor_id() != cpu))
            return -EIO;
        rdmsrq(ra->reg.msr, ra->value);
    }

This check fails for package-scoped MSRs like RAPL energy counters, which are readable from any CPU within the package.

The perf tool avoids hitting this check by validating against /sys/bus/event_source/devices/power/cpumask before opening events. However, turbostat does not perform this validation and may attempt reads from non-lead CPUs, causing the check to fail and return zero power values.

Since package-scoped MSRs are architecturally accessible from any CPU in the package, remove the CPU matching check.

Also rename 'atomic' to 'pmu_ctx' to clarify this indicates PMU context where rdmsrq() can be used directly instead of rdmsrl_safe_on_cpu().

---
 drivers/powercap/intel_rapl_common.c |  6 +++---
 drivers/powercap/intel_rapl_msr.c    | 12 +++++-------
 include/linux/intel_rapl.h           |  2 +-
 3 files changed, 9 insertions(+), 11 deletions(-)
drivers/powercap/intel_rapl_common.c +3 -3
index 3ff6da3bf4e63..3705d0608a0fb 100644
@@ -254,7 +254,7 @@ static void rapl_init_domains(struct rapl_package *rp);
 static int rapl_read_data_raw(struct rapl_domain *rd,
 			      enum rapl_primitives prim,
 			      bool xlate, u64 *data,
-			      bool atomic);
+			      bool pmu_ctx);
 static int rapl_write_data_raw(struct rapl_domain *rd,
 			       enum rapl_primitives prim,
 			       unsigned long long value);
@@ -832,7 +832,7 @@ prim_fixups(struct rapl_domain *rd, enum rapl_primitives prim)
  */
 static int rapl_read_data_raw(struct rapl_domain *rd,
 			      enum rapl_primitives prim, bool xlate, u64 *data,
-			      bool atomic)
+			      bool pmu_ctx)
 {
 	u64 value;
 	enum rapl_primitives prim_fixed = prim_fixups(rd, prim);
@@ -854,7 +854,7 @@ static int rapl_read_data_raw(struct rapl_domain *rd,
 
 	ra.mask = rpi->mask;
 
-	if (rd->rp->priv->read_raw(get_rid(rd->rp), &ra, atomic)) {
+	if (rd->rp->priv->read_raw(get_rid(rd->rp), &ra, pmu_ctx)) {
 		pr_debug("failed to read reg 0x%llx for %s:%s\n", ra.reg.val, rd->rp->name, rd->name);
 		return -EIO;
 	}
drivers/powercap/intel_rapl_msr.c +5 -7
index 9a7e150b3536b..152893dca5653 100644
@@ -110,16 +110,14 @@ static int rapl_cpu_down_prep(unsigned int cpu)
 	return 0;
 }
 
-static int rapl_msr_read_raw(int cpu, struct reg_action *ra, bool atomic)
+static int rapl_msr_read_raw(int cpu, struct reg_action *ra, bool pmu_ctx)
 {
 	/*
-	 * When called from atomic-context (eg PMU event handler)
-	 * perform MSR read directly using rdmsrq().
+	 * When called from PMU context, perform MSR read directly using
+	 * rdmsrq() without IPI overhead. Package-scoped MSRs are readable
+	 * from any CPU in the package.
 	 */
-	if (atomic) {
-		if (unlikely(smp_processor_id() != cpu))
-			return -EIO;
-
+	if (pmu_ctx) {
 		rdmsrq(ra->reg.msr, ra->value);
 		goto out;
 	}
include/linux/intel_rapl.h +1 -1
index f479ef5b3341c..fa1f328d67120 100644
@@ -152,7 +152,7 @@ struct rapl_if_priv {
 	union rapl_reg reg_unit;
 	union rapl_reg regs[RAPL_DOMAIN_MAX][RAPL_DOMAIN_REG_MAX];
 	int limits[RAPL_DOMAIN_MAX];
-	int (*read_raw)(int id, struct reg_action *ra, bool atomic);
+	int (*read_raw)(int id, struct reg_action *ra, bool pmu_ctx);
 	int (*write_raw)(int id, struct reg_action *ra);
 	void *defaults;
 	void *rpi;
Signature · 1 line
2.51.0
author maintainer
#627 lore raw

PATCH 624/781 ACPI: CPPC: Fix remaining for_each_possible_cpu() to use online CPUs

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Sean V Kelley <[email protected]>

[ Upstream commit 56eb0c0ed345da7815274aa821a8546a073d7e97 ]

per_cpu(cpc_desc_ptr, cpu) object is initialized for only the online CPUs via acpi_soft_cpu_online() --> __acpi_processor_start() --> acpi_cppc_processor_probe().

However, send_pcc_cmd() and acpi_get_psd_map() still iterate over all possible CPUs. In acpi_get_psd_map(), encountering an offline CPU returns -EFAULT, causing cppc_cpufreq initialization to fail.

This breaks systems booted with "nosmt" or "nosmt=force".

Fix by using for_each_online_cpu() in both functions.

Fixes 80b8286aeec0 ("ACPI / CPPC: support for batching CPPC requests")
---
 drivers/acpi/cppc_acpi.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/acpi/cppc_acpi.c +2 -2
index e66e20d1f31b7..b59b0100d03c5 100644
@@ -362,7 +362,7 @@ static int send_pcc_cmd(int pcc_ss_id, u16 cmd)
 end:
 	if (cmd == CMD_WRITE) {
 		if (unlikely(ret)) {
-			for_each_possible_cpu(i) {
+			for_each_online_cpu(i) {
 				struct cpc_desc *desc = per_cpu(cpc_desc_ptr, i);
 
 				if (!desc)
@@ -524,7 +524,7 @@ int acpi_get_psd_map(unsigned int cpu, struct cppc_cpudata *cpu_data)
 	else if (pdomain->coord_type == DOMAIN_COORD_TYPE_SW_ANY)
 		cpu_data->shared_type = CPUFREQ_SHARED_TYPE_ANY;
 
-	for_each_possible_cpu(i) {
+	for_each_online_cpu(i) {
 		if (i == cpu)
 			continue;
 
Signature · 1 line
2.51.0
author maintainer
#628 lore raw

PATCH 625/781 powercap: intel_rapl_tpmi: Remove FW_BUG from invalid version check

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Kuppuswamy Sathyanarayanan <[email protected]>

[ Upstream commit c7d54dafa042cf379859dba265fe5afef6fa8770 ]

On partitioned systems, multiple TPMI instances may exist per package, but RAPL registers are only valid on one instance since RAPL has package-scope control. Other instances return invalid versions during domain parsing, which is expected behavior on such systems.

Currently this generates a firmware bug warning:

intel_rapl_tpmi: [Firmware Bug]: Invalid version

Remove the FW_BUG tag, downgrade to pr_debug(), and update the message to clarify that invalid versions are expected on partitioned systems where only one instance can be valid.

---
 drivers/powercap/intel_rapl_tpmi.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/powercap/intel_rapl_tpmi.c +1 -1
index 0a0b85f4528b1..0f8abdc592bc1 100644
@@ -157,7 +157,7 @@ static int parse_one_domain(struct tpmi_rapl_package *trp, u32 offset)
 	tpmi_domain_flags = tpmi_domain_header >> 32 & 0xffff;
 
 	if (tpmi_domain_version == TPMI_VERSION_INVALID) {
-		pr_warn(FW_BUG "Invalid version\n");
+		pr_debug("Invalid version, other instances may be valid\n");
 		return -ENODEV;
 	}
 
Signature · 1 line
2.51.0
author maintainer
#629 lore raw

PATCH 626/781 kbuild: Add objtool to top-level clean target

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Josh Poimboeuf <[email protected]>

[ Upstream commit 68b4fe32d73789dea23e356f468de67c8367ef8f ]

Objtool is an integral part of the build, make sure it gets cleaned by "make clean" and "make mrproper".

Fixes 442f04c34a1a ("objtool: Add tool to perform compile-time stack metadata validation")
[nathan: use Closes: instead of Link: per checkpatch.pl]
---
 Makefile               | 11 ++++++++++-
 tools/objtool/Makefile |  2 ++
 2 files changed, 12 insertions(+), 1 deletion(-)
Makefile +10 -1
index 21df635071198..7e34042743d9e 100644
@@ -1474,6 +1474,15 @@ ifneq ($(wildcard $(resolve_btfids_O)),)
 	$(Q)$(MAKE) -sC $(srctree)/tools/bpf/resolve_btfids O=$(resolve_btfids_O) clean
 endif
 
+PHONY += objtool_clean
+
+objtool_O = $(abspath $(objtree))/tools/objtool
+
+objtool_clean:
+ifneq ($(wildcard $(objtool_O)),)
+	$(Q)$(MAKE) -sC $(abs_srctree)/tools/objtool O=$(objtool_O) srctree=$(abs_srctree) clean
+endif
+
 tools/: FORCE
 	$(Q)mkdir -p $(objtree)/tools
 	$(Q)$(MAKE) O=$(abspath $(objtree)) subdir=tools -C $(srctree)/tools/
@@ -1637,7 +1646,7 @@ vmlinuxclean:
 	$(Q)$(CONFIG_SHELL) $(srctree)/scripts/link-vmlinux.sh clean
 	$(Q)$(if $(ARCH_POSTLINK), $(MAKE) -f $(ARCH_POSTLINK) clean)
 
-clean: archclean vmlinuxclean resolve_btfids_clean
+clean: archclean vmlinuxclean resolve_btfids_clean objtool_clean
 
 # mrproper - Delete all generated files, including .config
 #
tools/objtool/Makefile +2 -0
index a40f302329291..6964175abdfdf 100644
@@ -29,6 +29,8 @@ srctree := $(patsubst %/,%,$(dir $(CURDIR)))
 srctree := $(patsubst %/,%,$(dir $(srctree)))
 endif
 
+RM ?= rm -f
+
 LIBSUBCMD_DIR = $(srctree)/tools/lib/subcmd/
 ifneq ($(OUTPUT),)
   LIBSUBCMD_OUTPUT = $(abspath $(OUTPUT))/libsubcmd
Signature · 1 line
2.51.0
#630 lore raw

Re: [PATCH 6.19 626/781] kbuild: Add objtool to top-level clean target

Quoted 7 lines · Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Josh Poimboeuf <[email protected]>

[ Upstream commit 68b4fe32d73789dea23e356f468de67c8367ef8f ]

Oh, I didn't notice earlier. This breaks external kernel modules build after make clean (which distros do).

A fix is on the way:
https://lore.kernel.org/all/20260227-avoid-objtool-binary-removal-clean-v1-1-122f3e55eae9@kernel.org/

thanks,

Signature · 2 lines
js
suse labs
author maintainer
#631 lore raw

PATCH 627/781 smb: client: fix regression with mount options parsing

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Paulo Alcantara <[email protected]>

[ Upstream commit 72f4d48034864b93700d1d23fc418d90fa28d7ae ]

After commit 1ef15fbe6771 ("cifs: client: enforce consistent handling of multichannel and max_channels"), invalid mount options started to be ignored, allowing cifs.ko to proceed with the mount instead of baling out.

The problem was related to smb3_handle_conflicting_options() being called even when an invalid parameter had been parsed, overwriting the return value of vfs_parse_fs_string() in smb3_fs_context_parse_monolithic().

Fix this by calling smb3_handle_conflicting_options() only when a valid mount option has been passed.

Reproducer:

$ mount.cifs //srv/share /mnt -o ${opts}
$ mount -o remount,foo,${opts} /mnt # must fail
Fixes 1ef15fbe6771 ("cifs: client: enforce consistent handling of multichannel and max_channels")
Cc David Howells <[email protected]>
---
 fs/smb/client/fs_context.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)
fs/smb/client/fs_context.c +1 -3
index d4291d3a9a485..2527d2d29f190 100644
@@ -826,9 +826,7 @@ static int smb3_fs_context_parse_monolithic(struct fs_context *fc,
 		if (ret < 0)
 			break;
 	}
-	ret = smb3_handle_conflicting_options(fc);
-
-	return ret;
+	return ret ?: smb3_handle_conflicting_options(fc);
 }
 
 /*
Signature · 1 line
2.51.0
author maintainer
#632 lore raw

PATCH 628/781 selftests/memfd: use IPC semaphore instead of SIGSTOP/SIGCONT

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Aristeu Rozanski <[email protected]>

[ Upstream commit b24335521de92fd2ee22460072b75367ca8860b0 ]

selftests/memfd: use IPC semaphore instead of SIGSTOP/SIGCONT

In order to synchronize new processes to test inheritance of memfd_noexec sysctl, memfd_test sets up the sysctl with a value before creating the new process. The new process then sends itself a SIGSTOP in order to wait for the parent to flip the sysctl value and send a SIGCONT signal.

This would work as intended if it wasn't the fact that the new process is being created with CLONE_NEWPID, which creates a new PID namespace and the new process has PID 1 in this namespace. There're restrictions on sending signals to PID 1 and, although it's relaxed for other than root PID namespace, it's biting us here. In this specific case the SIGSTOP sent by the new process is ignored (no error to kill() is returned) and it never stops its execution. This is usually not noticiable as the parent usually manages to set the new sysctl value before the child has a chance to run and the test succeeds. But if you run the test in a loop, it eventually reproduces:

	while [ 1 ]; do ./memfd_test >log 2>&1 || break; done; cat log

So this patch replaces the SIGSTOP/SIGCONT synchronization with IPC semaphore.

Fixes 6469b66e3f5a ("selftests: improve vm.memfd_noexec sysctl tests")
Cc Aleksa Sarai <[email protected]>
Cc Shuah Khan <[email protected]>
Cc Lorenzo Stoakes <[email protected]>
---
 tools/testing/selftests/memfd/memfd_test.c | 113 +++++++++++++++++++--
 1 file changed, 105 insertions(+), 8 deletions(-)
tools/testing/selftests/memfd/memfd_test.c +105 -8
index 5b993924cc3f5..2ca07ea7202a5 100644
@@ -18,6 +18,9 @@
 #include <sys/stat.h>
 #include <sys/syscall.h>
 #include <sys/wait.h>
+#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/sem.h>
 #include <unistd.h>
 #include <ctype.h>
 
@@ -39,6 +42,20 @@
 		    F_SEAL_EXEC)
 
 #define MFD_NOEXEC_SEAL	0x0008U
+union semun {
+	int val;
+	struct semid_ds *buf;
+	unsigned short int *array;
+	struct seminfo *__buf;
+};
+
+/*
+ * we use semaphores on nested wait tasks due the use of CLONE_NEWPID: the
+ * child will be PID 1 and can't send SIGSTOP to themselves due special
+ * treatment of the init task, so the SIGSTOP/SIGCONT synchronization
+ * approach can't be used here.
+ */
+#define SEM_KEY 0xdeadbeef
 
 /*
  * Default is not to test hugetlbfs
@@ -1333,8 +1350,22 @@ static int sysctl_nested(void *arg)
 
 static int sysctl_nested_wait(void *arg)
 {
-	/* Wait for a SIGCONT. */
-	kill(getpid(), SIGSTOP);
+	int sem = semget(SEM_KEY, 1, 0600);
+	struct sembuf sembuf;
+
+	if (sem < 0) {
+		perror("semget:");
+		abort();
+	}
+	sembuf.sem_num = 0;
+	sembuf.sem_flg = 0;
+	sembuf.sem_op = 0;
+
+	if (semop(sem, &sembuf, 1) < 0) {
+		perror("semop:");
+		abort();
+	}
+
 	return sysctl_nested(arg);
 }
 
@@ -1355,7 +1386,9 @@ static void test_sysctl_sysctl2_failset(void)
 
 static int sysctl_nested_child(void *arg)
 {
-	int pid;
+	int pid, sem;
+	union semun semun;
+	struct sembuf sembuf;
 
 	printf("%s nested sysctl 0\n", memfd_str);
 	sysctl_assert_write("0");
@@ -1389,23 +1422,53 @@ static int sysctl_nested_child(void *arg)
 			   test_sysctl_sysctl2_failset);
 	join_thread(pid);
 
+	sem = semget(SEM_KEY, 1, IPC_CREAT | 0600);
+	if (sem < 0) {
+		perror("semget:");
+		return 1;
+	}
+	semun.val = 1;
+	sembuf.sem_op = -1;
+	sembuf.sem_flg = 0;
+	sembuf.sem_num = 0;
+
 	/* Verify that the rules are actually inherited after fork. */
 	printf("%s nested sysctl 0 -> 1 after fork\n", memfd_str);
 	sysctl_assert_write("0");
 
+	if (semctl(sem, 0, SETVAL, semun) < 0) {
+		perror("semctl:");
+		return 1;
+	}
+
 	pid = spawn_thread(CLONE_NEWPID, sysctl_nested_wait,
 			   test_sysctl_sysctl1_failset);
 	sysctl_assert_write("1");
-	kill(pid, SIGCONT);
+
+	/* Allow child to continue */
+	if (semop(sem, &sembuf, 1) < 0) {
+		perror("semop:");
+		return 1;
+	}
 	join_thread(pid);
 
 	printf("%s nested sysctl 0 -> 2 after fork\n", memfd_str);
 	sysctl_assert_write("0");
 
+	if (semctl(sem, 0, SETVAL, semun) < 0) {
+		perror("semctl:");
+		return 1;
+	}
+
 	pid = spawn_thread(CLONE_NEWPID, sysctl_nested_wait,
 			   test_sysctl_sysctl2_failset);
 	sysctl_assert_write("2");
-	kill(pid, SIGCONT);
+
+	/* Allow child to continue */
+	if (semop(sem, &sembuf, 1) < 0) {
+		perror("semop:");
+		return 1;
+	}
 	join_thread(pid);
 
 	/*
@@ -1415,28 +1478,62 @@ static int sysctl_nested_child(void *arg)
 	 */
 	printf("%s nested sysctl 2 -> 1 after fork\n", memfd_str);
 	sysctl_assert_write("2");
+
+	if (semctl(sem, 0, SETVAL, semun) < 0) {
+		perror("semctl:");
+		return 1;
+	}
+
 	pid = spawn_thread(CLONE_NEWPID, sysctl_nested_wait,
 			   test_sysctl_sysctl2);
 	sysctl_assert_write("1");
-	kill(pid, SIGCONT);
+
+	/* Allow child to continue */
+	if (semop(sem, &sembuf, 1) < 0) {
+		perror("semop:");
+		return 1;
+	}
 	join_thread(pid);
 
 	printf("%s nested sysctl 2 -> 0 after fork\n", memfd_str);
 	sysctl_assert_write("2");
+
+	if (semctl(sem, 0, SETVAL, semun) < 0) {
+		perror("semctl:");
+		return 1;
+	}
+
 	pid = spawn_thread(CLONE_NEWPID, sysctl_nested_wait,
 			   test_sysctl_sysctl2);
 	sysctl_assert_write("0");
-	kill(pid, SIGCONT);
+
+	/* Allow child to continue */
+	if (semop(sem, &sembuf, 1) < 0) {
+		perror("semop:");
+		return 1;
+	}
 	join_thread(pid);
 
 	printf("%s nested sysctl 1 -> 0 after fork\n", memfd_str);
 	sysctl_assert_write("1");
+
+	if (semctl(sem, 0, SETVAL, semun) < 0) {
+		perror("semctl:");
+		return 1;
+	}
+
 	pid = spawn_thread(CLONE_NEWPID, sysctl_nested_wait,
 			   test_sysctl_sysctl1);
 	sysctl_assert_write("0");
-	kill(pid, SIGCONT);
+	/* Allow child to continue */
+	if (semop(sem, &sembuf, 1) < 0) {
+		perror("semop:");
+		return 1;
+	}
 	join_thread(pid);
 
+	semctl(sem, 0, IPC_RMID);
+
 	return 0;
 }
 
Signature · 1 line
2.51.0
author maintainer
#633 lore raw

PATCH 629/781 objpool: fix the overestimation of object pooling metadata size

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: zhouwenhao <[email protected]>

[ Upstream commit 5ed4b6b37c647d168ae31035b3f61b705997e043 ]

objpool uses struct objpool_head to store metadata information, and its cpu_slots member points to an array of pointers that store the addresses of the percpu ring arrays. However, the memory size allocated during the initialization of cpu_slots is nr_cpu_ids * sizeof(struct objpool_slot). On a 64-bit machine, the size of struct objpool_slot is 16 bytes, which is twice the size of the actual pointer required, and the extra memory is never be used, resulting in a waste of memory. Therefore, the memory size required for cpu_slots needs to be corrected.

Fixes b4edb8d2d464 ("lib: objpool added: ring-array based lockless MPMC")
Cc "Masami Hiramatsu (Google)" <[email protected]>
Cc Matt Wu <[email protected]>
Cc wuqiang.matt <[email protected]>
---
 lib/objpool.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
lib/objpool.c +1 -1
index b998b720c7329..d98fadf1de169 100644
@@ -142,7 +142,7 @@ int objpool_init(struct objpool_head *pool, int nr_objs, int object_size,
 	pool->gfp = gfp & ~__GFP_ZERO;
 	pool->context = context;
 	pool->release = release;
-	slot_size = nr_cpu_ids * sizeof(struct objpool_slot);
+	slot_size = nr_cpu_ids * sizeof(struct objpool_slot *);
 	pool->cpu_slots = kzalloc(slot_size, pool->gfp);
 	if (!pool->cpu_slots)
 		return -ENOMEM;
Signature · 1 line
2.51.0
author maintainer
#634 lore raw

PATCH 630/781 ACPI: PM: Add unused power resource quirk for THUNDEROBOT ZERO

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Zhai Can <[email protected]>

[ Upstream commit cd7ef20ba8c6e936dba133b4136537a8ada22976 ]

On the THUNDEROBOT ZERO laptop, the second NVMe slot and the discrete NVIDIA GPU are both controlled by power-resource PXP. Due to the SSDT table bug (lack of reference), PXP will be shut dow as an "unused" power resource during initialization, making the NVMe slot #2 + NVIDIA both inaccessible.

This issue was introduced by commit a1224f34d72a ("ACPI: PM: Check states of power resources during initialization"). Here are test results on the three consecutive commits:

(bad again!) a1224f34d72a ACPI: PM: Check states of power resources during initialization (good) bc2836859643 ACPI: PM: Do not turn off power resources in unknown state (bad) 519d81956ee2 Linux 5.15-rc6

On commit bc2836859643 ("ACPI: PM: Do not turn off power resources in unknown state") this was not an issue because the power resource state left UNKNOWN thus being ignored.

See also commit 9b04d99788cf ("ACPI: PM: Do not turn of unused power resources on the Toshiba Click Mini") which is another almost identical case to this one.

Fixes a1224f34d72a ("ACPI: PM: Check states of power resources during initialization")
---
 drivers/acpi/power.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)
drivers/acpi/power.c +13 -0
index 361a7721a6a87..7da5ae5594a72 100644
@@ -1113,6 +1113,19 @@ static const struct dmi_system_id dmi_leave_unused_power_resources_on[] = {
 			DMI_MATCH(DMI_PRODUCT_NAME, "SATELLITE Click Mini L9W-B"),
 		},
 	},
+	{
+		/*
+		 * THUNDEROBOT ZERO laptop: Due to its SSDT table bug, power
+		 * resource 'PXP' will be shut down on initialization, making
+		 * the NVMe #2 and the NVIDIA dGPU both unavailable (they're
+		 * both controlled by 'PXP').
+		 */
+		.matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "THUNDEROBOT"),
+			DMI_MATCH(DMI_PRODUCT_NAME, "ZERO"),
+		}
+
+	},
 	{}
 };
 
Signature · 1 line
2.51.0
author maintainer
#635 lore raw

PATCH 631/781 cpuidle: Skip governor when only one idle state is available

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Aboorva Devarajan <[email protected]>

[ Upstream commit e5c9ffc6ae1bcdb1062527d611043681ac301aca ]

On certain platforms (PowerNV systems without a power-mgt DT node), cpuidle may register only a single idle state. In cases where that single state is a polling state (state 0), the ladder governor may incorrectly treat state 1 as the first usable state and pass an out-of-bounds index. This can lead to a NULL enter callback being invoked, ultimately resulting in a system crash.

[   13.342636] cpuidle-powernv : Only Snooze is available
[   13.351854] Faulting instruction address: 0x00000000
[   13.376489] NIP [0000000000000000] 0x0
[   13.378351] LR  [c000000001e01974] cpuidle_enter_state+0x2c4/0x668

Fix this by adding a bail-out in cpuidle_select() that returns state 0 directly when state_count <= 1, bypassing the governor and keeping the tick running.

Fixes dc2251bf98c6 ("cpuidle: Eliminate the CPUIDLE_DRIVER_STATE_START symbol")
---
 drivers/cpuidle/cpuidle.c | 10 ++++++++++
 1 file changed, 10 insertions(+)
drivers/cpuidle/cpuidle.c +10 -0
index c7876e9e024f9..65fbb8e807b97 100644
@@ -359,6 +359,16 @@ noinstr int cpuidle_enter_state(struct cpuidle_device *dev,
 int cpuidle_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
 		   bool *stop_tick)
 {
+	/*
+	 * If there is only a single idle state (or none), there is nothing
+	 * meaningful for the governor to choose. Skip the governor and
+	 * always use state 0 with the tick running.
+	 */
+	if (drv->state_count <= 1) {
+		*stop_tick = false;
+		return 0;
+	}
+
 	return cpuidle_curr_governor->select(drv, dev, stop_tick);
 }
 
Signature · 1 line
2.51.0
author maintainer
#636 lore raw

PATCH 632/781 ovpn: set sk_user_data before overriding callbacks

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Ralf Lici <[email protected]>

[ Upstream commit 93686c472eb7b09a51b97a096449e7092fefcd1f ]

During initialization, we override socket callbacks and set sk_user_data to an ovpn_socket instance. Currently, these two operations are
decoupled: callbacks are overridden before sk_user_data is set. While existing callbacks perform safety checks for NULL or non-ovpn sk_user_data, this condition causes a "half-formed" state where valid packets arriving during attachment trigger error logs (e.g., "invoked on non ovpn socket").

Set sk_user_data before overriding the callbacks so that it can be accessed safely from them. Since we already check that the socket has no sk_user_data before setting it, this remains safe even if an interrupt accesses the socket after sk_user_data is set but before the callbacks are overridden.

This also requires initializing all protocol-specific fields (such as tcp_tx_work and peer links) before calling ovpn_socket_attach, ensuring the ovpn_socket is fully formed before it becomes visible to any callback.

Fixes f6226ae7a0cd ("ovpn: introduce the ovpn_socket object")
---
 drivers/net/ovpn/socket.c | 39 +++++++++++++++++++++------------------
 drivers/net/ovpn/tcp.c    |  9 +++++++--
 drivers/net/ovpn/udp.c    |  1 +
 3 files changed, 29 insertions(+), 20 deletions(-)
drivers/net/ovpn/socket.c +21 -18
index 9750871ab65ce..448cee3b3f9fa 100644
@@ -200,6 +200,22 @@ struct ovpn_socket *ovpn_socket_new(struct socket *sock, struct ovpn_peer *peer)
 	ovpn_sock->sk = sk;
 	kref_init(&ovpn_sock->refcount);
 
+	/* TCP sockets are per-peer, therefore they are linked to their unique
+	 * peer
+	 */
+	if (sk->sk_protocol == IPPROTO_TCP) {
+		INIT_WORK(&ovpn_sock->tcp_tx_work, ovpn_tcp_tx_work);
+		ovpn_sock->peer = peer;
+		ovpn_peer_hold(peer);
+	} else if (sk->sk_protocol == IPPROTO_UDP) {
+		/* in UDP we only link the ovpn instance since the socket is
+		 * shared among multiple peers
+		 */
+		ovpn_sock->ovpn = peer->ovpn;
+		netdev_hold(peer->ovpn->dev, &ovpn_sock->dev_tracker,
+			    GFP_KERNEL);
+	}
+
 	/* the newly created ovpn_socket is holding reference to sk,
 	 * therefore we increase its refcounter.
 	 *
@@ -212,29 +228,16 @@ struct ovpn_socket *ovpn_socket_new(struct socket *sock, struct ovpn_peer *peer)
 
 	ret = ovpn_socket_attach(ovpn_sock, sock, peer);
 	if (ret < 0) {
+		if (sk->sk_protocol == IPPROTO_TCP)
+			ovpn_peer_put(peer);
+		else if (sk->sk_protocol == IPPROTO_UDP)
+			netdev_put(peer->ovpn->dev, &ovpn_sock->dev_tracker);
+
 		sock_put(sk);
 		kfree(ovpn_sock);
 		ovpn_sock = ERR_PTR(ret);
-		goto sock_release;
-	}
-
-	/* TCP sockets are per-peer, therefore they are linked to their unique
-	 * peer
-	 */
-	if (sk->sk_protocol == IPPROTO_TCP) {
-		INIT_WORK(&ovpn_sock->tcp_tx_work, ovpn_tcp_tx_work);
-		ovpn_sock->peer = peer;
-		ovpn_peer_hold(peer);
-	} else if (sk->sk_protocol == IPPROTO_UDP) {
-		/* in UDP we only link the ovpn instance since the socket is
-		 * shared among multiple peers
-		 */
-		ovpn_sock->ovpn = peer->ovpn;
-		netdev_hold(peer->ovpn->dev, &ovpn_sock->dev_tracker,
-			    GFP_KERNEL);
 	}
 
-	rcu_assign_sk_user_data(sk, ovpn_sock);
 sock_release:
 	release_sock(sk);
 	return ovpn_sock;
drivers/net/ovpn/tcp.c +7 -2
index 0d7f30360d874..f0b4e07ba9245 100644
@@ -487,6 +487,7 @@ int ovpn_tcp_socket_attach(struct ovpn_socket *ovpn_sock,
 	/* make sure no pre-existing encapsulation handler exists */
 	if (ovpn_sock->sk->sk_user_data)
 		return -EBUSY;
+	rcu_assign_sk_user_data(ovpn_sock->sk, ovpn_sock);
 
 	/* only a fully connected socket is expected. Connection should be
 	 * handled in userspace
@@ -495,13 +496,14 @@ int ovpn_tcp_socket_attach(struct ovpn_socket *ovpn_sock,
 		net_err_ratelimited("%s: provided TCP socket is not in ESTABLISHED state: %d\n",
 				    netdev_name(peer->ovpn->dev),
 				    ovpn_sock->sk->sk_state);
-		return -EINVAL;
+		ret = -EINVAL;
+		goto err;
 	}
 
 	ret = strp_init(&peer->tcp.strp, ovpn_sock->sk, &cb);
 	if (ret < 0) {
 		DEBUG_NET_WARN_ON_ONCE(1);
-		return ret;
+		goto err;
 	}
 
 	INIT_WORK(&peer->tcp.defer_del_work, ovpn_tcp_peer_del_work);
@@ -536,6 +538,9 @@ int ovpn_tcp_socket_attach(struct ovpn_socket *ovpn_sock,
 	strp_check_rcv(&peer->tcp.strp);
 
 	return 0;
+err:
+	rcu_assign_sk_user_data(ovpn_sock->sk, NULL);
+	return ret;
 }
 
 static void ovpn_tcp_close(struct sock *sk, long timeout)
drivers/net/ovpn/udp.c +1 -0
index d6a0f7a0b75d7..272b535ecaad4 100644
@@ -386,6 +386,7 @@ int ovpn_udp_socket_attach(struct ovpn_socket *ovpn_sock, struct socket *sock,
 			   struct ovpn_priv *ovpn)
 {
 	struct udp_tunnel_sock_cfg cfg = {
+		.sk_user_data = ovpn_sock,
 		.encap_type = UDP_ENCAP_OVPNINUDP,
 		.encap_rcv = ovpn_udp_encap_recv,
 		.encap_destroy = ovpn_udp_encap_destroy,
Signature · 1 line
2.51.0
author maintainer
#637 lore raw

PATCH 633/781 ovpn: fix possible use-after-free in ovpn_net_xmit

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Ralf Lici <[email protected]>

[ Upstream commit a5ec7baa44ea3a1d6aa0ca31c0ad82edf9affe41 ]

When building the skb_list in ovpn_net_xmit, skb_share_check will free the original skb if it is shared. The current implementation continues to use the stale skb pointer for subsequent operations:
- peer lookup,
- skb_dst_drop (even though all segments produced by skb_gso_segment will have a dst attached),
- ovpn_peer_stats_increment_tx.

Fix this by moving the peer lookup and skb_dst_drop before segmentation so that the original skb is still valid when used. Return early if all segments fail skb_share_check and the list ends up empty. Also switch ovpn_peer_stats_increment_tx to use skb_list.next; the next patch fixes the stats logic.

Fixes 08857b5ec5d9 ("ovpn: implement basic TX path (UDP)")
---
 drivers/net/ovpn/io.c | 52 ++++++++++++++++++++++++++-----------------
 1 file changed, 31 insertions(+), 21 deletions(-)
drivers/net/ovpn/io.c +31 -21
index 3e9e7f8444b34..f70c58b10599b 100644
@@ -365,7 +365,27 @@ netdev_tx_t ovpn_net_xmit(struct sk_buff *skb, struct net_device *dev)
 	/* verify IP header size in network packet */
 	proto = ovpn_ip_check_protocol(skb);
 	if (unlikely(!proto || skb->protocol != proto))
-		goto drop;
+		goto drop_no_peer;
+
+	/* retrieve peer serving the destination IP of this packet */
+	peer = ovpn_peer_get_by_dst(ovpn, skb);
+	if (unlikely(!peer)) {
+		switch (skb->protocol) {
+		case htons(ETH_P_IP):
+			net_dbg_ratelimited("%s: no peer to send data to dst=%pI4\n",
+					    netdev_name(ovpn->dev),
+					    &ip_hdr(skb)->daddr);
+			break;
+		case htons(ETH_P_IPV6):
+			net_dbg_ratelimited("%s: no peer to send data to dst=%pI6c\n",
+					    netdev_name(ovpn->dev),
+					    &ipv6_hdr(skb)->daddr);
+			break;
+		}
+		goto drop_no_peer;
+	}
+	/* dst was needed for peer selection - it can now be dropped */
+	skb_dst_drop(skb);
 
 	if (skb_is_gso(skb)) {
 		segments = skb_gso_segment(skb, 0);
@@ -396,34 +416,24 @@ netdev_tx_t ovpn_net_xmit(struct sk_buff *skb, struct net_device *dev)
 
 		__skb_queue_tail(&skb_list, curr);
 	}
-	skb_list.prev->next = NULL;
 
-	/* retrieve peer serving the destination IP of this packet */
-	peer = ovpn_peer_get_by_dst(ovpn, skb);
-	if (unlikely(!peer)) {
-		switch (skb->protocol) {
-		case htons(ETH_P_IP):
-			net_dbg_ratelimited("%s: no peer to send data to dst=%pI4\n",
-					    netdev_name(ovpn->dev),
-					    &ip_hdr(skb)->daddr);
-			break;
-		case htons(ETH_P_IPV6):
-			net_dbg_ratelimited("%s: no peer to send data to dst=%pI6c\n",
-					    netdev_name(ovpn->dev),
-					    &ipv6_hdr(skb)->daddr);
-			break;
-		}
-		goto drop;
+	/* no segments survived: don't jump to 'drop' because we already
+	 * incremented the counter for each failure in the loop
+	 */
+	if (unlikely(skb_queue_empty(&skb_list))) {
+		ovpn_peer_put(peer);
+		return NETDEV_TX_OK;
 	}
-	/* dst was needed for peer selection - it can now be dropped */
-	skb_dst_drop(skb);
+	skb_list.prev->next = NULL;
 
-	ovpn_peer_stats_increment_tx(&peer->vpn_stats, skb->len);
+	ovpn_peer_stats_increment_tx(&peer->vpn_stats, skb_list.next->len);
 	ovpn_send(ovpn, skb_list.next, peer);
 
 	return NETDEV_TX_OK;
 
 drop:
+	ovpn_peer_put(peer);
+drop_no_peer:
 	dev_dstats_tx_dropped(ovpn->dev);
 	skb_tx_error(skb);
 	kfree_skb_list(skb);
Signature · 1 line
2.51.0
author maintainer
#638 lore raw

PATCH 634/781 ovpn: fix VPN TX bytes counting

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Ralf Lici <[email protected]>

[ Upstream commit b660b13d4c6379ca6360f24aaef8c5807fefd237 ]

In ovpn_net_xmit, after GSO segmentation and segment processing, the first segment on the list is used to increment VPN TX statistics, which fails to account for any subsequent segments in the chain.

Fix this by accumulating the length of every segment that successfully passes skb_share_check into a tx_bytes variable. This ensures the peer statistics accurately reflect the total data volume sent, regardless of whether the original packet was segmented.

Fixes 04ca14955f9a ("ovpn: store tunnel and transport statistics")
---
 drivers/net/ovpn/io.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/net/ovpn/io.c +4 -1
index f70c58b10599b..955c9a37e1f8d 100644
@@ -355,6 +355,7 @@ netdev_tx_t ovpn_net_xmit(struct sk_buff *skb, struct net_device *dev)
 	struct ovpn_priv *ovpn = netdev_priv(dev);
 	struct sk_buff *segments, *curr, *next;
 	struct sk_buff_head skb_list;
+	unsigned int tx_bytes = 0;
 	struct ovpn_peer *peer;
 	__be16 proto;
 	int ret;
@@ -414,6 +415,8 @@ netdev_tx_t ovpn_net_xmit(struct sk_buff *skb, struct net_device *dev)
 			continue;
 		}
 
+		/* only count what we actually send */
+		tx_bytes += curr->len;
 		__skb_queue_tail(&skb_list, curr);
 	}
 
@@ -426,7 +429,7 @@ netdev_tx_t ovpn_net_xmit(struct sk_buff *skb, struct net_device *dev)
 	}
 	skb_list.prev->next = NULL;
 
-	ovpn_peer_stats_increment_tx(&peer->vpn_stats, skb_list.next->len);
+	ovpn_peer_stats_increment_tx(&peer->vpn_stats, tx_bytes);
 	ovpn_send(ovpn, skb_list.next, peer);
 
 	return NETDEV_TX_OK;
Signature · 1 line
2.51.0
author maintainer
#639 lore raw

PATCH 635/781 net: mctp: ensure our nlmsg responses are initialised

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Jeremy Kerr <[email protected]>

[ Upstream commit a6a9bc544b675d8b5180f2718ec985ad267b5cbf ]

Syed Faraz Abrar (@farazsth98) from Zellic, and Pumpkin (@u1f383) from DEVCORE Research Team working with Trend Micro Zero Day Initiative report that a RTM_GETNEIGH will return uninitalised data in the pad bytes of the ndmsg data.

Ensure we're initialising the netlink data to zero, in the link, addr and neigh response messages.

Fixes 831119f88781 ("mctp: Add neighbour netlink interface")
Fixes 06d2f4c583a7 ("mctp: Add netlink route management")
Fixes 583be982d934 ("mctp: Add device handling and netlink interface")
---
 net/mctp/device.c | 1 +
 net/mctp/neigh.c  | 1 +
 net/mctp/route.c  | 1 +
 3 files changed, 3 insertions(+)
net/mctp/device.c +1 -0
index 4d404edd7446e..04c5570bacff6 100644
@@ -70,6 +70,7 @@ static int mctp_fill_addrinfo(struct sk_buff *skb,
 		return -EMSGSIZE;
 
 	hdr = nlmsg_data(nlh);
+	memset(hdr, 0, sizeof(*hdr));
 	hdr->ifa_family = AF_MCTP;
 	hdr->ifa_prefixlen = 0;
 	hdr->ifa_flags = 0;
net/mctp/neigh.c +1 -0
index 05b899f22d902..fc85f0e693014 100644
@@ -218,6 +218,7 @@ static int mctp_fill_neigh(struct sk_buff *skb, u32 portid, u32 seq, int event,
 		return -EMSGSIZE;
 
 	hdr = nlmsg_data(nlh);
+	memset(hdr, 0, sizeof(*hdr));
 	hdr->ndm_family = AF_MCTP;
 	hdr->ndm_ifindex = dev->ifindex;
 	hdr->ndm_state = 0; // TODO other state bits?
net/mctp/route.c +1 -0
index 2ac4011a953ff..ecbbe4beb2133 100644
@@ -1643,6 +1643,7 @@ static int mctp_fill_rtinfo(struct sk_buff *skb, struct mctp_route *rt,
 		return -EMSGSIZE;
 
 	hdr = nlmsg_data(nlh);
+	memset(hdr, 0, sizeof(*hdr));
 	hdr->rtm_family = AF_MCTP;
 
 	/* we use the _len fields as a number of EIDs, rather than
Signature · 1 line
2.51.0
author maintainer
#640 lore raw

PATCH 636/781 selftests: mlxsw: tc_restrictions: Fix test failure with new iproute2

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Ido Schimmel <[email protected]>

[ Upstream commit a2646773a005b59fd1dc7ff3ba15df84889ca5d2 ]

As explained in [1], iproute2 started rejecting tc-police burst sizes that result in an overflow. This can happen when the burst size is high enough and the rate is low enough.

A couple of test cases specify such configurations, resulting in iproute2 errors and test failure.

Fix by reducing the burst size so that the test will pass with both new and old iproute2 versions.

[1] https://lore.kernel.org/netdev/[email protected]/

---
 tools/testing/selftests/drivers/net/mlxsw/tc_restrictions.sh | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
tools/testing/selftests/drivers/net/mlxsw/tc_restrictions.sh +2 -2
index 0441a18f098b1..aac8ef490feb8 100755
@@ -317,7 +317,7 @@ police_limits_test()
 
 	tc filter add dev $swp1 ingress pref 1 proto ip handle 101 \
 		flower skip_sw \
-		action police rate 0.5kbit burst 1m conform-exceed drop/ok
+		action police rate 0.5kbit burst 2k conform-exceed drop/ok
 	check_fail $? "Incorrect success to add police action with too low rate"
 
 	tc filter add dev $swp1 ingress pref 1 proto ip handle 101 \
@@ -327,7 +327,7 @@ police_limits_test()
 
 	tc filter add dev $swp1 ingress pref 1 proto ip handle 101 \
 		flower skip_sw \
-		action police rate 1.5kbit burst 1m conform-exceed drop/ok
+		action police rate 1.5kbit burst 2k conform-exceed drop/ok
 	check_err $? "Failed to add police action with low rate"
 
 	tc filter del dev $swp1 ingress protocol ip pref 1 handle 101 flower
Signature · 1 line
2.51.0
author maintainer
#641 lore raw

PATCH 637/781 selftests: net: lib: Fix jq parsing error

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Yue Haibing <[email protected]>

[ Upstream commit 10ec0fc0ccc525abc807b0ca8ad5a26a0bd56361 ]

The testcase failed as below:
$./vlan_bridge_binding.sh
...
+ adf_ip_link_set_up d1
+ local name=d1
+ shift
+ ip_link_is_up d1
+ ip_link_has_flag d1 UP
+ local name=d1
+ shift
+ local flag=UP
+ shift
++ ip -j link show d1
++ jq --arg flag UP 'any(.[].flags.[]; . == $flag)'
jq: error: syntax error, unexpected '[', expecting FORMAT or QQSTRING_START
(Unix shell quoting issues?) at <top-level>, line 1:
any(.[].flags.[]; . == $flag)
jq: 1 compile error

Remove the extra dot (.) after flags array to fix this.

Fixes 4baa1d3a5080 ("selftests: net: lib: Add ip_link_has_flag()")
---
 tools/testing/selftests/net/lib.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
tools/testing/selftests/net/lib.sh +1 -1
index 0ec131b339bc4..b40694573f4c7 100644
@@ -577,7 +577,7 @@ ip_link_has_flag()
 	local flag=$1; shift
 
 	local state=$(ip -j link show "$name" |
-		      jq --arg flag "$flag" 'any(.[].flags.[]; . == $flag)')
+		      jq --arg flag "$flag" 'any(.[].flags[]; . == $flag)')
 	[[ $state == true ]]
 }
 
Signature · 1 line
2.51.0
author maintainer
#642 lore raw

PATCH 638/781 net: stmmac: fix oops when split header is enabled

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Jie Zhang <[email protected]>

[ Upstream commit babab1b42ed68877ef669a08384becf281ad2582 ]

For GMAC4, when split header is enabled, in some rare cases, the hardware does not fill buf2 of the first descriptor with payload. Thus we cannot assume buf2 is always fully filled if it is not the last descriptor. Otherwise, the length of buf2 of the second descriptor will be calculated wrong and cause an oops:

Unable to handle kernel paging request at virtual address ffff00019246bfc0
...
x2 : 0000000000000040 x1 : ffff00019246bfc0 x0 : ffff00009246c000
Call trace:
 dcache_inval_poc+0x28/0x58 (P)
 dma_direct_sync_single_for_cpu+0x38/0x6c
 __dma_sync_single_for_cpu+0x34/0x6c
 stmmac_napi_poll_rx+0x8f0/0xb60
 __napi_poll.constprop.0+0x30/0x144
 net_rx_action+0x160/0x274
 handle_softirqs+0x1b8/0x1fc

...

To fix this, the PL bit-field in RDES3 register is used for all descriptors, whether it is the last descriptor or not.

Fixes ec222003bd94 ("net: stmmac: Prepare to add Split Header support")
---
 .../net/ethernet/stmicro/stmmac/stmmac_main.c | 20 ++++++++++++++++---
 1 file changed, 17 insertions(+), 3 deletions(-)
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +17 -3
index a379221b96a34..f98fd254315f6 100644
@@ -5023,13 +5023,27 @@ static unsigned int stmmac_rx_buf2_len(struct stmmac_priv *priv,
 	if (!priv->sph_active)
 		return 0;
 
-	/* Not last descriptor */
-	if (status & rx_not_ls)
+	/* For GMAC4, when split header is enabled, in some rare cases, the
+	 * hardware does not fill buf2 of the first descriptor with payload.
+	 * Thus we cannot assume buf2 is always fully filled if it is not
+	 * the last descriptor. Otherwise, the length of buf2 of the second
+	 * descriptor will be calculated wrong and cause an oops.
+	 *
+	 * If this is the last descriptor, 'plen' is the length of the
+	 * received packet that was transferred to system memory.
+	 * Otherwise, it is the accumulated number of bytes that have been
+	 * transferred for the current packet.
+	 *
+	 * Thus 'plen - len' always gives the correct length of buf2.
+	 */
+
+	/* Not GMAC4 and not last descriptor */
+	if (priv->plat->core_type != DWMAC_CORE_GMAC4 && (status & rx_not_ls))
 		return priv->dma_conf.dma_buf_sz;
 
+	/* GMAC4 or last descriptor */
 	plen = stmmac_get_rx_frame_len(priv, p, coe);
 
-	/* Last descriptor */
 	return plen - len;
 }
 
Signature · 1 line
2.51.0
author maintainer
#643 lore raw

PATCH 639/781 net: sparx5/lan969x: fix DWRR cost max to match hardware register width

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Daniel Machon <[email protected]>

[ Upstream commit 6c28aa8dfdf24f554d4c5d4ff7d723a95360d94a ]

DWRR (Deficit Weighted Round Robin) scheduling distributes bandwidth across traffic classes based on per-queue cost values, where lower cost means higher bandwidth share.

The SPX5_DWRR_COST_MAX constant is 63 (6 bits) but the hardware register field HSCH_DWRR_ENTRY_DWRR_COST is GENMASK(24, 20), only 5 bits wide (max 31). This causes sparx5_weight_to_hw_cost() to compute cost values that silently overflow via FIELD_PREP, resulting in incorrect scheduling weights.

Set SPX5_DWRR_COST_MAX to 31 to match the hardware register width.

---
 drivers/net/ethernet/microchip/sparx5/sparx5_qos.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/ethernet/microchip/sparx5/sparx5_qos.h +1 -1
index 1231a80335d7b..04f76f1e23f60 100644
@@ -35,7 +35,7 @@
 #define SPX5_SE_BURST_UNIT 4096
 
 /* Dwrr */
-#define SPX5_DWRR_COST_MAX 63
+#define SPX5_DWRR_COST_MAX 31
 
 struct sparx5_shaper {
 	u32 mode;
Signature · 1 line
2.51.0
author maintainer
#644 lore raw

PATCH 640/781 net: mscc: ocelot: extract ocelot_xmit_timestamp() helper

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Ziyi Guo <[email protected]>

[ Upstream commit 29372f07f7969a2f0490793226ecf6c8c6bde0fa ]

Extract the PTP timestamp handling logic from ocelot_port_xmit() into a separate ocelot_xmit_timestamp() helper function. This is a pure refactor with no behavioral change.

The helper returns false if the skb was consumed (freed) due to a timestamp request failure, and true if the caller should continue with frame injection. The rew_op value is returned via pointer.

This prepares for splitting ocelot_port_xmit() into separate FDMA and register injection paths in a subsequent patch.

Stable-dep-of: 026f6513c588 ("net: mscc: ocelot: add missing lock protection in ocelot_port_xmit_inj()")

---
 drivers/net/ethernet/mscc/ocelot_net.c | 36 ++++++++++++++++----------
 1 file changed, 22 insertions(+), 14 deletions(-)
drivers/net/ethernet/mscc/ocelot_net.c +22 -14
index 469784d3a1a67..ef4a6c768de9b 100644
@@ -551,33 +551,41 @@ static int ocelot_port_stop(struct net_device *dev)
 	return 0;
 }
 
-static netdev_tx_t ocelot_port_xmit(struct sk_buff *skb, struct net_device *dev)
+static bool ocelot_xmit_timestamp(struct ocelot *ocelot, int port,
+				  struct sk_buff *skb, u32 *rew_op)
 {
-	struct ocelot_port_private *priv = netdev_priv(dev);
-	struct ocelot_port *ocelot_port = &priv->port;
-	struct ocelot *ocelot = ocelot_port->ocelot;
-	int port = priv->port.index;
-	u32 rew_op = 0;
-
-	if (!static_branch_unlikely(&ocelot_fdma_enabled) &&
-	    !ocelot_can_inject(ocelot, 0))
-		return NETDEV_TX_BUSY;
-
-	/* Check if timestamping is needed */
 	if (ocelot->ptp && (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) {
 		struct sk_buff *clone = NULL;
 
 		if (ocelot_port_txtstamp_request(ocelot, port, skb, &clone)) {
 			kfree_skb(skb);
-			return NETDEV_TX_OK;
+			return false;
 		}
 
 		if (clone)
 			OCELOT_SKB_CB(skb)->clone = clone;
 
-		rew_op = ocelot_ptp_rew_op(skb);
+		*rew_op = ocelot_ptp_rew_op(skb);
 	}
 
+	return true;
+}
+
+static netdev_tx_t ocelot_port_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct ocelot_port_private *priv = netdev_priv(dev);
+	struct ocelot_port *ocelot_port = &priv->port;
+	struct ocelot *ocelot = ocelot_port->ocelot;
+	int port = priv->port.index;
+	u32 rew_op = 0;
+
+	if (!static_branch_unlikely(&ocelot_fdma_enabled) &&
+	    !ocelot_can_inject(ocelot, 0))
+		return NETDEV_TX_BUSY;
+
+	if (!ocelot_xmit_timestamp(ocelot, port, skb, &rew_op))
+		return NETDEV_TX_OK;
+
 	if (static_branch_unlikely(&ocelot_fdma_enabled)) {
 		ocelot_fdma_inject_frame(ocelot, port, rew_op, skb, dev);
 	} else {
Signature · 1 line
2.51.0
author maintainer
#645 lore raw

PATCH 641/781 net: mscc: ocelot: split xmit into FDMA and register injection paths

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Ziyi Guo <[email protected]>

[ Upstream commit 47f79b20e7fb885aa1623b759a68e8e27401ec4d ]

Split ocelot_port_xmit() into two separate functions:
- ocelot_port_xmit_fdma(): handles the FDMA injection path
- ocelot_port_xmit_inj(): handles the register-based injection path

The top-level ocelot_port_xmit() now dispatches to the appropriate function based on the ocelot_fdma_enabled static key.

This is a pure refactor with no behavioral change. Separating the two code paths makes each one simpler and prepares for adding proper locking to the register injection path without affecting the FDMA path.

Stable-dep-of: 026f6513c588 ("net: mscc: ocelot: add missing lock protection in ocelot_port_xmit_inj()")

---
 drivers/net/ethernet/mscc/ocelot_net.c | 39 ++++++++++++++++++++------
 1 file changed, 30 insertions(+), 9 deletions(-)
drivers/net/ethernet/mscc/ocelot_net.c +30 -9
index ef4a6c768de9b..a7966c174b2e2 100644
@@ -571,7 +571,25 @@ static bool ocelot_xmit_timestamp(struct ocelot *ocelot, int port,
 	return true;
 }
 
-static netdev_tx_t ocelot_port_xmit(struct sk_buff *skb, struct net_device *dev)
+static netdev_tx_t ocelot_port_xmit_fdma(struct sk_buff *skb,
+					 struct net_device *dev)
+{
+	struct ocelot_port_private *priv = netdev_priv(dev);
+	struct ocelot_port *ocelot_port = &priv->port;
+	struct ocelot *ocelot = ocelot_port->ocelot;
+	int port = priv->port.index;
+	u32 rew_op = 0;
+
+	if (!ocelot_xmit_timestamp(ocelot, port, skb, &rew_op))
+		return NETDEV_TX_OK;
+
+	ocelot_fdma_inject_frame(ocelot, port, rew_op, skb, dev);
+
+	return NETDEV_TX_OK;
+}
+
+static netdev_tx_t ocelot_port_xmit_inj(struct sk_buff *skb,
+					struct net_device *dev)
 {
 	struct ocelot_port_private *priv = netdev_priv(dev);
 	struct ocelot_port *ocelot_port = &priv->port;
@@ -579,24 +597,27 @@ static netdev_tx_t ocelot_port_xmit(struct sk_buff *skb, struct net_device *dev)
 	int port = priv->port.index;
 	u32 rew_op = 0;
 
-	if (!static_branch_unlikely(&ocelot_fdma_enabled) &&
-	    !ocelot_can_inject(ocelot, 0))
+	if (!ocelot_can_inject(ocelot, 0))
 		return NETDEV_TX_BUSY;
 
 	if (!ocelot_xmit_timestamp(ocelot, port, skb, &rew_op))
 		return NETDEV_TX_OK;
 
-	if (static_branch_unlikely(&ocelot_fdma_enabled)) {
-		ocelot_fdma_inject_frame(ocelot, port, rew_op, skb, dev);
-	} else {
-		ocelot_port_inject_frame(ocelot, port, 0, rew_op, skb);
+	ocelot_port_inject_frame(ocelot, port, 0, rew_op, skb);
 
-		consume_skb(skb);
-	}
+	consume_skb(skb);
 
 	return NETDEV_TX_OK;
 }
 
+static netdev_tx_t ocelot_port_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	if (static_branch_unlikely(&ocelot_fdma_enabled))
+		return ocelot_port_xmit_fdma(skb, dev);
+
+	return ocelot_port_xmit_inj(skb, dev);
+}
+
 enum ocelot_action_type {
 	OCELOT_MACT_LEARN,
 	OCELOT_MACT_FORGET,
Signature · 1 line
2.51.0
author maintainer
#646 lore raw

PATCH 642/781 net: mscc: ocelot: add missing lock protection in ocelot_port_xmit_inj()

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Ziyi Guo <[email protected]>

[ Upstream commit 026f6513c5880c2c89e38ad66bbec2868f978605 ]

ocelot_port_xmit_inj() calls ocelot_can_inject() and ocelot_port_inject_frame() without holding the injection group lock. Both functions contain lockdep_assert_held() for the injection lock, and the correct caller felix_port_deferred_xmit() properly acquires the lock using ocelot_lock_inj_grp() before calling these functions.

Add ocelot_lock_inj_grp()/ocelot_unlock_inj_grp() around the register injection path to fix the missing lock protection. The FDMA path is not affected as it uses its own locking mechanism.

Fixes c5e12ac3beb0 ("net: mscc: ocelot: serialize access to the injection/extraction groups")
---
 drivers/net/ethernet/mscc/ocelot_net.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)
drivers/net/ethernet/mscc/ocelot_net.c +10 -2
index a7966c174b2e2..1b82693204640 100644
@@ -597,14 +597,22 @@ static netdev_tx_t ocelot_port_xmit_inj(struct sk_buff *skb,
 	int port = priv->port.index;
 	u32 rew_op = 0;
 
-	if (!ocelot_can_inject(ocelot, 0))
+	ocelot_lock_inj_grp(ocelot, 0);
+
+	if (!ocelot_can_inject(ocelot, 0)) {
+		ocelot_unlock_inj_grp(ocelot, 0);
 		return NETDEV_TX_BUSY;
+	}
 
-	if (!ocelot_xmit_timestamp(ocelot, port, skb, &rew_op))
+	if (!ocelot_xmit_timestamp(ocelot, port, skb, &rew_op)) {
+		ocelot_unlock_inj_grp(ocelot, 0);
 		return NETDEV_TX_OK;
+	}
 
 	ocelot_port_inject_frame(ocelot, port, 0, rew_op, skb);
 
+	ocelot_unlock_inj_grp(ocelot, 0);
+
 	consume_skb(skb);
 
 	return NETDEV_TX_OK;
Signature · 1 line
2.51.0
author maintainer
#647 lore raw

PATCH 643/781 selftests: netconsole: Increase port listening timeout

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Pin-yen Lin <[email protected]>

[ Upstream commit a68a9bd086c2822d0c629443bd16ad1317afe501 ]

wait_for_port() can wait up to 2 seconds with the sleep and the polling in wait_local_port_listen() combined. So, in netcons_basic.sh, the socat process could die before the test writes to the netconsole.

Increase the timeout to 3 seconds to make netcons_basic.sh pass consistently.

Fixes 3dc6c76391cb ("selftests: net: Add IPv6 support to netconsole basic tests")
---
 tools/testing/selftests/drivers/net/lib/sh/lib_netcons.sh | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
tools/testing/selftests/drivers/net/lib/sh/lib_netcons.sh +2 -2
index ae8abff4be409..64d3941576d5d 100644
@@ -247,8 +247,8 @@ function listen_port_and_save_to() {
 		SOCAT_MODE="UDP6-LISTEN"
 	fi
 
-	# Just wait for 2 seconds
-	timeout 2 ip netns exec "${NAMESPACE}" \
+	# Just wait for 3 seconds
+	timeout 3 ip netns exec "${NAMESPACE}" \
 		socat "${SOCAT_MODE}":"${PORT}",fork "${OUTPUT}" 2> /dev/null
 }
 
Signature · 1 line
2.51.0
author maintainer
#648 lore raw

PATCH 644/781 ipv6: Fix out-of-bound access in fib6_add_rt2node().

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Kuniyuki Iwashima <[email protected]>

[ Upstream commit 8244f959e2c125c849e569f5b23ed49804cce695 ]

syzbot reported out-of-bound read in fib6_add_rt2node(). [0]

When IPv6 route is created with RTA_NH_ID, struct fib6_info does not have the trailing struct fib6_nh.

The cited commit started to check !iter->fib6_nh->fib_nh_gw_family to ensure that rt6_qualify_for_ecmp() will return false for iter.

If iter->nh is not NULL, rt6_qualify_for_ecmp() returns false anyway.

Let's check iter->nh before reading iter->fib6_nh and avoid OOB read.

[0]:

BUG: KASAN: slab-out-of-bounds in fib6_add_rt2node+0x349c/0x3500 net/ipv6/ip6_fib.c:1142
Read of size 1 at addr ffff8880384ba6de by task syz.0.18/5500

CPU: 0 UID: 0 PID: 5500 Comm: syz.0.18 Not tainted syzkaller #0 PREEMPT(full)
Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
Call Trace:
 <TASK>
 dump_stack_lvl+0xe8/0x150 lib/dump_stack.c:120
 print_address_description mm/kasan/report.c:378 [inline]
 print_report+0xba/0x230 mm/kasan/report.c:482
 kasan_report+0x117/0x150 mm/kasan/report.c:595
 fib6_add_rt2node+0x349c/0x3500 net/ipv6/ip6_fib.c:1142
 fib6_add_rt2node_nh net/ipv6/ip6_fib.c:1363 [inline]
 fib6_add+0x910/0x18c0 net/ipv6/ip6_fib.c:1531
 __ip6_ins_rt net/ipv6/route.c:1351 [inline]
 ip6_route_add+0xde/0x1b0 net/ipv6/route.c:3957
 inet6_rtm_newroute+0x268/0x19e0 net/ipv6/route.c:5660
 rtnetlink_rcv_msg+0x7d5/0xbe0 net/core/rtnetlink.c:6958
 netlink_rcv_skb+0x232/0x4b0 net/netlink/af_netlink.c:2550
 netlink_unicast_kernel net/netlink/af_netlink.c:1318 [inline]
 netlink_unicast+0x80f/0x9b0 net/netlink/af_netlink.c:1344
 netlink_sendmsg+0x813/0xb40 net/netlink/af_netlink.c:1894
 sock_sendmsg_nosec net/socket.c:727 [inline]
 __sock_sendmsg net/socket.c:742 [inline]
 ____sys_sendmsg+0xa68/0xad0 net/socket.c:2592
 ___sys_sendmsg+0x2a5/0x360 net/socket.c:2646
 __sys_sendmsg net/socket.c:2678 [inline]
 __do_sys_sendmsg net/socket.c:2683 [inline]
 __se_sys_sendmsg net/socket.c:2681 [inline]
 __x64_sys_sendmsg+0x1bd/0x2a0 net/socket.c:2681
 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
 do_syscall_64+0xe2/0xf80 arch/x86/entry/syscall_64.c:94
 entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x7f9316b9aeb9
Code: ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 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:00007ffd8809b678 EFLAGS: 00000246 ORIG_RAX: 000000000000002e
RAX: ffffffffffffffda RBX: 00007f9316e15fa0 RCX: 00007f9316b9aeb9
RDX: 0000000000000000 RSI: 0000200000004380 RDI: 0000000000000003
RBP: 00007f9316c08c1f R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000
R13: 00007f9316e15fac R14: 00007f9316e15fa0 R15: 00007f9316e15fa0
 </TASK>

Allocated by task 5499:
 kasan_save_stack mm/kasan/common.c:57 [inline]
 kasan_save_track+0x3e/0x80 mm/kasan/common.c:78
 poison_kmalloc_redzone mm/kasan/common.c:398 [inline]
 __kasan_kmalloc+0x93/0xb0 mm/kasan/common.c:415
 kasan_kmalloc include/linux/kasan.h:263 [inline]
 __do_kmalloc_node mm/slub.c:5657 [inline]
 __kmalloc_noprof+0x40c/0x7e0 mm/slub.c:5669
 kmalloc_noprof include/linux/slab.h:961 [inline]
 kzalloc_noprof include/linux/slab.h:1094 [inline]
 fib6_info_alloc+0x30/0xf0 net/ipv6/ip6_fib.c:155
 ip6_route_info_create+0x142/0x860 net/ipv6/route.c:3820
 ip6_route_add+0x49/0x1b0 net/ipv6/route.c:3949
 inet6_rtm_newroute+0x268/0x19e0 net/ipv6/route.c:5660
 rtnetlink_rcv_msg+0x7d5/0xbe0 net/core/rtnetlink.c:6958
 netlink_rcv_skb+0x232/0x4b0 net/netlink/af_netlink.c:2550
 netlink_unicast_kernel net/netlink/af_netlink.c:1318 [inline]
 netlink_unicast+0x80f/0x9b0 net/netlink/af_netlink.c:1344
 netlink_sendmsg+0x813/0xb40 net/netlink/af_netlink.c:1894
 sock_sendmsg_nosec net/socket.c:727 [inline]
 __sock_sendmsg net/socket.c:742 [inline]
 ____sys_sendmsg+0xa68/0xad0 net/socket.c:2592
 ___sys_sendmsg+0x2a5/0x360 net/socket.c:2646
 __sys_sendmsg net/socket.c:2678 [inline]
 __do_sys_sendmsg net/socket.c:2683 [inline]
 __se_sys_sendmsg net/socket.c:2681 [inline]
 __x64_sys_sendmsg+0x1bd/0x2a0 net/socket.c:2681
 do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
 do_syscall_64+0xe2/0xf80 arch/x86/entry/syscall_64.c:94
 entry_SYSCALL_64_after_hwframe+0x77/0x7f
---
 net/ipv6/ip6_fib.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
net/ipv6/ip6_fib.c +1 -1
index c6439e30e892a..cc149227b49f4 100644
@@ -1139,7 +1139,7 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct fib6_info *rt,
 					fib6_add_gc_list(iter);
 				}
 				if (!(rt->fib6_flags & (RTF_ADDRCONF | RTF_PREFIX_RT)) &&
-				    !iter->fib6_nh->fib_nh_gw_family) {
+				    (iter->nh || !iter->fib6_nh->fib_nh_gw_family)) {
 					iter->fib6_flags &= ~RTF_ADDRCONF;
 					iter->fib6_flags &= ~RTF_PREFIX_RT;
 				}
Signature · 1 line
2.51.0
author maintainer
#649 lore raw

PATCH 645/781 net: sparx5/lan969x: fix PTP clock max_adj value

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Daniel Machon <[email protected]>

[ Upstream commit a49d2a2c37a6252c41cbdd505f9d1c58d5a3817a ]

The max_adj field in ptp_clock_info tells userspace how much the PHC clock frequency can be adjusted. ptp4l reads this and will never request a correction larger than max_adj.

On both sparx5 and lan969x the clock offset may never converge because the servo needs a frequency correction larger than the current max_adj of 200000 (200 ppm) allows. The servo rails at the max and the offset stays in the tens of microseconds.

The hardware has no inherent max adjustment limit; frequency correction is done by writing a 64-bit clock period increment to CLK_PER_CFG, and the register has plenty of range. The 200000 value was just an overly conservative software limit. The max_adj is shared between sparx5 and lan969x, and the increased value is safe for both.

Fix this by increasing max_adj to 10000000 (10000 ppm), giving the servo sufficient headroom.

---
 drivers/net/ethernet/microchip/sparx5/sparx5_ptp.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/ethernet/microchip/sparx5/sparx5_ptp.c +1 -1
index 2f168700f63c1..8b2e07821a950 100644
@@ -576,7 +576,7 @@ static int sparx5_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
 static struct ptp_clock_info sparx5_ptp_clock_info = {
 	.owner		= THIS_MODULE,
 	.name		= "sparx5 ptp",
-	.max_adj	= 200000,
+	.max_adj	= 10000000,
 	.gettime64	= sparx5_ptp_gettime64,
 	.settime64	= sparx5_ptp_settime64,
 	.adjtime	= sparx5_ptp_adjtime,
Signature · 1 line
2.51.0
author maintainer
#650 lore raw

PATCH 646/781 fbnic: close fw_log race between users and teardown

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Chengfeng Ye <[email protected]>

[ Upstream commit ee5492fd88cfc079c19fbeac78e9e53b7f6c04f3 ]

Fixes a theoretical race on fw_log between the teardown path and fw_log write functions.

fw_log is written inside fbnic_fw_log_write() and can be reached from the mailbox handler fbnic_fw_msix_intr(), but fw_log is freed before IRQ/MBX teardown during cleanup, resulting in a potential data race of dereferencing a freed/null variable.

Possible Interleaving Scenario:
CPU0: fbnic_fw_msix_intr() // Entry

          fbnic_fw_log_write()
            if (fbnic_fw_log_ready())   // true
            ... preempt ...
  CPU1: fbnic_remove() // Entry
          fbnic_fw_log_free()
            vfree(log->data_start);
            log->data_start = NULL;

CPU0: continues, walks log->entries or writes to log->data_start

The initialization also has an incorrect order problem, as the fw_log is currently allocated after MBX setup during initialization. Fix the problems by adjusting the synchronization order to put initialization in place before the mailbox is enabled, and not cleared until after the mailbox has been disabled.

Fixes ecc53b1b46c89 ("eth: fbnic: Enable firmware logging")
---
 .../net/ethernet/meta/fbnic/fbnic_fw_log.c    |  3 ---
 drivers/net/ethernet/meta/fbnic/fbnic_pci.c   | 19 ++++++++++++-------
 2 files changed, 12 insertions(+), 10 deletions(-)
drivers/net/ethernet/meta/fbnic/fbnic_fw_log.c +0 -3
index 85a883dba385f..d8a9a7d7c2375 100644
@@ -51,8 +51,6 @@ int fbnic_fw_log_init(struct fbnic_dev *fbd)
 	log->data_start = data;
 	log->data_end = data + FBNIC_FW_LOG_SIZE;
 
-	fbnic_fw_log_enable(fbd, true);
-
 	return 0;
 }
 
@@ -63,7 +61,6 @@ void fbnic_fw_log_free(struct fbnic_dev *fbd)
 	if (!fbnic_fw_log_ready(fbd))
 		return;
 
-	fbnic_fw_log_disable(fbd);
 	INIT_LIST_HEAD(&log->entries);
 	log->size = 0;
 	vfree(log->data_start);
drivers/net/ethernet/meta/fbnic/fbnic_pci.c +12 -7
index 9240673c7533d..e92187bc1c0fa 100644
@@ -307,11 +307,17 @@ static int fbnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 		goto free_irqs;
 	}
 
+	err = fbnic_fw_log_init(fbd);
+	if (err)
+		dev_warn(fbd->dev,
+			 "Unable to initialize firmware log buffer: %d\n",
+			 err);
+
 	err = fbnic_fw_request_mbx(fbd);
 	if (err) {
 		dev_err(&pdev->dev,
 			"Firmware mailbox initialization failure\n");
-		goto free_irqs;
+		goto free_fw_log;
 	}
 
 	/* Send the request to enable the FW logging to host. Note if this
@@ -319,11 +325,7 @@ static int fbnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 	 * possible the FW is just too old to support the logging and needs
 	 * to be updated.
 	 */
-	err = fbnic_fw_log_init(fbd);
-	if (err)
-		dev_warn(fbd->dev,
-			 "Unable to initialize firmware log buffer: %d\n",
-			 err);
+	fbnic_fw_log_enable(fbd, true);
 
 	fbnic_devlink_register(fbd);
 	fbnic_devlink_otp_check(fbd, "error detected during probe");
@@ -370,6 +372,8 @@ static int fbnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 	  * firmware updates for fixes.
 	  */
 	return 0;
+free_fw_log:
+	fbnic_fw_log_free(fbd);
 free_irqs:
 	fbnic_free_irqs(fbd);
 err_destroy_health:
@@ -404,8 +408,9 @@ static void fbnic_remove(struct pci_dev *pdev)
 	fbnic_hwmon_unregister(fbd);
 	fbnic_dbg_fbd_exit(fbd);
 	fbnic_devlink_unregister(fbd);
-	fbnic_fw_log_free(fbd);
+	fbnic_fw_log_disable(fbd);
 	fbnic_fw_free_mbx(fbd);
+	fbnic_fw_log_free(fbd);
 	fbnic_free_irqs(fbd);
 
 	fbnic_devlink_health_destroy(fbd);
Signature · 1 line
2.51.0
author maintainer
#651 lore raw

PATCH 647/781 libbpf: Fix invalid write loop logic in bpf_linker__add_buf()

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Amery Hung <[email protected]>

[ Upstream commit 04999b99e81eaa7b6223ec1c03af3bcb4ac57aaa ]

Fix bpf_linker__add_buf()'s logic of copying data from memory buffer into memfd. In the event of short write not writing entire buf_sz bytes into memfd file, we'll append bytes from the beginning of buf *again* (corrupting ELF file contents) instead of correctly appending the rest of not-yet-read buf contents.

---
 tools/lib/bpf/linker.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
tools/lib/bpf/linker.c +1 -1
index f4403e3cf9946..78f92c39290af 100644
@@ -581,7 +581,7 @@ int bpf_linker__add_buf(struct bpf_linker *linker, void *buf, size_t buf_sz,
 
 	written = 0;
 	while (written < buf_sz) {
-		ret = write(fd, buf, buf_sz);
+		ret = write(fd, buf + written, buf_sz - written);
 		if (ret < 0) {
 			ret = -errno;
 			pr_warn("failed to write '%s': %s\n", filename, errstr(ret));
Signature · 1 line
2.51.0
author maintainer
#652 lore raw

PATCH 648/781 bpf: Fix a potential use-after-free of BTF object

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Anton Protopopov <[email protected]>

[ Upstream commit ccd2d799ed4467c07f5ee18c2f5c59bcc990822c ]

Refcounting in the check_pseudo_btf_id() function is incorrect:
the __check_pseudo_btf_id() function might get called with a zero refcounted btf. Fix this, and patch related code accordingly.

v3: rephrase a comment (AI)
v2: fix a refcount leak introduced in v1 (AI)

---
 kernel/bpf/verifier.c | 52 +++++++++++++++++++++----------------------
 1 file changed, 26 insertions(+), 26 deletions(-)
kernel/bpf/verifier.c +26 -26
index c9e2e22da3309..a16aca34f5834 100644
@@ -20685,29 +20685,29 @@ static int find_btf_percpu_datasec(struct btf *btf)
 }
 
 /*
- * Add btf to the used_btfs array and return the index. (If the btf was
- * already added, then just return the index.) Upon successful insertion
- * increase btf refcnt, and, if present, also refcount the corresponding
- * kernel module.
+ * Add btf to the env->used_btfs array. If needed, refcount the
+ * corresponding kernel module. To simplify caller's logic
+ * in case of error or if btf was added before the function
+ * decreases the btf refcount.
  */
 static int __add_used_btf(struct bpf_verifier_env *env, struct btf *btf)
 {
 	struct btf_mod_pair *btf_mod;
+	int ret = 0;
 	int i;
 
 	/* check whether we recorded this BTF (and maybe module) already */
 	for (i = 0; i < env->used_btf_cnt; i++)
 		if (env->used_btfs[i].btf == btf)
-			return i;
+			goto ret_put;
 
 	if (env->used_btf_cnt >= MAX_USED_BTFS) {
 		verbose(env, "The total number of btfs per program has reached the limit of %u\n",
 			MAX_USED_BTFS);
-		return -E2BIG;
+		ret = -E2BIG;
+		goto ret_put;
 	}
 
-	btf_get(btf);
-
 	btf_mod = &env->used_btfs[env->used_btf_cnt];
 	btf_mod->btf = btf;
 	btf_mod->module = NULL;
@@ -20716,12 +20716,18 @@ static int __add_used_btf(struct bpf_verifier_env *env, struct btf *btf)
 	if (btf_is_module(btf)) {
 		btf_mod->module = btf_try_get_module(btf);
 		if (!btf_mod->module) {
-			btf_put(btf);
-			return -ENXIO;
+			ret = -ENXIO;
+			goto ret_put;
 		}
 	}
 
-	return env->used_btf_cnt++;
+	env->used_btf_cnt++;
+	return 0;
+
+ret_put:
+	/* Either error or this BTF was already added */
+	btf_put(btf);
+	return ret;
 }
 
 /* replace pseudo btf_id with kernel symbol address */
@@ -20818,9 +20824,7 @@ static int check_pseudo_btf_id(struct bpf_verifier_env *env,
 
 	btf_fd = insn[1].imm;
 	if (btf_fd) {
-		CLASS(fd, f)(btf_fd);
-
-		btf = __btf_get_by_fd(f);
+		btf = btf_get_by_fd(btf_fd);
 		if (IS_ERR(btf)) {
 			verbose(env, "invalid module BTF object FD specified.\n");
 			return -EINVAL;
@@ -20830,17 +20834,17 @@ static int check_pseudo_btf_id(struct bpf_verifier_env *env,
 			verbose(env, "kernel is missing BTF, make sure CONFIG_DEBUG_INFO_BTF=y is specified in Kconfig.\n");
 			return -EINVAL;
 		}
+		btf_get(btf_vmlinux);
 		btf = btf_vmlinux;
 	}
 
 	err = __check_pseudo_btf_id(env, insn, aux, btf);
-	if (err)
+	if (err) {
+		btf_put(btf);
 		return err;
+	}
 
-	err = __add_used_btf(env, btf);
-	if (err < 0)
-		return err;
-	return 0;
+	return __add_used_btf(env, btf);
 }
 
 static bool is_tracing_prog_type(enum bpf_prog_type type)
@@ -24654,13 +24658,9 @@ static int add_fd_from_fd_array(struct bpf_verifier_env *env, int fd)
 		return 0;
 	}
 
-	btf = __btf_get_by_fd(f);
-	if (!IS_ERR(btf)) {
-		err = __add_used_btf(env, btf);
-		if (err < 0)
-			return err;
-		return 0;
-	}
+	btf = btf_get_by_fd(fd);
+	if (!IS_ERR(btf))
+		return __add_used_btf(env, btf);
 
 	verbose(env, "fd %d is not pointing to valid bpf_map or btf\n", fd);
 	return PTR_ERR(map);
Signature · 1 line
2.51.0
author maintainer
#653 lore raw

PATCH 649/781 bpf: Add a map/btf from a fd array more consistently

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Anton Protopopov <[email protected]>

[ Upstream commit b0b1a8583d8e797114e613139e3e3318a1704690 ]

The add_fd_from_fd_array() function takes a file descriptor as a parameter and tries to add either map or btf to the corresponding list of used objects. As was reported by Dan Carpenter, since the commit c81e4322acf0 ("bpf: Fix a potential use-after-free of BTF object"), the fdget() is called twice on the file descriptor, and thus userspace, potentially, can replace the file pointed to by the file descriptor in between the two calls. On practice, this shouldn't break anything on the kernel side, but for consistency fix the code such that only one fdget() is executed.

---
 kernel/bpf/verifier.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)
kernel/bpf/verifier.c +4 -2
index a16aca34f5834..fe01edfcc34c6 100644
@@ -24658,9 +24658,11 @@ static int add_fd_from_fd_array(struct bpf_verifier_env *env, int fd)
 		return 0;
 	}
 
-	btf = btf_get_by_fd(fd);
-	if (!IS_ERR(btf))
+	btf = __btf_get_by_fd(f);
+	if (!IS_ERR(btf)) {
+		btf_get(btf);
 		return __add_used_btf(env, btf);
+	}
 
 	verbose(env, "fd %d is not pointing to valid bpf_map or btf\n", fd);
 	return PTR_ERR(map);
Signature · 1 line
2.51.0
author maintainer
#654 lore raw

PATCH 650/781 eth: fbnic: set FBNIC_QUEUE_RDE_CTL0_EN_HDR_SPLIT on RDE_CTL0

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Bobby Eshleman <[email protected]>

[ Upstream commit bbeb3bfbffe0279fa47c041658b037fb38a93965 ]

Fix EN_HDR_SPLIT configuration by writing the field to RDE_CTL0 instead of RDE_CTL1.

Because drop mode configuration and header splitting enablement both use RDE_CTL0, we consolidate these configurations into the single function fbnic_config_drop_mode.

Fixes 2b30fc01a6c7 ("eth: fbnic: Add support for HDS configuration")
---
 drivers/net/ethernet/meta/fbnic/fbnic_txrx.c | 25 +++++++++++---------
 1 file changed, 14 insertions(+), 11 deletions(-)
drivers/net/ethernet/meta/fbnic/fbnic_txrx.c +14 -11
index 13d508ce637f1..e119526fce14c 100644
@@ -2575,7 +2575,8 @@ static void fbnic_enable_bdq(struct fbnic_ring *hpq, struct fbnic_ring *ppq)
 }
 
 static void fbnic_config_drop_mode_rcq(struct fbnic_napi_vector *nv,
-				       struct fbnic_ring *rcq, bool tx_pause)
+				       struct fbnic_ring *rcq, bool tx_pause,
+				       bool hdr_split)
 {
 	struct fbnic_net *fbn = netdev_priv(nv->napi.dev);
 	u32 drop_mode, rcq_ctl;
@@ -2588,22 +2589,26 @@ static void fbnic_config_drop_mode_rcq(struct fbnic_napi_vector *nv,
 	/* Specify packet layout */
 	rcq_ctl = FIELD_PREP(FBNIC_QUEUE_RDE_CTL0_DROP_MODE_MASK, drop_mode) |
 	    FIELD_PREP(FBNIC_QUEUE_RDE_CTL0_MIN_HROOM_MASK, FBNIC_RX_HROOM) |
-	    FIELD_PREP(FBNIC_QUEUE_RDE_CTL0_MIN_TROOM_MASK, FBNIC_RX_TROOM);
+	    FIELD_PREP(FBNIC_QUEUE_RDE_CTL0_MIN_TROOM_MASK, FBNIC_RX_TROOM) |
+	    FIELD_PREP(FBNIC_QUEUE_RDE_CTL0_EN_HDR_SPLIT, hdr_split);
 
 	fbnic_ring_wr32(rcq, FBNIC_QUEUE_RDE_CTL0, rcq_ctl);
 }
 
-void fbnic_config_drop_mode(struct fbnic_net *fbn, bool tx_pause)
+void fbnic_config_drop_mode(struct fbnic_net *fbn, bool txp)
 {
+	bool hds;
 	int i, t;
 
+	hds = fbn->hds_thresh < FBNIC_HDR_BYTES_MIN;
+
 	for (i = 0; i < fbn->num_napi; i++) {
 		struct fbnic_napi_vector *nv = fbn->napi[i];
 
 		for (t = 0; t < nv->rxt_count; t++) {
 			struct fbnic_q_triad *qt = &nv->qt[nv->txt_count + t];
 
-			fbnic_config_drop_mode_rcq(nv, &qt->cmpl, tx_pause);
+			fbnic_config_drop_mode_rcq(nv, &qt->cmpl, txp, hds);
 		}
 	}
 }
@@ -2654,20 +2659,18 @@ static void fbnic_enable_rcq(struct fbnic_napi_vector *nv,
 {
 	struct fbnic_net *fbn = netdev_priv(nv->napi.dev);
 	u32 log_size = fls(rcq->size_mask);
-	u32 hds_thresh = fbn->hds_thresh;
 	u32 rcq_ctl = 0;
-
-	fbnic_config_drop_mode_rcq(nv, rcq, fbn->tx_pause);
+	bool hdr_split;
+	u32 hds_thresh;
 
 	/* Force lower bound on MAX_HEADER_BYTES. Below this, all frames should
 	 * be split at L4. It would also result in the frames being split at
 	 * L2/L3 depending on the frame size.
 	 */
-	if (fbn->hds_thresh < FBNIC_HDR_BYTES_MIN) {
-		rcq_ctl = FBNIC_QUEUE_RDE_CTL0_EN_HDR_SPLIT;
-		hds_thresh = FBNIC_HDR_BYTES_MIN;
-	}
+	hdr_split = fbn->hds_thresh < FBNIC_HDR_BYTES_MIN;
+	fbnic_config_drop_mode_rcq(nv, rcq, fbn->tx_pause, hdr_split);
 
+	hds_thresh = max(fbn->hds_thresh, FBNIC_HDR_BYTES_MIN);
 	rcq_ctl |= FIELD_PREP(FBNIC_QUEUE_RDE_CTL1_PADLEN_MASK, FBNIC_RX_PAD) |
 		   FIELD_PREP(FBNIC_QUEUE_RDE_CTL1_MAX_HDR_MASK, hds_thresh) |
 		   FIELD_PREP(FBNIC_QUEUE_RDE_CTL1_PAYLD_OFF_MASK,
Signature · 1 line
2.51.0
author maintainer
#655 lore raw

PATCH 651/781 eth: fbnic: increase FBNIC_HDR_BYTES_MIN from 128 to 256 bytes

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Bobby Eshleman <[email protected]>

[ Upstream commit bd254115f38db3c046332bb62e8719e0dc7c2b53 ]

Increase FBNIC_HDR_BYTES_MIN from 128 to 256 bytes. The previous minimum was too small to guarantee that very long L2+L3+L4 headers always fit within the header buffer. When EN_HDR_SPLIT is disabled and a packet exceeds MAX_HEADER_BYTES, splitting occurs at that byte offset instead of the header boundary, resulting in some of the header landing in the payload page. The increased minimum ensures headers always fit with the MAX_HEADER_BYTES cut off and land in the header page.

Fixes 2b30fc01a6c7 ("eth: fbnic: Add support for HDS configuration")
---
 drivers/net/ethernet/meta/fbnic/fbnic_txrx.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/ethernet/meta/fbnic/fbnic_txrx.h +1 -1
index 27776e844e29b..51a98f27d5d91 100644
@@ -66,7 +66,7 @@ struct fbnic_net;
 	(4096 - FBNIC_RX_HROOM - FBNIC_RX_TROOM - FBNIC_RX_PAD)
 #define FBNIC_HDS_THRESH_DEFAULT \
 	(1536 - FBNIC_RX_PAD)
-#define FBNIC_HDR_BYTES_MIN		128
+#define FBNIC_HDR_BYTES_MIN		256
 
 struct fbnic_pkt_buff {
 	struct xdp_buff buff;
Signature · 1 line
2.51.0
author maintainer
#656 lore raw

PATCH 652/781 eth: fbnic: set DMA_HINT_L4 for all flows

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Bobby Eshleman <[email protected]>

[ Upstream commit 0f30a31b55c4179fc55613a75ef41d496687d465 ]

fbnic always advertises ETHTOOL_TCP_DATA_SPLIT_ENABLED via ethtool .get_ringparam. To enable proper splitting for all flow types, even for IP/Ethernet flows, this patch sets DMA_HINT_L4 unconditionally for all RSS and NFC flow steering rules. According to the spec, L4 falls back to L3 if no valid L4 is found, and L3 falls back to L2 if no L3 is found. This makes sure that the correct header boundary is used regardless of traffic type. This is important for zero-copy use cases where we must ensure that all ZC packets are split correctly.

Fixes 2b30fc01a6c7 ("eth: fbnic: Add support for HDS configuration")
---
 drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c | 3 +++
 drivers/net/ethernet/meta/fbnic/fbnic_rpc.c     | 5 ++---
 2 files changed, 5 insertions(+), 3 deletions(-)
drivers/net/ethernet/meta/fbnic/fbnic_ethtool.c +3 -0
index 693ebdf387055..5edc28ba29553 100644
@@ -1142,6 +1142,9 @@ static int fbnic_set_cls_rule_ins(struct fbnic_net *fbn,
 		return -EINVAL;
 	}
 
+	dest |= FIELD_PREP(FBNIC_RPC_ACT_TBL0_DMA_HINT,
+			   FBNIC_RCD_HDR_AL_DMA_HINT_L4);
+
 	/* Write action table values */
 	act_tcam->dest = dest;
 	act_tcam->rss_en_mask = fbnic_flow_hash_2_rss_en_mask(fbn, hash_idx);
drivers/net/ethernet/meta/fbnic/fbnic_rpc.c +2 -3
index 7f31e890031c0..42a186db43ea9 100644
@@ -338,9 +338,8 @@ void fbnic_rss_reinit(struct fbnic_dev *fbd, struct fbnic_net *fbn)
 		else if (tstamp_mask & (1u << flow_type))
 			dest |= FBNIC_RPC_ACT_TBL0_TS_ENA;
 
-		if (act1_value[flow_type] & FBNIC_RPC_TCAM_ACT1_L4_VALID)
-			dest |= FIELD_PREP(FBNIC_RPC_ACT_TBL0_DMA_HINT,
-					   FBNIC_RCD_HDR_AL_DMA_HINT_L4);
+		dest |= FIELD_PREP(FBNIC_RPC_ACT_TBL0_DMA_HINT,
+				   FBNIC_RCD_HDR_AL_DMA_HINT_L4);
 
 		rss_en_mask = fbnic_flow_hash_2_rss_en_mask(fbn, flow_type);
 
Signature · 1 line
2.51.0
author maintainer
#657 lore raw

PATCH 653/781 ovpn: tcp - dont deref NULL sk_socket member after tcp_close()

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Antonio Quartulli <[email protected]>

[ Upstream commit 94560267d6c41b1ff3fafbab726e3f8a55a6af34 ]

When deleting a peer in case of keepalive expiration, the peer is removed from the OpenVPN hashtable and is temporary inserted in a "release list" for further processing.

This happens in:
ovpn_peer_keepalive_work()
unlock_ovpn(release_list)

This processing includes detaching from the socket being used to talk to this peer, by restoring its original proto and socket ops/callbacks.

In case of TCP it may happen that, while the peer is sitting in the release list, userspace decides to close the socket. This will result in a concurrent execution of:

tcp_close(sk)
__tcp_close(sk)
sock_orphan(sk)
sk_set_socket(sk, NULL)

The last function call will set sk->sk_socket to NULL.

When the releasing routine is resumed, ovpn_tcp_socket_detach() will attempt to dereference sk->sk_socket to restore its original ops member. This operation will crash due to sk->sk_socket being NULL.

Fix this race condition by testing-and-accessing sk->sk_socket atomically under sk->sk_callback_lock.

---
 drivers/net/ovpn/tcp.c | 14 +++++++++++++-
 1 file changed, 13 insertions(+), 1 deletion(-)
drivers/net/ovpn/tcp.c +13 -1
index f0b4e07ba9245..ec2bbc28c1966 100644
@@ -199,7 +199,19 @@ void ovpn_tcp_socket_detach(struct ovpn_socket *ovpn_sock)
 	sk->sk_data_ready = peer->tcp.sk_cb.sk_data_ready;
 	sk->sk_write_space = peer->tcp.sk_cb.sk_write_space;
 	sk->sk_prot = peer->tcp.sk_cb.prot;
-	sk->sk_socket->ops = peer->tcp.sk_cb.ops;
+
+	/* tcp_close() may race this function and could set
+	 * sk->sk_socket to NULL. It does so by invoking
+	 * sock_orphan(), which holds sk_callback_lock before
+	 * doing the assignment.
+	 *
+	 * For this reason we acquire the same lock to avoid
+	 * sk_socket to disappear under our feet
+	 */
+	write_lock_bh(&sk->sk_callback_lock);
+	if (sk->sk_socket)
+		sk->sk_socket->ops = peer->tcp.sk_cb.ops;
+	write_unlock_bh(&sk->sk_callback_lock);
 
 	rcu_assign_sk_user_data(sk, NULL);
 }
Signature · 1 line
2.51.0
author maintainer
#658 lore raw

PATCH 654/781 net: usb: catc: enable basic endpoint checking

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Ziyi Guo <[email protected]>

[ Upstream commit 9e7021d2aeae57c323a6f722ed7915686cdcc123 ]

catc_probe() fills three URBs with hardcoded endpoint pipes without verifying the endpoint descriptors:

- usb_sndbulkpipe(usbdev, 1) and usb_rcvbulkpipe(usbdev, 1) for TX/RX
- usb_rcvintpipe(usbdev, 2) for interrupt status

A malformed USB device can present these endpoints with transfer types that differ from what the driver assumes.

Add a catc_usb_ep enum for endpoint numbers, replacing magic constants throughout. Add usb_check_bulk_endpoints() and usb_check_int_endpoints() calls after usb_set_interface() to verify endpoint types before use, rejecting devices with mismatched descriptors at probe time.

Similar to
- commit 90b7f2961798 ("net: usb: rtl8150: enable basic endpoint checking") which fixed the issue in rtl8150.

---
 drivers/net/usb/catc.c | 37 +++++++++++++++++++++++++++++++------
 1 file changed, 31 insertions(+), 6 deletions(-)
drivers/net/usb/catc.c +31 -6
index 6759388692f8e..3c824340ffb06 100644
@@ -64,6 +64,16 @@ static const char driver_name[] = "catc";
 #define CTRL_QUEUE		16	/* Max control requests in flight (power of two) */
 #define RX_PKT_SZ		1600	/* Max size of receive packet for F5U011 */
 
+/*
+ * USB endpoints.
+ */
+
+enum catc_usb_ep {
+	CATC_USB_EP_CONTROL	= 0,
+	CATC_USB_EP_BULK	= 1,
+	CATC_USB_EP_INT_IN	= 2,
+};
+
 /*
  * Control requests.
  */
@@ -772,6 +782,13 @@ static int catc_probe(struct usb_interface *intf, const struct usb_device_id *id
 	u8 broadcast[ETH_ALEN];
 	u8 *macbuf;
 	int pktsz, ret = -ENOMEM;
+	static const u8 bulk_ep_addr[] = {
+		CATC_USB_EP_BULK | USB_DIR_OUT,
+		CATC_USB_EP_BULK | USB_DIR_IN,
+		0};
+	static const u8 int_ep_addr[] = {
+		CATC_USB_EP_INT_IN | USB_DIR_IN,
+		0};
 
 	macbuf = kmalloc(ETH_ALEN, GFP_KERNEL);
 	if (!macbuf)
@@ -784,6 +801,14 @@ static int catc_probe(struct usb_interface *intf, const struct usb_device_id *id
 		goto fail_mem;
 	}
 
+	/* Verify that all required endpoints are present */
+	if (!usb_check_bulk_endpoints(intf, bulk_ep_addr) ||
+	    !usb_check_int_endpoints(intf, int_ep_addr)) {
+		dev_err(dev, "Missing or invalid endpoints\n");
+		ret = -ENODEV;
+		goto fail_mem;
+	}
+
 	netdev = alloc_etherdev(sizeof(struct catc));
 	if (!netdev)
 		goto fail_mem;
@@ -828,14 +853,14 @@ static int catc_probe(struct usb_interface *intf, const struct usb_device_id *id
 	usb_fill_control_urb(catc->ctrl_urb, usbdev, usb_sndctrlpipe(usbdev, 0),
 		NULL, NULL, 0, catc_ctrl_done, catc);
 
-	usb_fill_bulk_urb(catc->tx_urb, usbdev, usb_sndbulkpipe(usbdev, 1),
-		NULL, 0, catc_tx_done, catc);
+	usb_fill_bulk_urb(catc->tx_urb, usbdev, usb_sndbulkpipe(usbdev, CATC_USB_EP_BULK),
+			  NULL, 0, catc_tx_done, catc);
 
-	usb_fill_bulk_urb(catc->rx_urb, usbdev, usb_rcvbulkpipe(usbdev, 1),
-		catc->rx_buf, pktsz, catc_rx_done, catc);
+	usb_fill_bulk_urb(catc->rx_urb, usbdev, usb_rcvbulkpipe(usbdev, CATC_USB_EP_BULK),
+			  catc->rx_buf, pktsz, catc_rx_done, catc);
 
-	usb_fill_int_urb(catc->irq_urb, usbdev, usb_rcvintpipe(usbdev, 2),
-                catc->irq_buf, 2, catc_irq_done, catc, 1);
+	usb_fill_int_urb(catc->irq_urb, usbdev, usb_rcvintpipe(usbdev, CATC_USB_EP_INT_IN),
+			 catc->irq_buf, 2, catc_irq_done, catc, 1);
 
 	if (!catc->is_f5u011) {
 		u32 *buf;
Signature · 1 line
2.51.0
author maintainer
#659 lore raw

PATCH 655/781 xen-netback: reject zero-queue configuration from guest

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Ziyi Guo <[email protected]>

[ Upstream commit 6d1dc8014334c7fb25719999bca84d811e60a559 ]

A malicious or buggy Xen guest can write "0" to the xenbus key "multi-queue-num-queues". The connect() function in the backend only validates the upper bound (requested_num_queues > xenvif_max_queues) but not zero, allowing requested_num_queues=0 to reach vzalloc(array_size(0, sizeof(struct xenvif_queue))), which triggers WARN_ON_ONCE(!size) in __vmalloc_node_range().

On systems with panic_on_warn=1, this allows a guest-to-host denial of service.

The Xen network interface specification requires
the queue count to be "greater than zero".

Add a zero check to match the validation already present in xen-blkback, which has included this
guard since its multi-queue support was added.

Fixes 8d3d53b3e433 ("xen-netback: Add support for multiple queues")
---
 drivers/net/xen-netback/xenbus.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/net/xen-netback/xenbus.c +3 -2
index a78a25b872409..61b547aab286a 100644
@@ -735,10 +735,11 @@ static void connect(struct backend_info *be)
 	 */
 	requested_num_queues = xenbus_read_unsigned(dev->otherend,
 					"multi-queue-num-queues", 1);
-	if (requested_num_queues > xenvif_max_queues) {
+	if (requested_num_queues > xenvif_max_queues ||
+	    requested_num_queues == 0) {
 		/* buggy or malicious guest */
 		xenbus_dev_fatal(dev, -EINVAL,
-				 "guest requested %u queues, exceeding the maximum of %u.",
+				 "guest requested %u queues, but valid range is 1 - %u.",
 				 requested_num_queues, xenvif_max_queues);
 		return;
 	}
Signature · 1 line
2.51.0
author maintainer
#660 lore raw

PATCH 656/781 net/rds: rds_sendmsg should not discard payload_len

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Allison Henderson <[email protected]>

[ Upstream commit da29e453dcb3aa7cabead7915f5f945d0add3a52 ]

Commit 3db6e0d172c9 ("rds: use RCU to synchronize work-enqueue with connection teardown") modifies rds_sendmsg to avoid enqueueing work while a tear down is in progress. However, it also changed the return value of rds_sendmsg to that of rds_send_xmit instead of the payload_len. This means the user may incorrectly receive errno values when it should have simply received a payload of 0 while the peer attempts a reconnections. So this patch corrects the teardown handling code to only use the out error path in that case, thus restoring the original payload_len return value.

Fixes 3db6e0d172c9 ("rds: use RCU to synchronize work-enqueue with connection teardown")
---
 net/rds/send.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)
net/rds/send.c +4 -2
index 0b3d0ef2f008b..071c5dca969a2 100644
@@ -1382,9 +1382,11 @@ int rds_sendmsg(struct socket *sock, struct msghdr *msg, size_t payload_len)
 		else
 			queue_delayed_work(rds_wq, &cpath->cp_send_w, 1);
 		rcu_read_unlock();
+
+		if (ret)
+			goto out;
 	}
-	if (ret)
-		goto out;
+
 	rds_message_put(rm);
 
 	for (ind = 0; ind < vct.indx; ind++)
Signature · 1 line
2.51.0
author maintainer
#661 lore raw

PATCH 657/781 net: bridge: mcast: always update mdb_n_entries for vlan contexts

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Nikolay Aleksandrov <[email protected]>

[ Upstream commit 8b769e311a86bb9d15c5658ad283b86fc8f080a2 ]

syzbot triggered a warning[1] about the number of mdb entries in a context. It turned out that there are multiple ways to trigger that warning today (some got added during the years), the root cause of the problem is that the increase is done conditionally, and over the years these different conditions increased so there were new ways to trigger the warning, that is to do a decrease which wasn't paired with a previous increase.

For example one way to trigger it is with flush:

 $ ip l add br0 up type bridge vlan_filtering 1 mcast_snooping 1
 $ ip l add dumdum up master br0 type dummy
 $ bridge mdb add dev br0 port dumdum grp 239.0.0.1 permanent vid 1
 $ ip link set dev br0 down
 $ ip link set dev br0 type bridge mcast_vlan_snooping 1
   ^^^^ this will enable snooping, but will not update mdb_n_entries
        because in __br_multicast_enable_port_ctx() we check !netif_running
 $ bridge mdb flush dev br0
   ^^^ this will trigger the warning because it will delete the pg which
       we added above, which will try to decrease mdb_n_entries

Fix the problem by removing the conditional increase and always keep the count up-to-date while the vlan exists. In order to do that we have to first initialize it on port-vlan context creation, and then always increase or decrease the value regardless of mcast options. To keep the current behaviour we have to enforce the mdb limit only if the context is port's or if the port-vlan's mcast snooping is enabled.

[1]

 ------------[ cut here ]------------
 n == 0
 WARNING: net/bridge/br_multicast.c:718 at br_multicast_port_ngroups_dec_one net/bridge/br_multicast.c:718 [inline], CPU#0: syz.4.4607/22043
 WARNING: net/bridge/br_multicast.c:718 at br_multicast_port_ngroups_dec net/bridge/br_multicast.c:771 [inline], CPU#0: syz.4.4607/22043
 WARNING: net/bridge/br_multicast.c:718 at br_multicast_del_pg+0x1bbe/0x1e20 net/bridge/br_multicast.c:825, CPU#0: syz.4.4607/22043
 Modules linked in:
 CPU: 0 UID: 0 PID: 22043 Comm: syz.4.4607 Not tainted syzkaller #0 PREEMPT(full)
 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/24/2026
 RIP: 0010:br_multicast_port_ngroups_dec_one net/bridge/br_multicast.c:718 [inline]
 RIP: 0010:br_multicast_port_ngroups_dec net/bridge/br_multicast.c:771 [inline]
 RIP: 0010:br_multicast_del_pg+0x1bbe/0x1e20 net/bridge/br_multicast.c:825
 Code: 41 5f 5d e9 04 7a 48 f7 e8 3f 73 5c f7 90 0f 0b 90 e9 cf fd ff ff e8 31 73 5c f7 90 0f 0b 90 e9 16 fd ff ff e8 23 73 5c f7 90 <0f> 0b 90 e9 60 fd ff ff e8 15 73 5c f7 eb 05 e8 0e 73 5c f7 48 8b
 RSP: 0018:ffffc9000c207220 EFLAGS: 00010293
 RAX: ffffffff8a68042d RBX: ffff88807c6f1800 RCX: ffff888066e90000
 RDX: 0000000000000000 RSI: 0000000000000000 RDI: 0000000000000000
 RBP: 0000000000000000 R08: ffff888066e90000 R09: 000000000000000c
 R10: 000000000000000c R11: 0000000000000000 R12: ffff8880303ef800
 R13: dffffc0000000000 R14: ffff888050eb11c4 R15: 1ffff1100a1d6238
 FS:  00007fa45921b6c0(0000) GS:ffff8881256f5000(0000) knlGS:0000000000000000
 CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
 CR2: 00007fa4591f9ff8 CR3: 0000000081df2000 CR4: 00000000003526f0
 Call Trace:
  <TASK>
  br_mdb_flush_pgs net/bridge/br_mdb.c:1525 [inline]
  br_mdb_flush net/bridge/br_mdb.c:1544 [inline]
  br_mdb_del_bulk+0x5e2/0xb20 net/bridge/br_mdb.c:1561
  rtnl_mdb_del+0x48a/0x640 net/core/rtnetlink.c:-1
  rtnetlink_rcv_msg+0x77e/0xbe0 net/core/rtnetlink.c:6967
  netlink_rcv_skb+0x232/0x4b0 net/netlink/af_netlink.c:2550
  netlink_unicast_kernel net/netlink/af_netlink.c:1318 [inline]
  netlink_unicast+0x80f/0x9b0 net/netlink/af_netlink.c:1344
  netlink_sendmsg+0x813/0xb40 net/netlink/af_netlink.c:1894
  sock_sendmsg_nosec net/socket.c:727 [inline]
  __sock_sendmsg net/socket.c:742 [inline]
  ____sys_sendmsg+0xa68/0xad0 net/socket.c:2592
  ___sys_sendmsg+0x2a5/0x360 net/socket.c:2646
  __sys_sendmsg net/socket.c:2678 [inline]
  __do_sys_sendmsg net/socket.c:2683 [inline]
  __se_sys_sendmsg net/socket.c:2681 [inline]
  __x64_sys_sendmsg+0x1bd/0x2a0 net/socket.c:2681
  do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
  do_syscall_64+0xe2/0xf80 arch/x86/entry/syscall_64.c:94
  entry_SYSCALL_64_after_hwframe+0x77/0x7f
 RIP: 0033:0x7fa45839aeb9
 Code: ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 44 00 00 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:00007fa45921b028 EFLAGS: 00000246 ORIG_RAX: 000000000000002e
 RAX: ffffffffffffffda RBX: 00007fa458615fa0 RCX: 00007fa45839aeb9
 RDX: 0000000000000000 RSI: 00002000000000c0 RDI: 0000000000000004
 RBP: 00007fa458408c1f R08: 0000000000000000 R09: 0000000000000000
 R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000
 R13: 00007fa458616038 R14: 00007fa458615fa0 R15: 00007fff0b59fae8
 </TASK>
---
 net/bridge/br_multicast.c | 45 ++++++++++++++++-----------------------
 1 file changed, 18 insertions(+), 27 deletions(-)
net/bridge/br_multicast.c +18 -27
index d55a4ab87837f..e9a7e65304017 100644
@@ -244,14 +244,11 @@ br_multicast_port_vid_to_port_ctx(struct net_bridge_port *port, u16 vid)
 
 	lockdep_assert_held_once(&port->br->multicast_lock);
 
-	if (!br_opt_get(port->br, BROPT_MCAST_VLAN_SNOOPING_ENABLED))
-		return NULL;
-
 	/* Take RCU to access the vlan. */
 	rcu_read_lock();
 
 	vlan = br_vlan_find(nbp_vlan_group_rcu(port), vid);
-	if (vlan && !br_multicast_port_ctx_vlan_disabled(&vlan->port_mcast_ctx))
+	if (vlan)
 		pmctx = &vlan->port_mcast_ctx;
 
 	rcu_read_unlock();
@@ -701,7 +698,10 @@ br_multicast_port_ngroups_inc_one(struct net_bridge_mcast_port *pmctx,
 	u32 max = READ_ONCE(pmctx->mdb_max_entries);
 	u32 n = READ_ONCE(pmctx->mdb_n_entries);
 
-	if (max && n >= max) {
+	/* enforce the max limit when it's a port pmctx or a port-vlan pmctx
+	 * with snooping enabled
+	 */
+	if (!br_multicast_port_ctx_vlan_disabled(pmctx) && max && n >= max) {
 		NL_SET_ERR_MSG_FMT_MOD(extack, "%s is already in %u groups, and mcast_max_groups=%u",
 				       what, n, max);
 		return -E2BIG;
@@ -736,9 +736,7 @@ static int br_multicast_port_ngroups_inc(struct net_bridge_port *port,
 		return err;
 	}
 
-	/* Only count on the VLAN context if VID is given, and if snooping on
-	 * that VLAN is enabled.
-	 */
+	/* Only count on the VLAN context if VID is given */
 	if (!group->vid)
 		return 0;
 
@@ -2011,6 +2009,18 @@ void br_multicast_port_ctx_init(struct net_bridge_port *port,
 	timer_setup(&pmctx->ip6_own_query.timer,
 		    br_ip6_multicast_port_query_expired, 0);
 #endif
+	/* initialize mdb_n_entries if a new port vlan is being created */
+	if (vlan) {
+		struct net_bridge_port_group *pg;
+		u32 n = 0;
+
+		spin_lock_bh(&port->br->multicast_lock);
+		hlist_for_each_entry(pg, &port->mglist, mglist)
+			if (pg->key.addr.vid == vlan->vid)
+				n++;
+		WRITE_ONCE(pmctx->mdb_n_entries, n);
+		spin_unlock_bh(&port->br->multicast_lock);
+	}
 }
 
 void br_multicast_port_ctx_deinit(struct net_bridge_mcast_port *pmctx)
@@ -2094,25 +2104,6 @@ static void __br_multicast_enable_port_ctx(struct net_bridge_mcast_port *pmctx)
 		br_ip4_multicast_add_router(brmctx, pmctx);
 		br_ip6_multicast_add_router(brmctx, pmctx);
 	}
-
-	if (br_multicast_port_ctx_is_vlan(pmctx)) {
-		struct net_bridge_port_group *pg;
-		u32 n = 0;
-
-		/* The mcast_n_groups counter might be wrong. First,
-		 * BR_VLFLAG_MCAST_ENABLED is toggled before temporary entries
-		 * are flushed, thus mcast_n_groups after the toggle does not
-		 * reflect the true values. And second, permanent entries added
-		 * while BR_VLFLAG_MCAST_ENABLED was disabled, are not reflected
-		 * either. Thus we have to refresh the counter.
-		 */
-
-		hlist_for_each_entry(pg, &pmctx->port->mglist, mglist) {
-			if (pg->key.addr.vid == pmctx->vlan->vid)
-				n++;
-		}
-		WRITE_ONCE(pmctx->mdb_n_entries, n);
-	}
 }
 
 static void br_multicast_enable_port_ctx(struct net_bridge_mcast_port *pmctx)
Signature · 1 line
2.51.0
author maintainer
#662 lore raw

PATCH 658/781 selftests: forwarding: vxlan_bridge_1d: fix test failure with br_netfilter enabled

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Aleksei Oladko <[email protected]>

[ Upstream commit 02cb2e6bacbb08ebf6acb61be816efd11e1f4a21 ]

The test generates VXLAN traffic using mausezahn, where the encapsulated inner IPv4 packet contains a zero IP header checksum. After VXLAN decapsulation, such packets do not pass sanity checks in br_netfilter and are dropped, which causes the test to fail.

Fix this by calculating and setting a valid IPv4 header checksum for the encapsulated packet generated by mausezahn, so that the packet is accepted by br_netfilter. Fixed by using the payload_template_calc_checksum() / payload_template_expand_checksum() helpers that are only available in v6.3 and newer kernels.

Fixes a0b61f3d8ebf ("selftests: forwarding: vxlan_bridge_1d: Add an ECN decap test")
---
 .../net/forwarding/vxlan_bridge_1d.sh         | 26 ++++++++++++-------
 1 file changed, 16 insertions(+), 10 deletions(-)
tools/testing/selftests/net/forwarding/vxlan_bridge_1d.sh +16 -10
index b43816dd998ca..457f41d5e584b 100755
@@ -567,6 +567,21 @@ vxlan_encapped_ping_do()
 	local inner_tos=$1; shift
 	local outer_tos=$1; shift
 
+	local ipv4hdr=$(:
+		    )"45:"$(                      : IP version + IHL
+		    )"$inner_tos:"$(              : IP TOS
+		    )"00:54:"$(                   : IP total length
+		    )"99:83:"$(                   : IP identification
+		    )"40:00:"$(                   : IP flags + frag off
+		    )"40:"$(                      : IP TTL
+		    )"01:"$(                      : IP proto
+		    )"CHECKSUM:"$(                : IP header csum
+		    )"c0:00:02:03:"$(             : IP saddr: 192.0.2.3
+		    )"c0:00:02:01"$(              : IP daddr: 192.0.2.1
+		)
+	local checksum=$(payload_template_calc_checksum "$ipv4hdr")
+	ipv4hdr=$(payload_template_expand_checksum "$ipv4hdr" $checksum)
+
 	$MZ $dev -c $count -d 100msec -q \
 		-b $next_hop_mac -B $dest_ip \
 		-t udp tos=$outer_tos,sp=23456,dp=$VXPORT,p=$(:
@@ -577,16 +592,7 @@ vxlan_encapped_ping_do()
 		    )"$dest_mac:"$(               : ETH daddr
 		    )"$(mac_get w2):"$(           : ETH saddr
 		    )"08:00:"$(                   : ETH type
-		    )"45:"$(                      : IP version + IHL
-		    )"$inner_tos:"$(              : IP TOS
-		    )"00:54:"$(                   : IP total length
-		    )"99:83:"$(                   : IP identification
-		    )"40:00:"$(                   : IP flags + frag off
-		    )"40:"$(                      : IP TTL
-		    )"01:"$(                      : IP proto
-		    )"00:00:"$(                   : IP header csum
-		    )"c0:00:02:03:"$(             : IP saddr: 192.0.2.3
-		    )"c0:00:02:01:"$(             : IP daddr: 192.0.2.1
+		    )"$ipv4hdr:"$(                : IPv4 header
 		    )"08:"$(                      : ICMP type
 		    )"00:"$(                      : ICMP code
 		    )"8b:f2:"$(                   : ICMP csum
Signature · 1 line
2.51.0
author maintainer
#663 lore raw

PATCH 659/781 selftests: forwarding: vxlan_bridge_1d_ipv6: fix test failure with br_netfilter enabled

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Aleksei Oladko <[email protected]>

[ Upstream commit ce9f6aec0fb780dafc1dfc5f47c688422aff464a ]

The test generates VXLAN traffic using mausezahn, where the encapsulated inner IPv6 packet has an incorrect payload length set in the IPv6 header. After VXLAN decapsulation, such packets do not pass sanity checks in br_netfilter and are dropped, which causes the test to fail.

Fix this by setting the correct IPv6 payload length for the encapsulated packet generated by mausezahn, so that the packet is accepted by br_netfilter.

tools/testing/selftests/net/forwarding/vxlan_bridge_1d_ipv6.sh lines 698-706

              )"00:03:"$(           : Payload length
              )"3a:"$(              : Next header
              )"04:"$(              : Hop limit
              )"$saddr:"$(          : IP saddr
              )"$daddr:"$(          : IP daddr
              )"80:"$(              : ICMPv6.type
              )"00:"$(              : ICMPv6.code
              )"00:"$(              : ICMPv6.checksum
              )

Data after IPv6 header:
• 80: — 1 byte (ICMPv6 type)
• 00: — 1 byte (ICMPv6 code)
• 00: — 1 byte (ICMPv6 checksum, truncated)

Total: 3 bytes → 00:03 is correct. The old value 00:08 did not match the actual payload size.

Fixes b07e9957f220 ("selftests: forwarding: Add VxLAN tests with a VLAN-unaware bridge for IPv6")
---
 tools/testing/selftests/net/forwarding/vxlan_bridge_1d_ipv6.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
tools/testing/selftests/net/forwarding/vxlan_bridge_1d_ipv6.sh +1 -1
index a603f7b0a08f0..e642feeada0e7 100755
@@ -695,7 +695,7 @@ vxlan_encapped_ping_do()
 		    )"6"$(			  : IP version
 		    )"$inner_tos"$(               : Traffic class
 		    )"0:00:00:"$(                 : Flow label
-		    )"00:08:"$(                   : Payload length
+		    )"00:03:"$(                   : Payload length
 		    )"3a:"$(                      : Next header
 		    )"04:"$(                      : Hop limit
 		    )"$saddr:"$(		  : IP saddr
Signature · 1 line
2.51.0
author maintainer
#664 lore raw

PATCH 660/781 selftests: forwarding: fix pedit tests failure with br_netfilter enabled

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Aleksei Oladko <[email protected]>

[ Upstream commit a8c198d16c64cdf57f481a4cd3e769502802369e ]

The tests use the tc pedit action to modify the IPv4 source address ("pedit ex munge ip src set"), but the IP header checksum is not recalculated after the modification. As a result, the modified packet fails sanity checks in br_netfilter after bridging and is dropped, which causes the test to fail.

Fix this by ensuring net.bridge.bridge-nf-call-iptables is set to 0 during the test execution. This prevents the bridge from passing L2 traffic to netfilter, bypassing the checksum validation that causes the test failure.

Fixes 92ad3828944e ("selftests: forwarding: Add a test for pedit munge SIP and DIP")
Fixes 226657ba2389 ("selftests: forwarding: Add a forwarding test for pedit munge dsfield")
---
 tools/testing/selftests/net/forwarding/pedit_dsfield.sh | 8 ++++++++
 tools/testing/selftests/net/forwarding/pedit_ip.sh      | 8 ++++++++
 2 files changed, 16 insertions(+)
tools/testing/selftests/net/forwarding/pedit_dsfield.sh +8 -0
index af008fbf2725e..eb2d8034de9c7 100755
@@ -98,12 +98,20 @@ setup_prepare()
 	h1_create
 	h2_create
 	switch_create
+
+	if [ -f /proc/sys/net/bridge/bridge-nf-call-iptables ]; then
+		sysctl_set net.bridge.bridge-nf-call-iptables 0
+	fi
 }
 
 cleanup()
 {
 	pre_cleanup
 
+	if [ -f /proc/sys/net/bridge/bridge-nf-call-iptables ]; then
+		sysctl_restore net.bridge.bridge-nf-call-iptables
+	fi
+
 	switch_destroy
 	h2_destroy
 	h1_destroy
tools/testing/selftests/net/forwarding/pedit_ip.sh +8 -0
index d14efb2d23b2e..9235674627abd 100755
@@ -91,12 +91,20 @@ setup_prepare()
 	h1_create
 	h2_create
 	switch_create
+
+	if [ -f /proc/sys/net/bridge/bridge-nf-call-iptables ]; then
+		sysctl_set net.bridge.bridge-nf-call-iptables 0
+	fi
 }
 
 cleanup()
 {
 	pre_cleanup
 
+	if [ -f /proc/sys/net/bridge/bridge-nf-call-iptables ]; then
+		sysctl_restore net.bridge.bridge-nf-call-iptables
+	fi
+
 	switch_destroy
 	h2_destroy
 	h1_destroy
Signature · 1 line
2.51.0
author maintainer
#665 lore raw

PATCH 661/781 netfilter: nft_counter: serialize reset with spinlock

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Brian Witte <[email protected]>

[ Upstream commit 779c60a5190c42689534172f4b49e927c9959e4e ]

Add a global static spinlock to serialize counter fetch+reset operations, preventing concurrent dump-and-reset from underrunning values.

The lock is taken before fetching the total so that two parallel resets cannot both read the same counter values and then both subtract them.

A global lock is used for simplicity since resets are infrequent. If this becomes a bottleneck, it can be replaced with a per-net lock later.

Fixes bd662c4218f9 ("netfilter: nf_tables: Add locking for NFT_MSG_GETOBJ_RESET requests")
Fixes 3d483faa6663 ("netfilter: nf_tables: Add locking for NFT_MSG_GETSETELEM_RESET requests")
Fixes 3cb03edb4de3 ("netfilter: nf_tables: Add locking for NFT_MSG_GETRULE_RESET requests")
---
 net/netfilter/nft_counter.c | 20 ++++++++++++++++----
 1 file changed, 16 insertions(+), 4 deletions(-)
net/netfilter/nft_counter.c +16 -4
index 0d70325280cc5..169ae93688bcc 100644
@@ -32,6 +32,9 @@ struct nft_counter_percpu_priv {
 
 static DEFINE_PER_CPU(struct u64_stats_sync, nft_counter_sync);
 
+/* control plane only: sync fetch+reset */
+static DEFINE_SPINLOCK(nft_counter_lock);
+
 static inline void nft_counter_do_eval(struct nft_counter_percpu_priv *priv,
 				       struct nft_regs *regs,
 				       const struct nft_pktinfo *pkt)
@@ -148,13 +151,25 @@ static void nft_counter_fetch(struct nft_counter_percpu_priv *priv,
 	}
 }
 
+static void nft_counter_fetch_and_reset(struct nft_counter_percpu_priv *priv,
+					struct nft_counter_tot *total)
+{
+	spin_lock(&nft_counter_lock);
+	nft_counter_fetch(priv, total);
+	nft_counter_reset(priv, total);
+	spin_unlock(&nft_counter_lock);
+}
+
 static int nft_counter_do_dump(struct sk_buff *skb,
 			       struct nft_counter_percpu_priv *priv,
 			       bool reset)
 {
 	struct nft_counter_tot total;
 
-	nft_counter_fetch(priv, &total);
+	if (unlikely(reset))
+		nft_counter_fetch_and_reset(priv, &total);
+	else
+		nft_counter_fetch(priv, &total);
 
 	if (nla_put_be64(skb, NFTA_COUNTER_BYTES, cpu_to_be64(total.bytes),
 			 NFTA_COUNTER_PAD) ||
@@ -162,9 +177,6 @@ static int nft_counter_do_dump(struct sk_buff *skb,
 			 NFTA_COUNTER_PAD))
 		goto nla_put_failure;
 
-	if (reset)
-		nft_counter_reset(priv, &total);
-
 	return 0;
 
 nla_put_failure:
Signature · 1 line
2.51.0
author maintainer
#666 lore raw

PATCH 662/781 netfilter: nft_quota: use atomic64_xchg for reset

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Brian Witte <[email protected]>

[ Upstream commit 30c4d7fb59ac4c8d7fa7937df11eed10b368fa11 ]

Use atomic64_xchg() to atomically read and zero the consumed value on reset, which is simpler than the previous read+sub pattern and doesn't require lock serialization.

Fixes bd662c4218f9 ("netfilter: nf_tables: Add locking for NFT_MSG_GETOBJ_RESET requests")
Fixes 3d483faa6663 ("netfilter: nf_tables: Add locking for NFT_MSG_GETSETELEM_RESET requests")
Fixes 3cb03edb4de3 ("netfilter: nf_tables: Add locking for NFT_MSG_GETRULE_RESET requests")
---
 net/netfilter/nft_quota.c | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)
net/netfilter/nft_quota.c +7 -6
index df0798da2329b..cb6c0e04ff675 100644
@@ -140,11 +140,16 @@ static int nft_quota_do_dump(struct sk_buff *skb, struct nft_quota *priv,
 	u64 consumed, consumed_cap, quota;
 	u32 flags = priv->flags;
 
-	/* Since we inconditionally increment consumed quota for each packet
+	/* Since we unconditionally increment consumed quota for each packet
 	 * that we see, don't go over the quota boundary in what we send to
 	 * userspace.
 	 */
-	consumed = atomic64_read(priv->consumed);
+	if (reset) {
+		consumed = atomic64_xchg(priv->consumed, 0);
+		clear_bit(NFT_QUOTA_DEPLETED_BIT, &priv->flags);
+	} else {
+		consumed = atomic64_read(priv->consumed);
+	}
 	quota = atomic64_read(&priv->quota);
 	if (consumed >= quota) {
 		consumed_cap = quota;
@@ -160,10 +165,6 @@ static int nft_quota_do_dump(struct sk_buff *skb, struct nft_quota *priv,
 	    nla_put_be32(skb, NFTA_QUOTA_FLAGS, htonl(flags)))
 		goto nla_put_failure;
 
-	if (reset) {
-		atomic64_sub(consumed, priv->consumed);
-		clear_bit(NFT_QUOTA_DEPLETED_BIT, &priv->flags);
-	}
 	return 0;
 
 nla_put_failure:
Signature · 1 line
2.51.0
author maintainer
#667 lore raw

PATCH 663/781 netfilter: nf_tables: revert commit_mutex usage in reset path

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Brian Witte <[email protected]>

[ Upstream commit 7f261bb906bf527c4a6e2a646e2d5f3679f2a8bc ]

It causes circular lock dependency between commit_mutex, nfnl_subsys_ipset and nlk_cb_mutex when nft reset, ipset list, and iptables-nft with '-m set' rule run at the same time.

Previous patches made it safe to run individual reset handlers concurrently so commit_mutex is no longer required to prevent this.

Fixes bd662c4218f9 ("netfilter: nf_tables: Add locking for NFT_MSG_GETOBJ_RESET requests")
Fixes 3d483faa6663 ("netfilter: nf_tables: Add locking for NFT_MSG_GETSETELEM_RESET requests")
Fixes 3cb03edb4de3 ("netfilter: nf_tables: Add locking for NFT_MSG_GETRULE_RESET requests")
---
 net/netfilter/nf_tables_api.c | 248 ++++++----------------------------
 1 file changed, 42 insertions(+), 206 deletions(-)
net/netfilter/nf_tables_api.c +42 -206
index daef07ee09427..f807183235e79 100644
@@ -3900,23 +3900,6 @@ static int nf_tables_dump_rules(struct sk_buff *skb,
 	return skb->len;
 }
 
-static int nf_tables_dumpreset_rules(struct sk_buff *skb,
-				     struct netlink_callback *cb)
-{
-	struct nftables_pernet *nft_net = nft_pernet(sock_net(skb->sk));
-	int ret;
-
-	/* Mutex is held is to prevent that two concurrent dump-and-reset calls
-	 * do not underrun counters and quotas. The commit_mutex is used for
-	 * the lack a better lock, this is not transaction path.
-	 */
-	mutex_lock(&nft_net->commit_mutex);
-	ret = nf_tables_dump_rules(skb, cb);
-	mutex_unlock(&nft_net->commit_mutex);
-
-	return ret;
-}
-
 static int nf_tables_dump_rules_start(struct netlink_callback *cb)
 {
 	struct nft_rule_dump_ctx *ctx = (void *)cb->ctx;
@@ -3936,16 +3919,10 @@ static int nf_tables_dump_rules_start(struct netlink_callback *cb)
 			return -ENOMEM;
 		}
 	}
-	return 0;
-}
-
-static int nf_tables_dumpreset_rules_start(struct netlink_callback *cb)
-{
-	struct nft_rule_dump_ctx *ctx = (void *)cb->ctx;
-
-	ctx->reset = true;
+	if (NFNL_MSG_TYPE(cb->nlh->nlmsg_type) == NFT_MSG_GETRULE_RESET)
+		ctx->reset = true;
 
-	return nf_tables_dump_rules_start(cb);
+	return 0;
 }
 
 static int nf_tables_dump_rules_done(struct netlink_callback *cb)
@@ -4011,6 +3988,8 @@ static int nf_tables_getrule(struct sk_buff *skb, const struct nfnl_info *info,
 	u32 portid = NETLINK_CB(skb).portid;
 	struct net *net = info->net;
 	struct sk_buff *skb2;
+	bool reset = false;
+	char *buf;
 
 	if (info->nlh->nlmsg_flags & NLM_F_DUMP) {
 		struct netlink_dump_control c = {
@@ -4024,47 +4003,16 @@ static int nf_tables_getrule(struct sk_buff *skb, const struct nfnl_info *info,
 		return nft_netlink_dump_start_rcu(info->sk, skb, info->nlh, &c);
 	}
 
-	skb2 = nf_tables_getrule_single(portid, info, nla, false);
-	if (IS_ERR(skb2))
-		return PTR_ERR(skb2);
-
-	return nfnetlink_unicast(skb2, net, portid);
-}
-
-static int nf_tables_getrule_reset(struct sk_buff *skb,
-				   const struct nfnl_info *info,
-				   const struct nlattr * const nla[])
-{
-	struct nftables_pernet *nft_net = nft_pernet(info->net);
-	u32 portid = NETLINK_CB(skb).portid;
-	struct net *net = info->net;
-	struct sk_buff *skb2;
-	char *buf;
-
-	if (info->nlh->nlmsg_flags & NLM_F_DUMP) {
-		struct netlink_dump_control c = {
-			.start= nf_tables_dumpreset_rules_start,
-			.dump = nf_tables_dumpreset_rules,
-			.done = nf_tables_dump_rules_done,
-			.module = THIS_MODULE,
-			.data = (void *)nla,
-		};
-
-		return nft_netlink_dump_start_rcu(info->sk, skb, info->nlh, &c);
-	}
-
-	if (!try_module_get(THIS_MODULE))
-		return -EINVAL;
-	rcu_read_unlock();
-	mutex_lock(&nft_net->commit_mutex);
-	skb2 = nf_tables_getrule_single(portid, info, nla, true);
-	mutex_unlock(&nft_net->commit_mutex);
-	rcu_read_lock();
-	module_put(THIS_MODULE);
+	if (NFNL_MSG_TYPE(info->nlh->nlmsg_type) == NFT_MSG_GETRULE_RESET)
+		reset = true;
 
+	skb2 = nf_tables_getrule_single(portid, info, nla, reset);
 	if (IS_ERR(skb2))
 		return PTR_ERR(skb2);
 
+	if (!reset)
+		return nfnetlink_unicast(skb2, net, portid);
+
 	buf = kasprintf(GFP_ATOMIC, "%.*s:%u",
 			nla_len(nla[NFTA_RULE_TABLE]),
 			(char *)nla_data(nla[NFTA_RULE_TABLE]),
@@ -6323,6 +6271,10 @@ static int nf_tables_dump_set(struct sk_buff *skb, struct netlink_callback *cb)
 	nla_nest_end(skb, nest);
 	nlmsg_end(skb, nlh);
 
+	if (dump_ctx->reset && args.iter.count > args.iter.skip)
+		audit_log_nft_set_reset(table, cb->seq,
+					args.iter.count - args.iter.skip);
+
 	rcu_read_unlock();
 
 	if (args.iter.err && args.iter.err != -EMSGSIZE)
@@ -6338,26 +6290,6 @@ static int nf_tables_dump_set(struct sk_buff *skb, struct netlink_callback *cb)
 	return -ENOSPC;
 }
 
-static int nf_tables_dumpreset_set(struct sk_buff *skb,
-				   struct netlink_callback *cb)
-{
-	struct nftables_pernet *nft_net = nft_pernet(sock_net(skb->sk));
-	struct nft_set_dump_ctx *dump_ctx = cb->data;
-	int ret, skip = cb->args[0];
-
-	mutex_lock(&nft_net->commit_mutex);
-
-	ret = nf_tables_dump_set(skb, cb);
-
-	if (cb->args[0] > skip)
-		audit_log_nft_set_reset(dump_ctx->ctx.table, cb->seq,
-					cb->args[0] - skip);
-
-	mutex_unlock(&nft_net->commit_mutex);
-
-	return ret;
-}
-
 static int nf_tables_dump_set_start(struct netlink_callback *cb)
 {
 	struct nft_set_dump_ctx *dump_ctx = cb->data;
@@ -6601,8 +6533,13 @@ static int nf_tables_getsetelem(struct sk_buff *skb,
 {
 	struct netlink_ext_ack *extack = info->extack;
 	struct nft_set_dump_ctx dump_ctx;
+	int rem, err = 0, nelems = 0;
+	struct net *net = info->net;
 	struct nlattr *attr;
-	int rem, err = 0;
+	bool reset = false;
+
+	if (NFNL_MSG_TYPE(info->nlh->nlmsg_type) == NFT_MSG_GETSETELEM_RESET)
+		reset = true;
 
 	if (info->nlh->nlmsg_flags & NLM_F_DUMP) {
 		struct netlink_dump_control c = {
@@ -6612,7 +6549,7 @@ static int nf_tables_getsetelem(struct sk_buff *skb,
 			.module = THIS_MODULE,
 		};
 
-		err = nft_set_dump_ctx_init(&dump_ctx, skb, info, nla, false);
+		err = nft_set_dump_ctx_init(&dump_ctx, skb, info, nla, reset);
 		if (err)
 			return err;
 
@@ -6623,75 +6560,21 @@ static int nf_tables_getsetelem(struct sk_buff *skb,
 	if (!nla[NFTA_SET_ELEM_LIST_ELEMENTS])
 		return -EINVAL;
 
-	err = nft_set_dump_ctx_init(&dump_ctx, skb, info, nla, false);
+	err = nft_set_dump_ctx_init(&dump_ctx, skb, info, nla, reset);
 	if (err)
 		return err;
 
 	nla_for_each_nested(attr, nla[NFTA_SET_ELEM_LIST_ELEMENTS], rem) {
-		err = nft_get_set_elem(&dump_ctx.ctx, dump_ctx.set, attr, false);
-		if (err < 0) {
-			NL_SET_BAD_ATTR(extack, attr);
-			break;
-		}
-	}
-
-	return err;
-}
-
-static int nf_tables_getsetelem_reset(struct sk_buff *skb,
-				      const struct nfnl_info *info,
-				      const struct nlattr * const nla[])
-{
-	struct nftables_pernet *nft_net = nft_pernet(info->net);
-	struct netlink_ext_ack *extack = info->extack;
-	struct nft_set_dump_ctx dump_ctx;
-	int rem, err = 0, nelems = 0;
-	struct nlattr *attr;
-
-	if (info->nlh->nlmsg_flags & NLM_F_DUMP) {
-		struct netlink_dump_control c = {
-			.start = nf_tables_dump_set_start,
-			.dump = nf_tables_dumpreset_set,
-			.done = nf_tables_dump_set_done,
-			.module = THIS_MODULE,
-		};
-
-		err = nft_set_dump_ctx_init(&dump_ctx, skb, info, nla, true);
-		if (err)
-			return err;
-
-		c.data = &dump_ctx;
-		return nft_netlink_dump_start_rcu(info->sk, skb, info->nlh, &c);
-	}
-
-	if (!nla[NFTA_SET_ELEM_LIST_ELEMENTS])
-		return -EINVAL;
-
-	if (!try_module_get(THIS_MODULE))
-		return -EINVAL;
-	rcu_read_unlock();
-	mutex_lock(&nft_net->commit_mutex);
-	rcu_read_lock();
-
-	err = nft_set_dump_ctx_init(&dump_ctx, skb, info, nla, true);
-	if (err)
-		goto out_unlock;
-
-	nla_for_each_nested(attr, nla[NFTA_SET_ELEM_LIST_ELEMENTS], rem) {
-		err = nft_get_set_elem(&dump_ctx.ctx, dump_ctx.set, attr, true);
+		err = nft_get_set_elem(&dump_ctx.ctx, dump_ctx.set, attr, reset);
 		if (err < 0) {
 			NL_SET_BAD_ATTR(extack, attr);
 			break;
 		}
 		nelems++;
 	}
-	audit_log_nft_set_reset(dump_ctx.ctx.table, nft_base_seq(info->net), nelems);
-
-out_unlock:
-	rcu_read_unlock();
-	mutex_unlock(&nft_net->commit_mutex);
-	rcu_read_lock();
-	module_put(THIS_MODULE);
+	if (reset)
+		audit_log_nft_set_reset(dump_ctx.ctx.table, nft_base_seq(net),
+					nelems);
 
 	return err;
 }
@@ -8562,19 +8445,6 @@ static int nf_tables_dump_obj(struct sk_buff *skb, struct netlink_callback *cb)
 	return skb->len;
 }
 
-static int nf_tables_dumpreset_obj(struct sk_buff *skb,
-				   struct netlink_callback *cb)
-{
-	struct nftables_pernet *nft_net = nft_pernet(sock_net(skb->sk));
-	int ret;
-
-	mutex_lock(&nft_net->commit_mutex);
-	ret = nf_tables_dump_obj(skb, cb);
-	mutex_unlock(&nft_net->commit_mutex);
-
-	return ret;
-}
-
 static int nf_tables_dump_obj_start(struct netlink_callback *cb)
 {
 	struct nft_obj_dump_ctx *ctx = (void *)cb->ctx;
@@ -8591,16 +8461,10 @@ static int nf_tables_dump_obj_start(struct netlink_callback *cb)
 	if (nla[NFTA_OBJ_TYPE])
 		ctx->type = ntohl(nla_get_be32(nla[NFTA_OBJ_TYPE]));
 
-	return 0;
-}
-
-static int nf_tables_dumpreset_obj_start(struct netlink_callback *cb)
-{
-	struct nft_obj_dump_ctx *ctx = (void *)cb->ctx;
-
-	ctx->reset = true;
+	if (NFNL_MSG_TYPE(cb->nlh->nlmsg_type) == NFT_MSG_GETOBJ_RESET)
+		ctx->reset = true;
 
-	return nf_tables_dump_obj_start(cb);
+	return 0;
 }
 
 static int nf_tables_dump_obj_done(struct netlink_callback *cb)
@@ -8662,42 +8526,16 @@ nf_tables_getobj_single(u32 portid, const struct nfnl_info *info,
 static int nf_tables_getobj(struct sk_buff *skb, const struct nfnl_info *info,
 			    const struct nlattr * const nla[])
 {
-	u32 portid = NETLINK_CB(skb).portid;
-	struct sk_buff *skb2;
-
-	if (info->nlh->nlmsg_flags & NLM_F_DUMP) {
-		struct netlink_dump_control c = {
-			.start = nf_tables_dump_obj_start,
-			.dump = nf_tables_dump_obj,
-			.done = nf_tables_dump_obj_done,
-			.module = THIS_MODULE,
-			.data = (void *)nla,
-		};
-
-		return nft_netlink_dump_start_rcu(info->sk, skb, info->nlh, &c);
-	}
-
-	skb2 = nf_tables_getobj_single(portid, info, nla, false);
-	if (IS_ERR(skb2))
-		return PTR_ERR(skb2);
-
-	return nfnetlink_unicast(skb2, info->net, portid);
-}
-
-static int nf_tables_getobj_reset(struct sk_buff *skb,
-				  const struct nfnl_info *info,
-				  const struct nlattr * const nla[])
-{
-	struct nftables_pernet *nft_net = nft_pernet(info->net);
 	u32 portid = NETLINK_CB(skb).portid;
 	struct net *net = info->net;
 	struct sk_buff *skb2;
+	bool reset = false;
 	char *buf;
 
 	if (info->nlh->nlmsg_flags & NLM_F_DUMP) {
 		struct netlink_dump_control c = {
-			.start = nf_tables_dumpreset_obj_start,
-			.dump = nf_tables_dumpreset_obj,
+			.start = nf_tables_dump_obj_start,
+			.dump = nf_tables_dump_obj,
 			.done = nf_tables_dump_obj_done,
 			.module = THIS_MODULE,
 			.data = (void *)nla,
@@ -8706,18 +8544,16 @@ static int nf_tables_getobj_reset(struct sk_buff *skb,
 		return nft_netlink_dump_start_rcu(info->sk, skb, info->nlh, &c);
 	}
 
-	if (!try_module_get(THIS_MODULE))
-		return -EINVAL;
-	rcu_read_unlock();
-	mutex_lock(&nft_net->commit_mutex);
-	skb2 = nf_tables_getobj_single(portid, info, nla, true);
-	mutex_unlock(&nft_net->commit_mutex);
-	rcu_read_lock();
-	module_put(THIS_MODULE);
+	if (NFNL_MSG_TYPE(info->nlh->nlmsg_type) == NFT_MSG_GETOBJ_RESET)
+		reset = true;
 
+	skb2 = nf_tables_getobj_single(portid, info, nla, reset);
 	if (IS_ERR(skb2))
 		return PTR_ERR(skb2);
 
+	if (!reset)
+		return nfnetlink_unicast(skb2, net, NETLINK_CB(skb).portid);
+
 	buf = kasprintf(GFP_ATOMIC, "%.*s:%u",
 			nla_len(nla[NFTA_OBJ_TABLE]),
 			(char *)nla_data(nla[NFTA_OBJ_TABLE]),
@@ -10035,7 +9871,7 @@ static const struct nfnl_callback nf_tables_cb[NFT_MSG_MAX] = {
 		.policy		= nft_rule_policy,
 	},
 	[NFT_MSG_GETRULE_RESET] = {
-		.call		= nf_tables_getrule_reset,
+		.call		= nf_tables_getrule,
 		.type		= NFNL_CB_RCU,
 		.attr_count	= NFTA_RULE_MAX,
 		.policy		= nft_rule_policy,
@@ -10089,7 +9925,7 @@ static const struct nfnl_callback nf_tables_cb[NFT_MSG_MAX] = {
 		.policy		= nft_set_elem_list_policy,
 	},
 	[NFT_MSG_GETSETELEM_RESET] = {
-		.call		= nf_tables_getsetelem_reset,
+		.call		= nf_tables_getsetelem,
 		.type		= NFNL_CB_RCU,
 		.attr_count	= NFTA_SET_ELEM_LIST_MAX,
 		.policy		= nft_set_elem_list_policy,
@@ -10135,7 +9971,7 @@ static const struct nfnl_callback nf_tables_cb[NFT_MSG_MAX] = {
 		.policy		= nft_obj_policy,
 	},
 	[NFT_MSG_GETOBJ_RESET] = {
-		.call		= nf_tables_getobj_reset,
+		.call		= nf_tables_getobj,
 		.type		= NFNL_CB_RCU,
 		.attr_count	= NFTA_OBJ_MAX,
 		.policy		= nft_obj_policy,
Signature · 1 line
2.51.0
author maintainer
#668 lore raw

PATCH 664/781 netfilter: nf_conntrack_h323: dont pass uninitialised l3num value

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Florian Westphal <[email protected]>

[ Upstream commit a6d28eb8efe96b3e35c92efdf1bfacb0cccf541f ]

Mihail Milev reports: Error: UNINIT (CWE-457):
net/netfilter/nf_conntrack_h323_main.c:1189:2: var_decl:
Declaring variable "tuple" without initializer.
net/netfilter/nf_conntrack_h323_main.c:1197:2:
uninit_use_in_call: Using uninitialized value "tuple.src.l3num" when calling "__nf_ct_expect_find".
net/netfilter/nf_conntrack_expect.c:142:2:

	read_value: Reading value "tuple->src.l3num" when calling "nf_ct_expect_dst_hash".
  1195|   	tuple.dst.protonum = IPPROTO_TCP;
  1196|
  1197|-> 	exp = __nf_ct_expect_find(net, nf_ct_zone(ct), &tuple);
  1198|   	if (exp && exp->master == ct)
  1199|   		return exp;

Switch this to a C99 initialiser and set the l3num value.

Fixes f587de0e2feb ("[NETFILTER]: nf_conntrack/nf_nat: add H.323 helper port")
---
 net/netfilter/nf_conntrack_h323_main.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)
net/netfilter/nf_conntrack_h323_main.c +5 -5
index 14f73872f6477..e35814d68ce30 100644
@@ -1186,13 +1186,13 @@ static struct nf_conntrack_expect *find_expect(struct nf_conn *ct,
 {
 	struct net *net = nf_ct_net(ct);
 	struct nf_conntrack_expect *exp;
-	struct nf_conntrack_tuple tuple;
+	struct nf_conntrack_tuple tuple = {
+		.src.l3num = nf_ct_l3num(ct),
+		.dst.protonum = IPPROTO_TCP,
+		.dst.u.tcp.port = port,
+	};
 
-	memset(&tuple.src.u3, 0, sizeof(tuple.src.u3));
-	tuple.src.u.tcp.port = 0;
 	memcpy(&tuple.dst.u3, addr, sizeof(tuple.dst.u3));
-	tuple.dst.u.tcp.port = port;
-	tuple.dst.protonum = IPPROTO_TCP;
 
 	exp = __nf_ct_expect_find(net, nf_ct_zone(ct), &tuple);
 	if (exp && exp->master == ct)
Signature · 1 line
2.51.0
author maintainer
#669 lore raw

PATCH 665/781 ipvs: skip ipv6 extension headers for csum checks

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Julian Anastasov <[email protected]>

[ Upstream commit 05cfe9863ef049d98141dc2969eefde72fb07625 ]

Protocol checksum validation fails for IPv6 if there are extension headers before the protocol header. iph->len already contains its offset, so use it to fix the problem.

Fixes 2906f66a5682 ("ipvs: SCTP Trasport Loadbalancing Support")
Fixes 0bbdd42b7efa ("IPVS: Extend protocol DNAT/SNAT and state handlers")
---
 net/netfilter/ipvs/ip_vs_proto_sctp.c | 18 ++++++------------
 net/netfilter/ipvs/ip_vs_proto_tcp.c  | 21 +++++++--------------
 net/netfilter/ipvs/ip_vs_proto_udp.c  | 20 +++++++-------------
 3 files changed, 20 insertions(+), 39 deletions(-)
net/netfilter/ipvs/ip_vs_proto_sctp.c +6 -12
index 83e452916403d..63c78a1f3918a 100644
@@ -10,7 +10,8 @@
 #include <net/ip_vs.h>
 
 static int
-sctp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp);
+sctp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
+		unsigned int sctphoff);
 
 static int
 sctp_conn_schedule(struct netns_ipvs *ipvs, int af, struct sk_buff *skb,
@@ -108,7 +109,7 @@ sctp_snat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
 		int ret;
 
 		/* Some checks before mangling */
-		if (!sctp_csum_check(cp->af, skb, pp))
+		if (!sctp_csum_check(cp->af, skb, pp, sctphoff))
 			return 0;
 
 		/* Call application helper if needed */
@@ -156,7 +157,7 @@ sctp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
 		int ret;
 
 		/* Some checks before mangling */
-		if (!sctp_csum_check(cp->af, skb, pp))
+		if (!sctp_csum_check(cp->af, skb, pp, sctphoff))
 			return 0;
 
 		/* Call application helper if needed */
@@ -185,19 +186,12 @@ sctp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
 }
 
 static int
-sctp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp)
+sctp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
+		unsigned int sctphoff)
 {
-	unsigned int sctphoff;
 	struct sctphdr *sh;
 	__le32 cmp, val;
 
-#ifdef CONFIG_IP_VS_IPV6
-	if (af == AF_INET6)
-		sctphoff = sizeof(struct ipv6hdr);
-	else
-#endif
-		sctphoff = ip_hdrlen(skb);
-
 	sh = (struct sctphdr *)(skb->data + sctphoff);
 	cmp = sh->checksum;
 	val = sctp_compute_cksum(skb, sctphoff);
net/netfilter/ipvs/ip_vs_proto_tcp.c +7 -14
index f68a1533ee455..8cc0a8ce62411 100644
@@ -28,7 +28,8 @@
 #include <net/ip_vs.h>
 
 static int
-tcp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp);
+tcp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
+	       unsigned int tcphoff);
 
 static int
 tcp_conn_schedule(struct netns_ipvs *ipvs, int af, struct sk_buff *skb,
@@ -165,7 +166,7 @@ tcp_snat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
 		int ret;
 
 		/* Some checks before mangling */
-		if (!tcp_csum_check(cp->af, skb, pp))
+		if (!tcp_csum_check(cp->af, skb, pp, tcphoff))
 			return 0;
 
 		/* Call application helper if needed */
@@ -243,7 +244,7 @@ tcp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
 		int ret;
 
 		/* Some checks before mangling */
-		if (!tcp_csum_check(cp->af, skb, pp))
+		if (!tcp_csum_check(cp->af, skb, pp, tcphoff))
 			return 0;
 
 		/*
@@ -300,17 +301,9 @@ tcp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
 
 
 static int
-tcp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp)
+tcp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
+	       unsigned int tcphoff)
 {
-	unsigned int tcphoff;
-
-#ifdef CONFIG_IP_VS_IPV6
-	if (af == AF_INET6)
-		tcphoff = sizeof(struct ipv6hdr);
-	else
-#endif
-		tcphoff = ip_hdrlen(skb);
-
 	switch (skb->ip_summed) {
 	case CHECKSUM_NONE:
 		skb->csum = skb_checksum(skb, tcphoff, skb->len - tcphoff, 0);
@@ -321,7 +314,7 @@ tcp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp)
 			if (csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
 					    &ipv6_hdr(skb)->daddr,
 					    skb->len - tcphoff,
-					    ipv6_hdr(skb)->nexthdr,
+					    IPPROTO_TCP,
 					    skb->csum)) {
 				IP_VS_DBG_RL_PKT(0, af, pp, skb, 0,
 						 "Failed checksum for");
net/netfilter/ipvs/ip_vs_proto_udp.c +7 -13
index 0f0107c80dd23..f9de632e38cdd 100644
@@ -24,7 +24,8 @@
 #include <net/ip6_checksum.h>
 
 static int
-udp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp);
+udp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
+	       unsigned int udphoff);
 
 static int
 udp_conn_schedule(struct netns_ipvs *ipvs, int af, struct sk_buff *skb,
@@ -154,7 +155,7 @@ udp_snat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
 		int ret;
 
 		/* Some checks before mangling */
-		if (!udp_csum_check(cp->af, skb, pp))
+		if (!udp_csum_check(cp->af, skb, pp, udphoff))
 			return 0;
 
 		/*
@@ -237,7 +238,7 @@ udp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
 		int ret;
 
 		/* Some checks before mangling */
-		if (!udp_csum_check(cp->af, skb, pp))
+		if (!udp_csum_check(cp->af, skb, pp, udphoff))
 			return 0;
 
 		/*
@@ -296,17 +297,10 @@ udp_dnat_handler(struct sk_buff *skb, struct ip_vs_protocol *pp,
 
 
 static int
-udp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp)
+udp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp,
+	       unsigned int udphoff)
 {
 	struct udphdr _udph, *uh;
-	unsigned int udphoff;
-
-#ifdef CONFIG_IP_VS_IPV6
-	if (af == AF_INET6)
-		udphoff = sizeof(struct ipv6hdr);
-	else
-#endif
-		udphoff = ip_hdrlen(skb);
 
 	uh = skb_header_pointer(skb, udphoff, sizeof(_udph), &_udph);
 	if (uh == NULL)
@@ -324,7 +318,7 @@ udp_csum_check(int af, struct sk_buff *skb, struct ip_vs_protocol *pp)
 				if (csum_ipv6_magic(&ipv6_hdr(skb)->saddr,
 						    &ipv6_hdr(skb)->daddr,
 						    skb->len - udphoff,
-						    ipv6_hdr(skb)->nexthdr,
+						    IPPROTO_UDP,
 						    skb->csum)) {
 					IP_VS_DBG_RL_PKT(0, af, pp, skb, 0,
 							 "Failed checksum for");
Signature · 1 line
2.51.0
author maintainer
#670 lore raw

PATCH 666/781 ipvs: do not keep dest_dst if dev is going down

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Julian Anastasov <[email protected]>

[ Upstream commit 8fde939b0206afc1d5846217a01a16b9bc8c7896 ]

There is race between the netdev notifier ip_vs_dst_event() and the code that caches dst with dev that is going down. As the FIB can be notified for the closed device after our handler finishes, it is possible valid route to be returned and cached resuling in a leaked dev reference until the dest is not removed.

To prevent new dest_dst to be attached to dest just after the handler dropped the old one, add a netif_running() check to make sure the notifier handler is not currently running for device that is closing.

Fixes 7a4f0761fce3 ("IPVS: init and cleanup restructuring")
---
 net/netfilter/ipvs/ip_vs_xmit.c | 46 ++++++++++++++++++++++++++-------
 1 file changed, 36 insertions(+), 10 deletions(-)
net/netfilter/ipvs/ip_vs_xmit.c +36 -10
index 64c697212578a..124f779424b0f 100644
@@ -294,6 +294,12 @@ static inline bool decrement_ttl(struct netns_ipvs *ipvs,
 	return true;
 }
 
+/* rt has device that is down */
+static bool rt_dev_is_down(const struct net_device *dev)
+{
+	return dev && !netif_running(dev);
+}
+
 /* Get route to destination or remote server */
 static int
 __ip_vs_get_out_rt(struct netns_ipvs *ipvs, int skb_af, struct sk_buff *skb,
@@ -309,9 +315,11 @@ __ip_vs_get_out_rt(struct netns_ipvs *ipvs, int skb_af, struct sk_buff *skb,
 
 	if (dest) {
 		dest_dst = __ip_vs_dst_check(dest);
-		if (likely(dest_dst))
+		if (likely(dest_dst)) {
 			rt = dst_rtable(dest_dst->dst_cache);
-		else {
+			if (ret_saddr)
+				*ret_saddr = dest_dst->dst_saddr.ip;
+		} else {
 			dest_dst = ip_vs_dest_dst_alloc();
 			spin_lock_bh(&dest->dst_lock);
 			if (!dest_dst) {
@@ -327,14 +335,22 @@ __ip_vs_get_out_rt(struct netns_ipvs *ipvs, int skb_af, struct sk_buff *skb,
 				ip_vs_dest_dst_free(dest_dst);
 				goto err_unreach;
 			}
-			__ip_vs_dst_set(dest, dest_dst, &rt->dst, 0);
+			/* It is forbidden to attach dest->dest_dst if
+			 * device is going down.
+			 */
+			if (!rt_dev_is_down(dst_dev_rcu(&rt->dst)))
+				__ip_vs_dst_set(dest, dest_dst, &rt->dst, 0);
+			else
+				noref = 0;
 			spin_unlock_bh(&dest->dst_lock);
 			IP_VS_DBG(10, "new dst %pI4, src %pI4, refcnt=%d\n",
 				  &dest->addr.ip, &dest_dst->dst_saddr.ip,
 				  rcuref_read(&rt->dst.__rcuref));
+			if (ret_saddr)
+				*ret_saddr = dest_dst->dst_saddr.ip;
+			if (!noref)
+				ip_vs_dest_dst_free(dest_dst);
 		}
-		if (ret_saddr)
-			*ret_saddr = dest_dst->dst_saddr.ip;
 	} else {
 		noref = 0;
 
@@ -471,9 +487,11 @@ __ip_vs_get_out_rt_v6(struct netns_ipvs *ipvs, int skb_af, struct sk_buff *skb,
 
 	if (dest) {
 		dest_dst = __ip_vs_dst_check(dest);
-		if (likely(dest_dst))
+		if (likely(dest_dst)) {
 			rt = dst_rt6_info(dest_dst->dst_cache);
-		else {
+			if (ret_saddr)
+				*ret_saddr = dest_dst->dst_saddr.in6;
+		} else {
 			u32 cookie;
 
 			dest_dst = ip_vs_dest_dst_alloc();
@@ -494,14 +512,22 @@ __ip_vs_get_out_rt_v6(struct netns_ipvs *ipvs, int skb_af, struct sk_buff *skb,
 			}
 			rt = dst_rt6_info(dst);
 			cookie = rt6_get_cookie(rt);
-			__ip_vs_dst_set(dest, dest_dst, &rt->dst, cookie);
+			/* It is forbidden to attach dest->dest_dst if
+			 * device is going down.
+			 */
+			if (!rt_dev_is_down(dst_dev_rcu(&rt->dst)))
+				__ip_vs_dst_set(dest, dest_dst, &rt->dst, cookie);
+			else
+				noref = 0;
 			spin_unlock_bh(&dest->dst_lock);
 			IP_VS_DBG(10, "new dst %pI6, src %pI6, refcnt=%d\n",
 				  &dest->addr.in6, &dest_dst->dst_saddr.in6,
 				  rcuref_read(&rt->dst.__rcuref));
+			if (ret_saddr)
+				*ret_saddr = dest_dst->dst_saddr.in6;
+			if (!noref)
+				ip_vs_dest_dst_free(dest_dst);
 		}
-		if (ret_saddr)
-			*ret_saddr = dest_dst->dst_saddr.in6;
 	} else {
 		noref = 0;
 		dst = __ip_vs_route_output_v6(net, daddr, ret_saddr, do_xfrm,
Signature · 1 line
2.51.0
author maintainer
#671 lore raw

PATCH 667/781 net: remove WARN_ON_ONCE when accessing forward path array

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Pablo Neira Ayuso <[email protected]>

[ Upstream commit 008e7a7c293b30bc43e4368dac6ea3808b75a572 ]

Although unlikely, recent support for IPIP tunnels increases chances of reaching this WARN_ON_ONCE if userspace manages to build a sufficiently long forward path.

Remove it.

Fixes ddb94eafab8b ("net: resolve forwarding path from virtual netdevice and HW destination address")
---
 net/core/dev.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
net/core/dev.c +1 -1
index ccef685023c29..f5e4040e08399 100644
@@ -738,7 +738,7 @@ static struct net_device_path *dev_fwd_path(struct net_device_path_stack *stack)
 {
 	int k = stack->num_paths++;
 
-	if (WARN_ON_ONCE(k >= NET_DEVICE_PATH_STACK_MAX))
+	if (k >= NET_DEVICE_PATH_STACK_MAX)
 		return NULL;
 
 	return &stack->path[k];
Signature · 1 line
2.51.0
author maintainer
#672 lore raw

PATCH 668/781 netfilter: nf_tables: fix use-after-free in nf_tables_addchain()

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Inseo An <[email protected]>

[ Upstream commit 71e99ee20fc3f662555118cf1159443250647533 ]

nf_tables_addchain() publishes the chain to table->chains via list_add_tail_rcu() (in nft_chain_add()) before registering hooks. If nf_tables_register_hook() then fails, the error path calls nft_chain_del() (list_del_rcu()) followed by nf_tables_chain_destroy() with no RCU grace period in between.

This creates two use-after-free conditions:

1) Control-plane: nf_tables_dump_chains() traverses table->chains under rcu_read_lock(). A concurrent dump can still be walking the chain when the error path frees it.

2) Packet path: for NFPROTO_INET, nf_register_net_hook() briefly installs the IPv4 hook before IPv6 registration fails. Packets entering nft_do_chain() via the transient IPv4 hook can still be dereferencing chain->blob_gen_X when the error path frees the chain.

Add synchronize_rcu() between nft_chain_del() and the chain destroy so that all RCU readers -- both dump threads and in-flight packet evaluation -- have finished before the chain is freed.

Fixes 91c7b38dc9f0 ("netfilter: nf_tables: use new transaction infrastructure to handle chain")
---
 net/netfilter/nf_tables_api.c | 1 +
 1 file changed, 1 insertion(+)
net/netfilter/nf_tables_api.c +1 -0
index f807183235e79..8dae197c7fafb 100644
@@ -2822,6 +2822,7 @@ static int nf_tables_addchain(struct nft_ctx *ctx, u8 family, u8 policy,
 
 err_register_hook:
 	nft_chain_del(chain);
+	synchronize_rcu();
 err_chain_add:
 	nft_trans_destroy(trans);
 err_trans:
Signature · 1 line
2.51.0
author maintainer
#673 lore raw

PATCH 669/781 ipv6: fix a race in ip6_sock_set_v6only()

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Eric Dumazet <[email protected]>

[ Upstream commit 452a3eee22c57a5786ae6db5c97f3b0ec13bb3b7 ]

It is unlikely that this function will be ever called with isk->inet_num being not zero.

Perform the check on isk->inet_num inside the locked section for complete safety.

---
 include/net/ipv6.h | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)
include/net/ipv6.h +7 -4
index 74fbf1ad8065a..6a933690e0ff5 100644
@@ -1280,12 +1280,15 @@ int ipv6_sock_mc_drop(struct sock *sk, int ifindex,
 
 static inline int ip6_sock_set_v6only(struct sock *sk)
 {
-	if (inet_sk(sk)->inet_num)
-		return -EINVAL;
+	int ret = 0;
+
 	lock_sock(sk);
-	sk->sk_ipv6only = true;
+	if (inet_sk(sk)->inet_num)
+		ret = -EINVAL;
+	else
+		sk->sk_ipv6only = true;
 	release_sock(sk);
-	return 0;
+	return ret;
 }
 
 static inline void ip6_sock_set_recverr(struct sock *sk)
Signature · 1 line
2.51.0
author maintainer
#674 lore raw

PATCH 670/781 bpftool: Fix truncated netlink dumps

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Jakub Kicinski <[email protected]>

[ Upstream commit 3b39d73cc3379360a33eb583b17f21fe55e1288e ]

Netlink requires that the recv buffer used during dumps is at least min(PAGE_SIZE, 8k) (see the man page). Otherwise the messages will get truncated. Make sure bpftool follows this requirement, avoid missing information on systems with large pages.

Fixes 7084566a236f ("tools/bpftool: Remove libbpf_internal.h usage in bpftool")
---
 tools/bpf/bpftool/net.c | 5 ++++-
 tools/lib/bpf/netlink.c | 4 +++-
 2 files changed, 7 insertions(+), 2 deletions(-)
tools/bpf/bpftool/net.c +4 -1
index cfc6f944f7c33..1a06b0b5eef35 100644
@@ -156,7 +156,7 @@ static int netlink_recv(int sock, __u32 nl_pid, __u32 seq,
 	bool multipart = true;
 	struct nlmsgerr *err;
 	struct nlmsghdr *nh;
-	char buf[4096];
+	char buf[8192];
 	int len, ret;
 
 	while (multipart) {
@@ -201,6 +201,9 @@ static int netlink_recv(int sock, __u32 nl_pid, __u32 seq,
 					return ret;
 			}
 		}
+
+		if (len)
+			p_err("Invalid message or trailing data in Netlink response: %d bytes left", len);
 	}
 	ret = 0;
 done:
tools/lib/bpf/netlink.c +3 -1
index c997e69d507fe..c9a78fb16f115 100644
@@ -143,7 +143,7 @@ static int libbpf_netlink_recv(int sock, __u32 nl_pid, int seq,
 	struct nlmsghdr *nh;
 	int len, ret;
 
-	ret = alloc_iov(&iov, 4096);
+	ret = alloc_iov(&iov, 8192);
 	if (ret)
 		goto done;
 
@@ -212,6 +212,8 @@ static int libbpf_netlink_recv(int sock, __u32 nl_pid, int seq,
 				}
 			}
 		}
+		if (len)
+			pr_warn("Invalid message or trailing data in Netlink response: %d bytes left\n", len);
 	}
 	ret = 0;
 done:
Signature · 1 line
2.51.0
author maintainer
#675 lore raw

PATCH 671/781 net: psp: select CONFIG_SKB_EXTENSIONS

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Arnd Bergmann <[email protected]>

[ Upstream commit 6e980df452169f82674f2e650079c1fe0aee343d ]

psp now uses skb extensions, failing to build when that is disabled:

In file included from include/net/psp.h:7,

                 from net/psp/psp_sock.c:9:
include/net/psp/functions.h: In function '__psp_skb_coalesce_diff':
include/net/psp/functions.h:60:13: error: implicit declaration of function 'skb_ext_find'; did you mean 'skb_ext_copy'? [-Wimplicit-function-declaration]
   60 |         a = skb_ext_find(one, SKB_EXT_PSP);
      |             ^~~~~~~~~~~~
      |             skb_ext_copy
include/net/psp/functions.h:60:31: error: 'SKB_EXT_PSP' undeclared (first use in this function)
   60 |         a = skb_ext_find(one, SKB_EXT_PSP);
      |                               ^~~~~~~~~~~

include/net/psp/functions.h:60:31: note: each undeclared identifier is reported only once for each function it appears in include/net/psp/functions.h: In function '__psp_sk_rx_policy_check':
include/net/psp/functions.h:94:53: error: 'SKB_EXT_PSP' undeclared (first use in this function)
94 | struct psp_skb_ext *pse = skb_ext_find(skb, SKB_EXT_PSP);
| ^~~~~~~~~~~
net/psp/psp_sock.c: In function 'psp_sock_recv_queue_check':
net/psp/psp_sock.c:164:41: error: 'SKB_EXT_PSP' undeclared (first use in this function)
164 | pse = skb_ext_find(skb, SKB_EXT_PSP);
| ^~~~~~~~~~~

Select the Kconfig symbol as we do from its other users.

---
 net/psp/Kconfig | 1 +
 1 file changed, 1 insertion(+)
net/psp/Kconfig +1 -0
index 371e8771f3bd3..84d6b0f254606 100644
@@ -6,6 +6,7 @@ config INET_PSP
 	bool "PSP Security Protocol support"
 	depends on INET
 	select SKB_DECRYPTED
+	select SKB_EXTENSIONS
 	select SOCK_VALIDATE_XMIT
 	help
 	Enable kernel support for the PSP Security Protocol (PSP).
Signature · 1 line
2.51.0
author maintainer
#676 lore raw

PATCH 672/781 net: do not delay zero-copy skbs in skb_attempt_defer_free()

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Eric Dumazet <[email protected]>

[ Upstream commit 0943404b1f3b178e1e54386dadcbf4f2729c7762 ]

After the blamed commit, TCP tx zero copy notifications could be arbitrarily delayed and cause regressions in applications waiting for them.

---
 net/core/skbuff.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)
net/core/skbuff.c +6 -1
index 61746c2b95f63..fa6209f45de9c 100644
@@ -7231,10 +7231,15 @@ void skb_attempt_defer_free(struct sk_buff *skb)
 {
 	struct skb_defer_node *sdn;
 	unsigned long defer_count;
-	int cpu = skb->alloc_cpu;
 	unsigned int defer_max;
 	bool kick;
+	int cpu;
 
+	/* zero copy notifications should not be delayed. */
+	if (skb_zcopy(skb))
+		goto nodefer;
+
+	cpu = skb->alloc_cpu;
 	if (cpu == raw_smp_processor_id() ||
 	    WARN_ON_ONCE(cpu >= nr_cpu_ids) ||
 	    !cpu_online(cpu)) {
Signature · 1 line
2.51.0
author maintainer
#677 lore raw

PATCH 673/781 dpll: zl3073x: Fix ref frequency setting

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Ivan Vecera <[email protected]>

[ Upstream commit a047497f952831e377564b606dcb74a7cb309384 ]

The frequency for an input reference is computed as:

frequency = freq_base * freq_mult * freq_ratio_m / freq_ratio_n

Before commit 5bc02b190a3fb ("dpll: zl3073x: Cache all reference properties in zl3073x_ref"), zl3073x_dpll_input_pin_frequency_set() explicitly wrote 1 to both the REF_RATIO_M and REF_RATIO_N hardware registers whenever a new frequency was set. This ensured the FEC ratio was always reset to 1:1 alongside the new base/multiplier values.

The refactoring in that commit introduced zl3073x_ref_freq_set() to update the cached ref state, but this helper only sets freq_base and freq_mult without resetting freq_ratio_m and freq_ratio_n to 1. Because zl3073x_ref_state_set() uses a compare-and-write strategy, unchanged ratio fields are never written to the hardware. If the device previously had non-unity FEC ratio values, they remain in effect after a frequency change, resulting in an incorrect computed frequency.

Explicitly set freq_ratio_m and freq_ratio_n to 1 in zl3073x_ref_freq_set() to restore the original behavior.

Fixes 5bc02b190a3fb ("dpll: zl3073x: Cache all reference properties in zl3073x_ref")
---
 drivers/dpll/zl3073x/ref.h | 2 ++
 1 file changed, 2 insertions(+)
drivers/dpll/zl3073x/ref.h +2 -0
index efc7f59cd9f9c..0d8618f5ce8df 100644
@@ -91,6 +91,8 @@ zl3073x_ref_freq_set(struct zl3073x_ref *ref, u32 freq)
 
 	ref->freq_base = base;
 	ref->freq_mult = mult;
+	ref->freq_ratio_m = 1;
+	ref->freq_ratio_n = 1;
 
 	return 0;
 }
Signature · 1 line
2.51.0
author maintainer
#678 lore raw

PATCH 674/781 ping: annotate data-races in ping_lookup()

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Eric Dumazet <[email protected]>

[ Upstream commit ad5dfde2a5733aaf652ea3e40c8c5e071e935901 ]

isk->inet_num, isk->inet_rcv_saddr and sk->sk_bound_dev_if are read locklessly in ping_lookup().

Add READ_ONCE()/WRITE_ONCE() annotations.

The race on isk->inet_rcv_saddr is probably coming from IPv6 support, but does not deserve a specific backport.

Fixes dbca1596bbb0 ("ping: convert to RCU lookups, get rid of rwlock")
---
 net/ipv4/ping.c | 31 +++++++++++++++++++------------
 1 file changed, 19 insertions(+), 12 deletions(-)
net/ipv4/ping.c +19 -12
index cfbd563498e85..0fec4e5645667 100644
@@ -148,7 +148,7 @@ void ping_unhash(struct sock *sk)
 	pr_debug("ping_unhash(isk=%p,isk->num=%u)\n", isk, isk->inet_num);
 	spin_lock(&ping_table.lock);
 	if (sk_del_node_init_rcu(sk)) {
-		isk->inet_num = 0;
+		WRITE_ONCE(isk->inet_num, 0);
 		isk->inet_sport = 0;
 		sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
 	}
@@ -181,31 +181,35 @@ static struct sock *ping_lookup(struct net *net, struct sk_buff *skb, u16 ident)
 	}
 
 	sk_for_each_rcu(sk, hslot) {
+		int bound_dev_if;
+
 		if (!net_eq(sock_net(sk), net))
 			continue;
 		isk = inet_sk(sk);
 
 		pr_debug("iterate\n");
-		if (isk->inet_num != ident)
+		if (READ_ONCE(isk->inet_num) != ident)
 			continue;
 
+		bound_dev_if = READ_ONCE(sk->sk_bound_dev_if);
 		if (skb->protocol == htons(ETH_P_IP) &&
 		    sk->sk_family == AF_INET) {
+			__be32 rcv_saddr = READ_ONCE(isk->inet_rcv_saddr);
+
 			pr_debug("found: %p: num=%d, daddr=%pI4, dif=%d\n", sk,
-				 (int) isk->inet_num, &isk->inet_rcv_saddr,
-				 sk->sk_bound_dev_if);
+				 ident, &rcv_saddr,
+				 bound_dev_if);
 
-			if (isk->inet_rcv_saddr &&
-			    isk->inet_rcv_saddr != ip_hdr(skb)->daddr)
+			if (rcv_saddr && rcv_saddr != ip_hdr(skb)->daddr)
 				continue;
 #if IS_ENABLED(CONFIG_IPV6)
 		} else if (skb->protocol == htons(ETH_P_IPV6) &&
 			   sk->sk_family == AF_INET6) {
 
 			pr_debug("found: %p: num=%d, daddr=%pI6c, dif=%d\n", sk,
-				 (int) isk->inet_num,
+				 ident,
 				 &sk->sk_v6_rcv_saddr,
-				 sk->sk_bound_dev_if);
+				 bound_dev_if);
 
 			if (!ipv6_addr_any(&sk->sk_v6_rcv_saddr) &&
 			    !ipv6_addr_equal(&sk->sk_v6_rcv_saddr,
@@ -216,8 +220,8 @@ static struct sock *ping_lookup(struct net *net, struct sk_buff *skb, u16 ident)
 			continue;
 		}
 
-		if (sk->sk_bound_dev_if && sk->sk_bound_dev_if != dif &&
-		    sk->sk_bound_dev_if != sdif)
+		if (bound_dev_if && bound_dev_if != dif &&
+		    bound_dev_if != sdif)
 			continue;
 
 		goto exit;
@@ -392,7 +396,9 @@ static void ping_set_saddr(struct sock *sk, struct sockaddr_unsized *saddr)
 	if (saddr->sa_family == AF_INET) {
 		struct inet_sock *isk = inet_sk(sk);
 		struct sockaddr_in *addr = (struct sockaddr_in *) saddr;
-		isk->inet_rcv_saddr = isk->inet_saddr = addr->sin_addr.s_addr;
+
+		isk->inet_saddr = addr->sin_addr.s_addr;
+		WRITE_ONCE(isk->inet_rcv_saddr, addr->sin_addr.s_addr);
 #if IS_ENABLED(CONFIG_IPV6)
 	} else if (saddr->sa_family == AF_INET6) {
 		struct sockaddr_in6 *addr = (struct sockaddr_in6 *) saddr;
@@ -849,7 +855,8 @@ int ping_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int flags,
 	struct sk_buff *skb;
 	int copied, err;
 
-	pr_debug("ping_recvmsg(sk=%p,sk->num=%u)\n", isk, isk->inet_num);
+	pr_debug("ping_recvmsg(sk=%p,sk->num=%u)\n", isk,
+		 READ_ONCE(isk->inet_num));
 
 	err = -EOPNOTSUPP;
 	if (flags & MSG_OOB)
Signature · 1 line
2.51.0
author maintainer
#679 lore raw

PATCH 675/781 selftests: tc_actions: dont dump 2MB of \0 to stdout

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Jakub Kicinski <[email protected]>

[ Upstream commit 32b70e62034aa72f8414ad4e9122cce7ad418c48 ]

Since we started running selftests in NIPA we have been seeing tc_actions.sh generate a soft lockup warning on ~20% of the runs. On the pre-netdev foundation setup it was actually a missed irq splat from the console. Now it's either that or a lockup.

I initially suspected a socket locking issue since the test is exercising local loopback with act_mirred.
After hours of staring at this I noticed in strace that ncat when -o $file is specified _both_ saves the output to the file and still prints it to stdout. Because the file being sent is constructed with:

dd conv=sparse status=none if=/dev/zero bs=1M count=2 of=$mirred

                                ^^^^^^^^^

the data printed is all \0. Most terminals don't display nul characters (and neither does vng output capture save them). But QEMU's serial console still has to poke them thru which is very slow and causes the lockup (if the file is >600kB).

Replace the '-o $file' with '> $file'. This speeds the test up from 2m20s to 18s on debug kernels, and prevents the warnings.

Fixes ca22da2fbd69 ("act_mirred: use the backlog for nested calls to mirred ingress")
---
 tools/testing/selftests/net/forwarding/tc_actions.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
tools/testing/selftests/net/forwarding/tc_actions.sh +1 -1
index ea89e558672db..86edbc7e2489b 100755
@@ -223,7 +223,7 @@ mirred_egress_to_ingress_tcp_test()
 		ip_proto icmp \
 			action drop
 
-	ip vrf exec v$h1 ncat --recv-only -w10 -l -p 12345 -o $mirred_e2i_tf2 &
+	ip vrf exec v$h1 ncat --recv-only -w10 -l -p 12345 > $mirred_e2i_tf2 &
 	local rpid=$!
 	ip vrf exec v$h1 ncat -w1 --send-only 192.0.2.2 12345 <$mirred_e2i_tf1
 	wait -n $rpid
Signature · 1 line
2.51.0
author maintainer
#680 lore raw

PATCH 676/781 macvlan: observe an RCU grace period in macvlan_common_newlink() error path

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Eric Dumazet <[email protected]>

[ Upstream commit e3f000f0dee1bfab52e2e61ca6a3835d9e187e35 ]

valis reported that a race condition still happens after my prior patch.

macvlan_common_newlink() might have made @dev visible before detecting an error, and its caller will directly call free_netdev(dev).

We must respect an RCU period, either in macvlan or the core networking stack.

After adding a temporary mdelay(1000) in macvlan_forward_source_one() to open the race window, valis repro was:

ip link add p1 type veth peer p2
ip link set address 00:00:00:00:00:20 dev p1
ip link set up dev p1
ip link set up dev p2
ip link add mv0 link p2 type macvlan mode source

(ip link add invalid% link p2 type macvlan mode source macaddr add 00:00:00:00:00:20 &) ; sleep 0.5 ; ping -c1 -I p1 1.2.3.4 PING 1.2.3.4 (1.2.3.4): 56 data bytes
RTNETLINK answers: Invalid argument

BUG: KASAN: slab-use-after-free in macvlan_forward_source
(drivers/net/macvlan.c:408 drivers/net/macvlan.c:444)
Read of size 8 at addr ffff888016bb89c0 by task e/175

CPU: 1 UID: 1000 PID: 175 Comm: e Not tainted 6.19.0-rc8+ #33 NONE
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.14.0-2 04/01/2014
Call Trace:
<IRQ>
dump_stack_lvl (lib/dump_stack.c:123)
print_report (mm/kasan/report.c:379 mm/kasan/report.c:482)
? macvlan_forward_source (drivers/net/macvlan.c:408 drivers/net/macvlan.c:444)
kasan_report (mm/kasan/report.c:597)
? macvlan_forward_source (drivers/net/macvlan.c:408 drivers/net/macvlan.c:444)
macvlan_forward_source (drivers/net/macvlan.c:408 drivers/net/macvlan.c:444)

? tasklet_init (kernel/softirq.c:983)
macvlan_handle_frame (drivers/net/macvlan.c:501)

Allocated by task 169:

kasan_save_stack (mm/kasan/common.c:58)
kasan_save_track (./arch/x86/include/asm/current.h:25 mm/kasan/common.c:70 mm/kasan/common.c:79)
__kasan_kmalloc (mm/kasan/common.c:419)
__kvmalloc_node_noprof (./include/linux/kasan.h:263 mm/slub.c:5657 mm/slub.c:7140)
alloc_netdev_mqs (net/core/dev.c:12012)
rtnl_create_link (net/core/rtnetlink.c:3648)
rtnl_newlink (net/core/rtnetlink.c:3830 net/core/rtnetlink.c:3957 net/core/rtnetlink.c:4072)
rtnetlink_rcv_msg (net/core/rtnetlink.c:6958)
netlink_rcv_skb (net/netlink/af_netlink.c:2550)
netlink_unicast (net/netlink/af_netlink.c:1319 net/netlink/af_netlink.c:1344) netlink_sendmsg (net/netlink/af_netlink.c:1894)
__sys_sendto (net/socket.c:727 net/socket.c:742 net/socket.c:2206) __x64_sys_sendto (net/socket.c:2209)
do_syscall_64 (arch/x86/entry/syscall_64.c:63 arch/x86/entry/syscall_64.c:94) entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:131)

Freed by task 169:

kasan_save_stack (mm/kasan/common.c:58) kasan_save_track (./arch/x86/include/asm/current.h:25 mm/kasan/common.c:70 mm/kasan/common.c:79) kasan_save_free_info (mm/kasan/generic.c:587) __kasan_slab_free (mm/kasan/common.c:287)

kfree (mm/slub.c:6674 mm/slub.c:6882)
rtnl_newlink (net/core/rtnetlink.c:3845 net/core/rtnetlink.c:3957

net/core/rtnetlink.c:4072)
rtnetlink_rcv_msg (net/core/rtnetlink.c:6958)
netlink_rcv_skb (net/netlink/af_netlink.c:2550)
netlink_unicast (net/netlink/af_netlink.c:1319 net/netlink/af_netlink.c:1344) netlink_sendmsg (net/netlink/af_netlink.c:1894)
__sys_sendto (net/socket.c:727 net/socket.c:742 net/socket.c:2206) __x64_sys_sendto (net/socket.c:2209)
do_syscall_64 (arch/x86/entry/syscall_64.c:63 arch/x86/entry/syscall_64.c:94) entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:131)

Fixes f8db6475a836 ("macvlan: fix error recovery in macvlan_common_newlink()")
---
 drivers/net/macvlan.c | 5 +++++
 1 file changed, 5 insertions(+)
drivers/net/macvlan.c +5 -0
index c509228be84d1..4433b8e95b6ac 100644
@@ -1572,6 +1572,11 @@ int macvlan_common_newlink(struct net_device *dev,
 		if (create)
 			macvlan_port_destroy(port->dev);
 	}
+	/* @dev might have been made visible before an error was detected.
+	 * Make sure to observe an RCU grace period before our caller
+	 * (rtnl_newlink()) frees it.
+	 */
+	synchronize_net();
 	return err;
 }
 EXPORT_SYMBOL_GPL(macvlan_common_newlink);
Signature · 1 line
2.51.0
author maintainer
#681 lore raw

PATCH 677/781 eth: fbnic: Add validation for MTU changes

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Dimitri Daskalakis <[email protected]>

[ Upstream commit ccd8e87748ad083047d6c8544c5809b7f96cc8df ]

Increasing the MTU beyond the HDS threshold causes the hardware to fragment packets across multiple buffers. If a single-buffer XDP program is attached, the driver will drop all multi-frag frames. While we can't prevent a remote sender from sending non-TCP packets larger than the MTU, this will prevent users from inadvertently breaking new TCP streams.

Traditionally, drivers supported XDP with MTU less than 4Kb (packet per page). Fbnic currently prevents attaching XDP when MTU is too high. But it does not prevent increasing MTU after XDP is attached.

Fixes 1b0a3950dbd4 ("eth: fbnic: Add XDP pass, drop, abort support")
---
 drivers/net/ethernet/meta/fbnic/fbnic_netdev.c | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)
drivers/net/ethernet/meta/fbnic/fbnic_netdev.c +18 -0
index 81c9d5c9a4b2c..e3ca5fcfabef3 100644
@@ -262,6 +262,23 @@ static int fbnic_set_mac(struct net_device *netdev, void *p)
 	return 0;
 }
 
+static int fbnic_change_mtu(struct net_device *dev, int new_mtu)
+{
+	struct fbnic_net *fbn = netdev_priv(dev);
+
+	if (fbnic_check_split_frames(fbn->xdp_prog, new_mtu, fbn->hds_thresh)) {
+		dev_err(&dev->dev,
+			"MTU %d is larger than HDS threshold %d in XDP mode\n",
+			new_mtu, fbn->hds_thresh);
+
+		return -EINVAL;
+	}
+
+	WRITE_ONCE(dev->mtu, new_mtu);
+
+	return 0;
+}
+
 void fbnic_clear_rx_mode(struct fbnic_dev *fbd)
 {
 	struct net_device *netdev = fbd->netdev;
@@ -533,6 +550,7 @@ static const struct net_device_ops fbnic_netdev_ops = {
 	.ndo_start_xmit		= fbnic_xmit_frame,
 	.ndo_features_check	= fbnic_features_check,
 	.ndo_set_mac_address	= fbnic_set_mac,
+	.ndo_change_mtu		= fbnic_change_mtu,
 	.ndo_set_rx_mode	= fbnic_set_rx_mode,
 	.ndo_get_stats64	= fbnic_get_stats64,
 	.ndo_bpf		= fbnic_bpf,
Signature · 1 line
2.51.0
author maintainer
#682 lore raw

PATCH 678/781 icmp: prevent possible overflow in icmp_global_allow()

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Eric Dumazet <[email protected]>

[ Upstream commit 034bbd806298e9ba4197dd1587b0348ee30996ea ]

Following expression can overflow
if sysctl_icmp_msgs_per_sec is big enough.

sysctl_icmp_msgs_per_sec * delta / HZ;

---
 net/ipv4/icmp.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
net/ipv4/icmp.c +2 -1
index a2cff16668d72..471dd862f6639 100644
@@ -248,7 +248,8 @@ bool icmp_global_allow(struct net *net)
 	if (delta < HZ / 50)
 		return false;
 
-	incr = READ_ONCE(net->ipv4.sysctl_icmp_msgs_per_sec) * delta / HZ;
+	incr = READ_ONCE(net->ipv4.sysctl_icmp_msgs_per_sec);
+	incr = div_u64((u64)incr * delta, HZ);
 	if (!incr)
 		return false;
 
Signature · 1 line
2.51.0
author maintainer
#683 lore raw

PATCH 679/781 inet: move icmp_global_{credit,stamp} to a separate cache line

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Eric Dumazet <[email protected]>

[ Upstream commit 87b08913a9ae82082e276d237ece08fc8ee24380 ]

icmp_global_credit was meant to be changed ~1000 times per second, but if an admin sets net.ipv4.icmp_msgs_per_sec to a very high value, icmp_global_credit changes can inflict false sharing to surrounding fields that are read mostly.

Move icmp_global_credit and icmp_global_stamp to a separate cacheline aligned group.

Fixes b056b4cd9178 ("icmp: move icmp_global.credit and icmp_global.stamp to per netns storage")
---
 include/net/netns/ipv4.h | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)
include/net/netns/ipv4.h +7 -2
index 2dbd46fc4734b..8e971c7bf1646 100644
@@ -88,6 +88,12 @@ struct netns_ipv4 {
 	int sysctl_tcp_rcvbuf_low_rtt;
 	__cacheline_group_end(netns_ipv4_read_rx);
 
+	/* ICMP rate limiter hot cache line. */
+	__cacheline_group_begin_aligned(icmp);
+	atomic_t	icmp_global_credit;
+	u32		icmp_global_stamp;
+	__cacheline_group_end_aligned(icmp);
+
 	struct inet_timewait_death_row tcp_death_row;
 	struct udp_table *udp_table;
 
@@ -141,8 +147,7 @@ struct netns_ipv4 {
 	int sysctl_icmp_ratemask;
 	int sysctl_icmp_msgs_per_sec;
 	int sysctl_icmp_msgs_burst;
-	atomic_t icmp_global_credit;
-	u32 icmp_global_stamp;
+
 	u32 ip_rt_min_pmtu;
 	int ip_rt_mtu_expires;
 	int ip_rt_min_advmss;
Signature · 1 line
2.51.0
author maintainer
#684 lore raw

PATCH 680/781 ipv6: icmp: remove obsolete code in icmpv6_xrlim_allow()

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Eric Dumazet <[email protected]>

[ Upstream commit 0201eedb69b24a6be9b7c1716287a89c4dde2320 ]

Following part was needed before the blamed commit, because inet_getpeer_v6() second argument was the prefix.

	/* Give more bandwidth to wider prefixes. */
	if (rt->rt6i_dst.plen < 128)
		tmo >>= ((128 - rt->rt6i_dst.plen)>>5);

Now inet_getpeer_v6() retrieves hosts, we need to remove @tmo adjustement or wider prefixes likes /24 allow 8x more ICMP to be sent for a given ratelimit.

As we had this issue for a while, this patch changes net.ipv6.icmp.ratelimit default value from 1000ms to 100ms to avoid potential regressions.

Also add a READ_ONCE() when reading net->ipv6.sysctl.icmpv6_time.

Fixes fd0273d7939f ("ipv6: Remove external dependency on rt6i_dst and rt6i_src")
Cc Martin KaFai Lau <[email protected]>
---
 Documentation/networking/ip-sysctl.rst | 7 ++++---
 net/ipv6/af_inet6.c                    | 2 +-
 net/ipv6/icmp.c                        | 7 +------
 3 files changed, 6 insertions(+), 10 deletions(-)
Documentation/networking/ip-sysctl.rst +4 -3
index bc9a01606daf5..2c65d57103fb1 100644
@@ -3232,12 +3232,13 @@ enhanced_dad - BOOLEAN
 ===========
 
 ratelimit - INTEGER
-	Limit the maximal rates for sending ICMPv6 messages.
+	Limit the maximal rates for sending ICMPv6 messages to a particular
+	peer.
 
 	0 to disable any limiting,
-	otherwise the minimal space between responses in milliseconds.
+	otherwise the space between responses in milliseconds.
 
-	Default: 1000
+	Default: 100
 
 ratemask - list of comma separated ranges
 	For ICMPv6 message types matching the ranges in the ratemask, limit
net/ipv6/af_inet6.c +1 -1
index b705751eb73c6..d3534bdb805da 100644
@@ -955,7 +955,7 @@ static int __net_init inet6_net_init(struct net *net)
 	int err = 0;
 
 	net->ipv6.sysctl.bindv6only = 0;
-	net->ipv6.sysctl.icmpv6_time = 1*HZ;
+	net->ipv6.sysctl.icmpv6_time = HZ / 10;
 	net->ipv6.sysctl.icmpv6_echo_ignore_all = 0;
 	net->ipv6.sysctl.icmpv6_echo_ignore_multicast = 0;
 	net->ipv6.sysctl.icmpv6_echo_ignore_anycast = 0;
net/ipv6/icmp.c +1 -6
index a77f3113ef23b..55b1aa75ab802 100644
@@ -217,14 +217,9 @@ static bool icmpv6_xrlim_allow(struct sock *sk, u8 type,
 	} else if (dev && (dev->flags & IFF_LOOPBACK)) {
 		res = true;
 	} else {
-		struct rt6_info *rt = dst_rt6_info(dst);
-		int tmo = net->ipv6.sysctl.icmpv6_time;
+		int tmo = READ_ONCE(net->ipv6.sysctl.icmpv6_time);
 		struct inet_peer *peer;
 
-		/* Give more bandwidth to wider prefixes. */
-		if (rt->rt6i_dst.plen < 128)
-			tmo >>= ((128 - rt->rt6i_dst.plen)>>5);
-
 		peer = inet_getpeer_v6(net->ipv6.peers, &fl6->daddr);
 		res = inet_peer_xrlim_allow(peer, tmo);
 	}
Signature · 1 line
2.51.0
author maintainer
#685 lore raw

PATCH 681/781 octeontx2-af: Fix default entries mcam entry action

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Hariprasad Kelam <[email protected]>

[ Upstream commit 45be47bf5d7db0f762a93e9c0ede6cb3c91edf3b ]

As per design, AF should update the default MCAM action only when mcam_index is -1. A bug in the previous patch caused default entries to be changed even when the request was not for them.

---
 .../ethernet/marvell/octeontx2/af/rvu_npc.c   | 41 ++++++++++---------
 1 file changed, 22 insertions(+), 19 deletions(-)
drivers/net/ethernet/marvell/octeontx2/af/rvu_npc.c +22 -19
index c7c70429eb6c1..8658cb2143dfc 100644
@@ -1042,32 +1042,35 @@ void rvu_npc_update_flowkey_alg_idx(struct rvu *rvu, u16 pcifunc, int nixlf,
 	rvu_write64(rvu, blkaddr,
 		    NPC_AF_MCAMEX_BANKX_ACTION(index, bank), *(u64 *)&action);
 
-	/* update the VF flow rule action with the VF default entry action */
-	if (mcam_index < 0)
-		npc_update_vf_flow_entry(rvu, mcam, blkaddr, pcifunc,
-					 *(u64 *)&action);
-
 	/* update the action change in default rule */
 	pfvf = rvu_get_pfvf(rvu, pcifunc);
 	if (pfvf->def_ucast_rule)
 		pfvf->def_ucast_rule->rx_action = action;
 
-	index = npc_get_nixlf_mcam_index(mcam, pcifunc,
-					 nixlf, NIXLF_PROMISC_ENTRY);
+	if (mcam_index < 0) {
+		/* update the VF flow rule action with the VF default
+		 * entry action
+		 */
+		npc_update_vf_flow_entry(rvu, mcam, blkaddr, pcifunc,
+					 *(u64 *)&action);
 
-	/* If PF's promiscuous entry is enabled,
-	 * Set RSS action for that entry as well
-	 */
-	npc_update_rx_action_with_alg_idx(rvu, action, pfvf, index, blkaddr,
-					  alg_idx);
+		index = npc_get_nixlf_mcam_index(mcam, pcifunc,
+						 nixlf, NIXLF_PROMISC_ENTRY);
 
-	index = npc_get_nixlf_mcam_index(mcam, pcifunc,
-					 nixlf, NIXLF_ALLMULTI_ENTRY);
-	/* If PF's allmulti  entry is enabled,
-	 * Set RSS action for that entry as well
-	 */
-	npc_update_rx_action_with_alg_idx(rvu, action, pfvf, index, blkaddr,
-					  alg_idx);
+		/* If PF's promiscuous  entry is enabled,
+		 * Set RSS action for that entry as well
+		 */
+		npc_update_rx_action_with_alg_idx(rvu, action, pfvf, index,
+						  blkaddr, alg_idx);
+
+		index = npc_get_nixlf_mcam_index(mcam, pcifunc,
+						 nixlf, NIXLF_ALLMULTI_ENTRY);
+		/* If PF's allmulti  entry is enabled,
+		 * Set RSS action for that entry as well
+		 */
+		npc_update_rx_action_with_alg_idx(rvu, action, pfvf, index,
+						  blkaddr, alg_idx);
+	}
 }
 
 void npc_enadis_default_mce_entry(struct rvu *rvu, u16 pcifunc,
Signature · 1 line
2.51.0
author maintainer
#686 lore raw

PATCH 682/781 eth: fbnic: Advertise supported XDP features.

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Dimitri Daskalakis <[email protected]>

[ Upstream commit e977fcb3a318b53b47f23b44ac237fceb1b731fe ]

Drivers are supposed to advertise the XDP features they support. This was missed while adding XDP support.

Before:

$ ynl --family netdev --dump dev-get
...
 {'ifindex': 3,
  'xdp-features': set(),
  'xdp-rx-metadata-features': set(),
  'xsk-features': set()},
...

After:

$ ynl --family netdev --dump dev-get
...
 {'ifindex': 3,
  'xdp-features': {'basic', 'rx-sg'},
  'xdp-rx-metadata-features': set(),
  'xsk-features': set()},
...
---
 drivers/net/ethernet/meta/fbnic/fbnic_netdev.c | 2 ++
 1 file changed, 2 insertions(+)
drivers/net/ethernet/meta/fbnic/fbnic_netdev.c +2 -0
index e3ca5fcfabef3..b4b396ca9bce3 100644
@@ -805,6 +805,8 @@ struct net_device *fbnic_netdev_alloc(struct fbnic_dev *fbd)
 	netdev->hw_enc_features |= netdev->features;
 	netdev->features |= NETIF_F_NTUPLE;
 
+	netdev->xdp_features = NETDEV_XDP_ACT_BASIC | NETDEV_XDP_ACT_RX_SG;
+
 	netdev->min_mtu = IPV6_MIN_MTU;
 	netdev->max_mtu = FBNIC_MAX_JUMBO_FRAME_SIZE - ETH_HLEN;
 
Signature · 1 line
2.51.0
author maintainer
#687 lore raw

PATCH 683/781 bnge: fix reserving resources from FW

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Vikas Gupta <[email protected]>

[ Upstream commit 604530085b2ef484843c723a105b6fd3218b4710 ]

HWRM_FUNC_CFG is used to reserve resources, whereas HWRM_FUNC_QCFG is intended for querying resource information from the firmware. Since __bnge_hwrm_reserve_pf_rings() reserves resources for a specific PF, the command type should be HWRM_FUNC_CFG.

---
 drivers/net/ethernet/broadcom/bnge/bnge_hwrm_lib.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/ethernet/broadcom/bnge/bnge_hwrm_lib.c +1 -1
index 198f49b40dbf0..2994f10446a63 100644
@@ -442,7 +442,7 @@ __bnge_hwrm_reserve_pf_rings(struct bnge_dev *bd, struct bnge_hw_rings *hwr)
 	struct hwrm_func_cfg_input *req;
 	u32 enables = 0;
 
-	if (bnge_hwrm_req_init(bd, req, HWRM_FUNC_QCFG))
+	if (bnge_hwrm_req_init(bd, req, HWRM_FUNC_CFG))
 		return NULL;
 
 	req->fid = cpu_to_le16(0xffff);
Signature · 1 line
2.51.0
author maintainer
#688 lore raw

PATCH 684/781 bonding: alb: fix UAF in rlb_arp_recv during bond up/down

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Hangbin Liu <[email protected]>

[ Upstream commit e6834a4c474697df23ab9948fd3577b26bf48656 ]

The ALB RX path may access rx_hashtbl concurrently with bond teardown. During rapid bond up/down cycles, rlb_deinitialize() frees rx_hashtbl while RX handlers are still running, leading to a null pointer dereference detected by KASAN.

However, the root cause is that rlb_arp_recv() can still be accessed after setting recv_probe to NULL, which is actually a use-after-free (UAF) issue. That is the reason for using the referenced commit in the Fixes tag.

[  214.174138] Oops: general protection fault, probably for non-canonical address 0xdffffc000000001d: 0000 [#1] SMP KASAN PTI
[  214.186478] KASAN: null-ptr-deref in range [0x00000000000000e8-0x00000000000000ef]
[  214.194933] CPU: 30 UID: 0 PID: 2375 Comm: ping Kdump: loaded Not tainted 6.19.0-rc8+ #2 PREEMPT(voluntary)
[  214.205907] Hardware name: Dell Inc. PowerEdge R730/0WCJNT, BIOS 2.14.0 01/14/2022
[  214.214357] RIP: 0010:rlb_arp_recv+0x505/0xab0 [bonding]
[  214.220320] Code: 0f 85 2b 05 00 00 48 b8 00 00 00 00 00 fc ff df 40 0f b6 ed 48 c1 e5 06 49 03 ad 78 01 00 00 48 8d 7d 28 48 89 fa 48 c1 ea 03 <0f> b6
 04 02 84 c0 74 06 0f 8e 12 05 00 00 80 7d 28 00 0f 84 8c 00
[  214.241280] RSP: 0018:ffffc900073d8870 EFLAGS: 00010206
[  214.247116] RAX: dffffc0000000000 RBX: ffff888168556822 RCX: ffff88816855681e
[  214.255082] RDX: 000000000000001d RSI: dffffc0000000000 RDI: 00000000000000e8
[  214.263048] RBP: 00000000000000c0 R08: 0000000000000002 R09: ffffed11192021c8
[  214.271013] R10: ffff8888c9010e43 R11: 0000000000000001 R12: 1ffff92000e7b119
[  214.278978] R13: ffff8888c9010e00 R14: ffff888168556822 R15: ffff888168556810
[  214.286943] FS:  00007f85d2d9cb80(0000) GS:ffff88886ccb3000(0000) knlGS:0000000000000000
[  214.295966] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[  214.302380] CR2: 00007f0d047b5e34 CR3: 00000008a1c2e002 CR4: 00000000001726f0
[  214.310347] Call Trace:
[  214.313070]  <IRQ>
[  214.315318]  ? __pfx_rlb_arp_recv+0x10/0x10 [bonding]
[  214.320975]  bond_handle_frame+0x166/0xb60 [bonding]
[  214.326537]  ? __pfx_bond_handle_frame+0x10/0x10 [bonding]
[  214.332680]  __netif_receive_skb_core.constprop.0+0x576/0x2710
[  214.339199]  ? __pfx_arp_process+0x10/0x10
[  214.343775]  ? sched_balance_find_src_group+0x98/0x630
[  214.349513]  ? __pfx___netif_receive_skb_core.constprop.0+0x10/0x10
[  214.356513]  ? arp_rcv+0x307/0x690
[  214.360311]  ? __pfx_arp_rcv+0x10/0x10
[  214.364499]  ? __lock_acquire+0x58c/0xbd0
[  214.368975]  __netif_receive_skb_one_core+0xae/0x1b0
[  214.374518]  ? __pfx___netif_receive_skb_one_core+0x10/0x10
[  214.380743]  ? lock_acquire+0x10b/0x140
[  214.385026]  process_backlog+0x3f1/0x13a0
[  214.389502]  ? process_backlog+0x3aa/0x13a0
[  214.394174]  __napi_poll.constprop.0+0x9f/0x370
[  214.399233]  net_rx_action+0x8c1/0xe60
[  214.403423]  ? __pfx_net_rx_action+0x10/0x10
[  214.408193]  ? lock_acquire.part.0+0xbd/0x260
[  214.413058]  ? sched_clock_cpu+0x6c/0x540
[  214.417540]  ? mark_held_locks+0x40/0x70
[  214.421920]  handle_softirqs+0x1fd/0x860
[  214.426302]  ? __pfx_handle_softirqs+0x10/0x10
[  214.431264]  ? __neigh_event_send+0x2d6/0xf50
[  214.436131]  do_softirq+0xb1/0xf0
[  214.439830]  </IRQ>

The issue is reproducible by repeatedly running
ip link set bond0 up/down while receiving ARP messages, where rlb_arp_recv() can race with rlb_deinitialize() and dereference a freed rx_hashtbl entry.

Fix this by setting recv_probe to NULL and then calling synchronize_net() to wait for any concurrent RX processing to finish. This ensures that no RX handler can access rx_hashtbl after it is freed in bond_alb_deinitialize().

---
 drivers/net/bonding/bond_main.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)
drivers/net/bonding/bond_main.c +5 -1
index 47f13d86cb7ef..4c58d1dafcacb 100644
@@ -4314,9 +4314,13 @@ static int bond_close(struct net_device *bond_dev)
 
 	bond_work_cancel_all(bond);
 	bond->send_peer_notif = 0;
+	WRITE_ONCE(bond->recv_probe, NULL);
+
+	/* Wait for any in-flight RX handlers */
+	synchronize_net();
+
 	if (bond_is_lb(bond))
 		bond_alb_deinitialize(bond);
-	bond->recv_probe = NULL;
 
 	if (BOND_MODE(bond) == BOND_MODE_8023AD &&
 	    bond->params.broadcast_neighbor)
Signature · 1 line
2.51.0
author maintainer
#689 lore raw

PATCH 685/781 net/mlx5: Fix multiport device check over light SFs

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Shay Drory <[email protected]>

[ Upstream commit 47bf2e813817159f4d195be83a9b5a640ee6baec ]

Driver is using num_vhca_ports capability to distinguish between multiport master device and multiport slave device. num_vhca_ports is a capability the driver sets according to the MAX num_vhca_ports capability reported by FW. On the other hand, light SFs doesn't set the above capbility.

This leads to wrong results whenever light SFs is checking whether he is a multiport master or slave.

Therefore, use the MAX capability to distinguish between master and slave devices.

---
 include/linux/mlx5/driver.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
include/linux/mlx5/driver.h +2 -2
index 1c54aa6f74fbc..1967d1c79139b 100644
@@ -1281,12 +1281,12 @@ static inline bool mlx5_rl_is_supported(struct mlx5_core_dev *dev)
 static inline int mlx5_core_is_mp_slave(struct mlx5_core_dev *dev)
 {
 	return MLX5_CAP_GEN(dev, affiliate_nic_vport_criteria) &&
-	       MLX5_CAP_GEN(dev, num_vhca_ports) <= 1;
+	       MLX5_CAP_GEN_MAX(dev, num_vhca_ports) <= 1;
 }
 
 static inline int mlx5_core_is_mp_master(struct mlx5_core_dev *dev)
 {
-	return MLX5_CAP_GEN(dev, num_vhca_ports) > 1;
+	return MLX5_CAP_GEN_MAX(dev, num_vhca_ports) > 1;
 }
 
 static inline int mlx5_core_mp_enabled(struct mlx5_core_dev *dev)
Signature · 1 line
2.51.0
author maintainer
#690 lore raw

PATCH 686/781 net/mlx5e: Fix misidentification of ASO CQE during poll loop

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Gal Pressman <[email protected]>

[ Upstream commit ae3cb71e6c4dbda0c0b7c10475b744377813c7bd ]

The ASO completion poll loop uses usleep_range() which can sleep much longer than requested due to scheduler latency. Under load, we witnessed a 20ms+ delay until the process was rescheduled, causing the jiffies based timeout to expire while the thread is sleeping.

The original do-while loop structure (poll, sleep, check timeout) would exit without a final poll when waking after timeout, missing a CQE that arrived during sleep.

Instead of the open-coded while loop, use the kernel's read_poll_timeout() which always performs an additional check after the sleep expiration, and is less error-prone.

Note: read_poll_timeout() doesn't accept a sleep range, by passing 10 sleep_us the sleep range effectively changes from 2-10 to 3-10 usecs.

Fixes 739cfa34518e ("net/mlx5: Make ASO poll CQ usable in atomic context")
Fixes 7e3fce82d945 ("net/mlx5e: Overcome slow response for first macsec ASO WQE")
---
 drivers/net/ethernet/mellanox/mlx5/core/en/tc/meter.c  | 10 +++-------
 .../net/ethernet/mellanox/mlx5/core/en_accel/macsec.c  | 10 +++-------
 2 files changed, 6 insertions(+), 14 deletions(-)
drivers/net/ethernet/mellanox/mlx5/core/en/tc/meter.c +3 -7
index 7819fb2972802..d5d9146efca67 100644
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
 // Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
 
+#include <linux/iopoll.h>
 #include <linux/math64.h>
 #include "lib/aso.h"
 #include "en/tc/post_act.h"
@@ -115,7 +116,6 @@ mlx5e_tc_meter_modify(struct mlx5_core_dev *mdev,
 	struct mlx5e_flow_meters *flow_meters;
 	u8 cir_man, cir_exp, cbs_man, cbs_exp;
 	struct mlx5_aso_wqe *aso_wqe;
-	unsigned long expires;
 	struct mlx5_aso *aso;
 	u64 rate, burst;
 	u8 ds_cnt;
@@ -187,12 +187,8 @@ mlx5e_tc_meter_modify(struct mlx5_core_dev *mdev,
 	mlx5_aso_post_wqe(aso, true, &aso_wqe->ctrl);
 
 	/* With newer FW, the wait for the first ASO WQE is more than 2us, put the wait 10ms. */
-	expires = jiffies + msecs_to_jiffies(10);
-	do {
-		err = mlx5_aso_poll_cq(aso, true);
-		if (err)
-			usleep_range(2, 10);
-	} while (err && time_is_after_jiffies(expires));
+	read_poll_timeout(mlx5_aso_poll_cq, err, !err, 10, 10 * USEC_PER_MSEC,
+			  false, aso, true);
 	mutex_unlock(&flow_meters->aso_lock);
 
 	return err;
drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c +3 -7
index 528b04d4de416..641cd3a2cdfab 100644
@@ -5,6 +5,7 @@
 #include <linux/mlx5/mlx5_ifc.h>
 #include <linux/xarray.h>
 #include <linux/if_vlan.h>
+#include <linux/iopoll.h>
 
 #include "en.h"
 #include "lib/aso.h"
@@ -1397,7 +1398,6 @@ static int macsec_aso_query(struct mlx5_core_dev *mdev, struct mlx5e_macsec *mac
 	struct mlx5e_macsec_aso *aso;
 	struct mlx5_aso_wqe *aso_wqe;
 	struct mlx5_aso *maso;
-	unsigned long expires;
 	int err;
 
 	aso = &macsec->aso;
@@ -1411,12 +1411,8 @@ static int macsec_aso_query(struct mlx5_core_dev *mdev, struct mlx5e_macsec *mac
 	macsec_aso_build_wqe_ctrl_seg(aso, &aso_wqe->aso_ctrl, NULL);
 
 	mlx5_aso_post_wqe(maso, false, &aso_wqe->ctrl);
-	expires = jiffies + msecs_to_jiffies(10);
-	do {
-		err = mlx5_aso_poll_cq(maso, false);
-		if (err)
-			usleep_range(2, 10);
-	} while (err && time_is_after_jiffies(expires));
+	read_poll_timeout(mlx5_aso_poll_cq, err, !err, 10, 10 * USEC_PER_MSEC,
+			  false, maso, false);
 
 	if (err)
 		goto err_out;
Signature · 1 line
2.51.0
author maintainer
#691 lore raw

PATCH 687/781 net/mlx5: Fix misidentification of write combining CQE during poll loop

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Gal Pressman <[email protected]>

[ Upstream commit d451994ebc7d4392610bd4b2ab339b255deb4143 ]

The write combining completion poll loop uses usleep_range() which can sleep much longer than requested due to scheduler latency. Under load, we witnessed a 20ms+ delay until the process was rescheduled, causing the jiffies based timeout to expire while the thread is sleeping.

The original do-while loop structure (poll, sleep, check timeout) would exit without a final poll when waking after timeout, missing a CQE that arrived during sleep.

Instead of the open-coded while loop, use the kernel's poll_timeout_us() which always performs an additional check after the sleep expiration, and is less error-prone.

Note: poll_timeout_us() doesn't accept a sleep range, by passing 10 sleep_us the sleep range effectively changes from 2-10 to 3-10 usecs.

---
 drivers/net/ethernet/mellanox/mlx5/core/wc.c | 14 +++++---------
 1 file changed, 5 insertions(+), 9 deletions(-)
drivers/net/ethernet/mellanox/mlx5/core/wc.c +5 -9
index 815a7c97d6b09..04d03be1bb775 100644
@@ -2,6 +2,7 @@
 // Copyright (c) 2024, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
 
 #include <linux/io.h>
+#include <linux/iopoll.h>
 #include <linux/mlx5/transobj.h>
 #include "lib/clock.h"
 #include "mlx5_core.h"
@@ -15,7 +16,7 @@
 #define TEST_WC_NUM_WQES 255
 #define TEST_WC_LOG_CQ_SZ (order_base_2(TEST_WC_NUM_WQES))
 #define TEST_WC_SQ_LOG_WQ_SZ TEST_WC_LOG_CQ_SZ
-#define TEST_WC_POLLING_MAX_TIME_JIFFIES msecs_to_jiffies(100)
+#define TEST_WC_POLLING_MAX_TIME_USEC (100 * USEC_PER_MSEC)
 
 struct mlx5_wc_cq {
 	/* data path - accessed per cqe */
@@ -359,7 +360,6 @@ static int mlx5_wc_poll_cq(struct mlx5_wc_sq *sq)
 static void mlx5_core_test_wc(struct mlx5_core_dev *mdev)
 {
 	unsigned int offset = 0;
-	unsigned long expires;
 	struct mlx5_wc_sq *sq;
 	int i, err;
 
@@ -389,13 +389,9 @@ static void mlx5_core_test_wc(struct mlx5_core_dev *mdev)
 
 	mlx5_wc_post_nop(sq, &offset, true);
 
-	expires = jiffies + TEST_WC_POLLING_MAX_TIME_JIFFIES;
-	do {
-		err = mlx5_wc_poll_cq(sq);
-		if (err)
-			usleep_range(2, 10);
-	} while (mdev->wc_state == MLX5_WC_STATE_UNINITIALIZED &&
-		 time_is_after_jiffies(expires));
+	poll_timeout_us(mlx5_wc_poll_cq(sq),
+			mdev->wc_state != MLX5_WC_STATE_UNINITIALIZED, 10,
+			TEST_WC_POLLING_MAX_TIME_USEC, false);
 
 	mlx5_wc_destroy_sq(sq);
 
Signature · 1 line
2.51.0
author maintainer
#692 lore raw

PATCH 688/781 net/mlx5e: MACsec, add ASO poll loop in macsec_aso_set_arm_event

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Gal Pressman <[email protected]>

[ Upstream commit 9854b243ce4225328d0b32fdc998d35b6952d3f7 ]

The macsec_aso_set_arm_event function calls mlx5_aso_poll_cq once without a retry loop. If the CQE is not immediately available after posting the WQE, the function fails unnecessarily.

Use read_poll_timeout() to poll 3-10 usecs for CQE, consistent with other ASO polling code paths in the driver.

---
 drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/net/ethernet/mellanox/mlx5/core/en_accel/macsec.c +2 -1
index 641cd3a2cdfab..90b3bc5f9166f 100644
@@ -1386,7 +1386,8 @@ static int macsec_aso_set_arm_event(struct mlx5_core_dev *mdev, struct mlx5e_mac
 			   MLX5_ACCESS_ASO_OPC_MOD_MACSEC);
 	macsec_aso_build_ctrl(aso, &aso_wqe->aso_ctrl, in);
 	mlx5_aso_post_wqe(maso, false, &aso_wqe->ctrl);
-	err = mlx5_aso_poll_cq(maso, false);
+	read_poll_timeout(mlx5_aso_poll_cq, err, !err, 10, 10 * USEC_PER_MSEC,
+			  false, maso, false);
 	mutex_unlock(&aso->aso_lock);
 
 	return err;
Signature · 1 line
2.51.0
author maintainer
#693 lore raw

PATCH 689/781 net/mlx5e: Fix deadlocks between devlink and netdev instance locks

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Cosmin Ratiu <[email protected]>

[ Upstream commit 83ac0304a2d77519dae1e54c9713cbe1aedf19c9 ]

In the mentioned "Fixes" commit, various work tasks triggering devlink health reporter recovery were switched to use netdev_trylock to protect against concurrent tear down of the channels being recovered. But this had the side effect of introducing potential deadlocks because of incorrect lock ordering.

The correct lock order is described by the init flow:
probe_one -> mlx5_init_one (acquires devlink lock)
-> mlx5_init_one_devl_locked -> mlx5_register_device -> mlx5_rescan_drivers_locked -...-> mlx5e_probe -> _mlx5e_probe -> register_netdev (acquires rtnl lock)
-> register_netdevice (acquires netdev lock)
=> devlink lock -> rtnl lock -> netdev lock.

But in the current recovery flow, the order is wrong:
mlx5e_tx_err_cqe_work (acquires netdev lock)
-> mlx5e_reporter_tx_err_cqe -> mlx5e_health_report
-> devlink_health_report (acquires devlink lock => boom!) -> devlink_health_reporter_recover
-> mlx5e_tx_reporter_recover -> mlx5e_tx_reporter_recover_from_ctx -> mlx5e_tx_reporter_err_cqe_recover

The same pattern exists in:
mlx5e_reporter_rx_timeout
mlx5e_reporter_tx_ptpsq_unhealthy
mlx5e_reporter_tx_timeout

Fix these by moving the netdev_trylock calls from the work handlers lower in the call stack, in the respective recovery functions, where they are actually necessary.

---
 .../net/ethernet/mellanox/mlx5/core/en/ptp.c  | 14 -----
 .../mellanox/mlx5/core/en/reporter_rx.c       | 13 +++++
 .../mellanox/mlx5/core/en/reporter_tx.c       | 52 +++++++++++++++++--
 .../net/ethernet/mellanox/mlx5/core/en_main.c | 40 --------------
 4 files changed, 61 insertions(+), 58 deletions(-)
drivers/net/ethernet/mellanox/mlx5/core/en/ptp.c +0 -14
index 424f8a2728a3e..74660e7fe6748 100644
@@ -457,22 +457,8 @@ static void mlx5e_ptpsq_unhealthy_work(struct work_struct *work)
 {
 	struct mlx5e_ptpsq *ptpsq =
 		container_of(work, struct mlx5e_ptpsq, report_unhealthy_work);
-	struct mlx5e_txqsq *sq = &ptpsq->txqsq;
-
-	/* Recovering the PTP SQ means re-enabling NAPI, which requires the
-	 * netdev instance lock. However, SQ closing has to wait for this work
-	 * task to finish while also holding the same lock. So either get the
-	 * lock or find that the SQ is no longer enabled and thus this work is
-	 * not relevant anymore.
-	 */
-	while (!netdev_trylock(sq->netdev)) {
-		if (!test_bit(MLX5E_SQ_STATE_ENABLED, &sq->state))
-			return;
-		msleep(20);
-	}
 
 	mlx5e_reporter_tx_ptpsq_unhealthy(ptpsq);
-	netdev_unlock(sq->netdev);
 }
 
 static int mlx5e_ptp_open_txqsq(struct mlx5e_ptp *c, u32 tisn,
drivers/net/ethernet/mellanox/mlx5/core/en/reporter_rx.c +13 -0
index 0686fbdd5a059..6efb626b55062 100644
@@ -1,6 +1,8 @@
 // SPDX-License-Identifier: GPL-2.0
 // Copyright (c) 2019 Mellanox Technologies.
 
+#include <net/netdev_lock.h>
+
 #include "health.h"
 #include "params.h"
 #include "txrx.h"
@@ -177,6 +179,16 @@ static int mlx5e_rx_reporter_timeout_recover(void *ctx)
 	rq = ctx;
 	priv = rq->priv;
 
+	/* Acquire netdev instance lock to synchronize with channel close and
+	 * reopen flows. Either successfully obtain the lock, or detect that
+	 * channels are closing for another reason, making this work no longer
+	 * necessary.
+	 */
+	while (!netdev_trylock(rq->netdev)) {
+		if (!test_bit(MLX5E_STATE_CHANNELS_ACTIVE, &rq->priv->state))
+			return 0;
+		msleep(20);
+	}
 	mutex_lock(&priv->state_lock);
 
 	eq = rq->cq.mcq.eq;
@@ -186,6 +198,7 @@ static int mlx5e_rx_reporter_timeout_recover(void *ctx)
 		clear_bit(MLX5E_SQ_STATE_ENABLED, &rq->icosq->state);
 
 	mutex_unlock(&priv->state_lock);
+	netdev_unlock(rq->netdev);
 
 	return err;
 }
drivers/net/ethernet/mellanox/mlx5/core/en/reporter_tx.c +48 -4

109 lines not on this page · raw message

drivers/net/ethernet/mellanox/mlx5/core/en_main.c +0 -40
index 4b2963bbe7ff4..e15e6fb4cd8ea 100644
@@ -688,19 +688,7 @@ static void mlx5e_rq_timeout_work(struct work_struct *timeout_work)
 					   struct mlx5e_rq,
 					   rx_timeout_work);
 
-	/* Acquire netdev instance lock to synchronize with channel close and
-	 * reopen flows. Either successfully obtain the lock, or detect that
-	 * channels are closing for another reason, making this work no longer
-	 * necessary.
-	 */
-	while (!netdev_trylock(rq->netdev)) {
-		if (!test_bit(MLX5E_STATE_CHANNELS_ACTIVE, &rq->priv->state))
-			return;
-		msleep(20);
-	}
-
 	mlx5e_reporter_rx_timeout(rq);
-	netdev_unlock(rq->netdev);
 }
 
 static int mlx5e_alloc_mpwqe_rq_drop_page(struct mlx5e_rq *rq)
@@ -1997,20 +1985,7 @@ void mlx5e_tx_err_cqe_work(struct work_struct *recover_work)
 	struct mlx5e_txqsq *sq = container_of(recover_work, struct mlx5e_txqsq,
 					      recover_work);
 
-	/* Recovering queues means re-enabling NAPI, which requires the netdev
-	 * instance lock. However, SQ closing flows have to wait for work tasks
-	 * to finish while also holding the netdev instance lock. So either get
-	 * the lock or find that the SQ is no longer enabled and thus this work
-	 * is not relevant anymore.
-	 */
-	while (!netdev_trylock(sq->netdev)) {
-		if (!test_bit(MLX5E_SQ_STATE_ENABLED, &sq->state))
-			return;
-		msleep(20);
-	}
-
 	mlx5e_reporter_tx_err_cqe(sq);
-	netdev_unlock(sq->netdev);
 }
 
 static struct dim_cq_moder mlx5e_get_def_tx_moderation(u8 cq_period_mode)
@@ -5121,19 +5096,6 @@ static void mlx5e_tx_timeout_work(struct work_struct *work)
 	struct net_device *netdev = priv->netdev;
 	int i;
 
-	/* Recovering the TX queues implies re-enabling NAPI, which requires
-	 * the netdev instance lock.
-	 * However, channel closing flows have to wait for this work to finish
-	 * while holding the same lock. So either get the lock or find that
-	 * channels are being closed for other reason and this work is not
-	 * relevant anymore.
-	 */
-	while (!netdev_trylock(netdev)) {
-		if (!test_bit(MLX5E_STATE_CHANNELS_ACTIVE, &priv->state))
-			return;
-		msleep(20);
-	}
-
 	for (i = 0; i < netdev->real_num_tx_queues; i++) {
 		struct netdev_queue *dev_queue =
 			netdev_get_tx_queue(netdev, i);
@@ -5146,8 +5108,6 @@ static void mlx5e_tx_timeout_work(struct work_struct *work)
 		/* break if tried to reopened channels */
 			break;
 	}
-
-	netdev_unlock(netdev);
 }
 
 static void mlx5e_tx_timeout(struct net_device *dev, unsigned int txqueue)
Signature · 1 line
2.51.0
author maintainer
#694 lore raw

PATCH 690/781 net/mlx5e: Use unsigned for mlx5e_get_max_num_channels

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Cosmin Ratiu <[email protected]>

[ Upstream commit 57a94d4b22b0c6cc5d601e6b6238d78fb923d991 ]

The max number of channels is always an unsigned int, use the correct type to fix compilation errors done with strict type checking, e.g.:

error: call to ‘__compiletime_assert_1110’ declared with attribute
error: min(mlx5e_get_devlink_param_num_doorbells(mdev), mlx5e_get_max_num_channels(mdev)) signedness error

Fixes 74a8dadac17e ("net/mlx5e: Preparations for supporting larger number of channels")
---
 drivers/net/ethernet/mellanox/mlx5/core/en.h | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/net/ethernet/mellanox/mlx5/core/en.h +2 -1
index ff4ab4691baf0..a06d08576fd4b 100644
@@ -179,7 +179,8 @@ static inline u16 mlx5_min_rx_wqes(int wq_type, u32 wq_size)
 }
 
 /* Use this function to get max num channels (rxqs/txqs) only to create netdev */
-static inline int mlx5e_get_max_num_channels(struct mlx5_core_dev *mdev)
+static inline unsigned int
+mlx5e_get_max_num_channels(struct mlx5_core_dev *mdev)
 {
 	return is_kdump_kernel() ?
 		MLX5E_MIN_NUM_CHANNELS :
Signature · 1 line
2.51.0
author maintainer
#695 lore raw

PATCH 691/781 apparmor: fix NULL pointer dereference in __unix_needs_revalidation

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: System Administrator <root@localhost>

[ Upstream commit e2938ad00b21340c0362562dfedd7cfec0554d67 ]

When receiving file descriptors via SCM_RIGHTS, both the socket pointer and the socket's sk pointer can be NULL during socket setup or teardown, causing NULL pointer dereferences in __unix_needs_revalidation().

This is a regression in AppArmor 5.0.0 (kernel 6.17+) where the new __unix_needs_revalidation() function was added without proper NULL checks.

The crash manifests as:

  BUG: kernel NULL pointer dereference, address: 0x0000000000000018
  RIP: aa_file_perm+0xb7/0x3b0 (or +0xbe/0x3b0, +0xc0/0x3e0)
  Call Trace:
   apparmor_file_receive+0x42/0x80
   security_file_receive+0x2e/0x50
   receive_fd+0x1d/0xf0
   scm_detach_fds+0xad/0x1c0

The function dereferences sock->sk->sk_family without checking if either sock or sock->sk is NULL first.

Add NULL checks for both sock and sock->sk before accessing sk_family.

---
 security/apparmor/file.c | 3 +++
 1 file changed, 3 insertions(+)
security/apparmor/file.c +3 -0
index c758204028780..919dbbbc87ab6 100644
@@ -578,6 +578,9 @@ static bool __unix_needs_revalidation(struct file *file, struct aa_label *label,
 		return false;
 	if (request & NET_PEER_MASK)
 		return false;
+	/* sock and sock->sk can be NULL for sockets being set up or torn down */
+	if (!sock || !sock->sk)
+		return false;
 	if (sock->sk->sk_family == PF_UNIX) {
 		struct aa_sk_ctx *ctx = aa_sock(sock->sk);
 
Signature · 1 line
2.51.0
author maintainer
#696 lore raw

PATCH 692/781 apparmor: fix NULL sock in aa_sock_file_perm

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: John Johansen <[email protected]>

[ Upstream commit 00b67657535dfea56e84d11492f5c0f61d0af297 ]

Deal with the potential that sock and sock-sk can be NULL during socket setup or teardown. This could lead to an oops. The fix for NULL pointer dereference in __unix_needs_revalidation shows this is at least possible for af_unix sockets. While the fix for af_unix sockets applies for newer mediation this is still the fall back path for older af_unix mediation and other sockets, so ensure it is covered.

Fixes 56974a6fcfef6 ("apparmor: add base infastructure for socket mediation")
---
 security/apparmor/net.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)
security/apparmor/net.c +4 -2
index 45cf25605c345..44c04102062f3 100644
@@ -326,8 +326,10 @@ int aa_sock_file_perm(const struct cred *subj_cred, struct aa_label *label,
 	struct socket *sock = (struct socket *) file->private_data;
 
 	AA_BUG(!label);
-	AA_BUG(!sock);
-	AA_BUG(!sock->sk);
+
+	/* sock && sock->sk can be NULL for sockets being set up or torn down */
+	if (!sock || !sock->sk)
+		return 0;
 
 	if (sock->sk->sk_family == PF_UNIX)
 		return aa_unix_file_perm(subj_cred, label, op, request, file);
Signature · 1 line
2.51.0
author maintainer
#697 lore raw

PATCH 693/781 AppArmor: Allow apparmor to handle unaligned dfa tables

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Helge Deller <[email protected]>

[ Upstream commit 64802f731214a51dfe3c6c27636b3ddafd003eb0 ]

The dfa tables can originate from kernel or userspace and 8-byte alignment isn't always guaranteed and as such may trigger unaligned memory accesses on various architectures. Resulting in the following

[   73.901376] WARNING: CPU: 0 PID: 341 at security/apparmor/match.c:316 aa_dfa_unpack+0x6cc/0x720
[   74.015867] Modules linked in: binfmt_misc evdev flash sg drm drm_panel_orientation_quirks backlight i2c_core configfs nfnetlink autofs4 ext4 crc16 mbcache jbd2 hid_generic usbhid sr_mod hid cdrom sd_mod ata_generic ohci_pci ehci_pci ehci_hcd ohci_hcd pata_ali libata sym53c8xx scsi_transport_spi tg3 scsi_mod usbcore libphy scsi_common mdio_bus usb_common
[   74.428977] CPU: 0 UID: 0 PID: 341 Comm: apparmor_parser Not tainted 6.18.0-rc6+ #9 NONE
[   74.536543] Call Trace:
[   74.568561] [<0000000000434c24>] dump_stack+0x8/0x18
[   74.633757] [<0000000000476438>] __warn+0xd8/0x100
[   74.696664] [<00000000004296d4>] warn_slowpath_fmt+0x34/0x74
[   74.771006] [<00000000008db28c>] aa_dfa_unpack+0x6cc/0x720
[   74.843062] [<00000000008e643c>] unpack_pdb+0xbc/0x7e0
[   74.910545] [<00000000008e7740>] unpack_profile+0xbe0/0x1300
[   74.984888] [<00000000008e82e0>] aa_unpack+0xe0/0x6a0
[   75.051226] [<00000000008e3ec4>] aa_replace_profiles+0x64/0x1160
[   75.130144] [<00000000008d4d90>] policy_update+0xf0/0x280
[   75.201057] [<00000000008d4fc8>] profile_replace+0xa8/0x100
[   75.274258] [<0000000000766bd0>] vfs_write+0x90/0x420
[   75.340594] [<00000000007670cc>] ksys_write+0x4c/0xe0
[   75.406932] [<0000000000767174>] sys_write+0x14/0x40
[   75.472126] [<0000000000406174>] linux_sparc_syscall+0x34/0x44
[   75.548802] ---[ end trace 0000000000000000 ]---
[   75.609503] dfa blob stream 0xfff0000008926b96 not aligned.
[   75.682695] Kernel unaligned access at TPC[8db2a8] aa_dfa_unpack+0x6e8/0x720

Work around it by using the get_unaligned_xx() helpers.

Fixes e6e8bf418850d ("apparmor: fix restricted endian type warnings for dfa unpack")
---
 security/apparmor/match.c | 15 ++++++++-------
 1 file changed, 8 insertions(+), 7 deletions(-)
security/apparmor/match.c +8 -7
index c5a91600842a1..26e82ba879d44 100644
@@ -15,6 +15,7 @@
 #include <linux/vmalloc.h>
 #include <linux/err.h>
 #include <linux/kref.h>
+#include <linux/unaligned.h>
 
 #include "include/lib.h"
 #include "include/match.h"
@@ -42,11 +43,11 @@ static struct table_header *unpack_table(char *blob, size_t bsize)
 	/* loaded td_id's start at 1, subtract 1 now to avoid doing
 	 * it every time we use td_id as an index
 	 */
-	th.td_id = be16_to_cpu(*(__be16 *) (blob)) - 1;
+	th.td_id = get_unaligned_be16(blob) - 1;
 	if (th.td_id > YYTD_ID_MAX)
 		goto out;
-	th.td_flags = be16_to_cpu(*(__be16 *) (blob + 2));
-	th.td_lolen = be32_to_cpu(*(__be32 *) (blob + 8));
+	th.td_flags = get_unaligned_be16(blob + 2);
+	th.td_lolen = get_unaligned_be32(blob + 8);
 	blob += sizeof(struct table_header);
 
 	if (!(th.td_flags == YYTD_DATA16 || th.td_flags == YYTD_DATA32 ||
@@ -313,14 +314,14 @@ struct aa_dfa *aa_dfa_unpack(void *blob, size_t size, int flags)
 	if (size < sizeof(struct table_set_header))
 		goto fail;
 
-	if (ntohl(*(__be32 *) data) != YYTH_MAGIC)
+	if (get_unaligned_be32(data) != YYTH_MAGIC)
 		goto fail;
 
-	hsize = ntohl(*(__be32 *) (data + 4));
+	hsize = get_unaligned_be32(data + 4);
 	if (size < hsize)
 		goto fail;
 
-	dfa->flags = ntohs(*(__be16 *) (data + 12));
+	dfa->flags = get_unaligned_be16(data + 12);
 	if (dfa->flags & ~(YYTH_FLAGS))
 		goto fail;
 
@@ -329,7 +330,7 @@ struct aa_dfa *aa_dfa_unpack(void *blob, size_t size, int flags)
 	 * if (dfa->flags & YYTH_FLAGS_OOB_TRANS) {
 	 *	if (hsize < 16 + 4)
 	 *		goto fail;
-	 *	dfa->max_oob = ntol(*(__be32 *) (data + 16));
+	 *	dfa->max_oob = get_unaligned_be32(data + 16);
 	 *	if (dfa->max <= MAX_OOB_SUPPORTED) {
 	 *		pr_err("AppArmor DFA OOB greater than supported\n");
 	 *		goto fail;
Signature · 1 line
2.51.0
author maintainer
#698 lore raw

PATCH 694/781 apparmor: Fix & Optimize table creation from possibly unaligned memory

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Helge Deller <[email protected]>

[ Upstream commit 6fc367bfd4c8886e6b1742aabbd1c0bdc310db3a ]

Source blob may come from userspace and might be unaligned. Try to optize the copying process by avoiding unaligned memory accesses.

- Added Fixes tag
- Added "Fix &" to description as this doesn't just optimize but fixes a potential unaligned memory access

Fixes e6e8bf418850d ("apparmor: fix restricted endian type warnings for dfa unpack")
[jj: remove duplicate word "convert" in comment trigger checkpatch warning]
---
 security/apparmor/include/match.h | 12 +++++++-----
 security/apparmor/match.c         |  7 +++----
 2 files changed, 10 insertions(+), 9 deletions(-)
security/apparmor/include/match.h +7 -5
index 1fbe82f5021b1..0dde8eda3d1a5 100644
@@ -104,16 +104,18 @@ struct aa_dfa {
 	struct table_header *tables[YYTD_ID_TSIZE];
 };
 
-#define byte_to_byte(X) (X)
-
 #define UNPACK_ARRAY(TABLE, BLOB, LEN, TTYPE, BTYPE, NTOHX)	\
 	do { \
 		typeof(LEN) __i; \
 		TTYPE *__t = (TTYPE *) TABLE; \
 		BTYPE *__b = (BTYPE *) BLOB; \
-		for (__i = 0; __i < LEN; __i++) { \
-			__t[__i] = NTOHX(__b[__i]); \
-		} \
+		BUILD_BUG_ON(sizeof(TTYPE) != sizeof(BTYPE)); \
+		if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)) \
+			memcpy(__t, __b, (LEN) * sizeof(BTYPE)); \
+		else /* copy & convert from big-endian */ \
+			for (__i = 0; __i < LEN; __i++) { \
+				__t[__i] = NTOHX(&__b[__i]); \
+			} \
 	} while (0)
 
 static inline size_t table_size(size_t len, size_t el_size)
security/apparmor/match.c +3 -4
index 26e82ba879d44..bbeb3be68572f 100644
@@ -67,14 +67,13 @@ static struct table_header *unpack_table(char *blob, size_t bsize)
 		table->td_flags = th.td_flags;
 		table->td_lolen = th.td_lolen;
 		if (th.td_flags == YYTD_DATA8)
-			UNPACK_ARRAY(table->td_data, blob, th.td_lolen,
-				     u8, u8, byte_to_byte);
+			memcpy(table->td_data, blob, th.td_lolen);
 		else if (th.td_flags == YYTD_DATA16)
 			UNPACK_ARRAY(table->td_data, blob, th.td_lolen,
-				     u16, __be16, be16_to_cpu);
+				     u16, __be16, get_unaligned_be16);
 		else if (th.td_flags == YYTD_DATA32)
 			UNPACK_ARRAY(table->td_data, blob, th.td_lolen,
-				     u32, __be32, be32_to_cpu);
+				     u32, __be32, get_unaligned_be32);
 		else
 			goto fail;
 		/* if table was vmalloced make sure the page tables are synced
Signature · 1 line
2.51.0
author maintainer
#699 lore raw

PATCH 695/781 apparmor: return -ENOMEM in unpack_perms_table upon alloc failure

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Ryan Lee <[email protected]>

[ Upstream commit 74b7105e53e80a4072bd3e1a50be7aa15e3f0a01 ]

In policy_unpack.c:unpack_perms_table, the perms struct is allocated via kcalloc, with the position being reset if the allocation fails. However, the error path results in -EPROTO being retured instead of -ENOMEM. Fix this to return the correct error code.

Fixes fd1b2b95a2117 ("apparmor: add the ability for policy to specify a permission table")
---
 security/apparmor/policy_unpack.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)
security/apparmor/policy_unpack.c +4 -2
index 7523971e37d9c..dd602bd5fca99 100644
@@ -687,8 +687,10 @@ static ssize_t unpack_perms_table(struct aa_ext *e, struct aa_perms **perms)
 		if (!aa_unpack_array(e, NULL, &size))
 			goto fail_reset;
 		*perms = kcalloc(size, sizeof(struct aa_perms), GFP_KERNEL);
-		if (!*perms)
-			goto fail_reset;
+		if (!*perms) {
+			e->pos = pos;
+			return -ENOMEM;
+		}
 		for (i = 0; i < size; i++) {
 			if (!unpack_perm(e, version, &(*perms)[i]))
 				goto fail;
Signature · 1 line
2.51.0
author maintainer
#700 lore raw

PATCH 696/781 apparmor: fix boolean argument in apparmor_mmap_file

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Ryan Lee <[email protected]>

[ Upstream commit 48d5268e911abcf7674ec33c9b0b3e952be1175e ]

The previous value of GFP_ATOMIC is an int and not a bool, potentially resulting in UB when being assigned to a bool. In addition, the mmap hook is called outside of locks (i.e. in a non-atomic context), so we can pass a fixed constant value of false instead to common_mmap.

Stable-dep-of: 4a134723f9f1 ("apparmor: move check for aa_null file to cover all cases")

---
 security/apparmor/lsm.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
security/apparmor/lsm.c +1 -1
index a87cd60ed2069..acca3d6efdbc8 100644
@@ -584,7 +584,7 @@ static int common_mmap(const char *op, struct file *file, unsigned long prot,
 static int apparmor_mmap_file(struct file *file, unsigned long reqprot,
 			      unsigned long prot, unsigned long flags)
 {
-	return common_mmap(OP_FMMAP, file, prot, flags, GFP_ATOMIC);
+	return common_mmap(OP_FMMAP, file, prot, flags, false);
 }
 
 static int apparmor_file_mprotect(struct vm_area_struct *vma,
Signature · 1 line
2.51.0
author maintainer
#701 lore raw

PATCH 697/781 apparmor: drop in_atomic flag in common_mmap, and common_file_perm

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: John Johansen <[email protected]>

[ Upstream commit c3f27ccdb2dce3f0f2814574d06017f46c11fa29 ]

with the previous changes to mmap the in_atomic flag is now always false, so drop it.

Stable-dep-of: 4a134723f9f1 ("apparmor: move check for aa_null file to cover all cases")

---
 security/apparmor/lsm.c | 21 +++++++++------------
 1 file changed, 9 insertions(+), 12 deletions(-)
security/apparmor/lsm.c +9 -12
index acca3d6efdbc8..e59e9bc7250bf 100644
@@ -520,8 +520,7 @@ static void apparmor_file_free_security(struct file *file)
 		aa_put_label(rcu_access_pointer(ctx->label));
 }
 
-static int common_file_perm(const char *op, struct file *file, u32 mask,
-			    bool in_atomic)
+static int common_file_perm(const char *op, struct file *file, u32 mask)
 {
 	struct aa_label *label;
 	int error = 0;
@@ -532,7 +531,7 @@ static int common_file_perm(const char *op, struct file *file, u32 mask,
 		return -EACCES;
 
 	label = __begin_current_label_crit_section(&needput);
-	error = aa_file_perm(op, current_cred(), label, file, mask, in_atomic);
+	error = aa_file_perm(op, current_cred(), label, file, mask, false);
 	__end_current_label_crit_section(label, needput);
 
 	return error;
@@ -540,13 +539,12 @@ static int common_file_perm(const char *op, struct file *file, u32 mask,
 
 static int apparmor_file_receive(struct file *file)
 {
-	return common_file_perm(OP_FRECEIVE, file, aa_map_file_to_perms(file),
-				false);
+	return common_file_perm(OP_FRECEIVE, file, aa_map_file_to_perms(file));
 }
 
 static int apparmor_file_permission(struct file *file, int mask)
 {
-	return common_file_perm(OP_FPERM, file, mask, false);
+	return common_file_perm(OP_FPERM, file, mask);
 }
 
 static int apparmor_file_lock(struct file *file, unsigned int cmd)
@@ -556,11 +554,11 @@ static int apparmor_file_lock(struct file *file, unsigned int cmd)
 	if (cmd == F_WRLCK)
 		mask |= MAY_WRITE;
 
-	return common_file_perm(OP_FLOCK, file, mask, false);
+	return common_file_perm(OP_FLOCK, file, mask);
 }
 
 static int common_mmap(const char *op, struct file *file, unsigned long prot,
-		       unsigned long flags, bool in_atomic)
+		       unsigned long flags)
 {
 	int mask = 0;
 
@@ -578,21 +576,20 @@ static int common_mmap(const char *op, struct file *file, unsigned long prot,
 	if (prot & PROT_EXEC)
 		mask |= AA_EXEC_MMAP;
 
-	return common_file_perm(op, file, mask, in_atomic);
+	return common_file_perm(op, file, mask);
 }
 
 static int apparmor_mmap_file(struct file *file, unsigned long reqprot,
 			      unsigned long prot, unsigned long flags)
 {
-	return common_mmap(OP_FMMAP, file, prot, flags, false);
+	return common_mmap(OP_FMMAP, file, prot, flags);
 }
 
 static int apparmor_file_mprotect(struct vm_area_struct *vma,
 				  unsigned long reqprot, unsigned long prot)
 {
 	return common_mmap(OP_FMPROT, vma->vm_file, prot,
-			   !(vma->vm_flags & VM_SHARED) ? MAP_PRIVATE : 0,
-			   false);
+			   !(vma->vm_flags & VM_SHARED) ? MAP_PRIVATE : 0);
 }
 
 #ifdef CONFIG_IO_URING
Signature · 1 line
2.51.0
author maintainer
#702 lore raw

PATCH 698/781 apparmor: account for in_atomic removal in common_file_perm

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Ryan Lee <[email protected]>

[ Upstream commit 9b829c0aa96e9385b1e9a308d3eb054b95fbeda2 ]

If we are not in an atomic context in common_file_perm, then we don't have to use the atomic versions, resulting in improved performance outside of atomic contexts.

Stable-dep-of: 4a134723f9f1 ("apparmor: move check for aa_null file to cover all cases")

---
 security/apparmor/lsm.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)
security/apparmor/lsm.c +2 -3
index e59e9bc7250bf..f47d60d8c40a2 100644
@@ -524,15 +524,14 @@ static int common_file_perm(const char *op, struct file *file, u32 mask)
 {
 	struct aa_label *label;
 	int error = 0;
-	bool needput;
 
 	/* don't reaudit files closed during inheritance */
 	if (unlikely(file->f_path.dentry == aa_null.dentry))
 		return -EACCES;
 
-	label = __begin_current_label_crit_section(&needput);
+	label = begin_current_label_crit_section();
 	error = aa_file_perm(op, current_cred(), label, file, mask, false);
-	__end_current_label_crit_section(label, needput);
+	end_current_label_crit_section(label);
 
 	return error;
 }
Signature · 1 line
2.51.0
author maintainer
#703 lore raw

PATCH 699/781 apparmor: move check for aa_null file to cover all cases

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: John Johansen <[email protected]>

[ Upstream commit 4a134723f9f1ad2f3621566259db673350d19cb1 ]

files with a dentry pointing aa_null.dentry where already rejected as part of file_inheritance. Unfortunately the check in common_file_perm() is insufficient to cover all cases causing unnecessary audit messages without the original files context.

Eg.

[ 442.886474] audit: type=1400 audit(1704822661.616:329): apparmor="DENIED" operation="file_inherit" class="file" namespace="root//lxd-juju-98527a-0_<var-snap-lxd-common-lxd>" profile="snap.lxd.activate" name="/apparmor/.null" pid=9525 comm="snap-exec"

Further examples of this are in the logs of
https://bugs.launchpad.net/ubuntu/+source/apparmor/+bug/2120439
https://bugs.launchpad.net/ubuntu/+source/snapd/+bug/1952084
https://bugs.launchpad.net/snapd/+bug/2049099

These messages have no value and should not be sent to the logs. AppArmor was already filtering the out in some cases but the original patch did not catch all cases. Fix this by push the existing check down into two functions that should cover all cases.

---
 security/apparmor/file.c | 12 ++++++++++--
 security/apparmor/lsm.c  |  4 ----
 2 files changed, 10 insertions(+), 6 deletions(-)
security/apparmor/file.c +10 -2
index 919dbbbc87ab6..7de23e85cd5d0 100644
@@ -154,8 +154,12 @@ static int path_name(const char *op, const struct cred *subj_cred,
 	const char *info = NULL;
 	int error;
 
-	error = aa_path_name(path, flags, buffer, name, &info,
-			     labels_profile(label)->disconnected);
+	/* don't reaudit files closed during inheritance */
+	if (unlikely(path->dentry == aa_null.dentry))
+		error = -EACCES;
+	else
+		error = aa_path_name(path, flags, buffer, name, &info,
+				     labels_profile(label)->disconnected);
 	if (error) {
 		fn_for_each_confined(label, profile,
 			aa_audit_file(subj_cred,
@@ -616,6 +620,10 @@ int aa_file_perm(const char *op, const struct cred *subj_cred,
 	AA_BUG(!label);
 	AA_BUG(!file);
 
+	/* don't reaudit files closed during inheritance */
+	if (unlikely(file->f_path.dentry == aa_null.dentry))
+		return -EACCES;
+
 	fctx = file_ctx(file);
 
 	rcu_read_lock();
security/apparmor/lsm.c +0 -4
index f47d60d8c40a2..8d5d9a966b719 100644
@@ -525,10 +525,6 @@ static int common_file_perm(const char *op, struct file *file, u32 mask)
 	struct aa_label *label;
 	int error = 0;
 
-	/* don't reaudit files closed during inheritance */
-	if (unlikely(file->f_path.dentry == aa_null.dentry))
-		return -EACCES;
-
 	label = begin_current_label_crit_section();
 	error = aa_file_perm(op, current_cred(), label, file, mask, false);
 	end_current_label_crit_section(label);
Signature · 1 line
2.51.0
author maintainer
#704 lore raw

PATCH 700/781 apparmor: fix rlimit for posix cpu timers

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: John Johansen <[email protected]>

[ Upstream commit 6ca56813f4a589f536adceb42882855d91fb1125 ]

Posix cpu timers requires an additional step beyond setting the rlimit. Refactor the code so its clear when what code is setting the limit and conditionally update the posix cpu timers when appropriate.

Fixes baa73d9e478ff ("posix-timers: Make them configurable")
---
 security/apparmor/resource.c | 5 +++++
 1 file changed, 5 insertions(+)
security/apparmor/resource.c +5 -0
index 8e80db3ae21c0..64212b39ba4bb 100644
@@ -196,6 +196,11 @@ void __aa_transition_rlimits(struct aa_label *old_l, struct aa_label *new_l)
 					     rules->rlimits.limits[j].rlim_max);
 			/* soft limit should not exceed hard limit */
 			rlim->rlim_cur = min(rlim->rlim_cur, rlim->rlim_max);
+			if (j == RLIMIT_CPU &&
+			    rlim->rlim_cur != RLIM_INFINITY &&
+			    IS_ENABLED(CONFIG_POSIX_TIMERS))
+				(void) update_rlimit_cpu(current->group_leader,
+							 rlim->rlim_cur);
 		}
 	}
 }
Signature · 1 line
2.51.0
author maintainer
#705 lore raw

PATCH 701/781 apparmor: remove apply_modes_to_perms from label_match

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: John Johansen <[email protected]>

[ Upstream commit b2e27be2948f2f8c38421cd554b5fc9383215648 ]

The modes shouldn't be applied at the point of label match, it just results in them being applied multiple times. Instead they should be applied after which is already being done by all callers so it can just be dropped from label_match.

Stable-dep-of: a4c9efa4dbad ("apparmor: make label_match return a consistent value")

---
 security/apparmor/label.c | 3 ---
 1 file changed, 3 deletions(-)
security/apparmor/label.c +0 -3
index 913678f199c35..02ee128f53d13 100644
@@ -1317,7 +1317,6 @@ static int label_compound_match(struct aa_profile *profile,
 			goto fail;
 	}
 	*perms = *aa_lookup_perms(rules->policy, state);
-	aa_apply_modes_to_perms(profile, perms);
 	if ((perms->allow & request) != request)
 		return -EACCES;
 
@@ -1370,7 +1369,6 @@ static int label_components_match(struct aa_profile *profile,
 
 next:
 	tmp = *aa_lookup_perms(rules->policy, state);
-	aa_apply_modes_to_perms(profile, &tmp);
 	aa_perms_accum(perms, &tmp);
 	label_for_each_cont(i, label, tp) {
 		if (!aa_ns_visible(profile->ns, tp->ns, subns))
@@ -1379,7 +1377,6 @@ static int label_components_match(struct aa_profile *profile,
 		if (!state)
 			goto fail;
 		tmp = *aa_lookup_perms(rules->policy, state);
-		aa_apply_modes_to_perms(profile, &tmp);
 		aa_perms_accum(perms, &tmp);
 	}
 
Signature · 1 line
2.51.0
author maintainer
#706 lore raw

PATCH 702/781 apparmor: make label_match return a consistent value

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: John Johansen <[email protected]>

[ Upstream commit a4c9efa4dbad6dacad6e8b274e30e814c8353097 ]

compound match is inconsistent in returning a state or an integer error this is problemati if the error is ever used as a state in the state machine

Fixes f1bd904175e81 ("apparmor: add the base fns() for domain labels")
---
 security/apparmor/label.c | 20 +++++++++-----------
 1 file changed, 9 insertions(+), 11 deletions(-)
security/apparmor/label.c +9 -11
index 02ee128f53d13..1d3fa5c28d97f 100644
@@ -1278,7 +1278,7 @@ static inline aa_state_t match_component(struct aa_profile *profile,
  * @request: permissions to request
  * @perms: perms struct to set
  *
- * Returns: 0 on success else ERROR
+ * Returns: state match stopped at or DFA_NOMATCH if aborted early
  *
  * For the label A//&B//&C this does the perm match for A//&B//&C
  * @perms should be preinitialized with allperms OR a previous permission
@@ -1305,7 +1305,7 @@ static int label_compound_match(struct aa_profile *profile,
 
 	/* no component visible */
 	*perms = allperms;
-	return 0;
+	return state;
 
 next:
 	label_for_each_cont(i, label, tp) {
@@ -1317,14 +1317,11 @@ static int label_compound_match(struct aa_profile *profile,
 			goto fail;
 	}
 	*perms = *aa_lookup_perms(rules->policy, state);
-	if ((perms->allow & request) != request)
-		return -EACCES;
-
-	return 0;
+	return state;
 
 fail:
 	*perms = nullperms;
-	return state;
+	return DFA_NOMATCH;
 }
 
 /**
@@ -1406,11 +1403,12 @@ int aa_label_match(struct aa_profile *profile, struct aa_ruleset *rules,
 		   struct aa_label *label, aa_state_t state, bool subns,
 		   u32 request, struct aa_perms *perms)
 {
-	int error = label_compound_match(profile, rules, label, state, subns,
-					 request, perms);
-	if (!error)
-		return error;
+	aa_state_t tmp = label_compound_match(profile, rules, label, state, subns,
+					request, perms);
+	if ((perms->allow & request) == request)
+		return 0;
 
+	/* failed compound_match try component matches */
 	*perms = allperms;
 	return label_components_match(profile, rules, label, state, subns,
 				      request, perms);
Signature · 1 line
2.51.0
author maintainer
#707 lore raw

PATCH 703/781 apparmor: avoid per-cpu hold underflow in aa_get_buffer

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Zhengmian Hu <[email protected]>

[ Upstream commit 640cf2f09575c9dc344b3f7be2498d31e3923ead ]

When aa_get_buffer() pulls from the per-cpu list it unconditionally decrements cache->hold. If hold reaches 0 while count is still non-zero, the unsigned decrement wraps to UINT_MAX. This keeps hold non-zero for a very long time, so aa_put_buffer() never returns buffers to the global list, which can starve other CPUs and force repeated kmalloc(aa_g_path_max) allocations.

Guard the decrement so hold never underflows.

Fixes ea9bae12d028 ("apparmor: cache buffers on percpu list if there is lock contention")
---
 security/apparmor/lsm.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
security/apparmor/lsm.c +2 -1
index 8d5d9a966b719..9175fd677ef3d 100644
@@ -2137,7 +2137,8 @@ char *aa_get_buffer(bool in_atomic)
 	if (!list_empty(&cache->head)) {
 		aa_buf = list_first_entry(&cache->head, union aa_buffer, list);
 		list_del(&aa_buf->list);
-		cache->hold--;
+		if (cache->hold)
+			cache->hold--;
 		cache->count--;
 		put_cpu_ptr(&aa_local_buffers);
 		return &aa_buf->buffer[0];
Signature · 1 line
2.51.0
author maintainer
#708 lore raw

PATCH 704/781 apparmor: fix invalid deref of rawdata when export_binary is unset

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Georgia Garcia <[email protected]>

[ Upstream commit df9ac55abd18628bd8cff687ea043660532a3654 ]

If the export_binary parameter is disabled on runtime, profiles that were loaded before that will still have their rawdata stored in apparmorfs, with a symbolic link to the rawdata on the policy directory. When one of those profiles are replaced, the rawdata is set to NULL, but when trying to resolve the symbolic links to rawdata for that profile, it will try to dereference profile->rawdata->name when profile->rawdata is now NULL causing an oops. Fix it by checking if rawdata is set.

[  168.653080] BUG: kernel NULL pointer dereference, address: 0000000000000088
[  168.657420] #PF: supervisor read access in kernel mode
[  168.660619] #PF: error_code(0x0000) - not-present page
[  168.663613] PGD 0 P4D 0
[  168.665450] Oops: Oops: 0000 [#1] SMP NOPTI
[  168.667836] CPU: 1 UID: 0 PID: 1729 Comm: ls Not tainted 6.19.0-rc7+ #3 PREEMPT(voluntary)
[  168.672308] Hardware name: QEMU Ubuntu 24.04 PC (i440FX + PIIX, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014
[  168.679327] RIP: 0010:rawdata_get_link_base.isra.0+0x23/0x330
[  168.682768] Code: 90 90 90 90 90 90 90 0f 1f 44 00 00 55 48 89 e5 41 57 41 56 41 55 41 54 53 48 83 ec 18 48 89 55 d0 48 85 ff 0f 84 e3 01 00 00 <48> 83 3c 25 88 00 00 00 00 0f 84 d4 01 00 00 49 89 f6 49 89 cc e8
[  168.689818] RSP: 0018:ffffcdcb8200fb80 EFLAGS: 00010282
[  168.690871] RAX: ffffffffaee74ec0 RBX: 0000000000000000 RCX: ffffffffb0120158
[  168.692251] RDX: ffffcdcb8200fbe0 RSI: ffff88c187c9fa80 RDI: ffff88c186c98a80
[  168.693593] RBP: ffffcdcb8200fbc0 R08: 0000000000000000 R09: 0000000000000000
[  168.694941] R10: 0000000000000000 R11: 0000000000000000 R12: ffff88c186c98a80
[  168.696289] R13: 00007fff005aaa20 R14: 0000000000000080 R15: ffff88c188f4fce0
[  168.697637] FS:  0000790e81c58280(0000) GS:ffff88c20a957000(0000) knlGS:0000000000000000
[  168.699227] CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
[  168.700349] CR2: 0000000000000088 CR3: 000000012fd3e000 CR4: 0000000000350ef0
[  168.701696] Call Trace:
[  168.702325]  <TASK>
[  168.702995]  rawdata_get_link_data+0x1c/0x30
[  168.704145]  vfs_readlink+0xd4/0x160
[  168.705152]  do_readlinkat+0x114/0x180
[  168.706214]  __x64_sys_readlink+0x1e/0x30
[  168.708653]  x64_sys_call+0x1d77/0x26b0
[  168.709525]  do_syscall_64+0x81/0x500
[  168.710348]  ? do_statx+0x72/0xb0
[  168.711109]  ? putname+0x3e/0x80
[  168.711845]  ? __x64_sys_statx+0xb7/0x100
[  168.712711]  ? x64_sys_call+0x10fc/0x26b0
[  168.713577]  ? do_syscall_64+0xbf/0x500
[  168.714412]  ? do_user_addr_fault+0x1d2/0x8d0
[  168.715404]  ? irqentry_exit+0xb2/0x740
[  168.716359]  ? exc_page_fault+0x90/0x1b0
[  168.717307]  entry_SYSCALL_64_after_hwframe+0x76/0x7e
Fixes 1180b4c757aab ("apparmor: fix dangling symlinks to policy rawdata after replacement")
---
 security/apparmor/apparmorfs.c | 9 +++++++++
 1 file changed, 9 insertions(+)
security/apparmor/apparmorfs.c +9 -0
index 907bd2667e28c..9252172d50682 100644
@@ -1644,6 +1644,15 @@ static const char *rawdata_get_link_base(struct dentry *dentry,
 
 	label = aa_get_label_rcu(&proxy->label);
 	profile = labels_profile(label);
+
+	/* rawdata can be null when aa_g_export_binary is unset during
+	 * runtime and a profile is replaced
+	 */
+	if (!profile->rawdata) {
+		aa_put_label(label);
+		return ERR_PTR(-ENOENT);
+	}
+
 	depth = profile_depth(profile);
 	target = gen_symlink_name(depth, profile->rawdata->name, name);
 	aa_put_label(label);
Signature · 1 line
2.51.0
author maintainer
#709 lore raw

PATCH 705/781 apparmor: fix aa_label to return state from compount and component match

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: John Johansen <[email protected]>

[ Upstream commit 9058798652c8bc0584ed1fb0766a1015046c06e8 ]

aa-label_match is not correctly returning the state in all cases. The only reason this didn't cause a error is that all callers currently ignore the return value.

Fixes a4c9efa4dbad6 ("apparmor: make label_match return a consistent value")
---
 security/apparmor/label.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)
security/apparmor/label.c +6 -6
index 1d3fa5c28d97f..dd6c58f595ba8 100644
@@ -1334,7 +1334,7 @@ static int label_compound_match(struct aa_profile *profile,
  * @request: permissions to request
  * @perms: an initialized perms struct to add accumulation to
  *
- * Returns: 0 on success else ERROR
+ * Returns: the state the match finished in, may be the none matching state
  *
  * For the label A//&B//&C this does the perm match for each of A and B and C
  * @perms should be preinitialized with allperms OR a previous permission
@@ -1362,7 +1362,7 @@ static int label_components_match(struct aa_profile *profile,
 	}
 
 	/* no subcomponents visible - no change in perms */
-	return 0;
+	return state;
 
 next:
 	tmp = *aa_lookup_perms(rules->policy, state);
@@ -1378,13 +1378,13 @@ static int label_components_match(struct aa_profile *profile,
 	}
 
 	if ((perms->allow & request) != request)
-		return -EACCES;
+		return DFA_NOMATCH;
 
-	return 0;
+	return state;
 
 fail:
 	*perms = nullperms;
-	return -EACCES;
+	return DFA_NOMATCH;
 }
 
 /**
@@ -1406,7 +1406,7 @@ int aa_label_match(struct aa_profile *profile, struct aa_ruleset *rules,
 	aa_state_t tmp = label_compound_match(profile, rules, label, state, subns,
 					request, perms);
 	if ((perms->allow & request) == request)
-		return 0;
+		return tmp;
 
 	/* failed compound_match try component matches */
 	*perms = allperms;
Signature · 1 line
2.51.0
author maintainer
#710 lore raw

PATCH 706/781 drm/amdgpu: Fix memory leak in amdgpu_acpi_enumerate_xcc()

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Zilin Guan <[email protected]>

[ Upstream commit c9be63d565789b56ca7b0197e2cb78a3671f95a8 ]

In amdgpu_acpi_enumerate_xcc(), if amdgpu_acpi_dev_init() returns -ENOMEM, the function returns directly without releasing the allocated xcc_info, resulting in a memory leak.

Fix this by ensuring that xcc_info is properly freed in the error paths.

Compile tested only. Issue found using a prototype static analysis tool and code review.

Fixes 4d5275ab0b18 ("drm/amdgpu: Add parsing of acpi xcc objects")
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_acpi.c +3 -1
index d31460a9e9582..7c9d8a6d0bfdb 100644
@@ -1135,8 +1135,10 @@ static int amdgpu_acpi_enumerate_xcc(void)
 		if (!dev_info)
 			ret = amdgpu_acpi_dev_init(&dev_info, xcc_info, sbdf);
 
-		if (ret == -ENOMEM)
+		if (ret == -ENOMEM) {
+			kfree(xcc_info);
 			return ret;
+		}
 
 		if (!dev_info) {
 			kfree(xcc_info);
Signature · 1 line
2.51.0
author maintainer
#711 lore raw

PATCH 707/781 drm/amdgpu: Use kvfree instead of kfree in amdgpu_gmc_get_nps_memranges()

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Zilin Guan <[email protected]>

[ Upstream commit 0c44d61945c4a80775292d96460aa2f22e62f86c ]

amdgpu_discovery_get_nps_info() internally allocates memory for ranges using kvcalloc(), which may use vmalloc() for large allocation. Using kfree() to release vmalloc memory will lead to a memory corruption.

Use kvfree() to safely handle both kmalloc and vmalloc allocations.

Compile tested only. Issue found using a prototype static analysis tool and code review.

Fixes b194d21b9bcc ("drm/amdgpu: Use NPS ranges from discovery table")
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_gmc.c +1 -1
index d9c7ad297293b..2b37398337afc 100644
@@ -1387,7 +1387,7 @@ int amdgpu_gmc_get_nps_memranges(struct amdgpu_device *adev,
 	if (!*exp_ranges)
 		*exp_ranges = range_cnt;
 err:
-	kfree(ranges);
+	kvfree(ranges);
 
 	return ret;
 }
Signature · 1 line
2.51.0
author maintainer
#712 lore raw

PATCH 708/781 drm/amdgpu: Fix memory leak in amdgpu_ras_init()

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Zilin Guan <[email protected]>

[ Upstream commit ee41e5b63c8210525c936ee637a2c8d185ce873c ]

When amdgpu_nbio_ras_sw_init() fails in amdgpu_ras_init(), the function returns directly without freeing the allocated con structure, leading to a memory leak.

Fix this by jumping to the release_con label to properly clean up the allocated memory before returning the error code.

Compile tested only. Issue found using a prototype static analysis tool and code review.

Fixes fdc94d3a8c88 ("drm/amdgpu: Rework pcie_bif ras sw_init")
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_ras.c +1 -1
index 2a6cf7963dde2..8de9f68f7bea6 100644
@@ -4343,7 +4343,7 @@ int amdgpu_ras_init(struct amdgpu_device *adev)
 	 * to handle fatal error */
 	r = amdgpu_nbio_ras_sw_init(adev);
 	if (r)
-		return r;
+		goto release_con;
 
 	if (adev->nbio.ras &&
 	    adev->nbio.ras->init_ras_controller_interrupt) {
Signature · 1 line
2.51.0
author maintainer
#713 lore raw

PATCH 709/781 drm/amdgpu/sdma5: enable queue resets unconditionally

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Alex Deucher <[email protected]>

[ Upstream commit 46a2cb7d24f21132e970cab52359210c3f5ea3c6 ]

There is no firmware version dependency.

Fixes 59fd50b8663b ("drm/amdgpu: Add sysfs interface for sdma reset mask")
Cc Jesse Zhang <[email protected]>
---
 drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c | 15 +++------------
 1 file changed, 3 insertions(+), 12 deletions(-)
drivers/gpu/drm/amd/amdgpu/sdma_v5_0.c +3 -12
index 8ddc4df06a1fd..45e2933214a80 100644
@@ -1424,18 +1424,9 @@ static int sdma_v5_0_sw_init(struct amdgpu_ip_block *ip_block)
 
 	adev->sdma.supported_reset =
 		amdgpu_get_soft_full_reset_mask(&adev->sdma.instance[0].ring);
-	switch (amdgpu_ip_version(adev, SDMA0_HWIP, 0)) {
-	case IP_VERSION(5, 0, 0):
-	case IP_VERSION(5, 0, 2):
-	case IP_VERSION(5, 0, 5):
-		if ((adev->sdma.instance[0].fw_version >= 35) &&
-		    !amdgpu_sriov_vf(adev) &&
-		    !adev->debug_disable_gpu_ring_reset)
-			adev->sdma.supported_reset |= AMDGPU_RESET_TYPE_PER_QUEUE;
-		break;
-	default:
-		break;
-	}
+	if (!amdgpu_sriov_vf(adev) &&
+	    !adev->debug_disable_gpu_ring_reset)
+		adev->sdma.supported_reset |= AMDGPU_RESET_TYPE_PER_QUEUE;
 
 	/* Allocate memory for SDMA IP Dump buffer */
 	ptr = kcalloc(adev->sdma.num_instances * reg_count, sizeof(uint32_t), GFP_KERNEL);
Signature · 1 line
2.51.0
author maintainer
#714 lore raw

PATCH 710/781 drm/amdgpu/sdma5.2: enable queue resets unconditionally

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Alex Deucher <[email protected]>

[ Upstream commit 314d30ad50622fc0d70da71509f9dff21545be14 ]

There is no firmware version dependency. This also enables sdma queue resets on all SDMA 5.2.x based chips.

Fixes 59fd50b8663b ("drm/amdgpu: Add sysfs interface for sdma reset mask")
Cc Jesse Zhang <[email protected]>
---
 drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c | 22 +++-------------------
 1 file changed, 3 insertions(+), 19 deletions(-)
drivers/gpu/drm/amd/amdgpu/sdma_v5_2.c +3 -19
index 51101b0aa2fab..82b1d34a6533e 100644
@@ -1342,25 +1342,9 @@ static int sdma_v5_2_sw_init(struct amdgpu_ip_block *ip_block)
 
 	adev->sdma.supported_reset =
 		amdgpu_get_soft_full_reset_mask(&adev->sdma.instance[0].ring);
-	switch (amdgpu_ip_version(adev, SDMA0_HWIP, 0)) {
-	case IP_VERSION(5, 2, 0):
-	case IP_VERSION(5, 2, 2):
-	case IP_VERSION(5, 2, 3):
-	case IP_VERSION(5, 2, 4):
-		if ((adev->sdma.instance[0].fw_version >= 76) &&
-		    !amdgpu_sriov_vf(adev) &&
-		    !adev->debug_disable_gpu_ring_reset)
-			adev->sdma.supported_reset |= AMDGPU_RESET_TYPE_PER_QUEUE;
-		break;
-	case IP_VERSION(5, 2, 5):
-		if ((adev->sdma.instance[0].fw_version >= 34) &&
-		    !amdgpu_sriov_vf(adev) &&
-		    !adev->debug_disable_gpu_ring_reset)
-			adev->sdma.supported_reset |= AMDGPU_RESET_TYPE_PER_QUEUE;
-		break;
-	default:
-		break;
-	}
+	if (!amdgpu_sriov_vf(adev) &&
+	    !adev->debug_disable_gpu_ring_reset)
+		adev->sdma.supported_reset |= AMDGPU_RESET_TYPE_PER_QUEUE;
 
 	/* Allocate memory for SDMA IP Dump buffer */
 	ptr = kcalloc(adev->sdma.num_instances * reg_count, sizeof(uint32_t), GFP_KERNEL);
Signature · 1 line
2.51.0
author maintainer
#715 lore raw

PATCH 711/781 drm/amdgpu/sdma6: enable queue resets unconditionally

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Alex Deucher <[email protected]>

[ Upstream commit 56423871e9eef1dd069bddef895207fa5ce275fe ]

There is no firmware version dependency. This also enables sdma queue resets on all SDMA 6.x based chips.

Fixes 59fd50b8663b ("drm/amdgpu: Add sysfs interface for sdma reset mask")
Cc Jesse Zhang <[email protected]>
---
 drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c | 15 +++------------
 1 file changed, 3 insertions(+), 12 deletions(-)
drivers/gpu/drm/amd/amdgpu/sdma_v6_0.c +3 -12
index 2170400449872..6809c6d4be5b1 100644
@@ -1351,18 +1351,9 @@ static int sdma_v6_0_sw_init(struct amdgpu_ip_block *ip_block)
 
 	adev->sdma.supported_reset =
 		amdgpu_get_soft_full_reset_mask(&adev->sdma.instance[0].ring);
-	switch (amdgpu_ip_version(adev, SDMA0_HWIP, 0)) {
-	case IP_VERSION(6, 0, 0):
-	case IP_VERSION(6, 0, 2):
-	case IP_VERSION(6, 0, 3):
-		if ((adev->sdma.instance[0].fw_version >= 21) &&
-		    !amdgpu_sriov_vf(adev) &&
-		    !adev->debug_disable_gpu_ring_reset)
-			adev->sdma.supported_reset |= AMDGPU_RESET_TYPE_PER_QUEUE;
-		break;
-	default:
-		break;
-	}
+	if (!amdgpu_sriov_vf(adev) &&
+	    !adev->debug_disable_gpu_ring_reset)
+		adev->sdma.supported_reset |= AMDGPU_RESET_TYPE_PER_QUEUE;
 
 	if (amdgpu_sdma_ras_sw_init(adev)) {
 		dev_err(adev->dev, "Failed to initialize sdma ras block!\n");
Signature · 1 line
2.51.0
author maintainer
#716 lore raw

PATCH 712/781 drm/amdgpu: clean up the amdgpu_cs_parser_bos

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Sunil Khatri <[email protected]>

[ Upstream commit f025a2b8d93358467b8e8f4b3a617e88c5f02fab ]

In low memory conditions, kmalloc can fail. In such conditions unlock the mutex for a clean exit.

We do not need to amdgpu_bo_list_put as it's been handled in the amdgpu_cs_parser_fini.

---
 drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +4 -2
index ecdfe6cb36ccd..dac0b15823f2a 100644
@@ -892,8 +892,10 @@ static int amdgpu_cs_parser_bos(struct amdgpu_cs_parser *p,
 		struct amdgpu_bo *bo = e->bo;
 
 		e->range = amdgpu_hmm_range_alloc(NULL);
-		if (unlikely(!e->range))
-			return -ENOMEM;
+		if (unlikely(!e->range)) {
+			r = -ENOMEM;
+			goto out_free_user_pages;
+		}
 
 		r = amdgpu_ttm_tt_get_user_pages(bo, e->range);
 		if (r)
Signature · 1 line
2.51.0
author maintainer
#717 lore raw

PATCH 713/781 mshv: fix SRCU protection in irqfd resampler ack handler

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Li RongQing <[email protected]>

[ Upstream commit 2e7577cd5ddc1f86d1b6c48caf3cfa87dbb14e34 ]

Replace hlist_for_each_entry_rcu() with hlist_for_each_entry_srcu() in mshv_irqfd_resampler_ack() to correctly handle SRCU-protected linked list traversal.

The function uses SRCU (sleepable RCU) synchronization via partition->pt_irq_srcu, but was incorrectly using the RCU variant for list iteration. This could lead to race conditions when the list is modified concurrently.

Also add srcu_read_lock_held() assertion as required by hlist_for_each_entry_srcu() to ensure we're in the proper read-side critical section.

Fixes 621191d709b14 ("Drivers: hv: Introduce mshv_root module to expose /dev/mshv to VMMs")
---
 drivers/hv/mshv_eventfd.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/hv/mshv_eventfd.c +3 -2
index 0b75ff1edb735..6d176ed8ae516 100644
@@ -87,8 +87,9 @@ static void mshv_irqfd_resampler_ack(struct mshv_irq_ack_notifier *mian)
 
 	idx = srcu_read_lock(&partition->pt_irq_srcu);
 
-	hlist_for_each_entry_rcu(irqfd, &resampler->rsmplr_irqfd_list,
-				 irqfd_resampler_hnode) {
+	hlist_for_each_entry_srcu(irqfd, &resampler->rsmplr_irqfd_list,
+				 irqfd_resampler_hnode,
+				 srcu_read_lock_held(&partition->pt_irq_srcu)) {
 		if (hv_should_clear_interrupt(irqfd->irqfd_lapic_irq.lapic_control.interrupt_type))
 			hv_call_clear_virtual_interrupt(partition->pt_id);
 
Signature · 1 line
2.51.0
author maintainer
#718 lore raw

PATCH 714/781 regulator: mt6363: Fix interrmittent timeout

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Adam Ford <[email protected]>

[ Upstream commit 1a4b0c999101b2532723f9bd9818b70ffa7580f4 ]

Sometimes, the mt6363 regulator would fail to initialize and return with a TIMEOUT error, so add an extra instruction to wake up the bus before issuing the commands.

Fixes 3c36965df808 ("regulator: Add support for MediaTek MT6363 SPMI PMIC Regulators")
---
 drivers/regulator/mt6363-regulator.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)
drivers/regulator/mt6363-regulator.c +8 -1
index e0fbf92e76851..03af5fa536007 100644
@@ -861,7 +861,7 @@ static int mt6363_regulator_probe(struct platform_device *pdev)
 	struct irq_domain *domain;
 	struct irq_fwspec fwspec;
 	struct spmi_device *sdev;
-	int i, ret;
+	int i, ret, val;
 
 	config.regmap = mt6363_spmi_register_regmap(dev);
 	if (IS_ERR(config.regmap))
@@ -870,6 +870,13 @@ static int mt6363_regulator_probe(struct platform_device *pdev)
 	config.dev = dev;
 	sdev = to_spmi_device(dev->parent);
 
+	/*
+	 * The first read may fail if the bootloader sets sleep mode: wake up
+	 * this PMIC with W/R on the SPMI bus and ignore the first result.
+	 * This matches the MT6373 driver behavior.
+	 */
+	regmap_read(config.regmap, MT6363_TOP_TRAP, &val);
+
 	interrupt_parent = of_irq_find_parent(dev->of_node);
 	if (!interrupt_parent)
 		return dev_err_probe(dev, -EINVAL, "Cannot find IRQ parent\n");
Signature · 1 line
2.51.0
author maintainer
#719 lore raw

PATCH 715/781 ASoC: fsl_xcvr: Revert fix missing lock in fsl_xcvr_mode_put()

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Ziyi Guo <[email protected]>

[ Upstream commit 9f16d96e1222391a6b996a1b676bec14fb91e3b2 ]

This reverts commit f51424872760 ("ASoC: fsl_xcvr: fix missing lock in fsl_xcvr_mode_put()").

The original patch attempted to acquire the card->controls_rwsem lock in fsl_xcvr_mode_put(). However, this function is called from the upper ALSA core function snd_ctl_elem_write(), which already holds the write lock on controls_rwsem for the whole put operation. So there is no need to simply hold the lock for fsl_xcvr_activate_ctl() again.

Acquiring the read lock while holding the write lock in the same thread results in a deadlock and a hung task, as reported by Alexander Stein.

---
 sound/soc/fsl/fsl_xcvr.c | 3 ---
 1 file changed, 3 deletions(-)
sound/soc/fsl/fsl_xcvr.c +0 -3
index 5de93f458b569..a268fb81a2f86 100644
@@ -223,13 +223,10 @@ static int fsl_xcvr_mode_put(struct snd_kcontrol *kcontrol,
 
 	xcvr->mode = snd_soc_enum_item_to_val(e, item[0]);
 
-	down_read(&card->snd_card->controls_rwsem);
 	fsl_xcvr_activate_ctl(dai, fsl_xcvr_arc_mode_kctl.name,
 			      (xcvr->mode == FSL_XCVR_MODE_ARC));
 	fsl_xcvr_activate_ctl(dai, fsl_xcvr_earc_capds_kctl.name,
 			      (xcvr->mode == FSL_XCVR_MODE_EARC));
-	up_read(&card->snd_card->controls_rwsem);
-
 	/* Allow playback for SPDIF only */
 	rtd = snd_soc_get_pcm_runtime(card, card->dai_link);
 	rtd->pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream_count =
Signature · 1 line
2.51.0
author maintainer
#720 lore raw

PATCH 716/781 drm/i915/acpi: free _DSM package when no connectors

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Kaushlendra Kumar <[email protected]>

[ Upstream commit 57b85fd53fccfdf14ce7b36d919c31aa752255f8 ]

acpi_evaluate_dsm_typed() returns an ACPI package in pkg. When pkg->package.count == 0, we returned without freeing pkg, leaking memory. Free pkg before returning on the empty case.

Fixes 337d7a1621c7 ("drm/i915: Fix invalid access to ACPI _DSM objects")
(cherry picked from commit c0a27a0ca8a34e96d08bb05a2c5d5ccf63fb8dc0)
---
 drivers/gpu/drm/i915/display/intel_acpi.c | 1 +
 1 file changed, 1 insertion(+)
drivers/gpu/drm/i915/display/intel_acpi.c +1 -0
index 68c01932f7b4f..e06f324027bec 100644
@@ -96,6 +96,7 @@ static void intel_dsm_platform_mux_info(acpi_handle dhandle)
 
 	if (!pkg->package.count) {
 		DRM_DEBUG_DRIVER("no connection in _DSM\n");
+		ACPI_FREE(pkg);
 		return;
 	}
 
Signature · 1 line
2.51.0
author maintainer
#721 lore raw

PATCH 717/781 ASoC: codecs: aw88261: Fix erroneous bitmask logic in Awinic init

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Alexandre Ferrieux <[email protected]>

[ Upstream commit b82fa9b0c26eeb2fde6017f7de2c3c544484efef ]

The aw88261_dev_reg_update() function sets the Awinic registers in a rather nonuniform way:
- most registers get directly overwritten from the firmware blob
- but a handful of them need more delicate logic to preserve some bits from their current value, according to a register- specific mask
For the latter, the logic is basically

       NEW = (OLD & MASK) | (VAL & ~MASK)

However, the ~MASK value is hand-computed, and in the specific case of the SYSCTRL register, in a buggy way.
This patch restores the proper ~MASK value.

Fixes 028a2ae25691 ("ASoC: codecs: Add aw88261 amplifier driver")
---
 sound/soc/codecs/aw88261.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
sound/soc/codecs/aw88261.c +2 -1
index 8f37bfb974ae4..96b1a85c26aa7 100644
@@ -423,9 +423,10 @@ static int aw88261_dev_reg_update(struct aw88261 *aw88261,
 			if (ret)
 				break;
 
+			/* keep all three bits from current hw status */
 			read_val &= (~AW88261_AMPPD_MASK) | (~AW88261_PWDN_MASK) |
 								(~AW88261_HMUTE_MASK);
-			reg_val &= (AW88261_AMPPD_MASK | AW88261_PWDN_MASK | AW88261_HMUTE_MASK);
+			reg_val &= (AW88261_AMPPD_MASK & AW88261_PWDN_MASK & AW88261_HMUTE_MASK);
 			reg_val |= read_val;
 
 			/* enable uls hmute */
Signature · 1 line
2.51.0
author maintainer
#722 lore raw

PATCH 718/781 PCI: Validate window resource type in pbus_select_window_for_type()

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Kai-Heng Feng <[email protected]>

[ Upstream commit e5f72cb9cea599dc9f5a9b80a33560a1d06f01cc ]

After ebe091ad81e1 ("PCI: Use pbus_select_window_for_type() during IO window sizing") and ae88d0b9c57f ("PCI: Use pbus_select_window_for_type() during mem window sizing"), many bridge windows can't get resources assigned:

pci 0006:05:00.0: bridge window [??? 0x00001000-0x00001fff flags 0x20080000]: can't assign; no space pci 0006:05:00.0: bridge window [??? 0x00001000-0x00001fff flags 0x20080000]: failed to assign

Those commits replace find_bus_resource_of_type() with pbus_select_window_for_type(), and the latter lacks resource type validation.

Add the resource type validation back to pbus_select_window_for_type() to match the original behavior.

---
 drivers/pci/setup-bus.c | 13 ++++++++++---
 1 file changed, 10 insertions(+), 3 deletions(-)
drivers/pci/setup-bus.c +10 -3
index 902fdae73c232..09a28cfcd5b88 100644
@@ -225,14 +225,21 @@ static struct resource *pbus_select_window_for_type(struct pci_bus *bus,
 
 	switch (iores_type) {
 	case IORESOURCE_IO:
-		return pci_bus_resource_n(bus, PCI_BUS_BRIDGE_IO_WINDOW);
+		win = pci_bus_resource_n(bus, PCI_BUS_BRIDGE_IO_WINDOW);
+		if (win && (win->flags & IORESOURCE_IO))
+			return win;
+		return NULL;
 
 	case IORESOURCE_MEM:
 		mmio = pci_bus_resource_n(bus, PCI_BUS_BRIDGE_MEM_WINDOW);
 		mmio_pref = pci_bus_resource_n(bus, PCI_BUS_BRIDGE_PREF_MEM_WINDOW);
 
-		if (!(type & IORESOURCE_PREFETCH) ||
-		    !(mmio_pref->flags & IORESOURCE_MEM))
+		if (mmio && !(mmio->flags & IORESOURCE_MEM))
+			mmio = NULL;
+		if (mmio_pref && !(mmio_pref->flags & IORESOURCE_MEM))
+			mmio_pref = NULL;
+
+		if (!(type & IORESOURCE_PREFETCH) || !mmio_pref)
 			return mmio;
 
 		if ((type & IORESOURCE_MEM_64) ||
Signature · 1 line
2.51.0
author maintainer
#723 lore raw

PATCH 719/781 drm/amd/display: Fix dc_link NULL handling in HPD init

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Srinivasan Shanmugam <[email protected]>

[ Upstream commit 226a40c06a183abaeb7529a4f54d6c203bd14407 ]

amdgpu_dm_hpd_init() may see connectors without a valid dc_link.

The code already checks dc_link for the polling decision, but later unconditionally dereferences it when setting up HPD interrupts.

Assign dc_link early and skip connectors where it is NULL.

Fixes the below:
drivers/gpu/drm/amd/amdgpu/../display/amdgpu_dm/amdgpu_dm_irq.c:940 amdgpu_dm_hpd_init()
error: we previously assumed 'dc_link' could be null (see line 931)

drivers/gpu/drm/amd/amdgpu/../display/amdgpu_dm/amdgpu_dm_irq.c

    923                 /*
    924                  * Analog connectors may be hot-plugged unlike other connector
    925                  * types that don't support HPD. Only poll analog connectors.
    926                  */
    927                 use_polling |=
    928                         amdgpu_dm_connector->dc_link &&
                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The patch adds this NULL check but hopefully it can be removed

    929                         dc_connector_supports_analog(amdgpu_dm_connector->dc_link->link_id.id);
    930
    931                 dc_link = amdgpu_dm_connector->dc_link;

dc_link assigned here.

932
933 /*
934 * Get a base driver irq reference for hpd ints for the lifetime
935 * of dm. Note that only hpd interrupt types are registered with
936 * base driver; hpd_rx types aren't. IOW, amdgpu_irq_get/put on
937 * hpd_rx isn't available. DM currently controls hpd_rx
938 * explicitly with dc_interrupt_set()
939 */
--> 940 if (dc_link->irq_source_hpd != DC_IRQ_SOURCE_INVALID) {
^^^^^^^^^^^^^^^^^^^^^^^ If it's NULL then we are trouble because we dereference it here.

941 irq_type = dc_link->irq_source_hpd - DC_IRQ_SOURCE_HPD1;
942 /*
943 * TODO: There's a mismatch between mode_info.num_hpd
944 * and what bios reports as the # of connectors with hpd

Fixes 4562236b3bc0 ("drm/amd/dc: Add dc display driver (v2)")
Cc Timur Kristóf <[email protected]>
Cc Harry Wentland <[email protected]>
Cc Mario Limonciello <[email protected]>
Cc Alex Hung <[email protected]>
Cc Aurabindo Pillai <[email protected]>
Cc ChiaHsuan Chung <[email protected]>
Cc Roman Li <[email protected]>
---
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_irq.c +4 -5
index e7b0928bd3db7..5948e2a6219e3 100644
@@ -919,16 +919,15 @@ void amdgpu_dm_hpd_init(struct amdgpu_device *adev)
 			continue;
 
 		amdgpu_dm_connector = to_amdgpu_dm_connector(connector);
+		dc_link = amdgpu_dm_connector->dc_link;
+		if (!dc_link)
+			continue;
 
 		/*
 		 * Analog connectors may be hot-plugged unlike other connector
 		 * types that don't support HPD. Only poll analog connectors.
 		 */
-		use_polling |=
-			amdgpu_dm_connector->dc_link &&
-			dc_connector_supports_analog(amdgpu_dm_connector->dc_link->link_id.id);
-
-		dc_link = amdgpu_dm_connector->dc_link;
+		use_polling |= dc_connector_supports_analog(dc_link->link_id.id);
 
 		/*
 		 * Get a base driver irq reference for hpd ints for the lifetime
Signature · 1 line
2.51.0
author maintainer
#724 lore raw

PATCH 720/781 drm/amdgpu: Fix missing unwind in amdgpu_ib_schedule() error path

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Srinivasan Shanmugam <[email protected]>

[ Upstream commit ba038065655c45728be346d0b174a6da08d8a5c5 ]

amdgpu_ib_schedule() returns early after calling amdgpu_ring_undo(). This skips the common free_fence cleanup path. Other error paths were already changed to use goto free_fence, but this one was missed.

Change the early return to goto free_fence so all error paths clean up the same way.

Fixes the below:
drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c:232 amdgpu_ib_schedule()
warn: missing unwind goto?

drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c

    124 int amdgpu_ib_schedule(struct amdgpu_ring *ring, unsigned int num_ibs,
    125                        struct amdgpu_ib *ibs, struct amdgpu_job *job,
    126                        struct dma_fence **f)
    127 {

    ...

    224
    225         if (ring->funcs->insert_start)
    226                 ring->funcs->insert_start(ring);
    227
    228         if (job) {
    229                 r = amdgpu_vm_flush(ring, job, need_pipe_sync);
    230                 if (r) {
    231                         amdgpu_ring_undo(ring);

--> 232 return r;

	The patch changed the other error paths to goto free_fence but
	this one was accidentally skipped.

    233                 }
    234         }
    235
    236         amdgpu_ring_ib_begin(ring);

    ...

    338
    339 free_fence:
    340         if (!job)
    341                 kfree(af);
    342         return r;
    343 }
Fixes f903b85ed0f1 ("drm/amdgpu: fix possible fence leaks from job structure")
Cc Alex Deucher <[email protected]>
Cc Christian König <[email protected]>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/amd/amdgpu/amdgpu_ib.c +1 -1
index 44f230d67da24..bfa64cd7a62d4 100644
@@ -229,7 +229,7 @@ int amdgpu_ib_schedule(struct amdgpu_ring *ring, unsigned int num_ibs,
 		r = amdgpu_vm_flush(ring, job, need_pipe_sync);
 		if (r) {
 			amdgpu_ring_undo(ring);
-			return r;
+			goto free_fence;
 		}
 	}
 
Signature · 1 line
2.51.0
author maintainer
#725 lore raw

PATCH 721/781 drm/amdkfd: Fix watch_id bounds checking in debug address watch v2

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Srinivasan Shanmugam <[email protected]>

[ Upstream commit 5a19302cab5cec7ae7f1a60c619951e6c17d8742 ]

The address watch clear code receives watch_id as an unsigned value (u32), but some helper functions were using a signed int and checked bits by shifting with watch_id.

If a very large watch_id is passed from userspace, it can be converted to a negative value. This can cause invalid shifts and may access memory outside the watch_points array.

drm/amdkfd: Fix watch_id bounds checking in debug address watch v2

Fix this by checking that watch_id is within MAX_WATCH_ADDRESSES before using it. Also use BIT(watch_id) to test and clear bits safely.

This keeps the behavior unchanged for valid watch IDs and avoids undefined behavior for invalid ones.

Fixes the below:
drivers/gpu/drm/amd/amdgpu/../amdkfd/kfd_debug.c:448 kfd_dbg_trap_clear_dev_address_watch() error: buffer overflow 'pdd->watch_points' 4 <= u32max user_rl='0-3,2147483648-u32max' uncapped

drivers/gpu/drm/amd/amdgpu/../amdkfd/kfd_debug.c

    433 int kfd_dbg_trap_clear_dev_address_watch(struct kfd_process_device *pdd,
    434                                         uint32_t watch_id)
    435 {
    436         int r;
    437
    438         if (!kfd_dbg_owns_dev_watch_id(pdd, watch_id))

kfd_dbg_owns_dev_watch_id() doesn't check for negative values so if watch_id is larger than INT_MAX it leads to a buffer overflow. (Negative shifts are undefined).

    439                 return -EINVAL;
    440
    441         if (!pdd->dev->kfd->shared_resources.enable_mes) {
    442                 r = debug_lock_and_unmap(pdd->dev->dqm);
    443                 if (r)
    444                         return r;
    445         }
    446
    447         amdgpu_gfx_off_ctrl(pdd->dev->adev, false);
--> 448         pdd->watch_points[watch_id] = pdd->dev->kfd2kgd->clear_address_watch(
    449                                                         pdd->dev->adev,
    450                                                         watch_id);

v2: (as per, Jonathan Kim)
- Add early watch_id >= MAX_WATCH_ADDRESSES validation in the set path to match the clear path.
- Drop the redundant bounds check in kfd_dbg_owns_dev_watch_id().

Fixes e0f85f4690d0 ("drm/amdkfd: add debug set and clear address watch points operation")
Cc Jonathan Kim <[email protected]>
Cc Felix Kuehling <[email protected]>
Cc Alex Deucher <[email protected]>
Cc Christian König <[email protected]>
---
 drivers/gpu/drm/amd/amdkfd/kfd_debug.c | 20 ++++++++++++--------
 1 file changed, 12 insertions(+), 8 deletions(-)
drivers/gpu/drm/amd/amdkfd/kfd_debug.c +12 -8
index ba99e0f258aee..986cb297de8f8 100644
@@ -401,27 +401,25 @@ static int kfd_dbg_get_dev_watch_id(struct kfd_process_device *pdd, int *watch_i
 	return -ENOMEM;
 }
 
-static void kfd_dbg_clear_dev_watch_id(struct kfd_process_device *pdd, int watch_id)
+static void kfd_dbg_clear_dev_watch_id(struct kfd_process_device *pdd, u32 watch_id)
 {
 	spin_lock(&pdd->dev->watch_points_lock);
 
 	/* process owns device watch point so safe to clear */
-	if ((pdd->alloc_watch_ids >> watch_id) & 0x1) {
-		pdd->alloc_watch_ids &= ~(0x1 << watch_id);
-		pdd->dev->alloc_watch_ids &= ~(0x1 << watch_id);
+	if (pdd->alloc_watch_ids & BIT(watch_id)) {
+		pdd->alloc_watch_ids &= ~BIT(watch_id);
+		pdd->dev->alloc_watch_ids &= ~BIT(watch_id);
 	}
 
 	spin_unlock(&pdd->dev->watch_points_lock);
 }
 
-static bool kfd_dbg_owns_dev_watch_id(struct kfd_process_device *pdd, int watch_id)
+static bool kfd_dbg_owns_dev_watch_id(struct kfd_process_device *pdd, u32 watch_id)
 {
 	bool owns_watch_id = false;
 
 	spin_lock(&pdd->dev->watch_points_lock);
-	owns_watch_id = watch_id < MAX_WATCH_ADDRESSES &&
-			((pdd->alloc_watch_ids >> watch_id) & 0x1);
-
+	owns_watch_id = pdd->alloc_watch_ids & BIT(watch_id);
 	spin_unlock(&pdd->dev->watch_points_lock);
 
 	return owns_watch_id;
@@ -432,6 +430,9 @@ int kfd_dbg_trap_clear_dev_address_watch(struct kfd_process_device *pdd,
 {
 	int r;
 
+	if (watch_id >= MAX_WATCH_ADDRESSES)
+		return -EINVAL;
+
 	if (!kfd_dbg_owns_dev_watch_id(pdd, watch_id))
 		return -EINVAL;
 
@@ -469,6 +470,9 @@ int kfd_dbg_trap_set_dev_address_watch(struct kfd_process_device *pdd,
 	if (r)
 		return r;
 
+	if (*watch_id >= MAX_WATCH_ADDRESSES)
+		return -EINVAL;
+
 	if (!pdd->dev->kfd->shared_resources.enable_mes) {
 		r = debug_lock_and_unmap(pdd->dev->dqm);
 		if (r) {
Signature · 1 line
2.51.0
author maintainer
#726 lore raw

PATCH 722/781 drm/amd/display: Reject cursor plane on DCE when scaled differently than primary

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Timur Kristóf <[email protected]>

[ Upstream commit 41af6215cdbcecd12920f211239479027904abf3 ]

Currently DCE doesn't support the overlay cursor, so the dm_crtc_get_cursor_mode() function returns DM_CURSOR_NATIVE_MODE unconditionally. The outcome is that it doesn't check for the conditions that would necessitate the overlay cursor, meaning that it doesn't reject cases where the native cursor mode isn't supported on DCE.

Remove the early return from dm_crtc_get_cursor_mode() for DCE and instead let it perform the necessary checks and return DM_CURSOR_OVERLAY_MODE. Add a later check that rejects when DM_CURSOR_OVERLAY_MODE would be used with DCE.

---
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +8 -3
index b31bd6fa70181..62622aa622066 100644
@@ -12275,10 +12275,9 @@ static int dm_crtc_get_cursor_mode(struct amdgpu_device *adev,
 
 	/* Overlay cursor not supported on HW before DCN
 	 * DCN401 does not have the cursor-on-scaled-plane or cursor-on-yuv-plane restrictions
-	 * as previous DCN generations, so enable native mode on DCN401 in addition to DCE
+	 * as previous DCN generations, so enable native mode on DCN401
 	 */
-	if (amdgpu_ip_version(adev, DCE_HWIP, 0) == 0 ||
-	    amdgpu_ip_version(adev, DCE_HWIP, 0) == IP_VERSION(4, 0, 1)) {
+	if (amdgpu_ip_version(adev, DCE_HWIP, 0) == IP_VERSION(4, 0, 1)) {
 		*cursor_mode = DM_CURSOR_NATIVE_MODE;
 		return 0;
 	}
@@ -12598,6 +12597,12 @@ static int amdgpu_dm_atomic_check(struct drm_device *dev,
 		 * need to be added for DC to not disable a plane by mistake
 		 */
 		if (dm_new_crtc_state->cursor_mode == DM_CURSOR_OVERLAY_MODE) {
+			if (amdgpu_ip_version(adev, DCE_HWIP, 0) == 0) {
+				drm_dbg(dev, "Overlay cursor not supported on DCE\n");
+				ret = -EINVAL;
+				goto fail;
+			}
+
 			ret = drm_atomic_add_affected_planes(state, crtc);
 			if (ret)
 				goto fail;
Signature · 1 line
2.51.0
author maintainer
#727 lore raw

PATCH 723/781 drm/amd/display: Fix out-of-bounds stream encoder index v3

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Srinivasan Shanmugam <[email protected]>

[ Upstream commit abde491143e4e12eecc41337910aace4e8d59603 ]

eng_id can be negative and that stream_enc_regs[]
can be indexed out of bounds.

eng_id is used directly as an index into stream_enc_regs[], which has only 5 entries. When eng_id is 5 (ENGINE_ID_DIGF) or negative, this can access memory past the end of the array.

Add a bounds check using ARRAY_SIZE() before using eng_id as an index. The unsigned cast also rejects negative values.

This avoids out-of-bounds access.

Fixes the below smatch error:
dcn*_resource.c: stream_encoder_create() may index stream_enc_regs[eng_id] out of bounds (size 5).

drivers/gpu/drm/amd/amdgpu/../display/dc/resource/dcn351/dcn351_resource.c

    1246 static struct stream_encoder *dcn35_stream_encoder_create(
    1247         enum engine_id eng_id,
    1248         struct dc_context *ctx)
    1249 {

    ...

    1255
    1256         /* Mapping of VPG, AFMT, DME register blocks to DIO block instance */
    1257         if (eng_id <= ENGINE_ID_DIGF) {

ENGINE_ID_DIGF is 5. should <= be <?

Unrelated but, ugh, why is Smatch saying that "eng_id" can be negative?
end_id is type signed long, but there are checks in the caller which prevent it from being negative.

    1258                 vpg_inst = eng_id;
    1259                 afmt_inst = eng_id;
    1260         } else
    1261                 return NULL;
    1262

    ...

    1281
    1282         dcn35_dio_stream_encoder_construct(enc1, ctx, ctx->dc_bios,
    1283                                         eng_id, vpg, afmt,
--> 1284                                         &stream_enc_regs[eng_id],
                                                  ^^^^^^^^^^^^^^^^^^^^^^^ This stream_enc_regs[] array has 5 elements so we are one element beyond the end of the array.

    ...

    1287         return &enc1->base;
    1288 }

v2: use explicit bounds check as suggested by Roman/Dan; avoid unsigned int cast

v3: The compiler already knows how to compare the two values, so the
cast (int) is not needed. (Roman)

Fixes 2728e9c7c842 ("drm/amd/display: add DC changes for DCN351")
Cc Harry Wentland <[email protected]>
Cc Mario Limonciello <[email protected]>
Cc Alex Hung <[email protected]>
Cc Aurabindo Pillai <[email protected]>
Cc ChiaHsuan Chung <[email protected]>
Cc Roman Li <[email protected]>
---
 .../drm/amd/display/dc/resource/dcn315/dcn315_resource.c  | 8 ++++----
 .../drm/amd/display/dc/resource/dcn316/dcn316_resource.c  | 8 ++++----
 .../drm/amd/display/dc/resource/dcn32/dcn32_resource.c    | 8 ++++----
 .../drm/amd/display/dc/resource/dcn321/dcn321_resource.c  | 8 ++++----
 .../drm/amd/display/dc/resource/dcn35/dcn35_resource.c    | 8 ++++----
 .../drm/amd/display/dc/resource/dcn351/dcn351_resource.c  | 8 ++++----
 6 files changed, 24 insertions(+), 24 deletions(-)
drivers/gpu/drm/amd/display/dc/resource/dcn315/dcn315_resource.c +4 -4
index 4e962f522f1be..228ae665c7893 100644
@@ -1230,12 +1230,12 @@ static struct stream_encoder *dcn315_stream_encoder_create(
 	/*PHYB is wired off in HW, allow front end to remapping, otherwise needs more changes*/
 
 	/* Mapping of VPG, AFMT, DME register blocks to DIO block instance */
-	if (eng_id <= ENGINE_ID_DIGF) {
-		vpg_inst = eng_id;
-		afmt_inst = eng_id;
-	} else
+	if (eng_id < 0 || eng_id >= ARRAY_SIZE(stream_enc_regs))
 		return NULL;
 
+	vpg_inst = eng_id;
+	afmt_inst = eng_id;
+
 	enc1 = kzalloc(sizeof(struct dcn10_stream_encoder), GFP_KERNEL);
 	vpg = dcn31_vpg_create(ctx, vpg_inst);
 	afmt = dcn31_afmt_create(ctx, afmt_inst);
drivers/gpu/drm/amd/display/dc/resource/dcn316/dcn316_resource.c +4 -4
index 5a95dd54cb429..45abf3b2eb2c4 100644
@@ -1223,12 +1223,12 @@ static struct stream_encoder *dcn316_stream_encoder_create(
 	int afmt_inst;
 
 	/* Mapping of VPG, AFMT, DME register blocks to DIO block instance */
-	if (eng_id <= ENGINE_ID_DIGF) {
-		vpg_inst = eng_id;
-		afmt_inst = eng_id;
-	} else
+	if (eng_id < 0 || eng_id >= ARRAY_SIZE(stream_enc_regs))
 		return NULL;
 
+	vpg_inst = eng_id;
+	afmt_inst = eng_id;
+
 	enc1 = kzalloc(sizeof(struct dcn10_stream_encoder), GFP_KERNEL);
 	vpg = dcn31_vpg_create(ctx, vpg_inst);
 	afmt = dcn31_afmt_create(ctx, afmt_inst);
drivers/gpu/drm/amd/display/dc/resource/dcn32/dcn32_resource.c +4 -4
index b276fec3e479a..d39a0f9c78c92 100644
@@ -1211,12 +1211,12 @@ static struct stream_encoder *dcn32_stream_encoder_create(
 	int afmt_inst;
 
 	/* Mapping of VPG, AFMT, DME register blocks to DIO block instance */
-	if (eng_id <= ENGINE_ID_DIGF) {
-		vpg_inst = eng_id;
-		afmt_inst = eng_id;
-	} else
+	if (eng_id < 0 || eng_id >= ARRAY_SIZE(stream_enc_regs))
 		return NULL;
 
+	vpg_inst = eng_id;
+	afmt_inst = eng_id;
+
 	enc1 = kzalloc(sizeof(struct dcn10_stream_encoder), GFP_KERNEL);
 	vpg = dcn32_vpg_create(ctx, vpg_inst);
 	afmt = dcn32_afmt_create(ctx, afmt_inst);
drivers/gpu/drm/amd/display/dc/resource/dcn321/dcn321_resource.c +4 -4
index 3466ca34c93fe..c72c6dbc0cb4d 100644
@@ -1192,12 +1192,12 @@ static struct stream_encoder *dcn321_stream_encoder_create(
 	int afmt_inst;
 
 	/* Mapping of VPG, AFMT, DME register blocks to DIO block instance */
-	if (eng_id <= ENGINE_ID_DIGF) {
-		vpg_inst = eng_id;
-		afmt_inst = eng_id;
-	} else
+	if (eng_id < 0 || eng_id >= ARRAY_SIZE(stream_enc_regs))
 		return NULL;
 
+	vpg_inst = eng_id;
+	afmt_inst = eng_id;
+
 	enc1 = kzalloc(sizeof(struct dcn10_stream_encoder), GFP_KERNEL);
 	vpg = dcn321_vpg_create(ctx, vpg_inst);
 	afmt = dcn321_afmt_create(ctx, afmt_inst);
drivers/gpu/drm/amd/display/dc/resource/dcn35/dcn35_resource.c +4 -4
index d056e5fd54587..9edabd8ceca9b 100644
@@ -1274,12 +1274,12 @@ static struct stream_encoder *dcn35_stream_encoder_create(
 	int afmt_inst;
 
 	/* Mapping of VPG, AFMT, DME register blocks to DIO block instance */
-	if (eng_id <= ENGINE_ID_DIGF) {
-		vpg_inst = eng_id;
-		afmt_inst = eng_id;
-	} else
+	if (eng_id < 0 || eng_id >= ARRAY_SIZE(stream_enc_regs))
 		return NULL;
 
+	vpg_inst = eng_id;
+	afmt_inst = eng_id;
+
 	enc1 = kzalloc(sizeof(struct dcn10_stream_encoder), GFP_KERNEL);
 	vpg = dcn31_vpg_create(ctx, vpg_inst);
 	afmt = dcn31_afmt_create(ctx, afmt_inst);
drivers/gpu/drm/amd/display/dc/resource/dcn351/dcn351_resource.c +4 -4
index 9fab3169069c4..43ece2bbcd64f 100644
@@ -1254,12 +1254,12 @@ static struct stream_encoder *dcn35_stream_encoder_create(
 	int afmt_inst;
 
 	/* Mapping of VPG, AFMT, DME register blocks to DIO block instance */
-	if (eng_id <= ENGINE_ID_DIGF) {
-		vpg_inst = eng_id;
-		afmt_inst = eng_id;
-	} else
+	if (eng_id < 0 || eng_id >= ARRAY_SIZE(stream_enc_regs))
 		return NULL;
 
+	vpg_inst = eng_id;
+	afmt_inst = eng_id;
+
 	enc1 = kzalloc(sizeof(struct dcn10_stream_encoder), GFP_KERNEL);
 	vpg = dcn31_vpg_create(ctx, vpg_inst);
 	afmt = dcn31_afmt_create(ctx, afmt_inst);
Signature · 1 line
2.51.0
author maintainer
#728 lore raw

PATCH 724/781 spi: wpcm-fiu: Fix potential NULL pointer dereference in wpcm_fiu_probe()

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Felix Gu <[email protected]>

[ Upstream commit 888a0a802c467bbe34a42167bdf9d7331333440a ]

platform_get_resource_byname() can return NULL, which would cause a crash when passed the pointer to resource_size().

Move the fiu->memory_size assignment after the error check for devm_ioremap_resource() to prevent the potential NULL pointer dereference.

Fixes 9838c182471e ("spi: wpcm-fiu: Add direct map support")
---
 drivers/spi/spi-wpcm-fiu.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/spi/spi-wpcm-fiu.c +1 -1
index a9aee2a6c7dcb..c47b56f0933f1 100644
@@ -459,11 +459,11 @@ static int wpcm_fiu_probe(struct platform_device *pdev)
 
 	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "memory");
 	fiu->memory = devm_ioremap_resource(dev, res);
-	fiu->memory_size = min_t(size_t, resource_size(res), MAX_MEMORY_SIZE_TOTAL);
 	if (IS_ERR(fiu->memory))
 		return dev_err_probe(dev, PTR_ERR(fiu->memory),
 			       "Failed to map flash memory window\n");
 
+	fiu->memory_size = min_t(size_t, resource_size(res), MAX_MEMORY_SIZE_TOTAL);
 	fiu->shm_regmap = syscon_regmap_lookup_by_phandle_optional(dev->of_node, "nuvoton,shm");
 
 	wpcm_fiu_hw_init(fiu);
Signature · 1 line
2.51.0
author maintainer
#729 lore raw

PATCH 725/781 gpio: cdev: Avoid NULL dereference in linehandle_create()

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Douglas Anderson <[email protected]>

[ Upstream commit 6af6be278e3ba2ffb6af5b796c89dfb3f5d9063e ]

In linehandle_create(), there is a statement like this:
retain_and_null_ptr(lh);

Soon after, there is a debug printout that dereferences "lh", which will crash things.

Avoid the crash by using handlereq.lines, which is the same value.

---
 drivers/gpio/gpiolib-cdev.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpio/gpiolib-cdev.c +1 -1
index 2adc3c0709082..189127721e383 100644
@@ -388,7 +388,7 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip)
 	fd_publish(fdf);
 
 	dev_dbg(&gdev->dev, "registered chardev handle for %d lines\n",
-		lh->num_descs);
+		handlereq.lines);
 
 	return 0;
 }
Signature · 1 line
2.51.0
author maintainer
#730 lore raw

PATCH 726/781 s390/kexec: Make KEXEC_SIG available when CONFIG_MODULES=n

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Alexander Egorenkov <[email protected]>

[ Upstream commit dd3411959b57df6e05a3ccbac67b0a836871c0c4 ]

The commit c8424e776b09 ("MODSIGN: Export module signature definitions") replaced the dependency of KEXEC_SIG on SYSTEM_DATA_VERIFICATION with the dependency on MODULE_SIG_FORMAT. This change disables KEXEC_SIG in s390 kernels built with MODULES=n if nothing else selects MODULE_SIG_FORMAT.

Furthermore, the signature verification in s390 kexec does not require MODULE_SIG_FORMAT because it requires only the struct module_signature and, therefore, does not depend on code in kernel/module_signature.c.

But making ARCH_SUPPORTS_KEXEC_SIG depend on SYSTEM_DATA_VERIFICATION is also incorrect because it makes KEXEC_SIG available on s390 only if some other arbitrary option (for instance a file system or device driver) selects it directly or indirectly.

To properly make KEXEC_SIG available for s390 kernels built with MODULES=y as well as MODULES=n _and_ also not depend on arbitrary options selecting SYSTEM_DATA_VERIFICATION, set ARCH_SUPPORTS_KEXEC_SIG=y for s390 and select SYSTEM_DATA_VERIFICATION when KEXEC_SIG=y.

Fixes c8424e776b09 ("MODSIGN: Export module signature definitions")
---
 arch/s390/Kconfig | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
arch/s390/Kconfig +2 -1
index 0e5fad5f06ca1..783be50f38f2b 100644
@@ -275,6 +275,7 @@ config S390
 	select SPARSE_IRQ
 	select SWIOTLB
 	select SYSCTL_EXCEPTION_TRACE
+	select SYSTEM_DATA_VERIFICATION if KEXEC_SIG
 	select THREAD_INFO_IN_TASK
 	select TRACE_IRQFLAGS_SUPPORT
 	select TTY
@@ -301,7 +302,7 @@ config ARCH_SUPPORTS_KEXEC_FILE
 	def_bool y
 
 config ARCH_SUPPORTS_KEXEC_SIG
-	def_bool MODULE_SIG_FORMAT
+	def_bool y
 
 config ARCH_SUPPORTS_KEXEC_PURGATORY
 	def_bool y
Signature · 1 line
2.51.0
author maintainer
#731 lore raw

PATCH 727/781 drm/xe/pf: Fix sysfs initialization

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Michal Wajdeczko <[email protected]>

[ Upstream commit bf7172cd25ed182f30af2cbb9f80c730dc717d8e ]

In case of devm_add_action_or_reset() failure the provided cleanup action will be run immediately on the not yet initialized kobject. This may lead to errors like:

[ ] kobject: '(null)' (ff110001393608e0): is not initialized, yet kobject_put() is being called. [ ] WARNING: lib/kobject.c:734 at kobject_put+0xd9/0x250, CPU#0: kworker/0:0/9
[ ] RIP: 0010:kobject_put+0xdf/0x250
[ ] Call Trace:

 [ ]  xe_sriov_pf_sysfs_init+0x21/0x100 [xe]
 [ ]  xe_sriov_pf_init_late+0x87/0x2b0 [xe]
 [ ]  xe_sriov_init_late+0x5f/0x2c0 [xe]
 [ ]  xe_device_probe+0x5f2/0xc20 [xe]
 [ ]  xe_pci_probe+0x396/0x610 [xe]
 [ ]  local_pci_probe+0x47/0xb0

[ ] refcount_t: underflow; use-after-free.
[ ] WARNING: lib/refcount.c:28 at refcount_warn_saturate+0x68/0xb0, CPU#0: kworker/0:0/9 [ ] RIP: 0010:refcount_warn_saturate+0x68/0xb0
[ ] Call Trace:

 [ ]  kobject_put+0x174/0x250
 [ ]  xe_sriov_pf_sysfs_init+0x21/0x100 [xe]
 [ ]  xe_sriov_pf_init_late+0x87/0x2b0 [xe]
 [ ]  xe_sriov_init_late+0x5f/0x2c0 [xe]
 [ ]  xe_device_probe+0x5f2/0xc20 [xe]
 [ ]  xe_pci_probe+0x396/0x610 [xe]
 [ ]  local_pci_probe+0x47/0xb0

Fix that by calling kobject_init() and kobject_add() separately and register cleanup action after the kobject is initialized.

Also make this cleanup registration a part of the create helper to fix another mistake, as in the loop we were wrongly passing parent kobject while registering cleanup action, and this resulted in some undetected leaks.

Fixes 5c170a4d9c53 ("drm/xe/pf: Prepare sysfs for SR-IOV admin attributes")
Cc Rodrigo Vivi <[email protected]>
(cherry picked from commit 98b16727f07e26a5d4de84d88805ce7ffcfdd324)
---
 drivers/gpu/drm/xe/xe_sriov_pf_sysfs.c | 54 +++++++++++++-------------
 1 file changed, 26 insertions(+), 28 deletions(-)
drivers/gpu/drm/xe/xe_sriov_pf_sysfs.c +26 -28
index c0b767ac735cf..d1c1f6c295664 100644
@@ -349,18 +349,33 @@ static const struct attribute_group *xe_sriov_vf_attr_groups[] = {
 
 /* no user serviceable parts below */
 
-static struct kobject *create_xe_sriov_kobj(struct xe_device *xe, unsigned int vfid)
+static void action_put_kobject(void *arg)
+{
+	struct kobject *kobj = arg;
+
+	kobject_put(kobj);
+}
+
+static struct kobject *create_xe_sriov_kobj(struct xe_device *xe, unsigned int vfid,
+					    const struct kobj_type *ktype)
 {
 	struct xe_sriov_kobj *vkobj;
+	int err;
 
 	xe_sriov_pf_assert_vfid(xe, vfid);
 
 	vkobj = kzalloc(sizeof(*vkobj), GFP_KERNEL);
 	if (!vkobj)
-		return NULL;
+		return ERR_PTR(-ENOMEM);
 
 	vkobj->xe = xe;
 	vkobj->vfid = vfid;
+	kobject_init(&vkobj->base, ktype);
+
+	err = devm_add_action_or_reset(xe->drm.dev, action_put_kobject, &vkobj->base);
+	if (err)
+		return ERR_PTR(err);
+
 	return &vkobj->base;
 }
 
@@ -471,28 +486,17 @@ static void pf_sysfs_note(struct xe_device *xe, int err, const char *what)
 	xe_sriov_dbg(xe, "Failed to setup sysfs %s (%pe)\n", what, ERR_PTR(err));
 }
 
-static void action_put_kobject(void *arg)
-{
-	struct kobject *kobj = arg;
-
-	kobject_put(kobj);
-}
-
 static int pf_setup_root(struct xe_device *xe)
 {
 	struct kobject *parent = &xe->drm.dev->kobj;
 	struct kobject *root;
 	int err;
 
-	root = create_xe_sriov_kobj(xe, PFID);
-	if (!root)
-		return pf_sysfs_error(xe, -ENOMEM, "root obj");
-
-	err = devm_add_action_or_reset(xe->drm.dev, action_put_kobject, root);
-	if (err)
-		return pf_sysfs_error(xe, err, "root action");
+	root = create_xe_sriov_kobj(xe, PFID, &xe_sriov_dev_ktype);
+	if (IS_ERR(root))
+		return pf_sysfs_error(xe, PTR_ERR(root), "root obj");
 
-	err = kobject_init_and_add(root, &xe_sriov_dev_ktype, parent, "sriov_admin");
+	err = kobject_add(root, parent, "sriov_admin");
 	if (err)
 		return pf_sysfs_error(xe, err, "root init");
 
@@ -513,20 +517,14 @@ static int pf_setup_tree(struct xe_device *xe)
 	root = xe->sriov.pf.sysfs.root;
 
 	for (n = 0; n <= totalvfs; n++) {
-		kobj = create_xe_sriov_kobj(xe, VFID(n));
-		if (!kobj)
-			return pf_sysfs_error(xe, -ENOMEM, "tree obj");
-
-		err = devm_add_action_or_reset(xe->drm.dev, action_put_kobject, root);
-		if (err)
-			return pf_sysfs_error(xe, err, "tree action");
+		kobj = create_xe_sriov_kobj(xe, VFID(n), &xe_sriov_vf_ktype);
+		if (IS_ERR(kobj))
+			return pf_sysfs_error(xe, PTR_ERR(kobj), "tree obj");
 
 		if (n)
-			err = kobject_init_and_add(kobj, &xe_sriov_vf_ktype,
-						   root, "vf%u", n);
+			err = kobject_add(kobj, root, "vf%u", n);
 		else
-			err = kobject_init_and_add(kobj, &xe_sriov_vf_ktype,
-						   root, "pf");
+			err = kobject_add(kobj, root, "pf");
 		if (err)
 			return pf_sysfs_error(xe, err, "tree init");
 
Signature · 1 line
2.51.0
author maintainer
#732 lore raw

PATCH 728/781 drm/xe/configfs: Fix parameter name omitted errors

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Michal Wajdeczko <[email protected]>

[ Upstream commit 2a673fb4d787ce6672862cb693112378bff86abb ]

On some configs and old compilers we can get following build errors:

../drivers/gpu/drm/xe/xe_configfs.h: In function 'xe_configfs_get_ctx_restore_mid_bb':
../drivers/gpu/drm/xe/xe_configfs.h:40:76: error: parameter name omitted
static inline u32 xe_configfs_get_ctx_restore_mid_bb(struct pci_dev *pdev, enum xe_engine_class,

                                                                            ^~~~~~~~~~~~~~~~~~~~
  ../drivers/gpu/drm/xe/xe_configfs.h: In function 'xe_configfs_get_ctx_restore_post_bb':
  ../drivers/gpu/drm/xe/xe_configfs.h:42:77: error: parameter name omitted
   static inline u32 xe_configfs_get_ctx_restore_post_bb(struct pci_dev *pdev, enum xe_engine_class,
                                                                             ^~~~~~~~~~~~~~~~~~~~

when trying to define our configfs stub functions. Fix that.

Fixes 7a4756b2fd04 ("drm/xe/lrc: Allow to add user commands mid context switch")
Cc Rodrigo Vivi <[email protected]>
(cherry picked from commit f59cde8a2452b392115d2af8f1143a94725f4827)
---
 drivers/gpu/drm/xe/xe_configfs.h | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)
drivers/gpu/drm/xe/xe_configfs.h +8 -4
index fed57be0b90e1..f3683bc7eb90c 100644
@@ -21,9 +21,11 @@ bool xe_configfs_primary_gt_allowed(struct pci_dev *pdev);
 bool xe_configfs_media_gt_allowed(struct pci_dev *pdev);
 u64 xe_configfs_get_engines_allowed(struct pci_dev *pdev);
 bool xe_configfs_get_psmi_enabled(struct pci_dev *pdev);
-u32 xe_configfs_get_ctx_restore_mid_bb(struct pci_dev *pdev, enum xe_engine_class,
+u32 xe_configfs_get_ctx_restore_mid_bb(struct pci_dev *pdev,
+				       enum xe_engine_class class,
 				       const u32 **cs);
-u32 xe_configfs_get_ctx_restore_post_bb(struct pci_dev *pdev, enum xe_engine_class,
+u32 xe_configfs_get_ctx_restore_post_bb(struct pci_dev *pdev,
+					enum xe_engine_class class,
 					const u32 **cs);
 #ifdef CONFIG_PCI_IOV
 unsigned int xe_configfs_get_max_vfs(struct pci_dev *pdev);
@@ -37,9 +39,11 @@ static inline bool xe_configfs_primary_gt_allowed(struct pci_dev *pdev) { return
 static inline bool xe_configfs_media_gt_allowed(struct pci_dev *pdev) { return true; }
 static inline u64 xe_configfs_get_engines_allowed(struct pci_dev *pdev) { return U64_MAX; }
 static inline bool xe_configfs_get_psmi_enabled(struct pci_dev *pdev) { return false; }
-static inline u32 xe_configfs_get_ctx_restore_mid_bb(struct pci_dev *pdev, enum xe_engine_class,
+static inline u32 xe_configfs_get_ctx_restore_mid_bb(struct pci_dev *pdev,
+						     enum xe_engine_class class,
 						     const u32 **cs) { return 0; }
-static inline u32 xe_configfs_get_ctx_restore_post_bb(struct pci_dev *pdev, enum xe_engine_class,
+static inline u32 xe_configfs_get_ctx_restore_post_bb(struct pci_dev *pdev,
+						      enum xe_engine_class class,
 						      const u32 **cs) { return 0; }
 static inline unsigned int xe_configfs_get_max_vfs(struct pci_dev *pdev) { return UINT_MAX; }
 #endif
Signature · 1 line
2.51.0
author maintainer
#733 lore raw

PATCH 729/781 drm/xe/mmio: Avoid double-adjust in 64-bit reads

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Shuicheng Lin <[email protected]>

[ Upstream commit 4a9b4e1fa52a6aaa1adbb7f759048df14afed54c ]

xe_mmio_read64_2x32() was adjusting register addresses and then calling xe_mmio_read32(), which applies the adjustment again. This may shift accesses twice if adj_offset < adj_limit. There is no issue currently, as for media gt, adj_offset > adj_limit, so the 2nd adjust will be a no-op. But it may not work in future.

To fix it, replace the adjusted-address comparison with a direct sanity check that ensures the MMIO address adjustment cutoff never falls within the 8-byte range of a 64-bit register. And let xe_mmio_read32() handle address translation.

v2: rewrite the sanity check in a more natural way. (Matt)
v3: Add Fixes tag. (Jani)

Fixes 07431945d8ae ("drm/xe: Avoid 64-bit register reads")
Cc Jani Nikula <[email protected]>
Cc Rodrigo Vivi <[email protected]>
(cherry picked from commit a30f999681126b128a43137793ac84b6a5b7443f)
---
 drivers/gpu/drm/xe/xe_mmio.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)
drivers/gpu/drm/xe/xe_mmio.c +5 -5
index 350dca1f09259..3d59440ec44dd 100644
@@ -260,11 +260,11 @@ u64 xe_mmio_read64_2x32(struct xe_mmio *mmio, struct xe_reg reg)
 	struct xe_reg reg_udw = { .addr = reg.addr + 0x4 };
 	u32 ldw, udw, oldudw, retries;
 
-	reg.addr = xe_mmio_adjusted_addr(mmio, reg.addr);
-	reg_udw.addr = xe_mmio_adjusted_addr(mmio, reg_udw.addr);
-
-	/* we shouldn't adjust just one register address */
-	xe_tile_assert(mmio->tile, reg_udw.addr == reg.addr + 0x4);
+	/*
+	 * The two dwords of a 64-bit register can never straddle the offset
+	 * adjustment cutoff.
+	 */
+	xe_tile_assert(mmio->tile, !in_range(mmio->adj_limit, reg.addr + 1, 7));
 
 	oldudw = xe_mmio_read32(mmio, reg_udw);
 	for (retries = 5; retries; --retries) {
Signature · 1 line
2.51.0
author maintainer
#734 lore raw

PATCH 730/781 drm/xe/xe2_hpg: Fix handling of Wa_14019988906 & Wa_14019877138

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Matt Roper <[email protected]>

[ Upstream commit bc6387a2e0c1562faa56ce2a98cef50cab809e08 ]

The PSS_CHICKEN register has been part of the RCS engine's LRC since it was first introduced in Xe_LP. That means that any workarounds that adjust its value (such as Wa_14019988906 and Wa_14019877138) need to be implemented in the lrc_was[] table so that they become part of the default LRC from which all subsequent LRCs are copied. Although these workarounds were implemented correctly on most platforms, they were incorrectly placed on the engine_was[] table for Xe2_HPG.

Move the workarounds to the proper lrc_was[] table and switch the 'xe_rtp_match_first_render_or_compute' rule to specifically match the RCS since that's the engine whose LRC manages the register.

Bspec: 65182

Fixes 7f3ee7d88058 ("drm/xe/xe2hpg: Add initial GT workarounds")
(cherry picked from commit e04c609eedf4d6748ac0bcada4de1275b034fed6)
---
 drivers/gpu/drm/xe/xe_wa.c | 18 ++++++++----------
 1 file changed, 8 insertions(+), 10 deletions(-)
drivers/gpu/drm/xe/xe_wa.c +8 -10
index e32dd2fde6f1c..c7eab0c4af7a8 100644
@@ -567,16 +567,6 @@ static const struct xe_rtp_entry_sr engine_was[] = {
 		       FUNC(xe_rtp_match_first_render_or_compute)),
 	  XE_RTP_ACTIONS(SET(ROW_CHICKEN, EARLY_EOT_DIS))
 	},
-	{ XE_RTP_NAME("14019988906"),
-	  XE_RTP_RULES(GRAPHICS_VERSION_RANGE(2001, 2002),
-		       FUNC(xe_rtp_match_first_render_or_compute)),
-	  XE_RTP_ACTIONS(SET(XEHP_PSS_CHICKEN, FLSH_IGNORES_PSD))
-	},
-	{ XE_RTP_NAME("14019877138"),
-	  XE_RTP_RULES(GRAPHICS_VERSION_RANGE(2001, 2002),
-		       FUNC(xe_rtp_match_first_render_or_compute)),
-	  XE_RTP_ACTIONS(SET(XEHP_PSS_CHICKEN, FD_END_COLLECT))
-	},
 	{ XE_RTP_NAME("14020338487"),
 	  XE_RTP_RULES(GRAPHICS_VERSION_RANGE(2001, 2002),
 		       FUNC(xe_rtp_match_first_render_or_compute)),
@@ -873,6 +863,14 @@ static const struct xe_rtp_entry_sr lrc_was[] = {
 	  XE_RTP_RULES(GRAPHICS_VERSION(2001), ENGINE_CLASS(RENDER)),
 	  XE_RTP_ACTIONS(SET(WM_CHICKEN3, HIZ_PLANE_COMPRESSION_DIS))
 	},
+	{ XE_RTP_NAME("14019988906"),
+	  XE_RTP_RULES(GRAPHICS_VERSION_RANGE(2001, 2002), ENGINE_CLASS(RENDER)),
+	  XE_RTP_ACTIONS(SET(XEHP_PSS_CHICKEN, FLSH_IGNORES_PSD))
+	},
+	{ XE_RTP_NAME("14019877138"),
+	  XE_RTP_RULES(GRAPHICS_VERSION_RANGE(2001, 2002), ENGINE_CLASS(RENDER)),
+	  XE_RTP_ACTIONS(SET(XEHP_PSS_CHICKEN, FD_END_COLLECT))
+	},
 	{ XE_RTP_NAME("14021490052"),
 	  XE_RTP_RULES(GRAPHICS_VERSION(2001), ENGINE_CLASS(RENDER)),
 	  XE_RTP_ACTIONS(SET(FF_MODE,
Signature · 1 line
2.51.0
author maintainer
#735 lore raw

PATCH 731/781 drm/xe/vf: Avoid reading media version when media GT is disabled

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Piotr Piórkowski <[email protected]>

[ Upstream commit 5e905ec67214444362b81345ef8fde63e58425b6 ]

When the media GT is not allowed, a VF must not attempt to read the media version from the GuC. The GuC may not be loaded, and any attempt to communicate with it would result in a timeout and a VF probe failure:

(...)

[ 1912.406046] xe 0000:01:00.1: [drm] *ERROR* Tile0: GT1: GuC mmio request 0x5507: no reply 0x5507
[ 1912.407277] xe 0000:01:00.1: [drm] *ERROR* Tile0: GT1: [GUC COMMUNICATION] MMIO send failed (-ETIMEDOUT)
[ 1912.408689] xe 0000:01:00.1: [drm] *ERROR* VF: Tile0: GT1: Failed to reset GuC state (-ETIMEDOUT)
[ 1912.413986] xe 0000:01:00.1: probe with driver xe failed with error -110

Let's skip reading the media version for VFs when the media GT is not allowed.

v2: move the condition directly to the VF path

Fixes 7abd69278bb5 ("drm/xe/configfs: Add attribute to disable GT types")
Cc Matt Roper <[email protected]>
Cc Michal Wajdeczko <[email protected]>
Cc Shuicheng Lin <[email protected]>
(cherry picked from commit 0bcacf56dc0b265f9c47056c6a4f0c1394a8a3f0)
---
 drivers/gpu/drm/xe/xe_pci.c | 6 ++++++
 1 file changed, 6 insertions(+)
drivers/gpu/drm/xe/xe_pci.c +6 -0
index 2aa883f5ef797..38ea9d7dad091 100644
@@ -533,6 +533,12 @@ static int read_gmdid(struct xe_device *xe, enum xe_gmdid_type type, u32 *ver, u
 		struct xe_gt *gt __free(kfree) = NULL;
 		int err;
 
+		/* Don't try to read media ver if media GT is not allowed */
+		if (type == GMDID_MEDIA && !xe_configfs_media_gt_allowed(to_pci_dev(xe->drm.dev))) {
+			*ver = *revid = 0;
+			return 0;
+		}
+
 		gt = kzalloc(sizeof(*gt), GFP_KERNEL);
 		if (!gt)
 			return -ENOMEM;
Signature · 1 line
2.51.0
author maintainer
#736 lore raw

PATCH 732/781 drm/xe: Make xe_modparam.force_vram_bar_size signed

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Shuicheng Lin <[email protected]>

[ Upstream commit 1acec6ef0511b92e7974cc5a8768bfd3a659feaf ]

vram_bar_size is registered as an int module parameter and is documented to accept negative values to disable BAR resizing.
Store it as an int in xe_modparam as well, so negative values work as intended and the module_param type matches.

Fixes 80742a1aa26e ("drm/xe: Allow to drop vram resizing")
(cherry picked from commit 25c9aa4dcb5ef2ad9f354d19f8f1eeb690d1c161)
---
 drivers/gpu/drm/xe/xe_module.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/xe/xe_module.h +1 -1
index 5a3bfea8b7b4c..b668495392701 100644
@@ -12,7 +12,7 @@
 struct xe_modparam {
 	bool force_execlist;
 	bool probe_display;
-	u32 force_vram_bar_size;
+	int force_vram_bar_size;
 	int guc_log_level;
 	char *guc_firmware_path;
 	char *huc_firmware_path;
Signature · 1 line
2.51.0
author maintainer
#737 lore raw

PATCH 733/781 drm/xe/bo: Redirect faults to dummy page for wedged device

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Raag Jadav <[email protected]>

[ Upstream commit 4e83a8d58e1c721a89b3ffe15f549007080272e2 ]

As per uapi documentation[1], the prerequisite for wedged device is to redirected page faults to a dummy page. Follow it.

[1] Documentation/gpu/drm-uapi.rst

v2: Add uapi reference and fixes tag (Matthew Brost)

Fixes 7bc00751f877 ("drm/xe: Use device wedged event")
(cherry picked from commit c020fff70d757612933711dd3cc3751d7d782d3c)
---
 drivers/gpu/drm/xe/xe_bo.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/xe/xe_bo.c +1 -1
index 71acd45aa33b0..579e98dec7492 100644
@@ -1942,7 +1942,7 @@ static vm_fault_t xe_bo_cpu_fault(struct vm_fault *vmf)
 	int err = 0;
 	int idx;
 
-	if (!drm_dev_enter(&xe->drm, &idx))
+	if (xe_device_wedged(xe) || !drm_dev_enter(&xe->drm, &idx))
 		return ttm_bo_vm_dummy_page(vmf, vmf->vma->vm_page_prot);
 
 	ret = xe_bo_cpu_fault_fastpath(vmf, xe, bo, needs_rpm);
Signature · 1 line
2.51.0
author maintainer
#738 lore raw

PATCH 734/781 gpio: amd-fch: ionly return allowed values from amd_fch_gpio_get()

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Dmitry Torokhov <[email protected]>

[ Upstream commit fbd03587ba732c612b8a569d1cf5bed72bd3a27c ]

As of 86ef402d805d ("gpiolib: sanitize the return value of gpio_chip::get()") gpiolib requires drivers implementing GPIOs to only return 0, 1 or negative error for the get() callbacks. Ensure that amd-fch complies with this requirement.

Fixes 86ef402d805d ("gpiolib: sanitize the return value of gpio_chip::get()")
Reported-and-tested-by Tj <[email protected]>
---
 drivers/gpio/gpio-amd-fch.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)
drivers/gpio/gpio-amd-fch.c +4 -3
index e6c6c3ec7656e..9f329938202bf 100644
@@ -8,6 +8,7 @@
  *
  */
 
+#include <linux/bitfield.h>
 #include <linux/err.h>
 #include <linux/io.h>
 #include <linux/kernel.h>
@@ -120,15 +121,15 @@ static int amd_fch_gpio_get(struct gpio_chip *gc,
 			    unsigned int offset)
 {
 	unsigned long flags;
-	int ret;
+	u32 val;
 	struct amd_fch_gpio_priv *priv = gpiochip_get_data(gc);
 	void __iomem *ptr = amd_fch_gpio_addr(priv, offset);
 
 	spin_lock_irqsave(&priv->lock, flags);
-	ret = (readl_relaxed(ptr) & AMD_FCH_GPIO_FLAG_READ);
+	val = readl_relaxed(ptr);
 	spin_unlock_irqrestore(&priv->lock, flags);
 
-	return ret;
+	return FIELD_GET(AMD_FCH_GPIO_FLAG_READ, val);
 }
 
 static int amd_fch_gpio_request(struct gpio_chip *chip,
Signature · 1 line
2.51.0
author maintainer
#739 lore raw

PATCH 735/781 efi: Fix reservation of unaccepted memory table

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Kiryl Shutsemau (Meta) <[email protected]>

[ Upstream commit 0862438c90487e79822d5647f854977d50381505 ]

The reserve_unaccepted() function incorrectly calculates the size of the memblock reservation for the unaccepted memory table. It aligns the size of the table, but fails to account for cases where the table's starting physical address (efi.unaccepted) is not page-aligned.

If the table starts at an offset within a page and its end crosses into a subsequent page that the aligned size does not cover, the end of the table will not be reserved. This can lead to the table being overwritten or inaccessible, causing a kernel panic in accept_memory().

This issue was observed when starting Intel TDX VMs with specific memory sizes (e.g., > 64GB).

Fix this by calculating the end address first (including the unaligned start) and then aligning it up, ensuring the entire range is covered by the reservation.

Fixes 8dbe33956d96 ("efi/unaccepted: Make sure unaccepted table is mapped")
---
 drivers/firmware/efi/efi.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/firmware/efi/efi.c +4 -4
index 17b5f3415465e..92e91c3eb4690 100644
@@ -692,13 +692,13 @@ static __init int match_config_table(const efi_guid_t *guid,
 
 static __init void reserve_unaccepted(struct efi_unaccepted_memory *unaccepted)
 {
-	phys_addr_t start, size;
+	phys_addr_t start, end;
 
 	start = PAGE_ALIGN_DOWN(efi.unaccepted);
-	size = PAGE_ALIGN(sizeof(*unaccepted) + unaccepted->size);
+	end = PAGE_ALIGN(efi.unaccepted + sizeof(*unaccepted) + unaccepted->size);
 
-	memblock_add(start, size);
-	memblock_reserve(start, size);
+	memblock_add(start, end - start);
+	memblock_reserve(start, end - start);
 }
 
 int __init efi_config_parse_tables(const efi_config_table_t *config_tables,
Signature · 1 line
2.51.0
author maintainer
#740 lore raw

PATCH 736/781 btrfs: reset block group size class when it becomes empty

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Jiasheng Jiang <[email protected]>

[ Upstream commit 5870ec7c8fe57a8b2c65005e5da5efc054faa3e6 ]

Block group size classes are managed consistently everywhere. Currently, btrfs_use_block_group_size_class() sets a block group's size class to specialize it for a specific allocation size. However, this size class remains "stale" even if the block group becomes completely empty (both used and reserved bytes reach zero).

This happens in two scenarios:

1. When space reservations are freed (e.g., due to errors or transaction aborts) via btrfs_free_reserved_bytes().
2. When the last extent in a block group is freed via btrfs_update_block_group().

While size classes are advisory, a stale size class can cause find_free_extent to unnecessarily skip candidate block groups during initial search loops. This undermines the purpose of size classes to reduce fragmentation by keeping block groups restricted to a specific size class when they could be reused for any size.

Fix this by resetting the size class to BTRFS_BG_SZ_NONE whenever a block group's used and reserved counts both reach zero. This ensures that empty block groups are fully available for any allocation size in the next cycle.

Fixes 52bb7a2166af ("btrfs: introduce size class to block group allocator")
---
 fs/btrfs/block-group.c | 10 ++++++++++
 1 file changed, 10 insertions(+)
fs/btrfs/block-group.c +10 -0
index 08b14449fabeb..c7be37bcbc48d 100644
@@ -3675,6 +3675,14 @@ int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans)
 	return ret;
 }
 
+static void btrfs_maybe_reset_size_class(struct btrfs_block_group *bg)
+{
+	lockdep_assert_held(&bg->lock);
+	if (btrfs_block_group_should_use_size_class(bg) &&
+	    bg->used == 0 && bg->reserved == 0)
+		bg->size_class = BTRFS_BG_SZ_NONE;
+}
+
 int btrfs_update_block_group(struct btrfs_trans_handle *trans,
 			     u64 bytenr, u64 num_bytes, bool alloc)
 {
@@ -3739,6 +3747,7 @@ int btrfs_update_block_group(struct btrfs_trans_handle *trans,
 		old_val -= num_bytes;
 		cache->used = old_val;
 		cache->pinned += num_bytes;
+		btrfs_maybe_reset_size_class(cache);
 		btrfs_space_info_update_bytes_pinned(space_info, num_bytes);
 		space_info->bytes_used -= num_bytes;
 		space_info->disk_used -= num_bytes * factor;
@@ -3867,6 +3876,7 @@ void btrfs_free_reserved_bytes(struct btrfs_block_group *cache, u64 num_bytes,
 	spin_lock(&cache->lock);
 	bg_ro = cache->ro;
 	cache->reserved -= num_bytes;
+	btrfs_maybe_reset_size_class(cache);
 	if (is_delalloc)
 		cache->delalloc_bytes -= num_bytes;
 	spin_unlock(&cache->lock);
Signature · 1 line
2.51.0
author maintainer
#741 lore raw

PATCH 737/781 btrfs: use the correct type to initialize block reserve for delayed refs

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Filipe Manana <[email protected]>

[ Upstream commit 2155d0c0a761a56ce7ede83a26eb23ea0f935260 ]

When initializing the delayed refs block reserve for a transaction handle we are passing a type of BTRFS_BLOCK_RSV_DELOPS, which is meant for delayed items and not for delayed refs. The correct type for delayed refs is BTRFS_BLOCK_RSV_DELREFS.

On release of any excess space reserved in a local delayed refs reserve, we also should transfer that excess space to the global block reserve (it it's full, we return to the space info for general availability).

By initializing a transaction's local delayed refs block reserve with a type of BTRFS_BLOCK_RSV_DELOPS, we were also causing any excess space released from the delayed block reserve (fs_info->delayed_block_rsv, used for delayed inodes and items) to be transferred to the global block reserve instead of the global delayed refs block reserve. This was an unintentional change in commit 28270e25c69a ("btrfs: always reserve space for delayed refs when starting transaction"), but it's not particularly serious as things tend to cancel out each other most of the time and it's relatively rare to be anywhere near exhaustion of the global reserve.

Fix this by initializing a transaction's local delayed refs reserve with a type of BTRFS_BLOCK_RSV_DELREFS and making btrfs_block_rsv_release() attempt to transfer unused space from such a reserve into the global block reserve, just as we did before that commit for when the block reserve is a delayed refs rsv.

---
 fs/btrfs/block-rsv.c   | 7 ++++---
 fs/btrfs/transaction.c | 2 +-
 2 files changed, 5 insertions(+), 4 deletions(-)
fs/btrfs/block-rsv.c +4 -3
index 96cf7a1629870..52fb7d9425917 100644
@@ -276,10 +276,11 @@ u64 btrfs_block_rsv_release(struct btrfs_fs_info *fs_info,
 	struct btrfs_block_rsv *target = NULL;
 
 	/*
-	 * If we are a delayed block reserve then push to the global rsv,
-	 * otherwise dump into the global delayed reserve if it is not full.
+	 * If we are a delayed refs block reserve then push to the global
+	 * reserve, otherwise dump into the global delayed refs reserve if it is
+	 * not full.
 	 */
-	if (block_rsv->type == BTRFS_BLOCK_RSV_DELOPS)
+	if (block_rsv->type == BTRFS_BLOCK_RSV_DELREFS)
 		target = global_rsv;
 	else if (block_rsv != global_rsv && !btrfs_block_rsv_full(delayed_rsv))
 		target = delayed_rsv;
fs/btrfs/transaction.c +1 -1
index e3e0d88d53476..d3e1ba257b9c0 100644
@@ -726,7 +726,7 @@ start_transaction(struct btrfs_root *root, unsigned int num_items,
 
 	h->type = type;
 	INIT_LIST_HEAD(&h->new_bgs);
-	btrfs_init_metadata_block_rsv(fs_info, &h->delayed_rsv, BTRFS_BLOCK_RSV_DELOPS);
+	btrfs_init_metadata_block_rsv(fs_info, &h->delayed_rsv, BTRFS_BLOCK_RSV_DELREFS);
 
 	smp_mb();
 	if (cur_trans->state >= TRANS_STATE_COMMIT_START &&
Signature · 1 line
2.51.0
author maintainer
#742 lore raw

PATCH 738/781 btrfs: fix invalid leaf access in btrfs_quota_enable() if ref key not found

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Filipe Manana <[email protected]>

[ Upstream commit ecb7c2484cfc83a93658907580035a8adf1e0a92 ]

If btrfs_search_slot_for_read() returns 1, it means we did not find any key greater than or equals to the key we asked for, meaning we have reached the end of the tree and therefore the path is not valid. If this happens we need to break out of the loop and stop, instead of continuing and accessing an invalid path.

Fixes 5223cc60b40a ("btrfs: drop the path before adding qgroup items when enabling qgroups")
---
 fs/btrfs/qgroup.c | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)
fs/btrfs/qgroup.c +7 -4
index c634e01140514..bed9d1c11c67a 100644
@@ -1137,11 +1137,14 @@ int btrfs_quota_enable(struct btrfs_fs_info *fs_info,
 			}
 			if (ret > 0) {
 				/*
-				 * Shouldn't happen, but in case it does we
-				 * don't need to do the btrfs_next_item, just
-				 * continue.
+				 * Shouldn't happen because the key should still
+				 * be there (return 0), but in case it does it
+				 * means we have reached the end of the tree -
+				 * there are no more leaves with items that have
+				 * a key greater than or equals to @found_key,
+				 * so just stop the search loop.
 				 */
-				continue;
+				break;
 			}
 		}
 		ret = btrfs_next_item(tree_root, path);
Signature · 1 line
2.51.0
author maintainer
#743 lore raw

PATCH 739/781 drm/amd/display: Use DCE 6 link encoder for DCE 6 analog connectors

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Timur Kristóf <[email protected]>

[ Upstream commit 2de34fbcab2063cd3d52e5872a801b9a5fc755d0 ]

DCE 6 should use the DCE 6 specific link encoder.
This was a copy paste mistake.

Fixes 0fbe321a93ce ("drm/amd/display: Implement DCE analog link encoders (v2)")
---
 drivers/gpu/drm/amd/display/dc/resource/dce60/dce60_resource.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/drm/amd/display/dc/resource/dce60/dce60_resource.c +1 -1
index f0152933bee2c..068fb1df8d889 100644
@@ -734,7 +734,7 @@ static struct link_encoder *dce60_link_encoder_create(
 		return NULL;
 
 	if (enc_init_data->connector.id == CONNECTOR_ID_VGA) {
-		dce110_link_encoder_construct(enc110,
+		dce60_link_encoder_construct(enc110,
 			enc_init_data,
 			&link_enc_feature,
 			&link_enc_regs[ENGINE_ID_DACA],
Signature · 1 line
2.51.0
author maintainer
#744 lore raw

PATCH 740/781 drm/amd/display: Only use analog link encoder with analog engine

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Timur Kristóf <[email protected]>

[ Upstream commit f402898bd101af3166bde236b7f6a43d926e17a0 ]

Some GPUs have analog connectors that work with a DP bridge chip and don't actually have an internal DAC: Those should not use the analog link encoder code path.

Fixes 0fbe321a93ce ("drm/amd/display: Implement DCE analog link encoders (v2)")
---
 .../gpu/drm/amd/display/dc/resource/dce100/dce100_resource.c   | 3 ++-
 drivers/gpu/drm/amd/display/dc/resource/dce60/dce60_resource.c | 3 ++-
 drivers/gpu/drm/amd/display/dc/resource/dce80/dce80_resource.c | 3 ++-
 3 files changed, 6 insertions(+), 3 deletions(-)
drivers/gpu/drm/amd/display/dc/resource/dce100/dce100_resource.c +2 -1
index d40d91ec2035f..a916872db7bd4 100644
@@ -638,7 +638,8 @@ static struct link_encoder *dce100_link_encoder_create(
 	if (!enc110)
 		return NULL;
 
-	if (enc_init_data->connector.id == CONNECTOR_ID_VGA) {
+	if (enc_init_data->connector.id == CONNECTOR_ID_VGA &&
+	    enc_init_data->analog_engine != ENGINE_ID_UNKNOWN) {
 		dce110_link_encoder_construct(enc110,
 			enc_init_data,
 			&link_enc_feature,
drivers/gpu/drm/amd/display/dc/resource/dce60/dce60_resource.c +2 -1
index 068fb1df8d889..90d826237cf00 100644
@@ -733,7 +733,8 @@ static struct link_encoder *dce60_link_encoder_create(
 	if (!enc110)
 		return NULL;
 
-	if (enc_init_data->connector.id == CONNECTOR_ID_VGA) {
+	if (enc_init_data->connector.id == CONNECTOR_ID_VGA &&
+	    enc_init_data->analog_engine != ENGINE_ID_UNKNOWN) {
 		dce60_link_encoder_construct(enc110,
 			enc_init_data,
 			&link_enc_feature,
drivers/gpu/drm/amd/display/dc/resource/dce80/dce80_resource.c +2 -1
index 8687104cabb72..cde2c2cba1dd6 100644
@@ -740,7 +740,8 @@ static struct link_encoder *dce80_link_encoder_create(
 	if (!enc110)
 		return NULL;
 
-	if (enc_init_data->connector.id == CONNECTOR_ID_VGA) {
+	if (enc_init_data->connector.id == CONNECTOR_ID_VGA &&
+	    enc_init_data->analog_engine != ENGINE_ID_UNKNOWN) {
 		dce110_link_encoder_construct(enc110,
 			enc_init_data,
 			&link_enc_feature,
Signature · 1 line
2.51.0
author maintainer
#745 lore raw

PATCH 741/781 drm/amd/display: Only use analog stream encoder with analog engine

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Timur Kristóf <[email protected]>

[ Upstream commit 17ff034f805e032ed1358624a71381f9d6e29e9e ]

Some GPUs have analog connectors that work with a DP bridge chip and don't actually have an internal DAC: Those should not use the analog stream encoders.

Fixes 5834c33fd3f6 ("drm/amd/display: Add concept of analog encoders (v2)")
---
 .../gpu/drm/amd/display/dc/resource/dce100/dce100_resource.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/gpu/drm/amd/display/dc/resource/dce100/dce100_resource.c +4 -1
index a916872db7bd4..83b9abb64bfcb 100644
@@ -979,7 +979,10 @@ struct stream_encoder *dce100_find_first_free_match_stream_enc_for_link(
 	struct dc_link *link = stream->link;
 	enum engine_id preferred_engine = link->link_enc->preferred_engine;
 
-	if (dc_is_rgb_signal(stream->signal))
+	/* Prefer analog engine if the link encoder has one.
+	 * Otherwise, it's an external encoder.
+	 */
+	if (dc_is_rgb_signal(stream->signal) && link->link_enc->analog_engine != ENGINE_ID_UNKNOWN)
 		preferred_engine = link->link_enc->analog_engine;
 
 	for (i = 0; i < pool->stream_enc_count; i++) {
Signature · 1 line
2.51.0
author maintainer
#746 lore raw

PATCH 742/781 x86/hyperv: Fix error pointer dereference

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Ethan Tidmore <[email protected]>

[ Upstream commit 705d01c8d78121ee1634bfc602ac4b0ad1438fab ]

The function idle_thread_get() can return an error pointer and is not checked for it. Add check for error pointer.

Detected by Smatch:
arch/x86/hyperv/hv_vtl.c:126 hv_vtl_bringup_vcpu() error:
'idle' dereferencing possible ERR_PTR()

Fixes 2b4b90e053a29 ("x86/hyperv: Use per cpu initial stack for vtl context")
---
 arch/x86/hyperv/hv_vtl.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)
arch/x86/hyperv/hv_vtl.c +5 -3
index c0edaed0efb30..9b6a9bc4ab760 100644
@@ -110,7 +110,7 @@ static void hv_vtl_ap_entry(void)
 
 static int hv_vtl_bringup_vcpu(u32 target_vp_index, int cpu, u64 eip_ignored)
 {
-	u64 status;
+	u64 status, rsp, rip;
 	int ret = 0;
 	struct hv_enable_vp_vtl *input;
 	unsigned long irq_flags;
@@ -123,9 +123,11 @@ static int hv_vtl_bringup_vcpu(u32 target_vp_index, int cpu, u64 eip_ignored)
 	struct desc_struct *gdt;
 
 	struct task_struct *idle = idle_thread_get(cpu);
-	u64 rsp = (unsigned long)idle->thread.sp;
+	if (IS_ERR(idle))
+		return PTR_ERR(idle);
 
-	u64 rip = (u64)&hv_vtl_ap_entry;
+	rsp = (unsigned long)idle->thread.sp;
+	rip = (u64)&hv_vtl_ap_entry;
 
 	native_store_gdt(&gdt_ptr);
 	store_idt(&idt_ptr);
Signature · 1 line
2.51.0
author maintainer
#747 lore raw

PATCH 743/781 ASoC: rockchip: i2s-tdm: Use param rate if not provided by set_sysclk

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Detlev Casanova <[email protected]>

[ Upstream commit 0783052534f547f8f201dd4554b1df9f1f8615b5 ]

Drivers will not always call set_sysclk() for all clocks, especially when default mclk-fs can be used.
When that is the case, use the clock rate set in the params multiplied by the default mclk-fs.

Fixes 5323186e2e8d ("ASoC: rockchip: i2s_tdm: Re-add the set_sysclk callback")
---
 sound/soc/rockchip/rockchip_i2s_tdm.c | 10 ++++++++++
 1 file changed, 10 insertions(+)
sound/soc/rockchip/rockchip_i2s_tdm.c +10 -0
index 770b9bfbb384a..fc52149ed6ae3 100644
@@ -22,6 +22,7 @@
 
 #define DRV_NAME "rockchip-i2s-tdm"
 
+#define DEFAULT_MCLK_FS				256
 #define CH_GRP_MAX				4  /* The max channel 8 / 2 */
 #define MULTIPLEX_CH_MAX			10
 
@@ -665,6 +666,15 @@ static int rockchip_i2s_tdm_hw_params(struct snd_pcm_substream *substream,
 			mclk_rate = i2s_tdm->mclk_rx_freq;
 		}
 
+		/*
+		 * When the dai/component driver doesn't need to set mclk-fs for a specific
+		 * clock, it can skip the call to set_sysclk() for that clock.
+		 * In that case, simply use the clock rate from the params and multiply it by
+		 * the default mclk-fs value.
+		 */
+		if (!mclk_rate)
+			mclk_rate = DEFAULT_MCLK_FS * params_rate(params);
+
 		err = clk_set_rate(mclk, mclk_rate);
 		if (err)
 			return err;
Signature · 1 line
2.51.0
author maintainer
#748 lore raw

PATCH 744/781 drm/amd/display: Use same max plane scaling limits for all 64 bpp formats

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Mario Kleiner <[email protected]>

[ Upstream commit f0157ce46cf0e5e2257e19d590c9b16036ce26d4 ]

The plane scaling hw seems to have the same min/max plane scaling limits for all 16 bpc / 64 bpp interleaved pixel color formats.

Therefore add cases to amdgpu_dm_plane_get_min_max_dc_plane_scaling() for all the 16 bpc fixed-point / unorm formats to use the same .fp16 up/downscaling factor limits as used by the fp16 floating point formats.

So far, 16 bpc unorm formats were not handled, and the default: path returned max/min factors for 32 bpp argb8888 formats, which were wrong and bigger than what many DCE / DCN hw generations could handle.

The result sometimes was misscaling of framebuffers with DRM_FORMAT_XRGB16161616, DRM_FORMAT_ARGB16161616, DRM_FORMAT_XBGR16161616, DRM_FORMAT_ABGR16161616, leading to very wrong looking display, as tested on Polaris11 / DCE-11.2.

So far this went unnoticed, because only few userspace clients used such 16 bpc unorm framebuffers, and those didn't use hw plane scaling, so they did not experience this issue.

With upcoming Mesa 26 exposing 16 bpc unorm formats under both OpenGL and Vulkan under Wayland, and the upcoming GNOME 50 Mutter Wayland compositor allowing for direct scanout of these formats, the scaling hw will be used on these formats if possible for HiDPI display scaling, so it is important to use the correct hw scaling limits to avoid wrong display.

Tested on AMD Polaris 11 / DCE 11.2 with upcoming Mesa 26 and GNOME 50 on HiDPI displays with scaling enabled. The mutter Wayland compositor now correctly falls back to scaling via desktop compositing instead of direct scanout, thereby avoiding wrong image display. For unscaled mode, it correctly uses direct scanout.

Fixes 580204038f5b ("drm/amd/display: Enable support for 16 bpc fixed-point framebuffers.")
Cc Alex Deucher <[email protected]>
Cc Harry Wentland <[email protected]>
Cc Leo Li <[email protected]>
---
 drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c | 5 +++++
 1 file changed, 5 insertions(+)
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_plane.c +5 -0
index 7c4496fb4b9d4..f0946e67aef97 100644
@@ -1060,10 +1060,15 @@ static void amdgpu_dm_plane_get_min_max_dc_plane_scaling(struct drm_device *dev,
 		*min_downscale = plane_cap->max_downscale_factor.nv12;
 		break;
 
+	/* All 64 bpp formats have the same fp16 scaling limits */
 	case DRM_FORMAT_XRGB16161616F:
 	case DRM_FORMAT_ARGB16161616F:
 	case DRM_FORMAT_XBGR16161616F:
 	case DRM_FORMAT_ABGR16161616F:
+	case DRM_FORMAT_XRGB16161616:
+	case DRM_FORMAT_ARGB16161616:
+	case DRM_FORMAT_XBGR16161616:
+	case DRM_FORMAT_ABGR16161616:
 		*max_upscale = plane_cap->max_upscale_factor.fp16;
 		*min_downscale = plane_cap->max_downscale_factor.fp16;
 		break;
Signature · 1 line
2.51.0
author maintainer
#749 lore raw

PATCH 745/781 drm/amd/display: Dont call find_analog_engine() twice

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Timur Kristóf <[email protected]>

[ Upstream commit 613b1737abe1bd0a65b49851e777231302095e28 ]

The analog engine is already there in the link_analog_engine variable and assigned to enc_init_data.analog_engine already.

I suspect this was a rebase mistake.

Fixes 436d0d22aa70 ("drm/amd/display: Pass proper DAC encoder ID to VBIOS")
---
 drivers/gpu/drm/amd/display/dc/link/link_factory.c | 1 -
 1 file changed, 1 deletion(-)
drivers/gpu/drm/amd/display/dc/link/link_factory.c +0 -1
index d9cb6b6714009..9003e0d314e00 100644
@@ -648,7 +648,6 @@ static bool construct_phy(struct dc_link *link,
 	enc_init_data.channel = get_ddc_line(link);
 	enc_init_data.hpd_source = get_hpd_line(link);
 	enc_init_data.transmitter = transmitter_from_encoder;
-	enc_init_data.analog_engine = find_analog_engine(link, &enc_init_data.analog_encoder);
 	enc_init_data.encoder = link_encoder;
 	enc_init_data.analog_engine = link_analog_engine;
 
Signature · 1 line
2.51.0
author maintainer
#750 lore raw

PATCH 746/781 drm/amd/display: Turn off DAC in DCE link encoder using VBIOS

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Timur Kristóf <[email protected]>

[ Upstream commit e021ee995056ee7e58114edd92bcd4578d8b4bb5 ]

Apparently, the VBIOS DAC1EncoderControl function is much more graceful about turning off the DAC. It writes various DAC registers in a specific sequence. Use that instead of just clearing the DAC_ENABLE register.

Do this in just the dce110_link_encoder_disable_output function and remove it from the HWSS.

Fixes 0fbe321a93ce ("drm/amd/display: Implement DCE analog link encoders (v2)")
---
 .../drm/amd/display/dc/dce/dce_link_encoder.c | 30 +++++++++++--------
 .../amd/display/dc/hwss/dce110/dce110_hwseq.c |  3 --
 2 files changed, 17 insertions(+), 16 deletions(-)
drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c +17 -13
index 5c1a10f77733a..2e742950a62c7 100644
@@ -131,6 +131,21 @@ static enum bp_result link_transmitter_control(
 	return result;
 }
 
+static enum bp_result link_dac_encoder_control(
+	struct dce110_link_encoder *link_enc,
+	enum bp_encoder_control_action action,
+	uint32_t pix_clk_100hz)
+{
+	struct dc_bios *bios = link_enc->base.ctx->dc_bios;
+	struct bp_encoder_control encoder_control = {0};
+
+	encoder_control.action = action;
+	encoder_control.engine_id = link_enc->base.analog_engine;
+	encoder_control.pixel_clock = pix_clk_100hz / 10;
+
+	return bios->funcs->encoder_control(bios, &encoder_control);
+}
+
 static void enable_phy_bypass_mode(
 	struct dce110_link_encoder *enc110,
 	bool enable)
@@ -1337,19 +1352,8 @@ void dce110_link_encoder_disable_output(
 	struct bp_transmitter_control cntl = { 0 };
 	enum bp_result result;
 
-	switch (enc->analog_engine) {
-	case ENGINE_ID_DACA:
-		REG_UPDATE(DAC_ENABLE, DAC_ENABLE, 0);
-		break;
-	case ENGINE_ID_DACB:
-		/* DACB doesn't seem to be present on DCE6+,
-		 * although there are references to it in the register file.
-		 */
-		DC_LOG_ERROR("%s DACB is unsupported\n", __func__);
-		break;
-	default:
-		break;
-	}
+	if (enc->analog_engine != ENGINE_ID_UNKNOWN)
+		link_dac_encoder_control(enc110, ENCODER_CONTROL_DISABLE, 0);
 
 	/* The code below only applies to connectors that support digital signals. */
 	if (enc->transmitter == TRANSMITTER_UNKNOWN)
drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c +0 -3
index ebd74b43e935e..fd41e52e4d2f1 100644
@@ -1218,9 +1218,6 @@ void dce110_disable_stream(struct pipe_ctx *pipe_ctx)
 		dccg->funcs->disable_symclk_se(dccg, stream_enc->stream_enc_inst,
 					       link_enc->transmitter - TRANSMITTER_UNIPHY_A);
 	}
-
-	if (dc_is_rgb_signal(pipe_ctx->stream->signal))
-		dce110_dac_encoder_control(pipe_ctx, false);
 }
 
 void dce110_unblank_stream(struct pipe_ctx *pipe_ctx,
Signature · 1 line
2.51.0
author maintainer
#751 lore raw

PATCH 747/781 drm/amd/display: Initialize DAC in DCE link encoder using VBIOS

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Timur Kristóf <[email protected]>

[ Upstream commit e2a024345bce78a8e1ed7d9e84c859b05979e41e ]

The VBIOS DAC1EncoderControl() function can initialize the DAC, by writing board-specific values to certain registers. Call this at link encoder hardware initialization time similarly to how the equivalent UNIPHYTransmitterControl initialization is done.

This fixes DAC output on the Radeon HD 7790.

Also remove the ENCODER_CONTROL_SETUP enum from the dac_encoder_control_prepare_params function which is actually not a supported operation for DAC encoders.

Fixes 0fbe321a93ce ("drm/amd/display: Implement DCE analog link encoders (v2)")
---
 drivers/gpu/drm/amd/display/dc/bios/command_table.c   |  3 +--
 drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c | 10 ++++++++++
 2 files changed, 11 insertions(+), 2 deletions(-)
drivers/gpu/drm/amd/display/dc/bios/command_table.c +1 -2
index 76a3559f0ddc1..b692fa37402d9 100644
@@ -1874,8 +1874,7 @@ static void dac_encoder_control_prepare_params(
 	uint8_t dac_standard)
 {
 	params->ucDacStandard = dac_standard;
-	if (action == ENCODER_CONTROL_SETUP ||
-	    action == ENCODER_CONTROL_INIT)
+	if (action == ENCODER_CONTROL_INIT)
 		params->ucAction = ATOM_ENCODER_INIT;
 	else if (action == ENCODER_CONTROL_ENABLE)
 		params->ucAction = ATOM_ENABLE;
drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c +10 -0
index 2e742950a62c7..48a1b3b492e7f 100644
@@ -1033,6 +1033,16 @@ void dce110_link_encoder_hw_init(
 	cntl.coherent = false;
 	cntl.hpd_sel = enc110->base.hpd_source;
 
+	if (enc110->base.analog_engine != ENGINE_ID_UNKNOWN) {
+		result = link_dac_encoder_control(enc110, ENCODER_CONTROL_INIT, 0);
+		if (result != BP_RESULT_OK) {
+			DC_LOG_ERROR("%s: Failed to execute VBIOS command table for DAC!\n",
+				__func__);
+			BREAK_TO_DEBUGGER();
+			return;
+		}
+	}
+
 	/* The code below is only applicable to encoders with a digital transmitter. */
 	if (enc110->base.transmitter == TRANSMITTER_UNKNOWN)
 		return;
Signature · 1 line
2.51.0
author maintainer
#752 lore raw

PATCH 748/781 drm/amd/display: Set CRTC source for DAC using registers

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Timur Kristóf <[email protected]>

[ Upstream commit cbced93894d145239c83881d7fd953b7392c23a8 ]

Apparently the VBIOS SelectCRTC_Source function overwrites a few registers (such as FMT_*) which DC writes in a different place, which can cause problems.

Instead of using the SelectCRTC_Source function from the VBIOS, use the DAC_SOURCE_SELECT register directly, similarly to how it is done for digital link encoders.

Fixes 3be26d81b150 ("drm/amd/display: Support DAC in dce110_hwseq")
---
 .../amd/display/dc/dce/dce_stream_encoder.c   | 23 +++++++++++++---
 .../amd/display/dc/dce/dce_stream_encoder.h   | 12 +++++++--
 .../amd/display/dc/hwss/dce110/dce110_hwseq.c | 26 +------------------
 .../dc/resource/dce100/dce100_resource.c      |  6 +++--
 .../dc/resource/dce60/dce60_resource.c        |  7 +++--
 .../dc/resource/dce80/dce80_resource.c        |  6 +++--
 6 files changed, 43 insertions(+), 37 deletions(-)
drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.c +19 -4
index 574618d5d4a4e..87c19f17c799f 100644
@@ -1498,7 +1498,10 @@ static void dig_connect_to_otg(
 {
 	struct dce110_stream_encoder *enc110 = DCE110STRENC_FROM_STRENC(enc);
 
-	REG_UPDATE(DIG_FE_CNTL, DIG_SOURCE_SELECT, tg_inst);
+	if (enc->id == ENGINE_ID_DACA || enc->id == ENGINE_ID_DACB)
+		REG_UPDATE(DAC_SOURCE_SELECT, DAC_SOURCE_SELECT, tg_inst);
+	else
+		REG_UPDATE(DIG_FE_CNTL, DIG_SOURCE_SELECT, tg_inst);
 }
 
 static unsigned int dig_source_otg(
@@ -1507,7 +1510,10 @@ static unsigned int dig_source_otg(
 	uint32_t tg_inst = 0;
 	struct dce110_stream_encoder *enc110 = DCE110STRENC_FROM_STRENC(enc);
 
-	REG_GET(DIG_FE_CNTL, DIG_SOURCE_SELECT, &tg_inst);
+	if (enc->id == ENGINE_ID_DACA || enc->id == ENGINE_ID_DACB)
+		REG_GET(DAC_SOURCE_SELECT, DAC_SOURCE_SELECT, &tg_inst);
+	else
+		REG_GET(DIG_FE_CNTL, DIG_SOURCE_SELECT, &tg_inst);
 
 	return tg_inst;
 }
@@ -1568,16 +1574,25 @@ void dce110_stream_encoder_construct(
 	enc110->se_mask = se_mask;
 }
 
-static const struct stream_encoder_funcs dce110_an_str_enc_funcs = {};
+static const struct stream_encoder_funcs dce110_an_str_enc_funcs = {
+	.dig_connect_to_otg  = dig_connect_to_otg,
+	.dig_source_otg = dig_source_otg,
+};
 
 void dce110_analog_stream_encoder_construct(
 	struct dce110_stream_encoder *enc110,
 	struct dc_context *ctx,
 	struct dc_bios *bp,
-	enum engine_id eng_id)
+	enum engine_id eng_id,
+	const struct dce110_stream_enc_registers *regs,
+	const struct dce_stream_encoder_shift *se_shift,
+	const struct dce_stream_encoder_mask *se_mask)
 {
 	enc110->base.funcs = &dce110_an_str_enc_funcs;
 	enc110->base.ctx = ctx;
 	enc110->base.id = eng_id;
 	enc110->base.bp = bp;
+	enc110->regs = regs;
+	enc110->se_shift = se_shift;
+	enc110->se_mask = se_mask;
 }
drivers/gpu/drm/amd/display/dc/dce/dce_stream_encoder.h +10 -2
index 068de1392121e..342c0afe6a949 100644
@@ -65,6 +65,7 @@
 	SRI(AFMT_60958_1, DIG, id), \
 	SRI(AFMT_60958_2, DIG, id), \
 	SRI(DIG_FE_CNTL, DIG, id), \
+	SR(DAC_SOURCE_SELECT), \
 	SRI(HDMI_CONTROL, DIG, id), \
 	SRI(HDMI_GC, DIG, id), \
 	SRI(HDMI_GENERIC_PACKET_CONTROL0, DIG, id), \
@@ -290,7 +291,8 @@
 #define SE_COMMON_MASK_SH_LIST_DCE80_100(mask_sh)\
 	SE_COMMON_MASK_SH_LIST_DCE_COMMON(mask_sh),\
 	SE_SF(TMDS_CNTL, TMDS_PIXEL_ENCODING, mask_sh),\
-	SE_SF(TMDS_CNTL, TMDS_COLOR_FORMAT, mask_sh)
+	SE_SF(TMDS_CNTL, TMDS_COLOR_FORMAT, mask_sh),\
+	SE_SF(DAC_SOURCE_SELECT, DAC_SOURCE_SELECT, mask_sh)
 
 #define SE_COMMON_MASK_SH_LIST_DCE110(mask_sh)\
 	SE_COMMON_MASK_SH_LIST_DCE_COMMON(mask_sh),\
@@ -494,6 +496,7 @@ struct dce_stream_encoder_shift {
 	uint8_t DP_VID_N_MUL;
 	uint8_t DP_VID_M_DOUBLE_VALUE_EN;
 	uint8_t DIG_SOURCE_SELECT;
+	uint8_t DAC_SOURCE_SELECT;
 };
 
 struct dce_stream_encoder_mask {
@@ -626,6 +629,7 @@ struct dce_stream_encoder_mask {
 	uint32_t DP_VID_N_MUL;
 	uint32_t DP_VID_M_DOUBLE_VALUE_EN;
 	uint32_t DIG_SOURCE_SELECT;
+	uint32_t DAC_SOURCE_SELECT;
 };
 
 struct dce110_stream_enc_registers {
@@ -653,6 +657,7 @@ struct dce110_stream_enc_registers {
 	uint32_t AFMT_60958_1;
 	uint32_t AFMT_60958_2;
 	uint32_t DIG_FE_CNTL;
+	uint32_t DAC_SOURCE_SELECT;
 	uint32_t DP_MSE_RATE_CNTL;
 	uint32_t DP_MSE_RATE_UPDATE;
 	uint32_t DP_PIXEL_FORMAT;
@@ -712,7 +717,10 @@ void dce110_analog_stream_encoder_construct(
 	struct dce110_stream_encoder *enc110,
 	struct dc_context *ctx,
 	struct dc_bios *bp,
-	enum engine_id eng_id);
+	enum engine_id eng_id,
+	const struct dce110_stream_enc_registers *regs,
+	const struct dce_stream_encoder_shift *se_shift,
+	const struct dce_stream_encoder_mask *se_mask);
 
 void dce110_se_audio_mute_control(
 	struct stream_encoder *enc, bool mute);
drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c +1 -25
index fd41e52e4d2f1..c472303276672 100644
@@ -1600,25 +1600,6 @@ static enum dc_status dce110_enable_stream_timing(
 	return DC_OK;
 }
 
-static void
-dce110_select_crtc_source(struct pipe_ctx *pipe_ctx)
-{
-	struct dc_link *link = pipe_ctx->stream->link;
-	struct dc_bios *bios = link->ctx->dc_bios;
-	struct bp_crtc_source_select crtc_source_select = {0};
-	enum engine_id engine_id = link->link_enc->preferred_engine;
-
-	if (dc_is_rgb_signal(pipe_ctx->stream->signal))
-		engine_id = link->link_enc->analog_engine;
-
-	crtc_source_select.controller_id = CONTROLLER_ID_D0 + pipe_ctx->stream_res.tg->inst;
-	crtc_source_select.color_depth = pipe_ctx->stream->timing.display_color_depth;
-	crtc_source_select.engine_id = engine_id;
-	crtc_source_select.sink_signal = pipe_ctx->stream->signal;
-
-	bios->funcs->select_crtc_source(bios, &crtc_source_select);
-}
-
 enum dc_status dce110_apply_single_controller_ctx_to_hw(
 		struct pipe_ctx *pipe_ctx,
 		struct dc_state *context,
@@ -1638,10 +1619,6 @@ enum dc_status dce110_apply_single_controller_ctx_to_hw(
 		hws->funcs.disable_stream_gating(dc, pipe_ctx);
 	}
 
-	if (pipe_ctx->stream->signal == SIGNAL_TYPE_RGB) {
-		dce110_select_crtc_source(pipe_ctx);
-	}
-
 	if (pipe_ctx->stream_res.audio != NULL) {
 		struct audio_output audio_output = {0};
 
@@ -1721,8 +1698,7 @@ enum dc_status dce110_apply_single_controller_ctx_to_hw(
 		pipe_ctx->stream_res.tg->funcs->set_static_screen_control(
 				pipe_ctx->stream_res.tg, event_triggers, 2);
 
-	if (!dc_is_virtual_signal(pipe_ctx->stream->signal) &&
-		!dc_is_rgb_signal(pipe_ctx->stream->signal))
+	if (!dc_is_virtual_signal(pipe_ctx->stream->signal))
 		pipe_ctx->stream_res.stream_enc->funcs->dig_connect_to_otg(
 			pipe_ctx->stream_res.stream_enc,
 			pipe_ctx->stream_res.tg->inst);
drivers/gpu/drm/amd/display/dc/resource/dce100/dce100_resource.c +4 -2
index 83b9abb64bfcb..b78bb595d69ed 100644
@@ -242,7 +242,8 @@ static const struct dce110_stream_enc_registers stream_enc_regs[] = {
 	stream_enc_regs(3),
 	stream_enc_regs(4),
 	stream_enc_regs(5),
-	stream_enc_regs(6)
+	stream_enc_regs(6),
+	{SR(DAC_SOURCE_SELECT),} /* DACA */
 };
 
 static const struct dce_stream_encoder_shift se_shift = {
@@ -491,7 +492,8 @@ static struct stream_encoder *dce100_stream_encoder_create(
 		return NULL;
 
 	if (eng_id == ENGINE_ID_DACA || eng_id == ENGINE_ID_DACB) {
-		dce110_analog_stream_encoder_construct(enc110, ctx, ctx->dc_bios, eng_id);
+		dce110_analog_stream_encoder_construct(enc110, ctx, ctx->dc_bios, eng_id,
+			&stream_enc_regs[eng_id], &se_shift, &se_mask);
 		return &enc110->base;
 	}
 
drivers/gpu/drm/amd/display/dc/resource/dce60/dce60_resource.c +5 -2
index 90d826237cf00..6cf2faffc961b 100644
@@ -258,7 +258,9 @@ static const struct dce110_stream_enc_registers stream_enc_regs[] = {
 	stream_enc_regs(2),
 	stream_enc_regs(3),
 	stream_enc_regs(4),
-	stream_enc_regs(5)
+	stream_enc_regs(5),
+	{0},
+	{SR(DAC_SOURCE_SELECT),} /* DACA */
 };
 
 static const struct dce_stream_encoder_shift se_shift = {
@@ -607,7 +609,8 @@ static struct stream_encoder *dce60_stream_encoder_create(
 		return NULL;
 
 	if (eng_id == ENGINE_ID_DACA || eng_id == ENGINE_ID_DACB) {
-		dce110_analog_stream_encoder_construct(enc110, ctx, ctx->dc_bios, eng_id);
+		dce110_analog_stream_encoder_construct(enc110, ctx, ctx->dc_bios, eng_id,
+			&stream_enc_regs[eng_id], &se_shift, &se_mask);
 		return &enc110->base;
 	}
 
drivers/gpu/drm/amd/display/dc/resource/dce80/dce80_resource.c +4 -2
index cde2c2cba1dd6..066dbf8125a87 100644
@@ -258,7 +258,8 @@ static const struct dce110_stream_enc_registers stream_enc_regs[] = {
 	stream_enc_regs(3),
 	stream_enc_regs(4),
 	stream_enc_regs(5),
-	stream_enc_regs(6)
+	stream_enc_regs(6),
+	{SR(DAC_SOURCE_SELECT),} /* DACA */
 };
 
 static const struct dce_stream_encoder_shift se_shift = {
@@ -614,7 +615,8 @@ static struct stream_encoder *dce80_stream_encoder_create(
 		return NULL;
 
 	if (eng_id == ENGINE_ID_DACA || eng_id == ENGINE_ID_DACB) {
-		dce110_analog_stream_encoder_construct(enc110, ctx, ctx->dc_bios, eng_id);
+		dce110_analog_stream_encoder_construct(enc110, ctx, ctx->dc_bios, eng_id,
+			&stream_enc_regs[eng_id], &se_shift, &se_mask);
 		return &enc110->base;
 	}
 
Signature · 1 line
2.51.0
author maintainer
#753 lore raw

PATCH 749/781 drm/amd/display: Enable DAC in DCE link encoder

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Timur Kristóf <[email protected]>

[ Upstream commit 4bd8b5f8bcb57b430c35494d8a2471ce5fd7661d ]

Ensure that the DAC output is enabled at the correct time by moving it to the DCE link encoder similarly to how digital outputs are enabled.

This also removes the call to DAC1EncoderControl from the DCE HWSS, which always felt like it was a hacky solution.

Fixes 0fbe321a93ce ("drm/amd/display: Implement DCE analog link encoders (v2)")
---
 .../drm/amd/display/dc/dce/dce_link_encoder.c | 18 +++++++++++++
 .../drm/amd/display/dc/dce/dce_link_encoder.h |  5 ++++
 .../amd/display/dc/hwss/dce110/dce110_hwseq.c | 26 +++++++------------
 .../drm/amd/display/dc/hwss/hw_sequencer.h    |  2 ++
 .../drm/amd/display/dc/inc/hw/link_encoder.h  |  2 ++
 .../gpu/drm/amd/display/dc/link/link_dpms.c   | 14 +++++++++-
 6 files changed, 50 insertions(+), 17 deletions(-)
drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.c +18 -0
index 48a1b3b492e7f..bec8dab156eec 100644
@@ -102,6 +102,7 @@ static const struct link_encoder_funcs dce110_lnk_enc_funcs = {
 	.enable_dp_output = dce110_link_encoder_enable_dp_output,
 	.enable_dp_mst_output = dce110_link_encoder_enable_dp_mst_output,
 	.enable_lvds_output = dce110_link_encoder_enable_lvds_output,
+	.enable_analog_output = dce110_link_encoder_enable_analog_output,
 	.disable_output = dce110_link_encoder_disable_output,
 	.dp_set_lane_settings = dce110_link_encoder_dp_set_lane_settings,
 	.dp_set_phy_pattern = dce110_link_encoder_dp_set_phy_pattern,
@@ -1192,6 +1193,22 @@ void dce110_link_encoder_enable_lvds_output(
 	}
 }
 
+void dce110_link_encoder_enable_analog_output(
+	struct link_encoder *enc,
+	uint32_t pixel_clock)
+{
+	struct dce110_link_encoder *enc110 = TO_DCE110_LINK_ENC(enc);
+	enum bp_result result;
+
+	result = link_dac_encoder_control(enc110, ENCODER_CONTROL_ENABLE, pixel_clock);
+
+	if (result != BP_RESULT_OK) {
+		DC_LOG_ERROR("%s: Failed to execute VBIOS command table!\n",
+			__func__);
+		BREAK_TO_DEBUGGER();
+	}
+}
+
 /* enables DP PHY output */
 void dce110_link_encoder_enable_dp_output(
 	struct link_encoder *enc,
@@ -1776,6 +1793,7 @@ static const struct link_encoder_funcs dce60_lnk_enc_funcs = {
 	.enable_dp_output = dce60_link_encoder_enable_dp_output,
 	.enable_dp_mst_output = dce60_link_encoder_enable_dp_mst_output,
 	.enable_lvds_output = dce110_link_encoder_enable_lvds_output,
+	.enable_analog_output = dce110_link_encoder_enable_analog_output,
 	.disable_output = dce110_link_encoder_disable_output,
 	.dp_set_lane_settings = dce110_link_encoder_dp_set_lane_settings,
 	.dp_set_phy_pattern = dce60_link_encoder_dp_set_phy_pattern,
drivers/gpu/drm/amd/display/dc/dce/dce_link_encoder.h +5 -0
index c58b69bc319b7..6870cb619d208 100644
@@ -273,6 +273,11 @@ void dce110_link_encoder_enable_lvds_output(
 	enum clock_source_id clock_source,
 	uint32_t pixel_clock);
 
+/* enables analog output from the DAC */
+void dce110_link_encoder_enable_analog_output(
+	struct link_encoder *enc,
+	uint32_t pixel_clock);
+
 /* disable PHY output */
 void dce110_link_encoder_disable_output(
 	struct link_encoder *enc,
drivers/gpu/drm/amd/display/dc/hwss/dce110/dce110_hwseq.c +10 -16
index c472303276672..5896ce5511ab1 100644
@@ -659,20 +659,6 @@ void dce110_update_info_frame(struct pipe_ctx *pipe_ctx)
 	}
 }
 
-static void
-dce110_dac_encoder_control(struct pipe_ctx *pipe_ctx, bool enable)
-{
-	struct dc_link *link = pipe_ctx->stream->link;
-	struct dc_bios *bios = link->ctx->dc_bios;
-	struct bp_encoder_control encoder_control = {0};
-
-	encoder_control.action = enable ? ENCODER_CONTROL_ENABLE : ENCODER_CONTROL_DISABLE;
-	encoder_control.engine_id = link->link_enc->analog_engine;
-	encoder_control.pixel_clock = pipe_ctx->stream->timing.pix_clk_100hz / 10;
-
-	bios->funcs->encoder_control(bios, &encoder_control);
-}
-
 void dce110_enable_stream(struct pipe_ctx *pipe_ctx)
 {
 	enum dc_lane_count lane_count =
@@ -703,8 +689,6 @@ void dce110_enable_stream(struct pipe_ctx *pipe_ctx)
 
 	tg->funcs->set_early_control(tg, early_control);
 
-	if (dc_is_rgb_signal(pipe_ctx->stream->signal))
-		dce110_dac_encoder_control(pipe_ctx, true);
 }
 
 static enum bp_result link_transmitter_control(
@@ -3285,6 +3269,15 @@ void dce110_enable_tmds_link_output(struct dc_link *link,
 	link->phy_state.symclk_state = SYMCLK_ON_TX_ON;
 }
 
+static void dce110_enable_analog_link_output(
+		struct dc_link *link,
+		uint32_t pix_clk_100hz)
+{
+	link->link_enc->funcs->enable_analog_output(
+			link->link_enc,
+			pix_clk_100hz);
+}
+
 void dce110_enable_dp_link_output(
 		struct dc_link *link,
 		const struct link_resource *link_res,
@@ -3422,6 +3415,7 @@ static const struct hw_sequencer_funcs dce110_funcs = {
 	.enable_lvds_link_output = dce110_enable_lvds_link_output,
 	.enable_tmds_link_output = dce110_enable_tmds_link_output,
 	.enable_dp_link_output = dce110_enable_dp_link_output,
+	.enable_analog_link_output = dce110_enable_analog_link_output,
 	.disable_link_output = dce110_disable_link_output,
 };
 
drivers/gpu/drm/amd/display/dc/hwss/hw_sequencer.h +2 -0
index 8ed9eea40c564..4f6bd365e055a 100644
@@ -1184,6 +1184,8 @@ struct hw_sequencer_funcs {
 			const struct link_resource *link_res,
 			enum clock_source_id clock_source,
 			uint32_t pixel_clock);
+	void (*enable_analog_link_output)(struct dc_link *link,
+			uint32_t pixel_clock);
 	void (*disable_link_output)(struct dc_link *link,
 			const struct link_resource *link_res,
 			enum signal_type signal);
drivers/gpu/drm/amd/display/dc/inc/hw/link_encoder.h +2 -0
index e638325e35ecf..b1a88618c5bf8 100644
@@ -130,6 +130,8 @@ struct link_encoder_funcs {
 	void (*enable_lvds_output)(struct link_encoder *enc,
 		enum clock_source_id clock_source,
 		uint32_t pixel_clock);
+	void (*enable_analog_output)(struct link_encoder *enc,
+		uint32_t pixel_clock);
 	void (*disable_output)(struct link_encoder *link_enc,
 		enum signal_type signal);
 	void (*dp_set_lane_settings)(struct link_encoder *enc,
drivers/gpu/drm/amd/display/dc/link/link_dpms.c +13 -1
index 6ae1341476171..635f614c06734 100644
@@ -2208,6 +2208,18 @@ static enum dc_status enable_link_dp_mst(
 	return enable_link_dp(state, pipe_ctx);
 }
 
+static enum dc_status enable_link_analog(
+		struct dc_state *state,
+		struct pipe_ctx *pipe_ctx)
+{
+	struct dc_link *link = pipe_ctx->stream->link;
+
+	link->dc->hwss.enable_analog_link_output(
+		link, pipe_ctx->stream->timing.pix_clk_100hz);
+
+	return DC_OK;
+}
+
 static enum dc_status enable_link_virtual(struct pipe_ctx *pipe_ctx)
 {
 	struct dc_link *link = pipe_ctx->stream->link;
@@ -2263,7 +2275,7 @@ static enum dc_status enable_link(
 		status = DC_OK;
 		break;
 	case SIGNAL_TYPE_RGB:
-		status = DC_OK;
+		status = enable_link_analog(state, pipe_ctx);
 		break;
 	case SIGNAL_TYPE_VIRTUAL:
 		status = enable_link_virtual(pipe_ctx);
Signature · 1 line
2.51.0
author maintainer
#754 lore raw

PATCH 750/781 PCI: dwc: ep: Always clear IB maps on BAR update

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Koichiro Den <[email protected]>

[ Upstream commit 8c746e22096579897d1f8f74dbb6b17a6862fb6d ]

dw_pcie_ep_set_bar() currently tears down existing inbound mappings only when either the previous or the new struct pci_epf_bar uses submaps (num_submap != 0). If both the old and new mappings are BAR Match Mode, reprogramming the same ATU index is sufficient, so no explicit teardown was needed.

However, some callers may reuse the same struct pci_epf_bar instance and update it in place before calling set_bar() again. In that case ep_func->epf_bar[bar] and the passed-in epf_bar can point to the same object, so we cannot reliably distinguish BAR Match Mode -> BAR Match Mode from Address Match Mode -> BAR Match Mode. As a result, the conditional teardown based on num_submap becomes unreliable and existing inbound maps may be left active.

Call dw_pcie_ep_clear_ib_maps() unconditionally before reprogramming the BAR so that in-place updates are handled correctly.

This introduces a behavioral change in a corner case: if a BAR reprogramming attempt fails (especially for the long-standing BAR Match Mode -> BAR Match Mode update case), the previously programmed inbound mapping will already have been torn down. This should be acceptable, since the caller observes the error and should not use the BAR for any real transactions in that case.

While at it, document that the existing update parameter check is best-effort for in-place updates.

Fixes cc839bef7727 ("PCI: dwc: ep: Support BAR subrange inbound mapping via Address Match Mode iATU")
---
 drivers/pci/controller/dwc/pcie-designware-ep.c | 14 +++++++++++---
 1 file changed, 11 insertions(+), 3 deletions(-)
drivers/pci/controller/dwc/pcie-designware-ep.c +11 -3
index 6d3c35dd280f3..59fd6ebf01489 100644
@@ -518,6 +518,12 @@ static int dw_pcie_ep_set_bar(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
 		/*
 		 * We can only dynamically change a BAR if the new BAR size and
 		 * BAR flags do not differ from the existing configuration.
+		 *
+		 * Note: this safety check only works when the caller uses
+		 * a new struct pci_epf_bar in the second set_bar() call.
+		 * If the same instance is updated in place and passed in,
+		 * we cannot reliably detect invalid barno/size/flags
+		 * changes here.
 		 */
 		if (ep_func->epf_bar[bar]->barno != bar ||
 		    ep_func->epf_bar[bar]->size != size ||
@@ -526,10 +532,12 @@ static int dw_pcie_ep_set_bar(struct pci_epc *epc, u8 func_no, u8 vfunc_no,
 
 		/*
 		 * When dynamically changing a BAR, tear down any existing
-		 * mappings before re-programming.
+		 * mappings before re-programming. This is redundant when
+		 * both the old and new mappings are BAR Match Mode, but
+		 * required to handle in-place updates and match-mode
+		 * changes reliably.
 		 */
-		if (ep_func->epf_bar[bar]->num_submap || epf_bar->num_submap)
-			dw_pcie_ep_clear_ib_maps(ep, func_no, bar);
+		dw_pcie_ep_clear_ib_maps(ep, func_no, bar);
 
 		/*
 		 * When dynamically changing a BAR, skip writing the BAR reg, as
Signature · 1 line
2.51.0
author maintainer
#755 lore raw

PATCH 751/781 usb: cdns3: fix role switching during resume

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Thomas Richard (TI) <[email protected]>

commit 87e4b043b98a1d269be0b812f383881abee0ca45 upstream.

If the role change while we are suspended, the cdns3 driver switches to the new mode during resume. However, switching to host mode in this context causes a NULL pointer dereference.

The host role's start() operation registers a xhci-hcd device, but its probe is deferred while we are in the resume path. The host role's resume() operation assumes the xhci-hcd device is already probed, which is not the case, leading to the dereference. Since the start() operation of the new role is already called, the resume operation can be skipped.

So skip the resume operation for the new role if a role switch occurs during resume. Once the resume sequence is complete, the xhci-hcd device can be probed in case of host mode.

Unable to handle kernel NULL pointer dereference at virtual address 0000000000000208

Mem abort info:
...
Data abort info:
...
[0000000000000208] pgd=0000000000000000, p4d=0000000000000000

Internal error: Oops: 0000000096000004 [#1]  SMP
Modules linked in:
CPU: 0 UID: 0 PID: 146 Comm: sh Not tainted
6.19.0-rc7-00013-g6e64f4aabfae-dirty #135 PREEMPT
Hardware name: Texas Instruments J7200 EVM (DT)
pstate: 20000005 (nzCv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--)
pc : usb_hcd_is_primary_hcd+0x0/0x1c
lr : cdns_host_resume+0x24/0x5c
...
Call trace:
 usb_hcd_is_primary_hcd+0x0/0x1c (P)
 cdns_resume+0x6c/0xbc
 cdns3_controller_resume.isra.0+0xe8/0x17c
 cdns3_plat_resume+0x18/0x24
 platform_pm_resume+0x2c/0x68
 dpm_run_callback+0x90/0x248
 device_resume+0x100/0x24c
 dpm_resume+0x190/0x2ec
 dpm_resume_end+0x18/0x34
 suspend_devices_and_enter+0x2b0/0xa44
 pm_suspend+0x16c/0x5fc
 state_store+0x80/0xec
 kobj_attr_store+0x18/0x2c
 sysfs_kf_write+0x7c/0x94
 kernfs_fop_write_iter+0x130/0x1dc
 vfs_write+0x240/0x370
 ksys_write+0x70/0x108
 __arm64_sys_write+0x1c/0x28
 invoke_syscall+0x48/0x10c
 el0_svc_common.constprop.0+0x40/0xe0
 do_el0_svc+0x1c/0x28
 el0_svc+0x34/0x108
 el0t_64_sync_handler+0xa0/0xe4
 el0t_64_sync+0x198/0x19c
Code: 52800003 f9407ca5 d63f00a0 17ffffe4 (f9410401)
---[ end trace 0000000000000000 ]---
---
 drivers/usb/cdns3/core.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/usb/cdns3/core.c +1 -1
@@ -551,7 +551,7 @@ int cdns_resume(struct cdns *cdns)
 		}
 	}
 
-	if (cdns->roles[cdns->role]->resume)
+	if (!role_changed && cdns->roles[cdns->role]->resume)
 		cdns->roles[cdns->role]->resume(cdns, power_lost);
 
 	return 0;
author maintainer
#756 lore raw

PATCH 752/781 MIPS: Work around LLVM bug when gp is used as global register variable

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Yao Zi <[email protected]>

commit 30bfc2d6a1132a89a5f1c3b96c59cf3e4d076ea3 upstream.

On MIPS, __current_thread_info is defined as global register variable locating in $gp, and is simply assigned with new address during kernel relocation.

This however is broken with LLVM, which always restores $gp if it finds $gp is clobbered in any form, including when intentionally through a global register variable. This is against GCC's documentation[1], which requires a callee-saved register used as global register variable not to be restored if it's clobbered.

As a result, $gp will continue to point to the unrelocated kernel after the epilog of relocate_kernel(), leading to an early crash in init_idle,

[    0.000000] CPU 0 Unable to handle kernel paging request at virtual address 0000000000000000, epc == ffffffff81afada8, ra == ffffffff81afad90
[    0.000000] Oops[#1]:
[    0.000000] CPU: 0 UID: 0 PID: 0 Comm: swapper Tainted: G        W           6.19.0-rc5-00262-gd3eeb99bbc99-dirty #188 VOLUNTARY
[    0.000000] Tainted: [W]=WARN
[    0.000000] Hardware name: loongson,loongson64v-4core-virtio
[    0.000000] $ 0   : 0000000000000000 0000000000000000 0000000000000001 0000000000000000
[    0.000000] $ 4   : ffffffff80b80ec0 ffffffff80b53d48 0000000000000000 00000000000f4240
[    0.000000] $ 8   : 0000000000000100 ffffffff81d82f80 ffffffff81d82f80 0000000000000001
[    0.000000] $12   : 0000000000000000 ffffffff81776f58 00000000000005da 0000000000000002
[    0.000000] $16   : ffffffff80b80e40 0000000000000000 ffffffff80b81614 9800000005dfbe80
[    0.000000] $20   : 00000000540000e0 ffffffff81980000 0000000000000000 ffffffff80f81c80
[    0.000000] $24   : 0000000000000a26 ffffffff8114fb90
[    0.000000] $28   : ffffffff80b50000 ffffffff80b53d40 0000000000000000 ffffffff81afad90
[    0.000000] Hi    : 0000000000000000
[    0.000000] Lo    : 0000000000000000
[    0.000000] epc   : ffffffff81afada8 init_idle+0x130/0x270
[    0.000000] ra    : ffffffff81afad90 init_idle+0x118/0x270
[    0.000000] Status: 540000e2	KX SX UX KERNEL EXL
[    0.000000] Cause : 00000008 (ExcCode 02)
[    0.000000] BadVA : 0000000000000000
[    0.000000] PrId  : 00006305 (ICT Loongson-3)
[    0.000000] Process swapper (pid: 0, threadinfo=(____ptrval____), task=(____ptrval____), tls=0000000000000000)
[    0.000000] Stack : 9800000005dfbf00 ffffffff8178e950 0000000000000000 0000000000000000
[    0.000000]         0000000000000000 ffffffff81970000 000000000000003f ffffffff810a6528
[    0.000000]         0000000000000001 9800000005dfbe80 9800000005dfbf00 ffffffff81980000
[    0.000000]         ffffffff810a6450 ffffffff81afb6c0 0000000000000000 ffffffff810a2258
[    0.000000]         ffffffff81d82ec8 ffffffff8198d010 ffffffff81b67e80 ffffffff8197dd98
[    0.000000]         ffffffff81d81c80 ffffffff81930000 0000000000000040 0000000000000000
[    0.000000]         0000000000000000 0000000000000000 0000000000000000 0000000000000000
[    0.000000]         0000000000000000 000000000000009e ffffffff9fc01000 0000000000000000
[    0.000000]         0000000000000000 0000000000000000 0000000000000000 0000000000000000
[    0.000000]         0000000000000000 ffffffff81ae86dc ffffffff81b3c741 0000000000000002
[    0.000000]         ...
[    0.000000] Call Trace:
[    0.000000] [<ffffffff81afada8>] init_idle+0x130/0x270
[    0.000000] [<ffffffff81afb6c0>] sched_init+0x5c8/0x6c0
[    0.000000] [<ffffffff81ae86dc>] start_kernel+0x27c/0x7a8

This bug has been reported to LLVM[2] and affects version from (at least) 18 to 21. Let's work around this by using inline assembly to assign $gp before a fix is widely available.

---
 arch/mips/kernel/relocate.c |   13 +++++++++++++
 1 file changed, 13 insertions(+)
arch/mips/kernel/relocate.c +13 -0
@@ -420,7 +420,20 @@ void *__init relocate_kernel(void)
 			goto out;
 
 		/* The current thread is now within the relocated image */
+#ifndef CONFIG_CC_IS_CLANG
 		__current_thread_info = RELOCATED(&init_thread_union);
+#else
+		/*
+		 * LLVM may wrongly restore $gp ($28) in epilog even if it's
+		 * intentionally modified. Work around this by using inline
+		 * assembly to assign $gp. $gp couldn't be listed as output or
+		 * clobber, or LLVM will still restore its original value.
+		 * See also LLVM upstream issue
+		 * https://github.com/llvm/llvm-project/issues/176546
+		 */
+		asm volatile("move $28, %0" : :
+			     "r" (RELOCATED(&init_thread_union)));
+#endif
 
 		/* Return the new kernel's entry point */
 		kernel_entry = RELOCATED(start_kernel);
author maintainer
#757 lore raw

PATCH 753/781 ksmbd: call ksmbd_vfs_kern_path_end_removing() on some error paths

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Fedor Pchelkin <[email protected]>

commit a09dc10d1353f0e92c21eae2a79af1c2b1ddcde8 upstream.

There are two places where ksmbd_vfs_kern_path_end_removing() needs to be called in order to balance what the corresponding successful call to ksmbd_vfs_kern_path_start_removing() has done, i.e. drop inode locks and put the taken references. Otherwise there might be potential deadlocks and unbalanced locks which are caught like:

BUG: workqueue leaked lock or atomic: kworker/5:21/0x00000000/7596
     last function: handle_ksmbd_work
2 locks held by kworker/5:21/7596:
 #0: ffff8881051ae448 (sb_writers#3){.+.+}-{0:0}, at: ksmbd_vfs_kern_path_locked+0x142/0x660
 #1: ffff888130e966c0 (&type->i_mutex_dir_key#3/1){+.+.}-{4:4}, at: ksmbd_vfs_kern_path_locked+0x17d/0x660
CPU: 5 PID: 7596 Comm: kworker/5:21 Not tainted 6.1.162-00456-gc29b353f383b #138
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.17.0-debian-1.17.0-1 04/01/2014
Workqueue: ksmbd-io handle_ksmbd_work
Call Trace:
 <TASK>
 dump_stack_lvl+0x44/0x5b
 process_one_work.cold+0x57/0x5c
 worker_thread+0x82/0x600
 kthread+0x153/0x190
 ret_from_fork+0x22/0x30
 </TASK>

Found by Linux Verification Center (linuxtesting.org).

Fixes d5fc1400a34b ("smb/server: avoid deadlock when linking with ReplaceIfExists")
---
 fs/smb/server/smb2pdu.c |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
fs/smb/server/smb2pdu.c +2 -2
@@ -6114,14 +6114,14 @@ static int smb2_create_link(struct ksmbd
 				rc = -EINVAL;
 				ksmbd_debug(SMB, "cannot delete %s\n",
 					    link_name);
-				goto out;
 			}
 		} else {
 			rc = -EEXIST;
 			ksmbd_debug(SMB, "link already exists\n");
-			goto out;
 		}
 		ksmbd_vfs_kern_path_end_removing(&path);
+		if (rc)
+			goto out;
 	}
 	rc = ksmbd_vfs_link(work, target_name, link_name);
 	if (rc)
author maintainer
#758 lore raw

PATCH 754/781 ext4: subdivide EXT4_EXT_DATA_VALID1

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Zhang Yi <[email protected]>

commit 22784ca541c0f01c5ebad14e8228298dc0a390ed upstream.

When splitting an extent, if the EXT4_GET_BLOCKS_CONVERT flag is set and it is necessary to split the target extent in the middle, ext4_split_extent() first handles splitting the latter half of the extent and passes the EXT4_EXT_DATA_VALID1 flag. This flag implies that all blocks before the split point contain valid data; however, this assumption is incorrect.

Therefore, subdivid EXT4_EXT_DATA_VALID1 into EXT4_EXT_DATA_ENTIRE_VALID1 and EXT4_EXT_DATA_PARTIAL_VALID1, which indicate that the first half of the extent is either entirely valid or only partially valid, respectively. These two flags cannot be set simultaneously.

This patch does not use EXT4_EXT_DATA_PARTIAL_VALID1, it only replaces EXT4_EXT_DATA_VALID1 with EXT4_EXT_DATA_ENTIRE_VALID1 at the location where it is set, no logical changes.

Message-ID: <[email protected]>

---
 fs/ext4/extents.c |   18 ++++++++++++------
 1 file changed, 12 insertions(+), 6 deletions(-)
fs/ext4/extents.c +12 -6
@@ -43,8 +43,13 @@
 #define EXT4_EXT_MARK_UNWRIT1	0x2  /* mark first half unwritten */
 #define EXT4_EXT_MARK_UNWRIT2	0x4  /* mark second half unwritten */
 
-#define EXT4_EXT_DATA_VALID1	0x8  /* first half contains valid data */
-#define EXT4_EXT_DATA_VALID2	0x10 /* second half contains valid data */
+/* first half contains valid data */
+#define EXT4_EXT_DATA_ENTIRE_VALID1	0x8   /* has entirely valid data */
+#define EXT4_EXT_DATA_PARTIAL_VALID1	0x10  /* has partially valid data */
+#define EXT4_EXT_DATA_VALID1		(EXT4_EXT_DATA_ENTIRE_VALID1 | \
+					 EXT4_EXT_DATA_PARTIAL_VALID1)
+
+#define EXT4_EXT_DATA_VALID2	0x20 /* second half contains valid data */
 
 static __le32 ext4_extent_block_csum(struct inode *inode,
 				     struct ext4_extent_header *eh)
@@ -3190,8 +3195,9 @@ static struct ext4_ext_path *ext4_split_
 	unsigned int ee_len, depth;
 	int err = 0;
 
-	BUG_ON((split_flag & (EXT4_EXT_DATA_VALID1 | EXT4_EXT_DATA_VALID2)) ==
-	       (EXT4_EXT_DATA_VALID1 | EXT4_EXT_DATA_VALID2));
+	BUG_ON((split_flag & EXT4_EXT_DATA_VALID1) == EXT4_EXT_DATA_VALID1);
+	BUG_ON((split_flag & EXT4_EXT_DATA_VALID1) &&
+	       (split_flag & EXT4_EXT_DATA_VALID2));
 
 	ext_debug(inode, "logical block %llu\n", (unsigned long long)split);
 
@@ -3373,7 +3379,7 @@ static struct ext4_ext_path *ext4_split_
 			split_flag1 |= EXT4_EXT_MARK_UNWRIT1 |
 				       EXT4_EXT_MARK_UNWRIT2;
 		if (split_flag & EXT4_EXT_DATA_VALID2)
-			split_flag1 |= EXT4_EXT_DATA_VALID1;
+			split_flag1 |= EXT4_EXT_DATA_ENTIRE_VALID1;
 		path = ext4_split_extent_at(handle, inode, path,
 				map->m_lblk + map->m_len, split_flag1, flags1);
 		if (IS_ERR(path))
@@ -3728,7 +3734,7 @@ static struct ext4_ext_path *ext4_split_
 
 	/* Convert to unwritten */
 	if (flags & EXT4_GET_BLOCKS_CONVERT_UNWRITTEN) {
-		split_flag |= EXT4_EXT_DATA_VALID1;
+		split_flag |= EXT4_EXT_DATA_ENTIRE_VALID1;
 	/* Convert to initialized */
 	} else if (flags & EXT4_GET_BLOCKS_CONVERT) {
 		/*
author maintainer
#759 lore raw

PATCH 755/781 ext4: dont set EXT4_GET_BLOCKS_CONVERT when splitting before submitting I/O

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Zhang Yi <[email protected]>

commit feaf2a80e78f89ee8a3464126077ba8683b62791 upstream.

When allocating blocks during within-EOF DIO and writeback with dioread_nolock enabled, EXT4_GET_BLOCKS_PRE_IO was set to split an existing large unwritten extent. However, EXT4_GET_BLOCKS_CONVERT was set when calling ext4_split_convert_extents(), which may potentially result in stale data issues.

Assume we have an unwritten extent, and then DIO writes the second half.

[UUUUUUUUUUUUUUUU] on-disk extent U: unwritten extent
[UUUUUUUUUUUUUUUU] extent status tree

            |<-   ->| ----> dio write this range

First, ext4_iomap_alloc() call ext4_map_blocks() with EXT4_GET_BLOCKS_PRE_IO, EXT4_GET_BLOCKS_UNWRIT_EXT and EXT4_GET_BLOCKS_CREATE flags set. ext4_map_blocks() find this extent and call ext4_split_convert_extents() with EXT4_GET_BLOCKS_CONVERT and the above flags set.

Then, ext4_split_convert_extents() calls ext4_split_extent() with EXT4_EXT_MAY_ZEROOUT, EXT4_EXT_MARK_UNWRIT2 and EXT4_EXT_DATA_VALID2 flags set, and it calls ext4_split_extent_at() to split the second half with EXT4_EXT_DATA_VALID2, EXT4_EXT_MARK_UNWRIT1, EXT4_EXT_MAY_ZEROOUT and EXT4_EXT_MARK_UNWRIT2 flags set. However, ext4_split_extent_at() failed to insert extent since a temporary lack -ENOSPC. It zeroes out the first half but convert the entire on-disk extent to written since the EXT4_EXT_DATA_VALID2 flag set, but left the second half as unwritten in the extent status tree.

   [0000000000SSSSSS]  data                S: stale data, 0: zeroed
   [WWWWWWWWWWWWWWWW]  on-disk extent      W: written extent
   [WWWWWWWWWWUUUUUU]  extent status tree

Finally, if the DIO failed to write data to the disk, the stale data in the second half will be exposed once the cached extent entry is gone.

Fix this issue by not passing EXT4_GET_BLOCKS_CONVERT when splitting an unwritten extent before submitting I/O, and make ext4_split_convert_extents() to zero out the entire extent range to zero for this case, and also mark the extent in the extent status tree for consistency.

Fixes b8a8684502a0 ("ext4: Introduce FALLOC_FL_ZERO_RANGE flag for fallocate")

Message-ID: <[email protected]>

---
 fs/ext4/extents.c |   12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)
fs/ext4/extents.c +8 -4
@@ -3735,15 +3735,19 @@ static struct ext4_ext_path *ext4_split_
 	/* Convert to unwritten */
 	if (flags & EXT4_GET_BLOCKS_CONVERT_UNWRITTEN) {
 		split_flag |= EXT4_EXT_DATA_ENTIRE_VALID1;
-	/* Convert to initialized */
-	} else if (flags & EXT4_GET_BLOCKS_CONVERT) {
+	/* Split the existing unwritten extent */
+	} else if (flags & (EXT4_GET_BLOCKS_UNWRIT_EXT |
+			    EXT4_GET_BLOCKS_CONVERT)) {
 		/*
 		 * It is safe to convert extent to initialized via explicit
 		 * zeroout only if extent is fully inside i_size or new_size.
 		 */
 		split_flag |= ee_block + ee_len <= eof_block ?
 			      EXT4_EXT_MAY_ZEROOUT : 0;
-		split_flag |= (EXT4_EXT_MARK_UNWRIT2 | EXT4_EXT_DATA_VALID2);
+		split_flag |= EXT4_EXT_MARK_UNWRIT2;
+		/* Convert to initialized */
+		if (flags & EXT4_GET_BLOCKS_CONVERT)
+			split_flag |= EXT4_EXT_DATA_VALID2;
 	}
 	flags |= EXT4_GET_BLOCKS_SPLIT_NOMERGE;
 	return ext4_split_extent(handle, inode, path, map, split_flag, flags,
@@ -3919,7 +3923,7 @@ ext4_ext_handle_unwritten_extents(handle
 	/* get_block() before submitting IO, split the extent */
 	if (flags & EXT4_GET_BLOCKS_SPLIT_NOMERGE) {
 		path = ext4_split_convert_extents(handle, inode, map, path,
-				flags | EXT4_GET_BLOCKS_CONVERT, allocated);
+						  flags, allocated);
 		if (IS_ERR(path))
 			return path;
 		/*
author maintainer
#760 lore raw

PATCH 756/781 ext4: dont zero the entire extent if EXT4_EXT_DATA_PARTIAL_VALID1

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Zhang Yi <[email protected]>

commit 1bf6974822d1dba86cf11b5f05498581cf3488a2 upstream.

When allocating initialized blocks from a large unwritten extent, or when splitting an unwritten extent during end I/O and converting it to initialized, there is currently a potential issue of stale data if the extent needs to be split in the middle.

0 A B N
[UUUUUUUUUUUU] U: unwritten extent
[--DDDDDDDD--] D: valid data
|<- ->| ----> this range needs to be initialized

ext4_split_extent() first try to split this extent at B with EXT4_EXT_DATA_ENTIRE_VALID1 and EXT4_EXT_MAY_ZEROOUT flag set, but ext4_split_extent_at() failed to split this extent due to temporary lack of space. It zeroout B to N and mark the entire extent from 0 to N as written.

0 A B N
[WWWWWWWWWWWW] W: written extent
[SSDDDDDDDDZZ] Z: zeroed, S: stale data

ext4_split_extent() then try to split this extent at A with EXT4_EXT_DATA_VALID2 flag set. This time, it split successfully and left a stale written extent from 0 to A.

       0  A      B   N
       [WW|WWWWWWWWWW]
       [SS|DDDDDDDDZZ]

Fix this by pass EXT4_EXT_DATA_PARTIAL_VALID1 to ext4_split_extent_at() when splitting at B, don't convert the entire extent to written and left it as unwritten after zeroing out B to N. The remaining work is just like the standard two-part split. ext4_split_extent() will pass the EXT4_EXT_DATA_VALID2 flag when it calls ext4_split_extent_at() for the second time, allowing it to properly handle the split. If the split is successful, it will keep extent from 0 to A as unwritten.

Message-ID: <[email protected]>

---
 fs/ext4/extents.c |   13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)
fs/ext4/extents.c +12 -1
@@ -3310,6 +3310,15 @@ static struct ext4_ext_path *ext4_split_
 		}
 
 		if (!err) {
+			/*
+			 * The first half contains partially valid data, the
+			 * splitting of this extent has not been completed, fix
+			 * extent length and ext4_split_extent() split will the
+			 * first half again.
+			 */
+			if (split_flag & EXT4_EXT_DATA_PARTIAL_VALID1)
+				goto fix_extent_len;
+
 			/* update the extent length and mark as initialized */
 			ex->ee_len = cpu_to_le16(ee_len);
 			ext4_ext_try_to_merge(handle, inode, path, ex);
@@ -3379,7 +3388,9 @@ static struct ext4_ext_path *ext4_split_
 			split_flag1 |= EXT4_EXT_MARK_UNWRIT1 |
 				       EXT4_EXT_MARK_UNWRIT2;
 		if (split_flag & EXT4_EXT_DATA_VALID2)
-			split_flag1 |= EXT4_EXT_DATA_ENTIRE_VALID1;
+			split_flag1 |= map->m_lblk > ee_block ?
+				       EXT4_EXT_DATA_PARTIAL_VALID1 :
+				       EXT4_EXT_DATA_ENTIRE_VALID1;
 		path = ext4_split_extent_at(handle, inode, path,
 				map->m_lblk + map->m_len, split_flag1, flags1);
 		if (IS_ERR(path))
author maintainer
#761 lore raw

PATCH 757/781 ext4: dont cache extent during splitting extent

In reply to Greg Kroah-Hartman

6.19-stable review patch. If anyone has any objections, please let me know.

------------------

From: Zhang Yi <[email protected]>

commit 8b4b19a2f96348d70bfa306ef7d4a13b0bcbea79 upstream.

Caching extents during the splitting process is risky, as it may result in stale extents remaining in the status tree. Moreover, in most cases, the corresponding extent block entries are likely already cached before the split happens, making caching here not particularly useful.

Assume we have an unwritten extent, and then DIO writes the first half.

[UUUUUUUUUUUUUUUU] on-disk extent U: unwritten extent
[UUUUUUUUUUUUUUUU] extent status tree
|<- ->| ----> dio write this range

First, when ext4_split_extent_at() splits this extent, it truncates the existing extent and then inserts a new one. During this process, this extent status entry may be shrunk, and calls to ext4_find_extent() and ext4_cache_extents() may occur, which could potentially insert the truncated range as a hole into the extent status tree. After the split is completed, this hole is not replaced with the correct status.

  [UUUUUUU|UUUUUUUU] on-disk extent        U: unwritten extent
  [UUUUUUU|HHHHHHHH] extent status tree    H: hole

Then, the outer calling functions will not correct this remaining hole extent either. Finally, if we perform a delayed buffer write on this latter part, it will re-insert the delayed extent and cause an error in space accounting.

In adition, if the unwritten extent cache is not shrunk during the splitting, ext4_cache_extents() also conflicts with existing extents when caching extents. In the future, we will add checks when caching extents, which will trigger a warning. Therefore, Do not cache extents that are being split.

Message-ID: <[email protected]>

---
 fs/ext4/extents.c |    6 ++++++
 1 file changed, 6 insertions(+)
fs/ext4/extents.c +6 -0
@@ -3199,6 +3199,9 @@ static struct ext4_ext_path *ext4_split_
 	BUG_ON((split_flag & EXT4_EXT_DATA_VALID1) &&
 	       (split_flag & EXT4_EXT_DATA_VALID2));
 
+	/* Do not cache extents that are in the process of being modified. */
+	flags |= EXT4_EX_NOCACHE;
+
 	ext_debug(inode, "logical block %llu\n", (unsigned long long)split);
 
 	ext4_ext_show_leaf(inode, path);
@@ -3381,6 +3384,9 @@ static struct ext4_ext_path *ext4_split_
 	ee_len = ext4_ext_get_actual_len(ex);
 	unwritten = ext4_ext_is_unwritten(ex);
 
+	/* Do not cache extents that are in the process of being modified. */
+	flags |= EXT4_EX_NOCACHE;
+
 	if (map->m_lblk + map->m_len < ee_block + ee_len) {
 		split_flag1 = split_flag & EXT4_EXT_MAY_ZEROOUT;
 		flags1 = flags | EXT4_GET_BLOCKS_SPLIT_NOMERGE;