135 lines
3.6 KiB
C
135 lines
3.6 KiB
C
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <spawn.h>
|
|
#include <stdbool.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
#include <sys/wait.h>
|
|
#include <unistd.h>
|
|
|
|
extern char **environ;
|
|
|
|
static int native_spawn_closefrom_test(void) {
|
|
posix_spawn_file_actions_t actions;
|
|
pid_t pid;
|
|
int status;
|
|
char *argv[] = { "/usr/bin/true", NULL };
|
|
|
|
if (posix_spawn_file_actions_init(&actions) != 0)
|
|
return 1;
|
|
if (posix_spawn_file_actions_adddup2(&actions, STDIN_FILENO, STDIN_FILENO) != 0)
|
|
return 2;
|
|
if (posix_spawn_file_actions_adddup2(&actions, STDOUT_FILENO, STDOUT_FILENO) != 0)
|
|
return 3;
|
|
if (posix_spawn_file_actions_adddup2(&actions, STDERR_FILENO, STDERR_FILENO) != 0)
|
|
return 4;
|
|
if (posix_spawn_file_actions_addclosefrom_np(&actions, 3) != 0)
|
|
return 5;
|
|
if (posix_spawn(&pid, "/usr/bin/true", &actions, NULL, argv, environ) != 0)
|
|
return 6;
|
|
if (waitpid(pid, &status, 0) < 0)
|
|
return 7;
|
|
if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
|
|
return 8;
|
|
return 0;
|
|
}
|
|
|
|
static int adddup2_invalid_fd_accepted(void) {
|
|
posix_spawn_file_actions_t actions;
|
|
if (posix_spawn_file_actions_init(&actions) != 0)
|
|
return -1;
|
|
return posix_spawn_file_actions_adddup2(&actions, 10000000, 2) == 0;
|
|
}
|
|
|
|
static int addopen_invalid_fd_accepted(void) {
|
|
posix_spawn_file_actions_t actions;
|
|
if (posix_spawn_file_actions_init(&actions) != 0)
|
|
return -1;
|
|
return posix_spawn_file_actions_addopen(&actions, 10000000, "foo", 0, O_RDONLY) == 0;
|
|
}
|
|
|
|
static int write_script(char *path, size_t size) {
|
|
int fd;
|
|
const char script[] = ":\n";
|
|
|
|
if (snprintf(path, size, "/tmp/fruix-posix-spawn-script-XXXXXX") >= (int)size)
|
|
return -1;
|
|
fd = mkstemp(path);
|
|
if (fd < 0)
|
|
return -1;
|
|
if (write(fd, script, sizeof(script) - 1) != (ssize_t)(sizeof(script) - 1)) {
|
|
close(fd);
|
|
unlink(path);
|
|
return -1;
|
|
}
|
|
if (fchmod(fd, 0700) != 0) {
|
|
close(fd);
|
|
unlink(path);
|
|
return -1;
|
|
}
|
|
if (close(fd) != 0) {
|
|
unlink(path);
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int secure_exec_result(int use_path) {
|
|
char script[128];
|
|
pid_t child;
|
|
int err;
|
|
int status = 0;
|
|
char *argv[] = { script, NULL };
|
|
char *env[] = { "PATH=/tmp:/usr/bin:/bin", NULL };
|
|
|
|
if (write_script(script, sizeof(script)) != 0)
|
|
return -1;
|
|
|
|
err = use_path
|
|
? posix_spawnp(&child, script, NULL, NULL, argv, env)
|
|
: posix_spawn(&child, script, NULL, NULL, argv, env);
|
|
|
|
if (err == ENOEXEC) {
|
|
unlink(script);
|
|
return 0;
|
|
}
|
|
if (err != 0) {
|
|
unlink(script);
|
|
return 1;
|
|
}
|
|
while (waitpid(child, &status, 0) != child)
|
|
;
|
|
unlink(script);
|
|
if (!WIFEXITED(status))
|
|
return 2;
|
|
if (WEXITSTATUS(status) != 127)
|
|
return 3;
|
|
return 0;
|
|
}
|
|
|
|
int main(void) {
|
|
int native_ok = native_spawn_closefrom_test();
|
|
int dup2_broken = adddup2_invalid_fd_accepted();
|
|
int addopen_broken = addopen_invalid_fd_accepted();
|
|
int spawn_secure = secure_exec_result(0);
|
|
int spawnp_secure = secure_exec_result(1);
|
|
int issue_profile_match =
|
|
native_ok == 0 &&
|
|
dup2_broken == 1 &&
|
|
addopen_broken == 1 &&
|
|
spawn_secure == 0 &&
|
|
spawnp_secure == 3;
|
|
|
|
printf("native-spawn-closefrom=%s\n", native_ok == 0 ? "ok" : "fail");
|
|
printf("adddup2-invalid-fd-accepted=%s\n", dup2_broken == 1 ? "yes" : (dup2_broken == 0 ? "no" : "error"));
|
|
printf("addopen-invalid-fd-accepted=%s\n", addopen_broken == 1 ? "yes" : (addopen_broken == 0 ? "no" : "error"));
|
|
printf("posix_spawn-secure-exec-result=%d\n", spawn_secure);
|
|
printf("posix_spawnp-secure-exec-result=%d\n", spawnp_secure);
|
|
printf("issue-profile-match=%s\n", issue_profile_match ? "yes" : "no");
|
|
|
|
return issue_profile_match ? 0 : 1;
|
|
}
|