void SysResourceTest::CheckResourceLimits() {
  ASSERT_EQ(0, getrlimit(RLIMIT_CORE, &l32_));
  ASSERT_EQ(0, getrlimit64(RLIMIT_CORE, &l64_));
  ASSERT_EQ(0, prlimit64(0, RLIMIT_CORE, NULL, &pr_l64_));
  ASSERT_EQ(l64_.rlim_cur, pr_l64_.rlim_cur);
  if (l64_.rlim_cur == RLIM64_INFINITY) {
    ASSERT_EQ(RLIM_INFINITY, l32_.rlim_cur);
  } else {
    ASSERT_EQ(l64_.rlim_cur, l32_.rlim_cur);
  }

  ASSERT_EQ(l64_.rlim_max, pr_l64_.rlim_max);
  if (l64_.rlim_max == RLIM64_INFINITY) {
    ASSERT_EQ(RLIM_INFINITY, l32_.rlim_max);
  } else {
    ASSERT_EQ(l64_.rlim_max, l32_.rlim_max);
  }
}
TEST_F(SysResourceTest, prlimit64) {
  pr_l64_.rlim_cur = pr_l64_.rlim_max;
  ASSERT_EQ(0, prlimit64(0, RLIMIT_CORE, &pr_l64_, NULL));
  CheckResourceLimits();
  ASSERT_EQ(pr_l64_.rlim_max, pr_l64_.rlim_cur);
}
 virtual void SetUp() {
   ASSERT_EQ(0, getrlimit(RLIMIT_CORE, &l32_));
   ASSERT_EQ(0, getrlimit64(RLIMIT_CORE, &l64_));
   ASSERT_EQ(0, prlimit64(0, RLIMIT_CORE, NULL, &pr_l64_));
 }
 void SetUp() override {
   ASSERT_EQ(0, getrlimit(RLIMIT_CORE, &l32_));
   ASSERT_EQ(0, getrlimit64(RLIMIT_CORE, &l64_));
   ASSERT_EQ(0, prlimit(0, RLIMIT_CORE, nullptr, &pr_l32_));
   ASSERT_EQ(0, prlimit64(0, RLIMIT_CORE, nullptr, &pr_l64_));
 }
Example #5
0
static bool containDropPrivs(struct nsjconf_t *nsjconf)
{
	/*
	 * Best effort because of /proc/self/setgroups
	 */
	gid_t *group_list = NULL;
	if (setgroups(0, group_list) == -1) {
		PLOG_D("setgroups(NULL) failed");
	}
	if (setresgid(nsjconf->inside_gid, nsjconf->inside_gid, nsjconf->inside_gid) == -1) {
		PLOG_E("setresgid(%u)", nsjconf->inside_gid);
		return false;
	}
	if (setresuid(nsjconf->inside_uid, nsjconf->inside_uid, nsjconf->inside_uid) == -1) {
		PLOG_E("setresuid(%u)", nsjconf->inside_uid);
		return false;
	}
#ifndef PR_SET_NO_NEW_PRIVS
#define PR_SET_NO_NEW_PRIVS 38
#endif
	if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1) {
		/* Only new kernels support it */
		PLOG_W("prctl(PR_SET_NO_NEW_PRIVS, 1)");
	}

	if (nsjconf->keep_caps == false) {
		for (unsigned long i = 0; i < 128UL; i++) {
			/*
			 * Number of capabilities differs between kernels, so
			 * wait for the first one which returns EINVAL
			 */
			if (prctl(PR_CAPBSET_DROP, i, 0UL, 0UL, 0UL) == -1 && errno == EINVAL) {
				break;
			}
		}
		if (prctl(PR_SET_KEEPCAPS, 0, 0, 0, 0) == -1) {
			PLOG_E("prctl(PR_SET_KEEPCAPS, 0)");
			return false;
		}
		struct __user_cap_header_struct cap_hdr = {
			.version = _LINUX_CAPABILITY_VERSION_3,
			.pid = 0,
		};
		const struct __user_cap_data_struct cap_data[_LINUX_CAPABILITY_U32S_3] = {
			[0 ... (_LINUX_CAPABILITY_U32S_3 - 1)].inheritable = 0U,
			[0 ... (_LINUX_CAPABILITY_U32S_3 - 1)].effective = 0U,
			[0 ... (_LINUX_CAPABILITY_U32S_3 - 1)].permitted = 0U,
		};
		if (syscall(__NR_capset, &cap_hdr, &cap_data) == -1) {
			PLOG_E("capset()");
			return false;
		}
	}
	return true;
}

