• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: LGPL-2.1-or-later
2 /*
3  * Copyright (C) 2005-2006 David Gibson & Adam Litke, IBM Corporation.
4  * Author: David Gibson & Adam Litke
5  */
6 
7 /*\
8  * [Descriptiom]
9  *
10  * At one stage, a misconversion of hugetlb_vmtruncate_list to a prio_tree
11  * meant that on 32-bit machines, certain combinations of mapping and
12  * truncations could truncate incorrect pages, or overwrite pmds from
13  * other VMAs, triggering BUG_ON()s or other wierdness.
14  *
15  * Test adapted from an example by Kenneth Chen <kenneth.w.chen@intel.com>
16  *
17  * WARNING: The offsets and addresses used within are specifically
18  * calculated to trigger the bug as it existed.  Don't mess with them
19  * unless you *really* know what you're doing.
20  *
21  * The kernel bug in question was fixed with commit
22  * 856fc2950555.
23  */
24 
25 #define _GNU_SOURCE
26 #include <stdio.h>
27 #include <sys/mount.h>
28 #include <limits.h>
29 #include <sys/param.h>
30 #include <sys/types.h>
31 
32 #include "hugetlb.h"
33 
34 #define MNTPOINT "hugetlbfs/"
35 #define MAP_LENGTH	(4UL * hpage_size)
36 #if defined(__s390__) && __WORDSIZE == 32
37 #define TRUNCATE_POINT 0x20000000UL
38 #else
39 #define TRUNCATE_POINT 0x60000000UL
40 #endif
41 #define HIGH_ADDR	0xa0000000UL
42 #define FOURGIG		((off64_t)0x100000000ULL)
43 
44 static unsigned long hpage_size;
45 static int  fd = -1;
46 
run_test(void)47 static void run_test(void)
48 {
49 	char *p, *q;
50 	unsigned long i;
51 
52 	p = SAFE_MMAP(0, MAP_LENGTH + TRUNCATE_POINT, PROT_READ | PROT_WRITE,
53 		 MAP_PRIVATE | MAP_NORESERVE, fd, 0);
54 
55 	SAFE_MUNMAP(p, MAP_LENGTH + TRUNCATE_POINT);
56 
57 	q = SAFE_MMAP((void *)HIGH_ADDR, MAP_LENGTH, PROT_READ | PROT_WRITE,
58 		 MAP_PRIVATE, fd, 0);
59 	tst_res(TINFO, "High map at %p", q);
60 
61 	for (i = 0; i < MAP_LENGTH; i += hpage_size)
62 		q[i] = 1;
63 
64 	SAFE_FTRUNCATE(fd, TRUNCATE_POINT);
65 
66 	if (q[0] != 1)
67 		tst_res(TFAIL, "data mismatch");
68 	else
69 		tst_res(TPASS, "Successful");
70 
71 	SAFE_MUNMAP(q, MAP_LENGTH);
72 }
73 
setup(void)74 static void setup(void)
75 {
76 	hpage_size = SAFE_READ_MEMINFO("Hugepagesize:")*1024;
77 
78 	if (hpage_size > TRUNCATE_POINT)
79 		tst_brk(TCONF, "Huge page size is too large");
80 	if (TRUNCATE_POINT % hpage_size)
81 		tst_brk(TCONF, "Truncation point is not aligned to huge page size");
82 	fd = tst_creat_unlinked(MNTPOINT, 0);
83 }
84 
cleanup(void)85 static void cleanup(void)
86 {
87 	if (fd >= 0)
88 		SAFE_CLOSE(fd);
89 }
90 
91 static struct tst_test test = {
92 	.tags = (struct tst_tag[]) {
93 		{"linux-git", "856fc2950555"},
94 		{}
95 	},
96 	.needs_root = 1,
97 	.mntpoint = MNTPOINT,
98 	.needs_hugetlbfs = 1,
99 	.setup = setup,
100 	.cleanup = cleanup,
101 	.test_all = run_test,
102 	.hugepages = {4, TST_NEEDS},
103 };
104