取消共享用户命名空间、fork、映射 uid 然后 execvp 失败
unshare user namespace, fork, map uid then execvp failing
我正在尝试执行以下操作序列:
unshare
user
命名空间;
- 将子进程中的
user
映射到 root
;
execvp
.
但是,当 运行ning id
时,我的代码将用户输出为 nobody
或失败而没有错误。
#include <sched.h>
#include <cstdio>
#include <cstring>
#include <cerrno>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/mount.h>
#include <system_error>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
void unshare_user_namespace() {
if (0 != unshare(CLONE_NEWUSER)) {
fprintf(stderr, "%s\n", "USER unshare has failed");
exit(1);
}
}
void map_id() {
int pid = getpid();
char file[100];
if (0 > sprintf(file, "/proc/%d/uid_map", pid)) {
printf("Couldn't sprintf uid_map path.");
exit(1);
}
int fd;
fd = open(file, 1);
if (fd < 0) {
printf("Coudln't open file for writing.\n");
exit(1);
}
int uid = getuid();
char * buf;
if (0 > sprintf(buf, "0 %d 1", uid)) {
printf("Couldn't sprintf uid_map content.");
exit(1);
}
if (write(fd, buf, strlen(buf))) {
printf("Coudln't write mapping into file.\n");
exit(1);
}
free(buf);
close(fd);
}
void start(char * command, char ** args) {
unshare_user_namespace();
int fork_pid = fork();
if (-1 == fork_pid) {
fprintf(stderr, "%s\n", "couldn't fork");
exit(1);
}
if (0 == fork_pid) {
map_id();
if (-1 == execvp(command, args)) {
fprintf(stderr, "%s\n", "couldn't execvp");
exit(1);
}
}
}
int main(int argc, char ** argv) {
start(argv[1], & argv[1]);
int status;
wait( & status);
return 0;
}
我尝试阅读 namespaces
、unshare
等的手册页,但无法弄清楚我的代码有什么问题。
要运行代码:
$ g++ <file_containing_code> && ./a.out id
很确定您已经找到了答案,但这是我能想到的最小示例:
// gcc -Wall -std=c11
#define _GNU_SOURCE
#include <stdio.h>
#include <unistd.h>
#include <sched.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <stdarg.h>
void write_to_file(const char *which, const char *format, ...) {
FILE * fu = fopen(which, "w");
va_list args;
va_start(args, format);
if (vfprintf(fu, format, args) < 0) {
perror("cannot write");
exit(1);
}
fclose(fu);
}
int main(int argc, char ** argv) {
// array of strings, terminated with NULL entry
char **cmd_and_args = (char**) calloc(argc, sizeof(char*));
for (int i = 1 ; i < argc; i++) {
cmd_and_args[i-1] = argv[i];
}
uid_t uid = getuid();
gid_t gid = getgid();
// first unshare
if (0 != unshare(CLONE_NEWUSER)) {
fprintf(stderr, "%s\n", "USER unshare has failed");
exit(1);
}
// remap uid
write_to_file("/proc/self/uid_map", "0 %d 1", uid);
// deny setgroups (see user_namespaces(7))
write_to_file("/proc/self/setgroups", "deny");
// remap gid
write_to_file("/proc/self/gid_map", "0 %d 1", gid);
// exec the command
if (execvp(cmd_and_args[0], cmd_and_args) < 0) {
perror("cannot execvp");
exit(1);
}
// unreachable
free(cmd_and_args);
return 0;
}
我正在尝试执行以下操作序列:
unshare
user
命名空间;- 将子进程中的
user
映射到root
; execvp
.
但是,当 运行ning id
时,我的代码将用户输出为 nobody
或失败而没有错误。
#include <sched.h>
#include <cstdio>
#include <cstring>
#include <cerrno>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/mount.h>
#include <system_error>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
void unshare_user_namespace() {
if (0 != unshare(CLONE_NEWUSER)) {
fprintf(stderr, "%s\n", "USER unshare has failed");
exit(1);
}
}
void map_id() {
int pid = getpid();
char file[100];
if (0 > sprintf(file, "/proc/%d/uid_map", pid)) {
printf("Couldn't sprintf uid_map path.");
exit(1);
}
int fd;
fd = open(file, 1);
if (fd < 0) {
printf("Coudln't open file for writing.\n");
exit(1);
}
int uid = getuid();
char * buf;
if (0 > sprintf(buf, "0 %d 1", uid)) {
printf("Couldn't sprintf uid_map content.");
exit(1);
}
if (write(fd, buf, strlen(buf))) {
printf("Coudln't write mapping into file.\n");
exit(1);
}
free(buf);
close(fd);
}
void start(char * command, char ** args) {
unshare_user_namespace();
int fork_pid = fork();
if (-1 == fork_pid) {
fprintf(stderr, "%s\n", "couldn't fork");
exit(1);
}
if (0 == fork_pid) {
map_id();
if (-1 == execvp(command, args)) {
fprintf(stderr, "%s\n", "couldn't execvp");
exit(1);
}
}
}
int main(int argc, char ** argv) {
start(argv[1], & argv[1]);
int status;
wait( & status);
return 0;
}
我尝试阅读 namespaces
、unshare
等的手册页,但无法弄清楚我的代码有什么问题。
要运行代码:
$ g++ <file_containing_code> && ./a.out id
很确定您已经找到了答案,但这是我能想到的最小示例:
// gcc -Wall -std=c11
#define _GNU_SOURCE
#include <stdio.h>
#include <unistd.h>
#include <sched.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <stdarg.h>
void write_to_file(const char *which, const char *format, ...) {
FILE * fu = fopen(which, "w");
va_list args;
va_start(args, format);
if (vfprintf(fu, format, args) < 0) {
perror("cannot write");
exit(1);
}
fclose(fu);
}
int main(int argc, char ** argv) {
// array of strings, terminated with NULL entry
char **cmd_and_args = (char**) calloc(argc, sizeof(char*));
for (int i = 1 ; i < argc; i++) {
cmd_and_args[i-1] = argv[i];
}
uid_t uid = getuid();
gid_t gid = getgid();
// first unshare
if (0 != unshare(CLONE_NEWUSER)) {
fprintf(stderr, "%s\n", "USER unshare has failed");
exit(1);
}
// remap uid
write_to_file("/proc/self/uid_map", "0 %d 1", uid);
// deny setgroups (see user_namespaces(7))
write_to_file("/proc/self/setgroups", "deny");
// remap gid
write_to_file("/proc/self/gid_map", "0 %d 1", gid);
// exec the command
if (execvp(cmd_and_args[0], cmd_and_args) < 0) {
perror("cannot execvp");
exit(1);
}
// unreachable
free(cmd_and_args);
return 0;
}