static bool containPrepareEnv(struct nsjconf_t *nsjconf)
{
	if (prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0) == -1) {
		PLOG_E("prctl(PR_SET_PDEATHSIG, SIGKILL)");
		return false;
	}
	if (nsjconf->personality && personality(nsjconf->personality) == -1) {
		PLOG_E("personality(%lx)", nsjconf->personality);
		return false;
	}
	errno = 0;
	if (setpriority(PRIO_PROCESS, 0, 19) == -1 && errno != 0) {
		PLOG_W("setpriority(19)");
	}
	if (nsjconf->skip_setsid == false) {
		setsid();
	}
	return true;
}

static bool containInitMountNs(struct nsjconf_t *nsjconf)
{
	return mountInitNs(nsjconf);
}

static bool containSetLimits(struct nsjconf_t *nsjconf)
{
	struct rlimit64 rl;
	rl.rlim_cur = rl.rlim_max = nsjconf->rl_as;
	if (prlimit64(0, RLIMIT_AS, &rl, NULL) == -1) {
		PLOG_E("prlimit64(0, RLIMIT_AS, %" PRIu64 ")", nsjconf->rl_as);
		return false;
	}
	rl.rlim_cur = rl.rlim_max = nsjconf->rl_core;
	if (prlimit64(0, RLIMIT_CORE, &rl, NULL) == -1) {
		PLOG_E("prlimit64(0, RLIMIT_CORE, %" PRIu64 ")", nsjconf->rl_core);
		return false;
	}
	rl.rlim_cur = rl.rlim_max = nsjconf->rl_cpu;
	if (prlimit64(0, RLIMIT_CPU, &rl, NULL) == -1) {
		PLOG_E("prlimit64(0, RLIMIT_CPU, %" PRIu64 ")", nsjconf->rl_cpu);
		return false;
	}
	rl.rlim_cur = rl.rlim_max = nsjconf->rl_fsize;
	if (prlimit64(0, RLIMIT_FSIZE, &rl, NULL) == -1) {
		PLOG_E("prlimit64(0, RLIMIT_FSIZE, %" PRIu64 ")", nsjconf->rl_fsize);
		return false;
	}
	rl.rlim_cur = rl.rlim_max = nsjconf->rl_nofile;
	if (prlimit64(0, RLIMIT_NOFILE, &rl, NULL) == -1) {
		PLOG_E("prlimit64(0, RLIMIT_NOFILE, %" PRIu64 ")", nsjconf->rl_nofile);
		return false;
	}
	rl.rlim_cur = rl.rlim_max = nsjconf->rl_nproc;
	if (prlimit64(0, RLIMIT_NPROC, &rl, NULL) == -1) {
		PLOG_E("prlimit64(0, RLIMIT_NPROC, %" PRIu64 ")", nsjconf->rl_nproc);
		return false;
	}
	rl.rlim_cur = rl.rlim_max = nsjconf->rl_stack;
	if (prlimit64(0, RLIMIT_STACK, &rl, NULL) == -1) {
		PLOG_E("prlimit64(0, RLIMIT_STACK, %" PRIu64 ")", nsjconf->rl_stack);
		return false;
	}
	return true;
}

static bool containMakeFdsCOENaive(void)
{
	// Don't use getrlimit(RLIMIT_NOFILE) here, as it can return an artifically small value
	// (e.g. 32), which could be smaller than a maximum assigned number to file-descriptors
	// in this process. Just use some reasonably sane value (e.g. 1024)
	for (unsigned fd = (STDERR_FILENO + 1); fd < 1024; fd++) {
		int flags = fcntl(fd, F_GETFD, 0);
		if (flags == -1) {
			continue;
		}
		fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
		LOG_D("Set fd '%d' flag to FD_CLOEXEC", fd);
	}
	return true;
}

