1// SPDX-License-Identifier: LGPL-2.1-or-later
2/*
3 * Copyright (C) 2005-2007 David Gibson & Adam Litke, IBM Corporation.
4 * Author: David Gibson & Adam Litke
5 */
6
7/*\
8 * [Description]
9 *
10 * Just as normal mmap()s can't have an address, length or offset which
11 * is not page aligned, so hugepage mmap()s can't have an address, length
12 * or offset with is not hugepage aligned.
13 *
14 * However, from time to time when the various mmap() /
15 * get_unmapped_area() paths are updated, somebody misses one of the
16 * necessary checks for the hugepage paths.  This testcase ensures
17 * that attempted hugepage mappings with parameters which are not
18 * correctly hugepage aligned are rejected.
19 *
20 * However starting with 3.10-rc1, length passed in mmap() doesn't need
21 * to be aligned because commit af73e4d9506d3b797509f3c030e7dcd554f7d9c4
22 * added ALIGN() to kernel side, in mmap_pgoff(), when mapping huge page
23 * files.
24 */
25
26#define _GNU_SOURCE
27#include <stdio.h>
28#include <stdlib.h>
29#include <sys/mman.h>
30
31#include "hugetlb.h"
32
33#define MNTPOINT "hugetlbfs/"
34static long hpage_size;
35static int  fd = -1;
36static long page_size;
37
38static void run_test(void)
39{
40	void *p, *q;
41
42	/*
43	 * First see what an ok mapping looks like, as a basis for our
44	 * bad addresses and so forth
45	 */
46	p = mmap(NULL, hpage_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
47	if (p == MAP_FAILED) {
48		tst_res(TFAIL|TERRNO, "mmap() without hint failed");
49		return;
50	}
51	if (((unsigned long)p % hpage_size) != 0) {
52		tst_res(TFAIL, "mmap() without hint at misaligned address");
53		goto cleanup1;
54	}
55
56	tst_res(TINFO, "Mapped at %p, length 0x%lx", p, hpage_size);
57
58	SAFE_MUNMAP(p, hpage_size);
59
60	/* 1) Try a misaligned hint address */
61	q = mmap(p + page_size, hpage_size, PROT_READ|PROT_WRITE,
62		 MAP_PRIVATE, fd, 0);
63	if (q == MAP_FAILED) {
64		/* Bad hint shouldn't fail, just ignore the hint */
65		tst_res(TFAIL|TERRNO, "mmap() with hint failed");
66		return;
67	}
68	if (((unsigned long)q % hpage_size) != 0) {
69		tst_res(TFAIL, "mmap() with hint at misaligned address");
70		goto cleanup2;
71	}
72	SAFE_MUNMAP(q, hpage_size);
73
74	/* 2) Try a misaligned address with MAP_FIXED */
75	q = mmap(p + page_size, hpage_size, PROT_READ|PROT_WRITE,
76		 MAP_PRIVATE|MAP_FIXED, fd, 0);
77	if (q != MAP_FAILED) {
78		tst_res(TFAIL, "mmap() MAP_FIXED at misaligned address succeeded");
79		goto cleanup2;
80	}
81
82	/* 3) Try a misaligned length */
83	q = mmap(NULL, page_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
84	if (q == MAP_FAILED) {
85		tst_res(TFAIL, "mmap() with misaligned length 0x%lx failed",
86			page_size);
87		return;
88	}
89	SAFE_MUNMAP(q, hpage_size);
90
91	/* 4) Try a misaligned length with MAP_FIXED */
92	q = mmap(p, page_size, PROT_READ|PROT_WRITE,
93			MAP_PRIVATE|MAP_FIXED, fd, 0);
94	if (q == MAP_FAILED) {
95		tst_res(TFAIL, "mmap() MAP_FIXED with misaligned length 0x%lx "
96			"failed", page_size);
97		return;
98	}
99	SAFE_MUNMAP(q, hpage_size);
100
101	/* 5) Try a misaligned offset */
102	q = mmap(NULL, hpage_size, PROT_READ|PROT_WRITE,
103		 MAP_PRIVATE, fd, page_size);
104	if (q != MAP_FAILED) {
105		tst_res(TFAIL, "mmap() with misaligned offset 0x%lx succeeded",
106		     page_size);
107		goto cleanup2;
108	}
109
110	/* 6) Try a misaligned offset with MAP_FIXED*/
111	q = mmap(p, hpage_size, PROT_READ|PROT_WRITE,
112		 MAP_PRIVATE|MAP_FIXED, fd, page_size);
113	if (q != MAP_FAILED) {
114		tst_res(TFAIL, "mmap() MAP_FIXED with misaligned offset 0x%lx succeeded",
115		     page_size);
116		goto cleanup2;
117	}
118
119	tst_res(TPASS, "mmap worked as expected with misaligned addr and length");
120	return;
121cleanup2:
122	SAFE_MUNMAP(q, hpage_size);
123	return;
124cleanup1:
125	SAFE_MUNMAP(p, hpage_size);
126}
127
128static void setup(void)
129{
130	hpage_size = SAFE_READ_MEMINFO("Hugepagesize:")*1024;
131	page_size = getpagesize();
132	fd = tst_creat_unlinked(MNTPOINT, 0);
133}
134
135static void cleanup(void)
136{
137	if (fd >= 0)
138		SAFE_CLOSE(fd);
139}
140
141static struct tst_test test = {
142	.tags = (struct tst_tag[]) {
143		{"linux-git", "af73e4d9506d"},
144		{}
145	},
146	.needs_root = 1,
147	.mntpoint = MNTPOINT,
148	.needs_hugetlbfs = 1,
149	.setup = setup,
150	.cleanup = cleanup,
151	.test_all = run_test,
152	.hugepages = {4, TST_NEEDS},
153};
154