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) 2018 Google, Inc.
*/
/*\
* [Description]
*
* Regression test for commit
* 3f05317d9889 (ipc/shm: fix use-after-free of shm file via remap_file_pages()).
*
* This bug allowed the remap_file_pages() syscall to use the file of a System
* V shared memory segment after its ID had been reallocated and the file
* freed. This test reproduces the bug as a NULL pointer dereference in
* touch_atime(), although it's a race condition so it's not guaranteed to
* work. This test is based on the reproducer provided in the fix's commit
* message.
*/
#include "tst_test.h"
#include "tst_fuzzy_sync.h"
#include "tst_safe_pthread.h"
#include "tst_safe_sysv_ipc.h"
#include "tst_timer.h"
#include "lapi/syscalls.h"
static struct tst_fzsync_pair fzsync_pair;
/*
* Thread 2: repeatedly remove the shm ID and reallocate it again for a
* new shm segment.
*/
static void *thrproc(void *unused)
{
int id = SAFE_SHMGET(0xF00F, 4096, IPC_CREAT|0700);
while (tst_fzsync_run_b(&fzsync_pair)) {
tst_fzsync_start_race_b(&fzsync_pair);
SAFE_SHMCTL(id, IPC_RMID, NULL);
id = SAFE_SHMGET(0xF00F, 4096, IPC_CREAT|0700);
tst_fzsync_end_race_b(&fzsync_pair);
}
return unused;
}
static void setup(void)
{
/* Skip test if either remap_file_pages() or SysV IPC is unavailable */
tst_syscall(__NR_remap_file_pages, NULL, 0, 0, 0, 0);
tst_syscall(__NR_shmctl, 0xF00F, IPC_RMID, NULL);
tst_fzsync_pair_init(&fzsync_pair);
}
static void do_test(void)
{
/*
* Thread 1: repeatedly attach a shm segment, then remap it until the ID
* seems to have been removed by the other process.
*/
tst_fzsync_pair_reset(&fzsync_pair, thrproc);
while (tst_fzsync_run_a(&fzsync_pair)) {
int id;
void *addr;
id = SAFE_SHMGET(0xF00F, 4096, IPC_CREAT|0700);
addr = SAFE_SHMAT(id, NULL, 0);
tst_fzsync_start_race_a(&fzsync_pair);
do {
/* This is the system call that crashed */
TEST(syscall(__NR_remap_file_pages, addr, 4096,
0, 0, 0));
} while (TST_RET == 0);
tst_fzsync_end_race_a(&fzsync_pair);
if (TST_ERR != EIDRM && TST_ERR != EINVAL) {
tst_brk(TBROK | TTERRNO,
"Unexpected remap_file_pages() error");
}
/*
* Ensure that a shm segment will actually be destroyed.
* This call may fail on recent kernels (v4.0+) because
* remap_file_pages() already unmapped the shm segment.
*/
shmdt(addr);
}
tst_res(TPASS, "didn't crash");
}
static void cleanup(void)
{
int id;
tst_fzsync_pair_cleanup(&fzsync_pair);
id = shmget(0xF00F, 4096, 0);
if (id == -1) {
if (errno != ENOENT)
tst_res(TWARN | TERRNO, "shmget()");
return;
}
SAFE_SHMCTL(id, IPC_RMID, NULL);
}
static struct tst_test test = {
.max_runtime = 10,
.setup = setup,
.test_all = do_test,
.cleanup = cleanup,
.tags = (const struct tst_tag[]) {
{"linux-git", "3f05317d9889"},
{}
}
};