5
#include <sys/socket.h>
10
#include <sys/ioctl.h>
26
#define CHROOTDIR "/var/run/pipelight-sandbox-chroot"
27
#define SANDBOXSHM "/pipelight-sandbox-shm"
28
#define ENVWRITEDIR "SANDBOXWRITEDIR"
29
#define XSERVERSOCKET "/tmp/.X11-unix/X0"
30
#define XSERVERDIR "/tmp/.X11-unix"
31
#define STACK_SIZE 0x100000
32
#define SOCKET_FWD_SIZE 0x10000
33
#define MAXINTCHARLEN 21
35
#if !defined(PATH_MAX) || PATH_MAX < 0 || PATH_MAX > 4096
40
static char childStack[STACK_SIZE];
43
pid_t initPid; /* Pid of the init process in this sandbox */
44
int refCount; /* refCount (number of processes started + 1) */
47
struct childDataStruct{
48
char* cwDir; /* current working dir */
49
char* writeDir; /* directory where write access should be allowed */
50
struct shmDataStruct *shmData; /* shared memory structure */
51
int server; /* xorg socket file handle */
57
static void usage(const char* argv0){
58
fprintf(stdout, "Usage: %s EXECUTABLE [ARGS ...]\n", argv0);
59
fprintf(stdout, " Runs a executable in a sandboxed environment.\n");
60
fprintf(stdout, "\n");
61
fprintf(stdout, " Arguments:\n");
62
fprintf(stdout, " --help shows this help\n");
63
fprintf(stdout, "\n");
64
fprintf(stdout, " Environment variables:\n");
65
fprintf(stdout, " " ENVWRITEDIR " allow writing in this directory\n");
66
fprintf(stdout, "\n");
67
fprintf(stdout, " The sandbox uses the following techniques:\n");
68
fprintf(stdout, " - separate pid namespace\n");
69
fprintf(stdout, " - separate mount namespace\n");
70
fprintf(stdout, " - separate ipc namespace\n");
71
fprintf(stdout, " - separate network namespace (no network allowed at all!)\n");
72
fprintf(stdout, " - chroot with minimal privileges (nosuid, readonly, ...)\n");
73
fprintf(stdout, " - deny gaining root again (only if PR_SET_NO_NEW_PRIVS is available)\n");
74
fprintf(stdout, "\n");
75
fprintf(stdout, " DISCLAIMER: Depending on what you are going to do these security methods\n");
76
fprintf(stdout, " might not be sufficient! For really evil stuff a virtual machine without\n");
77
fprintf(stdout, " network access should be always preferred!\n");
78
fprintf(stdout, "\n");
79
fprintf(stdout, "Report bugs to webmaster@fds-team.de\n");
83
Forwards data between two sockets a <-> b and closes both socket handles after the connection is terminated
84
(runs as regular user)
86
static void socketForward(int a, int b){
88
char bufa[SOCKET_FWD_SIZE]; /* data from b to a */
89
char bufb[SOCKET_FWD_SIZE]; /* data from a to b */
94
/* select maximum file descriptor */
95
int nfds = ((a < b) ? b : a) + 1;
97
while ( (a || buflenb) && /* either a still connected or data from a to b */
98
(b || buflena) ){ /* either b still connected or data from b to a */
101
if (a && buflenb < SOCKET_FWD_SIZE) FD_SET(a, &rfds);
102
if (b && buflena < SOCKET_FWD_SIZE) FD_SET(b, &rfds);
105
if (a && buflena > 0) FD_SET(a, &wfds);
106
if (b && buflenb > 0) FD_SET(b, &wfds);
108
/* wait for socket events */
109
if (select(nfds, &rfds, &wfds, NULL, NULL) < 0) break;
111
/* read from a (to buffer b) */
112
if (FD_ISSET(a, &rfds) && buflenb < SOCKET_FWD_SIZE){
113
len = recv(a, &bufb[buflenb], SOCKET_FWD_SIZE - buflenb, 0);
114
if ( len <= 0 ){ close(a); a = 0; }else{
119
/* read from b (to buffer a) */
120
if (FD_ISSET(b, &rfds) && buflena < SOCKET_FWD_SIZE){
121
len = recv(b, &bufa[buflena], SOCKET_FWD_SIZE - buflena, 0);
122
if ( len <= 0 ){ close(b); b = 0; }else{
128
if (FD_ISSET(b, &wfds) && buflenb > 0){
129
len = send(b, bufb, buflenb, 0);
130
if ( len <= 0 ){ close(b); b = 0; }else{
131
if (len < buflenb) memmove(bufb, &bufb[len], buflenb - len);
137
if (FD_ISSET(a, &wfds) && buflena > 0){
138
len = send(a, bufa, buflena, 0);
139
if ( len <= 0 ){ close(a); a = 0; }else{
140
if (len < buflena) memmove(bufa, &bufa[len], buflena - len);
153
Opens a connection to the xserver and starts forwarding packets until the connectionis terminated by one side.
154
(runs as regular user)
156
static void socketForwardXorg(int client){
157
struct sockaddr_un xorgAddress;
160
xorgAddress.sun_family = AF_UNIX;
161
strncpy(xorgAddress.sun_path, XSERVERSOCKET, sizeof(xorgAddress.sun_path));
163
xorg = socket(AF_UNIX, SOCK_STREAM, 0);
168
if (connect(xorg, (struct sockaddr *)&xorgAddress, sizeof(struct sockaddr_un)) != 0){
172
/* forwards between both sockets */
173
socketForward(client, xorg);
177
Chroots into the specified directory and ensures that no write access is possible!
180
static bool root_doChroot(char *cwd){
182
fprintf(stderr, "[SANDBOX:%d] root_doChroot()\n", getpid());
185
/* switch to chroot */
186
if (chroot(CHROOTDIR) != 0){
187
perror("Failed to chroot to " CHROOTDIR ".");
191
/* set current dir (required to ensure that the curdir is not outside) */
192
if (chdir("/") != 0){
193
perror("Failed to chdir to /.");
197
/* try to switch back to the original wd after chroot */
204
Drops the rights to the specified realUser:realGroup
207
static bool root_doDropRights(int realUser, int realGroup){
209
fprintf(stderr, "[SANDBOX:%d] root_doDropRights(%d, %d)\n", getpid(), realUser, realGroup);
213
if (setgroups(0, NULL) != 0){
214
perror("Failed to set empty group list.");
218
/* Try to set exactly the required rights */
219
if (setuid(realUser) != 0 || setgid(realGroup) != 0){
220
perror("Failed to change user/group.");
224
/* Ensure that this really worked! (if not this would be fatal) */
225
if (geteuid() != realUser || getegid() != realGroup ){
226
fprintf(stderr, "Dropping root rights failed.\n");
231
prevent any child process from changing the user (i.e. get root rights)
232
(only available since kernel 3.5)
234
if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0){
235
fprintf(stderr, "[SANDBOX] WARNING: PR_SET_NO_NEW_PRIVS could not be set, the sandbox may be less secure.\n");
238
/* Ensure that we don't have write access to the root directory */
239
if (access("/", W_OK) == 0){
240
fprintf(stderr, "You have write access to the root directory, sandbox not possible!\n");
248
Setup mount namespace for chroot
251
static bool root_doSetupChrootMnt(char *writeDir){
252
char pathBuffer[PATH_MAX + 1];
256
fprintf(stderr, "[SANDBOX:%d] root_doSetupChrootMnt('%s')\n", getpid(), writeDir);
260
fprintf(stderr, "Unable to setup chroot mnt without root rights.\n");
264
if (mkdir(CHROOTDIR, 700) != 0 && errno != EEXIST){
265
perror("Failed to create chroot directory " CHROOTDIR ".");
269
/* NOTE: all the following mounts don't affect the space outside! */
272
if (mount("/", CHROOTDIR, 0, MS_BIND | MS_NOSUID, NULL) != 0){
273
perror("Failed to bind mount /.");
277
if (mount("/", CHROOTDIR, 0, MS_BIND | MS_REMOUNT | MS_RDONLY | MS_NOSUID, NULL) != 0){
278
perror("Failed to rebind mount / with readonly+nosuid rights.");
282
/* writeable path (if given) */
284
tmp = snprintf(pathBuffer, PATH_MAX + 1, "%s%s", CHROOTDIR, writeDir);
285
if (tmp < 0 || tmp > PATH_MAX){
286
fprintf(stderr, "Your " ENVWRITEDIR " is too long.\n");
290
if (mount(writeDir, pathBuffer, 0, MS_BIND | MS_NOSUID | MS_NODEV, NULL) != 0){
291
perror("Failed to bind mount " ENVWRITEDIR ".");
296
/* mount proc, so that we will only see processes inside */
297
if (mount("proc", CHROOTDIR "/proc", "proc", 0, NULL) != 0){
298
perror("Failed to mount /proc.");
302
/* mount /dev and /dev/pts */
303
if (mount("/dev", CHROOTDIR "/dev", 0, MS_BIND | MS_NOSUID | MS_NOEXEC, NULL) != 0){
304
perror("Failed to bind mount /dev.");
308
if (mount("/dev/pts", CHROOTDIR "/dev/pts", 0, MS_BIND | MS_NOSUID | MS_NOEXEC, NULL) != 0){
309
perror("Failed to bind mount /dev/pts.");
313
/* we need a /tmp directory, so we'll mount a tmpfs inside the sandbox */
314
if (mount("tmpfs", CHROOTDIR "/tmp", "tmpfs", MS_NOSUID | MS_NODEV | MS_NOEXEC, NULL) != 0){
315
perror("Failed to mount /tmp.");
319
/* create directory for the xserver redirection */
320
if (mkdir(CHROOTDIR XSERVERDIR, 777) != 0){
321
perror("Failed to mkdir " XSERVERDIR ".");
329
Binds the xserver socket
332
static bool root_doSetupXServer(int server){
333
struct sockaddr_un xorgAddress;
336
fprintf(stderr, "[SANDBOX:%d] root_doSetupXServer(%d)\n", getpid(), server);
339
xorgAddress.sun_family = AF_UNIX;
340
strncpy(xorgAddress.sun_path, XSERVERSOCKET, sizeof(xorgAddress.sun_path));
342
/* bind the unix socket */
343
if (bind(server, (struct sockaddr *)&xorgAddress, sizeof(struct sockaddr_un)) != 0){
344
perror("Error while binding unix Xorg socket.");
348
/* start listening */
349
if (listen(server, 5) != 0){
350
perror("Error while listen on unix Xorg socket.");
358
Switches to a namespace by PID and name of the corresponding namespace
361
static bool root_doSwitchNS( pid_t pid , char* ns, int nstype ){
362
char pathBuffer[PATH_MAX + 1];
367
fprintf(stderr, "[SANDBOX:%d] root_doSwitchNS(%d, '%s', %d)\n", getpid(), pid, ns, nstype);
370
tmp = snprintf(pathBuffer, PATH_MAX + 1, "/proc/%d/ns/%s", pid, ns);
371
if (tmp < 0 || tmp > PATH_MAX){
372
fprintf(stderr, "Incorrect namespace name given.\n");
376
nsfd = open(pathBuffer, O_RDONLY | O_CLOEXEC);
378
perror("Unable to open namespace file handle.");
382
if (setns(nsfd, nstype) != 0){
383
perror("Unable to switch to namespace.");
393
Checks if a process is really a chroot namespaced sandbox
396
static bool root_checkIsSandboxedProcess( pid_t pid ){
397
char pathBuffer[PATH_MAX + 1];
398
char resBuffer[PATH_MAX + 1];
400
char *canonChrootDir;
405
fprintf(stderr, "[SANDBOX:%d] root_checkIsSandboxedProcess(%d)", getpid(), pid);
408
tmp = snprintf(pathBuffer, PATH_MAX + 1, "/proc/%ld/root", (long)pid);
409
if (tmp < 0 || tmp > PATH_MAX){
410
fprintf(stderr, "Incorrect pid given.\n");
414
resLength = readlink(pathBuffer, resBuffer, PATH_MAX);
415
if (resLength <= 0 || resLength >= PATH_MAX){
416
perror("Unable to read root directory of process.");
420
/* make it nullterminated */
421
resBuffer[resLength] = 0;
423
/* get the full path */
424
canonChrootDir = canonicalize_file_name(CHROOTDIR);
425
if (!canonChrootDir){
426
fprintf(stderr, "Unable to canonicalize path " CHROOTDIR ".\n");
430
/* NOTE: we have to free canonChrootDir */
432
res = (strcmp(resBuffer, canonChrootDir) == 0);
434
fprintf(stderr, "Hacking attempt! Sandbox initPID points to wrong process.\n");
437
free(canonChrootDir);
446
static bool root_checkPrivileges(int realUser, int realGroup){
448
fprintf(stderr, "[SANDBOX:%d] root_checkPrivileges(%d, %d)\n", getpid(), realUser, realGroup);
451
/* check our privileges */
453
fprintf(stderr, "This program needs to be setuid and owned by root.\n");
457
if (realUser == 0 || realGroup == 0){
458
fprintf(stderr, "It is not allowed to run this program with root rights.\n");
466
Reads the environment variable WRITEDIR and checks if everything is okay
469
static char* root_getWriteDir(int realUser, int realGroup){
470
char* writeDir = NULL;
471
struct stat fileInfo;
475
fprintf(stderr, "[SANDBOX:%d] root_getWriteDir(%d, %d)\n", getpid(), realUser, realGroup);
478
/* check for environment variable */
479
tmpDir = getenv(ENVWRITEDIR);
481
fprintf(stderr, "No environment variable " ENVWRITEDIR " specified.\n");
485
/* get the full path */
486
writeDir = canonicalize_file_name(tmpDir);
488
fprintf(stderr, "Unable to canonicalize path " ENVWRITEDIR ".\n");
492
/* NOTE: we have to free the writeDir ptr when not successful */
494
if (stat(writeDir, &fileInfo) != 0){
495
perror("Failed to stat " ENVWRITEDIR ".");
499
/* this should be a directory */
500
if (!S_ISDIR(fileInfo.st_mode)){
501
fprintf(stderr, ENVWRITEDIR " must be a directory.\n");
506
although this is technically not really a security enhancement, since filesystem rights
507
are still enforced, but to prevent wrong usage we check if the user owns the directory
509
if (fileInfo.st_uid != realUser || fileInfo.st_gid != realGroup){
510
fprintf(stderr, ENVWRITEDIR " must be a owned by you.\n");
517
if(writeDir) free(writeDir);
522
Returns a memory location with the mapped shm
525
static struct shmDataStruct* root_getShm(int realUser, int realGroup, char *writeDir){
526
struct shmDataStruct* shmData;
527
char shmBuffer[PATH_MAX + 1];
528
struct stat fileInfo;
533
fprintf(stderr, "[SANDBOX:%d] root_getShm()\n", getpid());
536
/* NOTE: this code assumes that the newly created shm is initialized with zeros! */
539
if (stat(writeDir, &fileInfo) != 0){
540
perror("Failed to stat " ENVWRITEDIR ".");
544
tmp = snprintf(shmBuffer, PATH_MAX + 1, SANDBOXSHM ".%d.%d.%" PRIu64 ".%" PRIu64 ".rw", realUser, realGroup, \
545
(uint64_t)fileInfo.st_dev, (uint64_t)fileInfo.st_ino);
549
tmp = snprintf(shmBuffer, PATH_MAX + 1, SANDBOXSHM ".%d.%d.ro", realUser, realGroup);
552
if (tmp < 0 || tmp > PATH_MAX){
553
fprintf(stderr, "Your sandbox directory " SANDBOXSHM " is too long.\n");
557
/* open shared memory - has FD_CLOEXEC set automatically */
558
shmfd = shm_open(shmBuffer, O_RDWR | O_CREAT, 0600);
560
perror("Unable to connect to shm IPC channel for " ENVWRITEDIR);
564
/* ensure that the channel has the required size */
565
if (ftruncate(shmfd, sizeof(struct shmDataStruct)) != 0){
566
perror("Unable to set size of shm IPC channel for " ENVWRITEDIR);
572
shmData = mmap(NULL, sizeof(struct shmDataStruct), PROT_READ|PROT_WRITE, MAP_SHARED, shmfd, 0);
573
if (shmData == MAP_FAILED){
574
perror("Unable to map shm IPC channel for " ENVWRITEDIR);
579
/* close file descriptor, mmap has incremented the refcount */
585
Brings a network device up
588
static bool root_interfaceUp(char *name){
594
sock = socket(AF_INET, SOCK_DGRAM, 0);
596
perror("Error while creating interface socket.\n");
600
/* create and send command */
601
memset(&ifr, 0, sizeof ifr);
602
strncpy(ifr.ifr_name, name, IFNAMSIZ);
603
ifr.ifr_flags |= IFF_UP;
605
res = (ioctl(sock, SIOCSIFFLAGS, &ifr) == 0);
607
perror("Unable to bring up loopback device.");
617
Increments the value only if it is nonzero
619
static bool __sync_inc_if_nonzero( int *ptr ){
624
if (!value || __sync_bool_compare_and_swap(ptr, value, value+1)) break;
631
Decrements the value only if it is one
633
static bool __sync_dec_if_one( int *ptr ){
634
return __sync_bool_compare_and_swap(ptr, 1, 0);
638
Several functions to wait for child termination
640
bool processChildTerminated(int pid){
644
res = waitpid(pid, &status, WNOHANG);
646
perror("Waiting for pid failed.");
649
return (res == pid) && WIFEXITED(status);
652
bool processNonchildTerminated(int pid){
653
return (kill(pid, 0) != 0);
656
bool processAllchildsTerminated(){
657
int res = waitpid(-1, NULL, WNOHANG);
658
return (res == -1 && errno == ECHILD);
663
Closes all file descriptors above a threshold
664
(runs as regular user)
666
static bool closeFileDescriptorsAbove(int minfd){
667
char pathBuffer[PATH_MAX + 1];
672
tmp = snprintf(pathBuffer, PATH_MAX + 1, "/proc/%ld/fd", (long)getpid());
673
if (tmp < 0 || tmp > PATH_MAX){
674
fprintf(stderr, "Incorrect pid given.\n");
678
DIR *dir = opendir(pathBuffer);
679
struct dirent *dirEnt;
682
perror("Failed to open list of file descriptors.");
686
while (dirEnt = readdir(dir)){
687
fd = strtol(dirEnt->d_name, &endp, 10);
689
if (dirEnt->d_name == endp || *endp != 0)
692
if (fd < 0 || fd > INT_MAX )
695
if (fd < minfd || fd == dirfd(dir))
706
Starts the xserver daemon
707
(runs as normal user)
709
static bool startXserverDaemon(int realUser, int realGroup, int server, int initPid){
713
fprintf(stderr, "[SANDBOX:%d] startXserverDaemon(%d, %d, %d, %d)\n", getpid(), realUser, realGroup, server, initPid);
717
if (daemonPid == 0){ /* daemon */
718
struct timeval timeout;
724
if (!root_doDropRights(realUser, realGroup)){
725
fprintf(stderr, "Failed to drop rights.\n");
729
/* we don't need child notifications, otherwise we will get [defunct] zombies */
730
signal(SIGCHLD, SIG_IGN);
732
while ( !processNonchildTerminated(initPid) ){
735
FD_SET(server, &fds);
739
/* check for events */
740
if (select(server+1, &fds, NULL, NULL, &timeout) < 0) break;
741
if (!FD_ISSET(server, &fds)) continue;
743
/* accept incoming sockets */
744
int client = accept(server, NULL, 0);
749
pid_t forwardPid = fork();
751
socketForwardXorg(client);
755
/* close the client here */
761
}else if (daemonPid == -1){ /* error */
762
perror("Unable to fork Xorg socket redirect process.");
770
init process inside the sandbox
773
static int initProcess(struct childDataStruct *data){
774
int realUser = getuid();
775
int realGroup = getgid();
778
struct timespec curTime;
782
fprintf(stderr, "[SANDBOX:%d] initProcess(%p)\n", getpid(), data);
785
/* check root privileges */
786
if (!root_checkPrivileges(realUser, realGroup)){
787
fprintf(stderr, "Aborting because of incorrect privileges.\n");
791
/* check that we're the init process */
793
fprintf(stderr, "You kernel does not support PID namespaces, exiting.\n");
797
/* setup the chroot mnt */
798
if (!root_doSetupChrootMnt( data->writeDir )){
799
fprintf(stderr, "Unable to setup chroot.\n");
803
/* do the actual chroot */
804
if (!root_doChroot(data->cwDir)){
805
fprintf(stderr, "Unable to chroot.\n");
810
if (!root_doSetupXServer(data->server)){
811
fprintf(stderr, "Unable to setup Xorg socket redirection.\n");
815
/* close the file descriptor */
819
/* start up loopback device */
820
root_interfaceUp("lo");
823
if (!root_doDropRights(realUser, realGroup)){
824
fprintf(stderr, "Unable to drop root rights.\n");
828
/* close all file handles above 3 */
829
if (!closeFileDescriptorsAbove(3)){
830
fprintf(stderr, "Failed to close file descriptor.\n");
834
/* let the others in! */
835
data->shmData->refCount = 2;
837
/* wait until our refcount reaches zero */
841
clock_gettime(CLOCK_MONOTONIC, &curTime);
843
/* more processes left */
844
if (data->shmData->refCount != 1){
849
/* give other processes 30 sec to terminate */
850
if (killTime == 0) killTime = curTime.tv_sec + 30;
852
/* processes running, but time remaining */
853
if (!processAllchildsTerminated() && curTime.tv_sec < killTime)
856
/* try to terminate, if failed: new process */
857
if (!__sync_dec_if_one(&data->shmData->refCount)){
866
/* open the way for some new init processes */
867
data->shmData->initPid = 0;
869
/* normal termination */
873
if (data->cwDir) free(data->cwDir);
874
if (data->writeDir) free(data->writeDir);
875
if (data->shmData) munmap(data->shmData, sizeof(struct shmDataStruct));
876
if (data->server != -1) close(data->server);
881
Switches to the namespace
884
int main(int argc, char *argv[]){
885
int realUser = getuid();
886
int realGroup = getgid();
889
struct childDataStruct data;
895
/* initialize struct */
896
data.cwDir = getcwd(NULL, 0);
897
data.writeDir = NULL;
901
/* ensure that we got at least the program filename */
902
if (argc < 1 || !argv){
903
fprintf(stderr, "Missing argument array, terminating.\n");
907
/* show usage information */
908
if (argc < 2 || !strcmp(argv[1], "--help")){
914
/* TODO: can we execute the given file? if not, it makes no sense to continue! */
916
/* check root privileges */
917
if (!root_checkPrivileges(realUser, realGroup)){
918
fprintf(stderr, "Aborting because of incorrect privileges.\n");
923
data.writeDir = root_getWriteDir(realUser, realGroup);
924
if (data.writeDir == NULL){
925
fprintf(stderr, "[SANDBOX] WARNING: You will not have write access to anything except temp dirs!\n");
929
data.shmData = root_getShm(realUser, realGroup, data.writeDir);
930
if (data.shmData == NULL){
931
fprintf(stderr, "Aborting because incorrect IPC.\n");
935
/* maybe several attempts required */
938
/* no sandbox available, should we create it? */
939
if (__sync_bool_compare_and_swap( &data.shmData->initPid, 0, (pid_t)-1 ) ){
940
fprintf(stderr, "[SANDBOX] Creating new sandbox.\n");
942
/* reset refcounter */
943
data.shmData->refCount = 0;
945
/* create socket which will be used for the xserver in the chroot */
946
data.server = socket(AF_UNIX, SOCK_STREAM, 0);
947
if (data.server == -1){
948
perror("Error while creating Xorg unix socket.");
952
/* switch to the new namespace */
953
sandboxPid = clone( (int (*)(void *))initProcess, childStack + STACK_SIZE,
954
CLONE_NEWPID | CLONE_NEWNS | CLONE_NEWIPC | CLONE_NEWNET | SIGCHLD, &data);
955
if (sandboxPid == -1){
956
perror("Failed to clone into new namespace.");
960
/* refcounter == 0 means not yet started or crashed */
961
while( data.shmData->refCount == 0 ){
963
if(processChildTerminated(sandboxPid)){
964
fprintf(stderr, "Failed to initialize cloned process, terminating.\n");
971
/* announce the PID */
972
data.shmData->initPid = sandboxPid;
974
/* start xserver daemon (will terminate as soon as the init process terminates) */
975
if (!startXserverDaemon(realUser, realGroup, data.server, sandboxPid)){
976
fprintf(stderr, "Xserver daemon not running properly, DISPLAY outwill will not work.\n");
980
/* close socket to xserver */
984
fprintf(stderr, "[SANDBOX] Created sandbox with pid %d.\n", sandboxPid);
986
/* there exists a sandbox, try to connect */
987
}else if (data.shmData->initPid > 0 && __sync_inc_if_nonzero(&data.shmData->refCount) ){
988
sandboxPid = data.shmData->initPid;
990
fprintf(stderr, "[SANDBOX] Joining existing sandbox with pid %d.\n", sandboxPid);
992
/* we have to ensure that this pid is really the right sandbox, */
993
if ( sandboxPid <= 0 || \
994
processNonchildTerminated(sandboxPid) || \
995
!root_checkIsSandboxedProcess(sandboxPid) ){
997
fprintf(stderr, "Sandbox structure contains invalid pid - hacking attempt?\n");
999
/* unlock this and retry with new sandbox */
1000
__sync_bool_compare_and_swap(&data.shmData->initPid, sandboxPid, 0);
1005
NOTE: we do not explicitly check if its really the right sandbox - in case a virus is running
1006
inside the worst thing it can do is modify initPid, such that new processes are either spawned
1007
in a wrong or new sandbox. As the file system attributes are checked this isn't really a big deal
1011
/* wait and retry */
1016
/* we got a parent process */
1017
if( !root_doSwitchNS(sandboxPid, "pid", 0) ||
1018
!root_doSwitchNS(sandboxPid, "mnt", 0) ||
1019
!root_doSwitchNS(sandboxPid, "ipc", CLONE_NEWIPC) ||
1020
!root_doSwitchNS(sandboxPid, "net", CLONE_NEWNET) ){
1021
fprintf(stderr, "Unable to join namespaces!\n");
1025
if (!root_doChroot(data.cwDir)){
1026
fprintf(stderr, "Unable to chroot.\n");
1031
if (!root_doDropRights(realUser, realGroup)){
1032
fprintf(stderr, "Unable to drop root rights.\n");
1037
if (clientPid == 0){
1039
/* ensure that we're not leaking anything */
1040
if (data.cwDir) free(data.cwDir);
1041
if (data.writeDir) free(data.writeDir);
1042
if (data.shmData) munmap(data.shmData, sizeof(struct shmDataStruct));
1043
if (data.server != -1) close(data.server);
1045
/* close all file handles above 3 */
1046
if (!closeFileDescriptorsAbove(3)){
1047
fprintf(stderr, "Failed to close file descriptor.\n");
1051
/* check that argv array is nullterminated */
1052
if (argv[argc] != NULL){
1053
fprintf(stderr, "Argument array is not nullterminated.\n");
1057
/* set environment variable */
1058
setenv("debian_chroot", "SANDBOX", true);
1060
/* otherwise execute the program */
1061
execvp(argv[1], &argv[1]);
1063
/* in case something goes wrong */
1064
perror("Error while execvp.");
1067
}else if (clientPid == -1){
1068
fprintf(stderr, "Failed to fork and run actual client process.\n");
1072
/* close file descriptors */
1073
/* for (fd = 0; fd < 3; fd++) close(fd); */
1075
waitpid(clientPid, &status, 0);
1077
res = (WIFEXITED(status) ? WEXITSTATUS(status) : 1);
1081
/* will never be reached */
1085
if (data.shmData) data.shmData->initPid = (pid_t)0;
1089
if (data.shmData) __sync_fetch_and_add(&data.shmData->refCount, -1);
1093
if (data.cwDir) free(data.cwDir);
1094
if (data.writeDir) free(data.writeDir);
1095
if (data.shmData) munmap(data.shmData, sizeof(struct shmDataStruct));
1096
if (data.server != -1) close(data.server);