cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

fd-001-lookup.c (3678B)


      1/*
      2 * Copyright © 2018 Alexey Dobriyan <adobriyan@gmail.com>
      3 *
      4 * Permission to use, copy, modify, and distribute this software for any
      5 * purpose with or without fee is hereby granted, provided that the above
      6 * copyright notice and this permission notice appear in all copies.
      7 *
      8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     15 */
     16// Test /proc/*/fd lookup.
     17
     18#undef NDEBUG
     19#include <assert.h>
     20#include <dirent.h>
     21#include <errno.h>
     22#include <limits.h>
     23#include <sched.h>
     24#include <stdio.h>
     25#include <unistd.h>
     26#include <sys/types.h>
     27#include <sys/stat.h>
     28#include <fcntl.h>
     29
     30#include "proc.h"
     31
     32/* lstat(2) has more "coverage" in case non-symlink pops up somehow. */
     33static void test_lookup_pass(const char *pathname)
     34{
     35	struct stat st;
     36	ssize_t rv;
     37
     38	memset(&st, 0, sizeof(struct stat));
     39	rv = lstat(pathname, &st);
     40	assert(rv == 0);
     41	assert(S_ISLNK(st.st_mode));
     42}
     43
     44static void test_lookup_fail(const char *pathname)
     45{
     46	struct stat st;
     47	ssize_t rv;
     48
     49	rv = lstat(pathname, &st);
     50	assert(rv == -1 && errno == ENOENT);
     51}
     52
     53static void test_lookup(unsigned int fd)
     54{
     55	char buf[64];
     56	unsigned int c;
     57	unsigned int u;
     58	int i;
     59
     60	snprintf(buf, sizeof(buf), "/proc/self/fd/%u", fd);
     61	test_lookup_pass(buf);
     62
     63	/* leading junk */
     64	for (c = 1; c <= 255; c++) {
     65		if (c == '/')
     66			continue;
     67		snprintf(buf, sizeof(buf), "/proc/self/fd/%c%u", c, fd);
     68		test_lookup_fail(buf);
     69	}
     70
     71	/* trailing junk */
     72	for (c = 1; c <= 255; c++) {
     73		if (c == '/')
     74			continue;
     75		snprintf(buf, sizeof(buf), "/proc/self/fd/%u%c", fd, c);
     76		test_lookup_fail(buf);
     77	}
     78
     79	for (i = INT_MIN; i < INT_MIN + 1024; i++) {
     80		snprintf(buf, sizeof(buf), "/proc/self/fd/%d", i);
     81		test_lookup_fail(buf);
     82	}
     83	for (i = -1024; i < 0; i++) {
     84		snprintf(buf, sizeof(buf), "/proc/self/fd/%d", i);
     85		test_lookup_fail(buf);
     86	}
     87	for (u = INT_MAX - 1024; u <= (unsigned int)INT_MAX + 1024; u++) {
     88		snprintf(buf, sizeof(buf), "/proc/self/fd/%u", u);
     89		test_lookup_fail(buf);
     90	}
     91	for (u = UINT_MAX - 1024; u != 0; u++) {
     92		snprintf(buf, sizeof(buf), "/proc/self/fd/%u", u);
     93		test_lookup_fail(buf);
     94	}
     95
     96
     97}
     98
     99int main(void)
    100{
    101	struct dirent *de;
    102	unsigned int fd, target_fd;
    103
    104	if (unshare(CLONE_FILES) == -1)
    105		return 1;
    106
    107	/* Wipe fdtable. */
    108	do {
    109		DIR *d;
    110
    111		d = opendir("/proc/self/fd");
    112		if (!d)
    113			return 1;
    114
    115		de = xreaddir(d);
    116		assert(de->d_type == DT_DIR);
    117		assert(streq(de->d_name, "."));
    118
    119		de = xreaddir(d);
    120		assert(de->d_type == DT_DIR);
    121		assert(streq(de->d_name, ".."));
    122next:
    123		de = xreaddir(d);
    124		if (de) {
    125			unsigned long long fd_ull;
    126			unsigned int fd;
    127			char *end;
    128
    129			assert(de->d_type == DT_LNK);
    130
    131			fd_ull = xstrtoull(de->d_name, &end);
    132			assert(*end == '\0');
    133			assert(fd_ull == (unsigned int)fd_ull);
    134
    135			fd = fd_ull;
    136			if (fd == dirfd(d))
    137				goto next;
    138			close(fd);
    139		}
    140
    141		closedir(d);
    142	} while (de);
    143
    144	/* Now fdtable is clean. */
    145
    146	fd = open("/", O_PATH|O_DIRECTORY);
    147	assert(fd == 0);
    148	test_lookup(fd);
    149	close(fd);
    150
    151	/* Clean again! */
    152
    153	fd = open("/", O_PATH|O_DIRECTORY);
    154	assert(fd == 0);
    155	/* Default RLIMIT_NOFILE-1 */
    156	target_fd = 1023;
    157	while (target_fd > 0) {
    158		if (dup2(fd, target_fd) == target_fd)
    159			break;
    160		target_fd /= 2;
    161	}
    162	assert(target_fd > 0);
    163	close(fd);
    164	test_lookup(target_fd);
    165	close(target_fd);
    166
    167	return 0;
    168}