示例#1
0
static NORETURN void *
spawn_thread_func (void *param)
{
	UNUSED (param);

	while (true) {
		do_sem_op (SEM_LAUNCH_START, -1);
		do_spawn ();
	}
}
示例#2
0
static ret_t
sem_adquire (int sem_ref, int sem_num)
{
    return do_sem_op (sem_ref, sem_num, -1);
}
示例#3
0
static void
do_spawn (void)
{
	int          n;
	int          size;
	uid_t        uid;
	gid_t        gid;
	int          env_inherit;
	pid_t        child;
	int          envs         = 0;
	int          log_stderr   = 0;
	char        *interpreter  = NULL;
	char        *log_file     = NULL;
	char        *uid_str      = NULL;
	char        *chroot_dir   = NULL;
	char       **envp         = NULL;
	char        *p            = spawn_shared;
	const char  *argv[]       = {"sh", "-c", NULL, NULL};

#define CHECK_MARK(val)           \
	if ((*(int *)p) != val) { \
		goto cleanup;     \
	} else {                  \
		p += sizeof(int); \
	}

#define ALIGN4(buf) while ((long)p & 0x3) p++;

	/* Read the shared memory
	 */

	/* 1.- Interpreter */
	CHECK_MARK (0xF0);

	size = *((int *)p);
	p += sizeof(int);
	if (size <= 0) {
		goto cleanup;
	}

	interpreter = malloc (sizeof("exec ") + size);
	if (interpreter == NULL) {
		goto cleanup;
	}
	strncpy (interpreter, "exec ", 5);
	strncpy (interpreter + 5, p, size + 1);
	p += size + 1;
	ALIGN4 (p);

	/* 2.- UID & GID */
	CHECK_MARK (0xF1);

	size = *((int *)p);
	if (size > 0) {
		uid_str = strdup (p + sizeof(int));
	}
	p += sizeof(int) + size + 1;
	ALIGN4 (p);

	memcpy (&uid, p, sizeof(uid_t));
	p += sizeof(uid_t);

	memcpy (&gid, p, sizeof(gid_t));
	p += sizeof(gid_t);

	/* 3.- Chroot directory */
	CHECK_MARK (0xF2);
	size = *((int *) p);
	p += sizeof(int);
	if (size > 0) {
		chroot_dir = malloc(size + 1);
		memcpy(chroot_dir, p, size + 1);
	}
	p += size + 1;
	ALIGN4 (p);

	/* 4.- Environment */
	CHECK_MARK (0xF3);

	env_inherit = *((int *)p);
	p += sizeof(int);

	envs = *((int *)p);
	p += sizeof(int);

	envp = malloc (sizeof(char *) * (envs + 1));
	if (envp == NULL) {
		goto cleanup;
	}
	envp[envs] = NULL;

	for (n=0; n<envs; n++) {
		char *e;

		size = *((int *)p);
		p += sizeof(int);

		e = malloc (size + 1);
		if (e == NULL) {
			goto cleanup;
		}

		memcpy (e, p, size);
		e[size] = '\0';

		envp[n] = e;
		p += size + 1;
		ALIGN4 (p);
	}

	/* 5.- Error log */
	CHECK_MARK (0xF4);

	size = *((int *)p);
	p += sizeof(int);

	if (size > 0) {
		if (! strncmp (p, "stderr", 6)) {
			log_stderr = 1;
		} else if (! strncmp (p, "file,", 5)) {
			log_file = p+5;
		}

		p += (size + 1);
		ALIGN4 (p);
	}

	/* 6.- PID: it's -1 now */
	CHECK_MARK (0xF5);

	n = *((int *)p);
	if (n > 0) {
		kill (n, SIGTERM);
		*p = -1;
	}

	/* Spawn
	 */
	child = fork();
	switch (child) {
	case 0: {
		int              i;
		struct sigaction sig_action;

		/* Reset signal handlers */
		sig_action.sa_handler = SIG_DFL;
		sig_action.sa_flags   = 0;
		sigemptyset (&sig_action.sa_mask);

		for (i=0 ; i < NSIG ; i++) {
			sigaction (i, &sig_action, NULL);
		}

		/* Logging */
		if (log_file) {
			int fd;
			fd = open (log_file, O_WRONLY | O_APPEND | O_CREAT, 0600);
			if (fd < 0) {
				PRINT_ERROR ("(warning) Couldn't open '%s' for writing..\n", log_file);
			}
			close (STDOUT_FILENO);
			close (STDERR_FILENO);
			dup2 (fd, STDOUT_FILENO);
			dup2 (fd, STDERR_FILENO);
		} else if (log_stderr) {
			/* do nothing */
		} else {
			int tmp_fd;
			tmp_fd = open ("/dev/null", O_WRONLY);

			close (STDOUT_FILENO);
			close (STDERR_FILENO);
			dup2 (tmp_fd, STDOUT_FILENO);
			dup2 (tmp_fd, STDERR_FILENO);
		}

		/* Change root */
		if (chroot_dir) {
			int re = chroot(chroot_dir);
			if (re < 0) {
				PRINT_ERROR ("(critial) Couldn't chroot to %s\n", chroot_dir);
				exit (1);
			}
		}

		/* Change user & group */
		if (uid_str != NULL) {
			n = initgroups (uid_str, gid);
			if (n == -1) {
				PRINT_ERROR ("(warning) initgroups failed User=%s, GID=%d\n", uid_str, gid);
			}
		}

		if ((int)gid != -1) {
			n = setgid (gid);
			if (n != 0) {
				PRINT_ERROR ("(warning) Couldn't set GID=%d\n", gid);
			}
		}

		if ((int)uid != -1) {
			n = setuid (uid);
			if (n != 0) {
				PRINT_ERROR ("(warning) Couldn't set UID=%d\n", uid);
			}
		}

		/* Clean the shared memory */
		size = (p - spawn_shared) - sizeof(int);
		memset (spawn_shared, 0, size);

		/* Execute the interpreter */
		argv[2] = interpreter;

		if (env_inherit) {
			do {
				execv ("/bin/sh", (char **)argv);
			} while (errno == EINTR);
		} else {
			do {
				execve ("/bin/sh", (char **)argv, envp);
			} while (errno == EINTR);
		}

		PRINT_MSG ("(critical) Couldn't spawn: sh -c %s\n", interpreter);
		exit (1);
	}

	case -1:
		/* Error */
		PRINT_MSG ("(critical) Couldn't fork(): %s\n", strerror(errno));
		goto cleanup;

	default:
		break;
	}

	/* Return the PID
	 */
	memcpy (p, (char *)&child, sizeof(int));
	printf ("PID %d: launched '/bin/sh -c %s' with uid=%d, gid=%d, chroot=%s, env=%s\n", child, interpreter, uid, gid, chroot_dir, env_inherit ? "inherited":"custom");

cleanup:
	/* Unlock worker
	 */
	do_sem_op (SEM_LAUNCH_READY, 1);

	/* Clean up
	 */
	free (uid_str);
	free (interpreter);
	free (chroot_dir);

	if (envp != NULL) {
		for (n=0; n<envs; n++) {
			free (envp[n]);
		}
		free (envp);
	}
}
示例#4
0
static ret_t
sem_unlock (int sem_ref, int sem_num)
{
    return do_sem_op (sem_ref, sem_num, 1);
}