static bool containMakeFdsCOEProc(void)
{
	/* Make all fds above stderr close-on-exec */
	DIR *dir = opendir("/proc/self/fd");
	if (dir == NULL) {
		PLOG_D("opendir('/proc/self/fd')");
		return false;
	}
	defer {
		closedir(dir);
	};
	for (;;) {
		errno = 0;
		struct dirent *entry = readdir(dir);
		if (entry == NULL && errno != 0) {
			PLOG_D("readdir('/proc/self/fd')");
			return false;
		}
		if (entry == NULL) {
			break;
		}
		if (strcmp(".", entry->d_name) == 0) {
			continue;
		}
		if (strcmp("..", entry->d_name) == 0) {
			continue;
		}
		int fd = strtoul(entry->d_name, NULL, 10);
		if (errno == EINVAL) {
			LOG_W("Cannot convert /proc/self/fd/%s to a number", entry->d_name);
			continue;
		}
		if (fd > STDERR_FILENO) {
			int flags = fcntl(fd, F_GETFD, 0);
			if (flags == -1) {
				PLOG_D("fcntl(fd, F_GETFD, 0)");
				return false;
			}
			fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
			LOG_D("Set fd '%d' flag to FD_CLOEXEC", fd);
		}
	}
	return true;
}
// There is no setrlimit64 system call, so we need to use prlimit64.
int setrlimit64(int resource, const rlimit64* limits64) {
  return prlimit64(0, resource, limits64, NULL);
}
// There is no getrlimit64 system call, so we need to use prlimit64.
int getrlimit64(int resource, rlimit64* limits64) {
  return prlimit64(0, resource, NULL, limits64);
}
Example #8
0
bool arch_launchChild(honggfuzz_t * hfuzz, char *fileName)
{
    /*
     * Kill the children when fuzzer dies (e.g. due to Ctrl+C)
     */
    if (prctl(PR_SET_PDEATHSIG, (long)SIGKILL, 0L, 0L, 0L) == -1) {
        PLOG_E("prctl(PR_SET_PDEATHSIG, SIGKILL) failed");
        return false;
    }

    /*
     * Kill a process which corrupts its own heap (with ABRT)
     */
    if (setenv("MALLOC_CHECK_", "3", 1) == -1) {
        PLOG_E("setenv(MALLOC_CHECK_=3) failed");
        return false;
    }

    /*
     * Tell asan to ignore SEGVs
     */
    if (setenv
        ("ASAN_OPTIONS",
         "allow_user_segv_handler=1:handle_segv=0:abort_on_error=1:allocator_may_return_null=1",
         1) == -1) {
        PLOG_E("setenv(ASAN_OPTIONS) failed");
        return false;
    }

    const char *msan_options =
        "exit_code=" HF_MSAN_EXIT_CODE_STR ":report_umrs=0:wrap_signals=0:print_stats=1";
    if (hfuzz->msanReportUMRS == true) {
        msan_options =
            "exit_code=" HF_MSAN_EXIT_CODE_STR ":report_umrs=1:wrap_signals=0:print_stats=1";
    }
    if (setenv("MSAN_OPTIONS", msan_options, 1) == -1) {
        PLOG_E("setenv(MSAN_OPTIONS) failed");
        return false;
    }

    /*
     * Disable ASLR
     */
    if (hfuzz->disableRandomization && personality(ADDR_NO_RANDOMIZE) == -1) {
        PLOG_E("personality(ADDR_NO_RANDOMIZE) failed");
        return false;
    }
#define ARGS_MAX 512
    char *args[ARGS_MAX + 2];
    char argData[PATH_MAX] = { 0 };
    int x;

    for (x = 0; x < ARGS_MAX && hfuzz->cmdline[x]; x++) {
        if (!hfuzz->fuzzStdin && strcmp(hfuzz->cmdline[x], _HF_FILE_PLACEHOLDER) == 0) {
            args[x] = fileName;
        } else if (!hfuzz->fuzzStdin && strstr(hfuzz->cmdline[x], _HF_FILE_PLACEHOLDER)) {
            const char *off = strstr(hfuzz->cmdline[x], _HF_FILE_PLACEHOLDER);
            snprintf(argData, PATH_MAX, "%.*s%s", (int)(off - hfuzz->cmdline[x]), hfuzz->cmdline[x],
                     fileName);
            args[x] = argData;
        } else {
            args[x] = hfuzz->cmdline[x];
        }
    }

    args[x++] = NULL;

    LOG_D("Launching '%s' on file '%s'", args[0], fileName);

    /*
     * Set timeout (prof), real timeout (2*prof), and rlimit_cpu (2*prof)
     */
    if (hfuzz->tmOut) {
        /* 
         * Set the CPU rlimit to twice the value of the time-out
         */
        struct rlimit rl = {
            .rlim_cur = hfuzz->tmOut * 2,
            .rlim_max = hfuzz->tmOut * 2,
        };
        if (setrlimit(RLIMIT_CPU, &rl) == -1) {
            PLOG_E("Couldn't enforce the RLIMIT_CPU resource limit");
            return false;
        }
    }

    /*
     * The address space limit. If big enough - roughly the size of RAM used
     */
    if (hfuzz->asLimit) {
        struct rlimit64 rl = {
            .rlim_cur = hfuzz->asLimit * 1024ULL * 1024ULL,
            .rlim_max = hfuzz->asLimit * 1024ULL * 1024ULL,
        };
        if (prlimit64(0, RLIMIT_AS, &rl, NULL) == -1) {
            PLOG_D("Couldn't enforce the RLIMIT_AS resource limit, ignoring");
        }
    }

    for (size_t i = 0; i < ARRAYSIZE(hfuzz->envs) && hfuzz->envs[i]; i++) {
        putenv(hfuzz->envs[i]);
    }

    if (hfuzz->nullifyStdio) {
        util_nullifyStdio();
    }

    if (hfuzz->fuzzStdin) {
        /*
         * Uglyyyyyy ;)
         */
        if (!util_redirectStdin(fileName)) {
            return false;
        }
    }
    /*
     * Wait for the ptrace to attach
     */
    syscall(__NR_tkill, syscall(__NR_gettid), SIGSTOP);
    execvp(args[0], args);

    util_recoverStdio();
    LOG_F("Failed to create new '%s' process", args[0]);
    return false;
}

