lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [day] [month] [year] [list]
Message-ID: 
 <fm-32642-20250327135626e1f5d2a07a0019fdb6-JTnh8c@errorhandling.siemens-energy.com>
Date: Thu, 27 Mar 2025 14:56:24 +0100
From: Simon Schuster <schuster.simon@...mens-energy.com>
To: Dinh Nguyen <dinguyen@...nel.org>, Arnd Bergmann <arnd@...db.de>
Cc: Andreas Oetken <andreas.oetken@...mens-energy.com>,
	Mike Rapoport <rppt@...nel.org>, Song Liu <song@...nel.org>,
	linux-kernel@...r.kernel.org,
	Simon Schuster <schuster.simon@...mens-energy.com>
Subject: [PATCH 2/2] nios2: do not introduce conflicting mappings when
 flushing tlb entries

The NIOS2 hardware does not support conflicting mappings for the same
virtual address (see Nios II Processor Reference Guide from 2023.08.28):

 "The operating system software is responsible for guaranteeing that
  multiple TLB entries do not map the same virtual address. The hardware
  behavior is undefined when multiple entries map the same virtual
  address."

When flushing tlb-entries, the kernel may violate this invariant for
virtual addresses related to PID 0 as flushing is currently implemented
by assigning physical address, pid and flags to 0.

A small example:

Before flushing TLB mappings for pid:0x42:
  dump tlb-entries for line=0xd (addr 000d0000):
  -- way:09 vpn:0x0006d000 phys:0x01145000 pid:0x00 flags:rw--c
  ...
  -- way:0d vpn:0x0006d000 phys:0x02020000 pid:0x42 flags:rw--c

After flushing TLB mappings for pid:0x42:
  dump tlb-entries for line=0xd (addr 000d0000):
  -- way:09 vpn:0x0006d000 phys:0x01145000 pid:0x00 flags:rw--c
  ...
  -- way:0d vpn:0x0006d000 phys:0x00000000 pid:0x00 flags:-----

As functions such as replace_tlb_one_pid operate on the assumption of
unique mappings, this can cause repeated pagefaults for a single
address that are not covered by the existing spurious pagefault handling.

This commit fixes this issue by keeping the pid field of the entries
when flushing. That way, no conflicting mappings are introduced as the
pair of <address,pid> is now kept unique:

Fixed example after flushing TLB mappings for pid:0x42:
  dump tlb-entries for line=0xd (addr 000d0000):
  -- way:09 vpn:0x0006d000 phys:0x01145000 pid:0x00 flags:rw--c
  ...
  -- way:0d vpn:0x0006d000 phys:0x00000000 pid:0x42 flags:-----

When flushing the complete tlb/initialising all entries, the way is
used as a substitute mmu pid value for the "invalid" entries.

Signed-off-by: Simon Schuster <schuster.simon@...mens-energy.com>
Signed-off-by: Andreas Oetken <andreas.oetken@...mens-energy.com>
---
 arch/nios2/mm/tlb.c | 18 +++++++++++-------
 1 file changed, 11 insertions(+), 7 deletions(-)

diff --git a/arch/nios2/mm/tlb.c b/arch/nios2/mm/tlb.c
index f90ac35f05f3..a9cbe20f9e79 100644
--- a/arch/nios2/mm/tlb.c
+++ b/arch/nios2/mm/tlb.c
@@ -144,10 +144,11 @@ static void flush_tlb_one(unsigned long addr)
 		if (((pteaddr >> 2) & 0xfffff) != (addr >> PAGE_SHIFT))
 			continue;
 
+		tlbmisc = RDCTL(CTL_TLBMISC);
 		pr_debug("Flush entry by writing way=%dl pid=%ld\n",
-			 way, (pid_misc >> TLBMISC_PID_SHIFT));
+			 way, ((tlbmisc >> TLBMISC_PID_SHIFT) & TLBMISC_PID_MASK));
 
-		tlbmisc = TLBMISC_WE | (way << TLBMISC_WAY_SHIFT);
+		tlbmisc = TLBMISC_WE | (way << TLBMISC_WAY_SHIFT) | (tlbmisc & TLBMISC_PID);
 		WRCTL(CTL_TLBMISC, tlbmisc);
 		WRCTL(CTL_PTEADDR, pteaddr_invalid(addr));
 		WRCTL(CTL_TLBACC, 0);
@@ -237,7 +238,8 @@ void flush_tlb_pid(unsigned long mmu_pid)
 			if (pid != mmu_pid)
 				continue;
 
-			tlbmisc = TLBMISC_WE | (way << TLBMISC_WAY_SHIFT);
+			tlbmisc = TLBMISC_WE | (way << TLBMISC_WAY_SHIFT) |
+				  (pid << TLBMISC_PID_SHIFT);
 			WRCTL(CTL_TLBMISC, tlbmisc);
 			WRCTL(CTL_TLBACC, 0);
 		}
@@ -272,15 +274,17 @@ void flush_tlb_all(void)
 	/* remember pid/way until we return */
 	get_misc_and_pid(&org_misc, &pid_misc);
 
-	/* Start at way 0, way is auto-incremented after each TLBACC write */
-	WRCTL(CTL_TLBMISC, TLBMISC_WE);
-
 	/* Map each TLB entry to physcal address 0 with no-access and a
 	   bad ptbase */
 	for (line = 0; line < cpuinfo.tlb_num_lines; line++) {
 		WRCTL(CTL_PTEADDR, pteaddr_invalid(addr));
-		for (way = 0; way < cpuinfo.tlb_num_ways; way++)
+		for (way = 0; way < cpuinfo.tlb_num_ways; way++) {
+			// Code such as replace_tlb_one_pid assumes that no duplicate entries exist
+			// for a single address across ways, so also use way as a dummy PID
+			WRCTL(CTL_TLBMISC, TLBMISC_WE | (way << TLBMISC_WAY_SHIFT) |
+					   (way << TLBMISC_PID_SHIFT));
 			WRCTL(CTL_TLBACC, 0);
+		}
 
 		addr += PAGE_SIZE;
 	}
-- 
2.39.5


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