linux/arch/arm64/mm
Catalin Marinas a8ffaaa060 arm64: asid: Do not replace active_asids if already 0
Under some uncommon timing conditions, a generation check and
xchg(active_asids, A1) in check_and_switch_context() on P1 can race with
an ASID roll-over on P2. If P2 has not seen the update to
active_asids[P1], it can re-allocate A1 to a new task T2 on P2. P1 ends
up waiting on the spinlock since the xchg() returned 0 while P2 can go
through a second ASID roll-over with (T2,A1,G2) active on P2. This
roll-over copies active_asids[P1] == A1,G1 into reserved_asids[P1] and
active_asids[P2] == A1,G2 into reserved_asids[P2]. A subsequent
scheduling of T1 on P1 and T2 on P2 would match reserved_asids and get
their generation bumped to G3:

P1					P2
--                                      --
TTBR0.BADDR = T0
TTBR0.ASID = A0
asid_generation = G1
check_and_switch_context(T1,A1,G1)
  generation match
					check_and_switch_context(T2,A0,G0)
 				          new_context()
					    ASID roll-over
					    asid_generation = G2
					    flush_context()
					      active_asids[P1] = 0
					      asid_map[A1] = 0
					      reserved_asids[P1] = A0,G0
  xchg(active_asids, A1)
    active_asids[P1] = A1,G1
    xchg returns 0
  spin_lock_irqsave()
					    allocated ASID (T2,A1,G2)
					    asid_map[A1] = 1
					  active_asids[P2] = A1,G2
					...
					check_and_switch_context(T3,A0,G0)
					  new_context()
					    ASID roll-over
					    asid_generation = G3
					    flush_context()
					      active_asids[P1] = 0
					      asid_map[A1] = 1
					      reserved_asids[P1] = A1,G1
					      reserved_asids[P2] = A1,G2
					    allocated ASID (T3,A2,G3)
					    asid_map[A2] = 1
					  active_asids[P2] = A2,G3
  new_context()
    check_update_reserved_asid(A1,G1)
      matches reserved_asid[P1]
      reserved_asid[P1] = A1,G3
  updated T1 ASID to (T1,A1,G3)
					check_and_switch_context(T2,A1,G2)
					  new_context()
					    check_and_switch_context(A1,G2)
					      matches reserved_asids[P2]
					      reserved_asids[P2] = A1,G3
					  updated T2 ASID to (T2,A1,G3)

At this point, we have two tasks, T1 and T2 both using ASID A1 with the
latest generation G3. Any of them is allowed to be scheduled on the
other CPU leading to two different tasks with the same ASID on the same
CPU.

This patch changes the xchg to cmpxchg so that the active_asids is only
updated if non-zero to avoid a race with an ASID roll-over on a
different CPU.

The ASID allocation algorithm has been formally verified using the TLA+
model checker (see
https://git.kernel.org/pub/scm/linux/kernel/git/cmarinas/kernel-tla.git/tree/asidalloc.tla
for the spec).

Reviewed-by: Will Deacon <will.deacon@arm.com>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
2018-01-05 11:29:11 +00:00
..
cache.S arm64: mm: Fix and re-enable ARM64_SW_TTBR0_PAN 2017-12-11 13:40:35 +00:00
context.c arm64: asid: Do not replace active_asids if already 0 2018-01-05 11:29:11 +00:00
copypage.c arm64: Defer dcache flush in __cpu_copy_user_page 2015-12-17 11:07:13 +00:00
dma-mapping.c dma mapping : export caller to vmallocinfo 2017-10-04 13:43:00 +01:00
dump.c arm64: dump: Add checking for writable and exectuable pages 2016-11-07 18:15:04 +00:00
extable.c License cleanup: add SPDX GPL-2.0 license identifier to files with no license 2017-11-02 11:10:55 +01:00
fault.c arm64 updates for 4.15 2017-11-15 10:56:56 -08:00
flush.c arm64: fix pmem interface definition 2017-08-10 18:13:59 +01:00
hugetlbpage.c arm64: hugetlb: Cleanup setup_hugepagesz 2017-08-22 17:47:12 +01:00
init.c arm64: kdump: provide /proc/vmcore file 2017-04-05 18:31:38 +01:00
ioremap.c arm64: use is_vmalloc_addr 2017-02-09 13:47:56 +00:00
kasan_init.c arm64/mm/kasan: don't use vmemmap_populate() to initialize shadow 2017-11-15 18:21:05 -08:00
Makefile License cleanup: add SPDX GPL-2.0 license identifier to files with no license 2017-11-02 11:10:55 +01:00
mmap.c arm64/mmap: properly account for stack randomization in mmap_base 2017-07-12 16:26:03 -07:00
mmu.c Merge branch 'for-next/52-bit-pa' into for-next/core 2017-12-22 17:40:58 +00:00
numa.c arm64/numa: Drop duplicate message 2017-07-20 17:03:53 +01:00
pageattr.c arm64: use set_memory.h header 2017-05-08 17:15:13 -07:00
pgd.c arm64: handle 52-bit addresses in TTBR 2017-12-22 17:35:21 +00:00
physaddr.c License cleanup: add SPDX GPL-2.0 license identifier to files with no license 2017-11-02 11:10:55 +01:00
proc.S Merge branch 'for-next/52-bit-pa' into for-next/core 2017-12-22 17:40:58 +00:00
ptdump_debugfs.c License cleanup: add SPDX GPL-2.0 license identifier to files with no license 2017-11-02 11:10:55 +01:00