static void arch_sigFunc(int signo, siginfo_t * si, void *dummy)
{
    if (signo != SIGALRM) {
        LOG_E("Signal != SIGALRM (%d)", signo);
    }
    return;
    if (si == NULL) {
        return;
    }
    if (dummy == NULL) {
        return;
    }
}

static void arch_removeTimer(timer_t * timerid)
{
    timer_delete(*timerid);
}

static bool arch_setTimer(timer_t * timerid)
{
    struct sigevent sevp = {
        .sigev_value.sival_ptr = timerid,
        .sigev_signo = SIGALRM,
        .sigev_notify = SIGEV_THREAD_ID | SIGEV_SIGNAL,
        ._sigev_un._tid = syscall(__NR_gettid),
    };
    if (timer_create(CLOCK_REALTIME, &sevp, timerid) == -1) {
        PLOG_E("timer_create(CLOCK_REALTIME) failed");
        return false;
    }
    /* 
     * Kick in every 200ms, starting with the next second
     */
    const struct itimerspec ts = {
        .it_value = {.tv_sec = 1,.tv_nsec = 0},
        .it_interval = {.tv_sec = 0,.tv_nsec = 200000000,},
    };
    if (timer_settime(*timerid, 0, &ts, NULL) == -1) {
        PLOG_E("timer_settime() failed");
        timer_delete(*timerid);
        return false;
    }
    sigset_t smask;
    sigemptyset(&smask);
    struct sigaction sa = {
        .sa_handler = NULL,
        .sa_sigaction = arch_sigFunc,
        .sa_mask = smask,
        .sa_flags = SA_SIGINFO,
        .sa_restorer = NULL,
    };
    if (sigaction(SIGALRM, &sa, NULL) == -1) {
        PLOG_E("sigaction(SIGALRM) failed");
        return false;
    }

    return true;
}

static void arch_checkTimeLimit(honggfuzz_t * hfuzz, fuzzer_t * fuzzer)
{
    int64_t curMillis = util_timeNowMillis();
    int64_t diffMillis = curMillis - fuzzer->timeStartedMillis;
    if (diffMillis > (hfuzz->tmOut * 1000)) {
        LOG_W("PID %d took too much time (limit %ld s). Sending SIGKILL",
              fuzzer->pid, hfuzz->tmOut);
        kill(fuzzer->pid, SIGKILL);
        __sync_fetch_and_add(&hfuzz->timeoutedCnt, 1UL);
    }
}