Skip to contentSkip to conversation

x86 tlb: fix overflow of flush_end in remote tlb flush

PATCH New Dave Hansen 1 participant 2 messages Dec 8, 2014

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

PATCH 1/2 x86 tlb: fix overflow of flush_end in remote tlb flush

From: Dave Hansen <[email protected]>

If flush_end ends up being at or above 1 page before the end of memory, the following calculation can overflow:

	f->flush_end = f->flush_start + PAGE_SIZE;

x86_64 has a 2MB hole at the end of memory, so we don't expect this to be possible there. On i386, I believe this page is in the fixmap, and we never use this code there. We only do _local_ tlb flushes.

Either way, just fall back to a full tlb flush and spit out a warning if we ever run in to this.

---

 b/arch/x86/mm/tlb.c |   11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)
arch/x86/mm/tlb.c renamed from arch/x86/mm/tlb.c~x86-tlb-fix-overflow +10 -1
diff -puN arch/x86/mm/tlb.c~x86-tlb-fix-overflow arch/x86/mm/tlb.c
@@ -109,8 +109,17 @@ static void flush_tlb_func(void *info)
 
 	if (f->flush_mm != this_cpu_read(cpu_tlbstate.active_mm))
 		return;
-	if (!f->flush_end)
+	if (!f->flush_end) {
 		f->flush_end = f->flush_start + PAGE_SIZE;
+		/*
+		 * Check for an overflow and just flush the whole
+		 * TLB in that case.
+		 */
+		if (f->flush_end < f->flush_start + PAGE_SIZE) {
+			f->flush_end = TLB_FLUSH_ALL;
+			VM_WARN_ON_ONCE(1);
+		}
+	}
 
 	count_vm_tlb_event(NR_TLB_REMOTE_FLUSH_RECEIVED);
 	if (this_cpu_read(cpu_tlbstate.state) == TLBSTATE_OK) {

_

#1 lore raw

PATCH 2/2 x86 tlb: fix tracepoint nr_pages calculation

From: Dave Hansen <[email protected]>

We calculate nr_pages with f->flush_end and f->flush_start, both of which are virtual addresses. However, we only divide f->flush_start by PAGE_SIZE, and missed f->flush_end. This patch adds some parenthesis to catch f->flush_end as well.

nr_pages is only used for a trace point. This should not have any functional impact other than keeping the trace point from spitting out garbage for the flush length.

---

 b/arch/x86/mm/tlb.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
arch/x86/mm/tlb.c renamed from arch/x86/mm/tlb.c~x86-tlb-fix-tracepoint-data +1 -1
diff -puN arch/x86/mm/tlb.c~x86-tlb-fix-tracepoint-data arch/x86/mm/tlb.c
@@ -129,7 +129,7 @@ static void flush_tlb_func(void *info)
 		} else {
 			unsigned long addr;
 			unsigned long nr_pages =
-				f->flush_end - f->flush_start / PAGE_SIZE;
+				(f->flush_end - f->flush_start) / PAGE_SIZE;
 			addr = f->flush_start;
 			while (addr < f->flush_end) {
 				__flush_tlb_single(addr);

_