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 44static unsigned long hpage_size; 45static int fd = -1; 46 47static 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 74static 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 85static void cleanup(void) 86{ 87 if (fd >= 0) 88 SAFE_CLOSE(fd); 89} 90 91static 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