summaryrefslogtreecommitdiff
path: root/test/skodic.c
blob: 4152ad651daaf0ca3662957a132808ab2dec61e6 (plain)
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
/*
 * This demonstrates races: kernel may actually open other file
 * than you read in the strace output.
 * If you see a successful open of /etc/shadow,
 * you know you've seen a race.
 *
 * $ gcc -Wall -O0 skodic.c -o skodic
 * $ timeout 0.1 ../strace -yeopen -o'|grep "shadow.*= [0-9]"' ./skodic
 */

#ifndef _GNU_SOURCE
# define _GNU_SOURCE 1
#endif

#include <errno.h>
#include <error.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/mman.h>

int
main(void)
{
	FILE *fp = tmpfile();
	if (!fp)
		error(1, errno, "tmpfile");

	int fd = fileno(fp);
	size_t size = sysconf(_SC_PAGESIZE);

	if (ftruncate(fd, size))
		error(1, errno, "ftruncate");

	char *p = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
	if (p == MAP_FAILED)
		error(1, errno, "mmap");
	fclose(fp);
	fp = NULL;
	fd = -1;

	strcpy(p, "/etc/shadow");
	if (open(p, 0) >= 0)
		error(1, 0, p);

	pid_t pid = fork();
	if (pid < 0)
		error(1, errno, "fork");

	if (!pid) {
		for (;;) {
			strcpy(p, "/etc/passwd");
			strcpy(p, "/etc/shadow");
		}
	} else {
		for (;;) {
			if ((fd = open(p, 0)) >= 0)
				close(fd);
		}
	}

	return 0;
}