Exemple #1
0
int
restore(pink_easy_process_t *current)
{
	pid_t pid = pink_easy_process_get_pid(current);
	pink_bitness_t bit = pink_easy_process_get_bitness(current);
	proc_data_t *data = pink_easy_process_get_userdata(current);

	/* Restore system call number */
	if (!pink_util_set_syscall(pid, bit, data->sno)) {
		if (errno == ESRCH)
			return PINK_EASY_CFLAG_DROP;
		warning("pink_util_set_syscall(%lu, %s, %s): errno:%d (%s)",
				(unsigned long)pid, pink_bitness_name(bit),
				pink_name_syscall(data->sno, bit),
				errno, strerror(errno));
	}

	/* Return the saved return value */
	if (!pink_util_set_return(pid, data->ret)) {
		if (errno == ESRCH)
			return PINK_EASY_CFLAG_DROP;
		warning("pink_util_set_return(%lu, %s, %s): errno:%d (%s)",
				(unsigned long)pid, pink_bitness_name(bit),
				pink_name_syscall(data->sno, bit),
				errno, strerror(errno));
	}

	return 0;
}
static void
handle_sigtrap(struct child *son)
{
	long scno, ret;
	const char *scname;

	/* We get this event twice, one at entering a
	 * system call and one at exiting a system
	 * call. */
	if (son->insyscall) {
		if (!pink_util_get_return(son->pid, &ret))
			err(1, "pink_util_get_return");
		if (son->inexecve) {
			son->inexecve = false;
			if (ret == 0) { /* execve was successful */
				/* Update bitness */
				son->bitness = pink_bitness_get(son->pid);
				if (son->bitness == PINK_BITNESS_UNKNOWN)
					err(1, "pink_bitness_get");
				printf(" = 0 (Updating the bitness of child %i to %s mode)\n",
					son->pid, pink_bitness_name(son->bitness));
				son->printret = false;
				return;
			}
		}
		son->insyscall = false;
		if (!son->printret) {
			son->printret = true;
			return;
		}
		/* Exiting the system call, print the
		 * return value. */
		putchar(' ');
		print_ret(ret);
		putchar('\n');
	}
	else {
		son->insyscall = true;
		/* Get the system call number and call
		 * the appropriate decoder. */
		if (!pink_util_get_syscall(son->pid, son->bitness, &scno))
			err(1, "pink_util_get_syscall");
		scname = pink_name_syscall(scno, son->bitness);
		assert(scname != NULL);

		if (!strcmp(scname, "execve"))
			son->inexecve = true;

		if (!strcmp(scname, "open"))
			decode_open(son->pid, son->bitness);
		else if (!strcmp(scname, "execve"))
			decode_execve(son->pid, son->bitness);
		else if (!strcmp(scname, "bind") || !strcmp(scname, "connect"))
			decode_socketcall(son->pid, son->bitness, scname);
		else
			printf("%s()", scname);
	}
}
Exemple #3
0
static void
report(pink_easy_process_t *current, const char *fmt, va_list ap)
{
	char *cmdline;
	pid_t pid = pink_easy_process_get_pid(current);
	pink_bitness_t bit = pink_easy_process_get_bitness(current);
	proc_data_t *data = pink_easy_process_get_userdata(current);

	warning("-- Access Violation! --");
	warning("process id:%lu (%s name:\"%s\")", (unsigned long)pid, pink_bitness_name(bit), data->comm);
	warning("cwd: `%s'", data->cwd);

	if (!proc_cmdline(pid, 128, &cmdline)) {
		warning("cmdline: `%s'", cmdline);
		free(cmdline);
	}

	log_msg_va(1, fmt, ap);
}
Exemple #4
0
int
sys_linkat(pink_easy_process_t *current, const char *name)
{
	int r;
	long flags;
	pid_t pid = pink_easy_process_get_pid(current);
	pink_bitness_t bit = pink_easy_process_get_bitness(current);
	proc_data_t *data = pink_easy_process_get_userdata(current);
	sys_info_t info;

	if (data->config.sandbox_write == SANDBOX_OFF)
		return 0;

	/* Check for AT_SYMLINK_FOLLOW */
	if (!pink_util_get_arg(pid, bit, 4, &flags)) {
		if (errno != ESRCH) {
			warning("pink_util_get_arg(%lu, \"%s\", 4): %d(%s)",
					(unsigned long)pid,
					pink_bitness_name(bit),
					errno, strerror(errno));
			return panic(current);
		}
		return PINK_EASY_CFLAG_DROP;
	}

	memset(&info, 0, sizeof(sys_info_t));
	info.at     = true;
	info.resolv = !!(flags & AT_SYMLINK_FOLLOW);
	info.index  = 1;
	info.whitelisting = data->config.sandbox_write == SANDBOX_DENY;

	r = box_check_path(current, name, &info);
	if (!r && !data->deny) {
		info.create = MAY_CREATE;
		info.index  = 3;
		return box_check_path(current, name, &info);
	}

	return r;
}
Exemple #5
0
int
deny(pink_easy_process_t *current)
{
	pid_t pid = pink_easy_process_get_pid(current);
	pink_bitness_t bit = pink_easy_process_get_bitness(current);
	proc_data_t *data = pink_easy_process_get_userdata(current);

	data->deny = true;
	data->ret = errno2retval();

	if (!pink_util_set_syscall(pid, bit, PINKTRACE_INVALID_SYSCALL)) {
		if (errno != ESRCH) {
			warning("pink_util_set_syscall(%d, \"%s\", 0xbadca11): %d(%s)",
					pid, pink_bitness_name(bit),
					errno, strerror(errno));
			return panic(current);
		}
		return PINK_EASY_CFLAG_DROP;
	}

	return 0;
}
int
main(int argc, char **argv)
{
	int sig, status, exit_code;
	pink_event_t event;
	struct child son;

	/* Parse arguments */
	if (argc < 2) {
		fprintf(stderr, "Usage: %s program [argument...]\n", argv[0]);
		return EXIT_FAILURE;
	}

	/* Fork */
	if ((son.pid = fork()) < 0) {
		perror("fork");
		return EXIT_FAILURE;
	}
	else if (!son.pid) { /* child */
		/* Set up for tracing */
		if (!pink_trace_me()) {
			perror("pink_trace_me");
			_exit(EXIT_FAILURE);
		}
		/* Stop and let the parent continue the execution. */
		kill(getpid(), SIGSTOP);

		++argv;
		execvp(argv[0], argv);
		perror("execvp");
		_exit(-1);
	}
	else {
		waitpid(son.pid, &status, 0);
		event = pink_event_decide(status);
		assert(event == PINK_EVENT_STOP);

		/* Set up the tracing options. */
		if (!pink_trace_setup(son.pid, PINK_TRACE_OPTION_SYSGOOD | PINK_TRACE_OPTION_EXEC)) {
			perror("pink_trace_setup");
			pink_trace_kill(son.pid);
			return EXIT_FAILURE;
		}

		/* Figure out the bitness of the traced child. */
		son.bitness = pink_bitness_get(son.pid);
		if (son.bitness == PINK_BITNESS_UNKNOWN)
			err(1, "pink_bitness_get");
		printf("Child %i runs in %s mode\n", son.pid, pink_bitness_name(son.bitness));

		son.dead = son.insyscall = false;
		sig = exit_code = 0;
		for (;;) {
			/* At this point the traced child is stopped and needs
			 * to be resumed.
			 */
			if (!pink_trace_syscall(son.pid, sig)) {
				perror("pink_trace_syscall");
				return (errno == ESRCH) ? 0 : 1;
			}
			sig = 0;

			/* Wait for the child */
			if ((son.pid = waitpid(son.pid, &status, 0)) < 0) {
				perror("waitpid");
				return (errno == ECHILD) ? 0 : 1;
			}

			/* Check the event. */
			event = pink_event_decide(status);
			switch (event) {
			case PINK_EVENT_SYSCALL:
				handle_syscall(&son);
				break;
				break;
			case PINK_EVENT_EXEC:
				/* Update bitness */
				son.bitness = pink_bitness_get(son.pid);
				if (son.bitness == PINK_BITNESS_UNKNOWN)
					err(1, "pink_bitness_get");
				else
					printf(" (Updating the bitness of child %i to %s mode)\n",
						son.pid, pink_bitness_name(son.bitness));
				break;
			case PINK_EVENT_GENUINE:
			case PINK_EVENT_UNKNOWN:
				/* Send the signal to the traced child as it
				 * was a genuine signal.
				 */
				sig = WSTOPSIG(status);
				break;
			case PINK_EVENT_EXIT_GENUINE:
				exit_code = WEXITSTATUS(status);
				printf("Child %i exited normally with return code %d\n",
						son.pid, exit_code);
				son.dead = true;
				break;
			case PINK_EVENT_EXIT_SIGNAL:
				exit_code = 128 + WTERMSIG(status);
				printf("Child %i exited with signal %d\n",
						son.pid, WTERMSIG(status));
				son.dead = true;
				break;
			default:
				/* Nothing */
				;
			}
			if (son.dead)
				break;
		}

		return exit_code;
	}
}
int
main(int argc, char **argv)
{
	int sig, status, exit_code;
	struct child son;

	/* Parse arguments */
	if (argc < 2) {
		fprintf(stderr, "Usage: %s program [argument...]\n", argv[0]);
		return EXIT_FAILURE;
	}

	/* Fork */
	if ((son.pid = fork()) < 0) {
		perror("fork");
		return EXIT_FAILURE;
	}
	else if (!son.pid) { /* child */
		/* Set up for tracing */
		if (!pink_trace_me()) {
			perror("pink_trace_me");
			_exit(EXIT_FAILURE);
		}
		/* Stop and let the parent continue the execution. */
		kill(getpid(), SIGSTOP);

		++argv;
		execvp(argv[0], argv);
		perror("execvp");
		_exit(-1);
	}
	else {
		waitpid(son.pid, &status, 0);
		assert(WIFSTOPPED(status));
		assert(WSTOPSIG(status) == SIGSTOP);

		/* Figure out the bitness of the traced child. */
		son.bitness = pink_bitness_get(son.pid);
		if (son.bitness == PINK_BITNESS_UNKNOWN)
			err(1, "pink_bitness_get");
		printf("Child %i runs in %s mode\n", son.pid, pink_bitness_name(son.bitness));

		son.inexecve = son.insyscall = false;
		son.printret = true;
		sig = exit_code = 0;
		for (;;) {
			/* At this point the traced child is stopped and needs
			 * to be resumed.
			 */
			if (!pink_trace_syscall(son.pid, sig)) {
				perror("pink_trace_syscall");
				return (errno == ESRCH) ? 0 : 1;
			}
			sig = 0;

			/* Wait for the child */
			if ((son.pid = waitpid(son.pid, &status, 0)) < 0) {
				perror("waitpid");
				return (errno == ECHILD) ? 0 : 1;
			}

			/* Check the event */
			if (WIFSTOPPED(status)) {
				if (WSTOPSIG(status) == SIGTRAP)
					handle_sigtrap(&son);
				else {
					/* Child received a genuine signal.
					 * Send it to the child. */
					sig = WSTOPSIG(status);
				}
			}
			else if (WIFEXITED(status)) {
				exit_code = WEXITSTATUS(status);
				printf("Child %i exited normally with return code %d\n",
						son.pid, exit_code);
				break;
			}
			else if (WIFSIGNALED(status)) {
				exit_code = 128 + WTERMSIG(status);
				printf("Child %i exited with signal %d\n",
						son.pid, WTERMSIG(status));
				break;
			}
		}

		return exit_code;
	}
}
Exemple #8
0
int
sys_execve(pink_easy_process_t *current, const char *name)
{
	int r;
	char *path, *abspath;
	pid_t pid = pink_easy_process_get_pid(current);
	pink_bitness_t bit = pink_easy_process_get_bitness(current);
	proc_data_t *data = pink_easy_process_get_userdata(current);

	path = abspath = NULL;

	r = path_decode(current, 0, &path);
	if (r < 0)
		return deny(current);
	else if (r /* > 0 */)
		return r;

	if ((r = box_resolve_path(path, data->cwd, pid, 0, 1, &abspath)) < 0) {
		info("resolving path:\"%s\" [%s() index:0] failed for process:%lu [%s name:\"%s\" cwd:\"%s\"] (errno:%d %s)",
				path, name,
				(unsigned long)pid, pink_bitness_name(bit),
				data->comm, data->cwd,
				-r, strerror(-r));
		errno = -r;
		r = deny(current);
		if (pandora->config.violation_raise_fail)
			violation(current, "%s(\"%s\")", name, path);
		free(path);
		return r;
	}
	free(path);

	/* Handling exec.kill_if_match and exec.resume_if_match:
	 *
	 * Resolve and save the path argument in data->abspath.
	 * When we receive a PINK_EVENT_EXEC which means execve() was
	 * successful, we'll check for kill_if_match and resume_if_match lists
	 * and kill or resume the process as necessary.
	 */
	data->abspath = abspath;

	switch (data->config.sandbox_exec) {
	case SANDBOX_OFF:
		return 0;
	case SANDBOX_DENY:
		if (box_match_path(abspath, &data->config.whitelist_exec, NULL))
			return 0;
		break;
	case SANDBOX_ALLOW:
		if (!box_match_path(abspath, &data->config.blacklist_exec, NULL))
			return 0;
		break;
	default:
		abort();
	}

	errno = EACCES;
	r = deny(current);

	if (!box_match_path(abspath, &pandora->config.filter_exec, NULL))
		violation(current, "%s(\"%s\")", name, abspath);

	free(abspath);
	data->abspath = NULL;

	return r;
}