1f08c3bdfSopenharmony_ci/*
2f08c3bdfSopenharmony_ci * Copyright (C) 2012 Red Hat, Inc.
3f08c3bdfSopenharmony_ci *
4f08c3bdfSopenharmony_ci * This program is free software; you can redistribute it and/or
5f08c3bdfSopenharmony_ci * modify it under the terms of version 2 of the GNU General Public
6f08c3bdfSopenharmony_ci * License as published by the Free Software Foundation.
7f08c3bdfSopenharmony_ci *
8f08c3bdfSopenharmony_ci * This program is distributed in the hope that it would be useful,
9f08c3bdfSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of
10f08c3bdfSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11f08c3bdfSopenharmony_ci *
12f08c3bdfSopenharmony_ci * Further, this software is distributed without any warranty that it
13f08c3bdfSopenharmony_ci * is free of the rightful claim of any third person regarding
14f08c3bdfSopenharmony_ci * infringement or the like.  Any license provided herein, whether
15f08c3bdfSopenharmony_ci * implied or otherwise, applies only to this software file.  Patent
16f08c3bdfSopenharmony_ci * licenses, if any, provided herein do not apply to combinations of
17f08c3bdfSopenharmony_ci * this program with other software, or any other product whatsoever.
18f08c3bdfSopenharmony_ci *
19f08c3bdfSopenharmony_ci * You should have received a copy of the GNU General Public License
20f08c3bdfSopenharmony_ci * along with this program; if not, write the Free Software
21f08c3bdfSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
22f08c3bdfSopenharmony_ci * 02110-1301, USA.
23f08c3bdfSopenharmony_ci */
24f08c3bdfSopenharmony_ci/*
25f08c3bdfSopenharmony_ci * This is a reproducer for CVE-2011-2496.
26f08c3bdfSopenharmony_ci *
27f08c3bdfSopenharmony_ci * The normal mmap paths all avoid creating a mapping where the pgoff
28f08c3bdfSopenharmony_ci * inside the mapping could wrap around due to overflow.  However, an
29f08c3bdfSopenharmony_ci * expanding mremap() can take such a non-wrapping mapping and make it
30f08c3bdfSopenharmony_ci * bigger and cause a wrapping condition. There is also another case
31f08c3bdfSopenharmony_ci * where we expand mappings hiding in plain sight: the automatic stack
32f08c3bdfSopenharmony_ci * expansion.
33f08c3bdfSopenharmony_ci *
34f08c3bdfSopenharmony_ci * This program tries to remap a mapping with a new size that would
35f08c3bdfSopenharmony_ci * wrap pgoff. Notice that it only works on 32-bit arch for now.
36f08c3bdfSopenharmony_ci */
37f08c3bdfSopenharmony_ci
38f08c3bdfSopenharmony_ci#define _GNU_SOURCE
39f08c3bdfSopenharmony_ci#include "config.h"
40f08c3bdfSopenharmony_ci#include <sys/types.h>
41f08c3bdfSopenharmony_ci#include <sys/mman.h>
42f08c3bdfSopenharmony_ci#include <sys/stat.h>
43f08c3bdfSopenharmony_ci#include <sys/syscall.h>
44f08c3bdfSopenharmony_ci#include <errno.h>
45f08c3bdfSopenharmony_ci#include <fcntl.h>
46f08c3bdfSopenharmony_ci#include <limits.h>
47f08c3bdfSopenharmony_ci#include <stdio.h>
48f08c3bdfSopenharmony_ci#include <stdlib.h>
49f08c3bdfSopenharmony_ci#include <unistd.h>
50f08c3bdfSopenharmony_ci
51f08c3bdfSopenharmony_ci#include "test.h"
52f08c3bdfSopenharmony_ci#include "safe_macros.h"
53f08c3bdfSopenharmony_ci#include "tst_kernel.h"
54f08c3bdfSopenharmony_ci#include "lapi/abisize.h"
55f08c3bdfSopenharmony_ci
56f08c3bdfSopenharmony_cichar *TCID = "vma03";
57f08c3bdfSopenharmony_ciint TST_TOTAL = 1;
58f08c3bdfSopenharmony_ci
59f08c3bdfSopenharmony_ci#ifdef __NR_mmap2
60f08c3bdfSopenharmony_ci#define TESTFILE "testfile"
61f08c3bdfSopenharmony_ci
62f08c3bdfSopenharmony_cistatic size_t pgsz;
63f08c3bdfSopenharmony_cistatic int fd;
64f08c3bdfSopenharmony_ci
65f08c3bdfSopenharmony_cistatic void *mmap2(void *addr, size_t length, int prot,
66f08c3bdfSopenharmony_ci		   int flags, int fd, off_t pgoffset);
67f08c3bdfSopenharmony_cistatic void setup(void);
68f08c3bdfSopenharmony_cistatic void cleanup(void);
69f08c3bdfSopenharmony_ci
70f08c3bdfSopenharmony_ciint main(int argc, char *argv[])
71f08c3bdfSopenharmony_ci{
72f08c3bdfSopenharmony_ci	int lc;
73f08c3bdfSopenharmony_ci	void *map, *remap;
74f08c3bdfSopenharmony_ci	off_t pgoff;
75f08c3bdfSopenharmony_ci
76f08c3bdfSopenharmony_ci	if (TST_ABI != 32 || tst_kernel_bits() != 32) {
77f08c3bdfSopenharmony_ci		tst_brkm(TCONF, NULL,
78f08c3bdfSopenharmony_ci			 "test is designed for 32-bit system only.");
79f08c3bdfSopenharmony_ci	}
80f08c3bdfSopenharmony_ci
81f08c3bdfSopenharmony_ci	tst_parse_opts(argc, argv, NULL, NULL);
82f08c3bdfSopenharmony_ci
83f08c3bdfSopenharmony_ci	pgsz = sysconf(_SC_PAGE_SIZE);
84f08c3bdfSopenharmony_ci	setup();
85f08c3bdfSopenharmony_ci
86f08c3bdfSopenharmony_ci	for (lc = 0; TEST_LOOPING(lc); lc++) {
87f08c3bdfSopenharmony_ci		tst_count = 0;
88f08c3bdfSopenharmony_ci
89f08c3bdfSopenharmony_ci		fd = SAFE_OPEN(NULL, TESTFILE, O_RDWR);
90f08c3bdfSopenharmony_ci
91f08c3bdfSopenharmony_ci		/*
92f08c3bdfSopenharmony_ci		 * The pgoff is counted in 4K units and must be page-aligned,
93f08c3bdfSopenharmony_ci		 * hence we must align it down to page_size/4096 in a case that
94f08c3bdfSopenharmony_ci		 * the system has page_size > 4K.
95f08c3bdfSopenharmony_ci		 */
96f08c3bdfSopenharmony_ci		pgoff = (ULONG_MAX - 1)&(~((pgsz-1)>>12));
97f08c3bdfSopenharmony_ci		map = mmap2(NULL, pgsz, PROT_READ | PROT_WRITE, MAP_PRIVATE,
98f08c3bdfSopenharmony_ci			    fd, pgoff);
99f08c3bdfSopenharmony_ci		if (map == MAP_FAILED)
100f08c3bdfSopenharmony_ci			tst_brkm(TBROK | TERRNO, cleanup, "mmap2");
101f08c3bdfSopenharmony_ci
102f08c3bdfSopenharmony_ci		remap = mremap(map, pgsz, 2 * pgsz, 0);
103f08c3bdfSopenharmony_ci		if (remap == MAP_FAILED) {
104f08c3bdfSopenharmony_ci			if (errno == EINVAL)
105f08c3bdfSopenharmony_ci				tst_resm(TPASS, "mremap failed as expected.");
106f08c3bdfSopenharmony_ci			else
107f08c3bdfSopenharmony_ci				tst_resm(TFAIL | TERRNO, "mremap");
108f08c3bdfSopenharmony_ci			munmap(map, pgsz);
109f08c3bdfSopenharmony_ci		} else {
110f08c3bdfSopenharmony_ci			tst_resm(TFAIL, "mremap succeeded unexpectedly.");
111f08c3bdfSopenharmony_ci			munmap(remap, 2 * pgsz);
112f08c3bdfSopenharmony_ci		}
113f08c3bdfSopenharmony_ci
114f08c3bdfSopenharmony_ci		close(fd);
115f08c3bdfSopenharmony_ci	}
116f08c3bdfSopenharmony_ci
117f08c3bdfSopenharmony_ci	cleanup();
118f08c3bdfSopenharmony_ci	tst_exit();
119f08c3bdfSopenharmony_ci}
120f08c3bdfSopenharmony_ci
121f08c3bdfSopenharmony_cistatic void *mmap2(void *addr, size_t length, int prot,
122f08c3bdfSopenharmony_ci		   int flags, int fd, off_t pgoffset)
123f08c3bdfSopenharmony_ci{
124f08c3bdfSopenharmony_ci	return (void *)syscall(SYS_mmap2, addr, length, prot,
125f08c3bdfSopenharmony_ci			       flags, fd, pgoffset);
126f08c3bdfSopenharmony_ci}
127f08c3bdfSopenharmony_ci
128f08c3bdfSopenharmony_cistatic void setup(void)
129f08c3bdfSopenharmony_ci{
130f08c3bdfSopenharmony_ci	tst_sig(FORK, DEF_HANDLER, cleanup);
131f08c3bdfSopenharmony_ci
132f08c3bdfSopenharmony_ci	tst_tmpdir();
133f08c3bdfSopenharmony_ci
134f08c3bdfSopenharmony_ci	fd = SAFE_CREAT(NULL, TESTFILE, 0644);
135f08c3bdfSopenharmony_ci	close(fd);
136f08c3bdfSopenharmony_ci
137f08c3bdfSopenharmony_ci	TEST_PAUSE;
138f08c3bdfSopenharmony_ci}
139f08c3bdfSopenharmony_ci
140f08c3bdfSopenharmony_cistatic void cleanup(void)
141f08c3bdfSopenharmony_ci{
142f08c3bdfSopenharmony_ci	tst_rmdir();
143f08c3bdfSopenharmony_ci}
144f08c3bdfSopenharmony_ci#else /* __NR_mmap2 */
145f08c3bdfSopenharmony_ciint main(int argc, char *argv[])
146f08c3bdfSopenharmony_ci{
147f08c3bdfSopenharmony_ci	tst_brkm(TCONF, NULL, "__NR_mmap2 is not defined on your system");
148f08c3bdfSopenharmony_ci}
149f08c3bdfSopenharmony_ci#endif
150