• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2012-2017  Red Hat, Inc.
3  *
4  * This program is free software;  you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY;  without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See
12  * the GNU General Public License for more details.
13  */
14 
15 /* thp03 - Case for spliting unaligned memory.
16  *       - System will panic if failed.
17  *
18  * Modified form a reproducer for
19  *          https://patchwork.kernel.org/patch/1358441/
20  * Kernel Commit id: 027ef6c87853b0a9df53175063028edb4950d476
21  * There was a bug in THP, will crash happened due to the following
22  * reason according to developers:
23  *
24  * most VM places are using pmd_none but a few are still using
25  * pmd_present. The meaning is about the same for the pmd. However
26  * pmd_present would return the wrong value on PROT_NONE ranges or in
27  * case of a non reproducible race with split_huge_page.
28  * When the code using pmd_present gets a false negative, the kernel will
29  * crash. It's just an annoying DoS with a BUG_ON triggering: no memory
30  * corruption and no data corruption (nor userland nor kernel).
31  */
32 
33 #include <sys/mman.h>
34 #include <sys/types.h>
35 #include <sys/wait.h>
36 #include <fcntl.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <errno.h>
40 #include "mem.h"
41 #include "lapi/mmap.h"
42 
43 static void thp_test(void);
44 
45 static long hugepage_size;
46 static long unaligned_size;
47 static long page_size;
48 
thp_test(void)49 static void thp_test(void)
50 {
51 	void *p;
52 
53 	p = SAFE_MMAP(NULL, unaligned_size, PROT_READ | PROT_WRITE,
54 		 MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
55 
56 	memset(p, 0x00, unaligned_size);
57 	if (mprotect(p, unaligned_size, PROT_NONE) == -1)
58 		tst_brk(TBROK | TERRNO, "mprotect");
59 
60 	if (madvise(p + hugepage_size, page_size, MADV_MERGEABLE) == -1) {
61 		if (errno == EINVAL) {
62 			tst_brk(TCONF,
63 			         "MADV_MERGEABLE is not enabled/supported");
64 		} else {
65 			tst_brk(TBROK | TERRNO, "madvise");
66 		}
67 	}
68 
69 	switch (SAFE_FORK()) {
70 	case 0:
71 		exit(0);
72 	default:
73 		SAFE_WAITPID(-1, NULL, 0);
74 	}
75 
76 	tst_res(TPASS, "system didn't crash, pass.");
77 	munmap(p, unaligned_size);
78 }
79 
setup(void)80 static void setup(void)
81 {
82 	if (access(PATH_THP, F_OK) == -1)
83 		tst_brk(TCONF, "THP not enabled in kernel?");
84 
85 	check_hugepage();
86 
87 	hugepage_size = SAFE_READ_MEMINFO("Hugepagesize:") * KB;
88 	unaligned_size = hugepage_size * 4 - 1;
89 	page_size = SAFE_SYSCONF(_SC_PAGESIZE);
90 }
91 
92 static struct tst_test test = {
93 	.needs_root = 1,
94 	.forks_child = 1,
95 	.setup = setup,
96 	.test_all = thp_test,
97 };
98