···6161make install
6262````
63636464+To build the new, experimental `darling` executable:
6565+6666+````
6767+cmake ../.. -DCMAKE_TOOLCHAIN_FILE=../../Toolchain-x86_64.cmake -DNEW_DARLING=TRUE
6868+make
6969+make install
7070+chmod +s $(which darling)
7171+````
7272+6473#### For running i386 OS X binaries
65746675<a href="http://teamcity.dolezel.info/viewType.html?buildTypeId=Darling_DebianStableX8664&guest=1">
···164173165174### AppKit
166175167167-AppKit is still highly expiramental and incomplete, but to work on it you need to configure CMake with `-DFRAMEWORK_APPKIT=1` and install some additional packages.
176176+AppKit is still highly experimental and incomplete, but to work on it you need to configure CMake with `-DFRAMEWORK_APPKIT=1` and install some additional packages.
168177169178Ubuntu 16.04:
170179```
+514-138
src/dyld/darling.c
···3737#include "darling.h"
3838#include "darling-config.h"
39394040+// Path where the system root gets "mounted" inside the prefix
4141+#define SYSTEM_ROOT "/system-root"
4242+4043const char* DARLING_INIT_COMM = "darling-init";
4141-uid_t g_originalUid;
4444+char *prefix;
4545+uid_t g_originalUid, g_originalGid;
42464347int main(int argc, const char** argv)
4448{
4545- const char* dprefix;
4646- int pidInit;
4747-4949+ pid_t pidInit, pidChild;
5050+ char path[4096];
5151+ int wstatus;
5252+4853 if (argc <= 1)
4954 {
5055 showHelp(argv[0]);
5156 return 1;
5257 }
5353-5454- /*if (geteuid() != 0)
5858+5959+ if (geteuid() != 0)
5560 {
5661 missingSetuidRoot();
5762 return 1;
5858- }*/
5959-6363+ }
6464+6065 if (loadKernelModule())
6166 return 1;
62676363- // Temporarily drop root privileges
6468 g_originalUid = getuid();
6565- seteuid(getuid());
6666- setegid(getgid());
6767-6868- dprefix = getenv("DPREFIX");
6969- if (!dprefix)
7070- dprefix = defaultPrefixPath();
7171- if (!dprefix)
6969+ g_originalGid = getgid();
7070+7171+ prefix = getenv("DPREFIX");
7272+ if (!prefix)
7373+ prefix = defaultPrefixPath();
7474+ if (!prefix)
7275 return 1;
7373- checkPrefixOwner(dprefix);
7474-7575- pidInit = getInitProcess(dprefix);
7676-7676+ setenv("DPREFIX", prefix, 0);
7777+7878+ if (!checkPrefixDir())
7979+ setupPrefix();
8080+ checkPrefixOwner();
8181+8282+ pidInit = getInitProcess();
8383+7784 // If prefix's init is not running, start it up
7885 if (pidInit == 0)
7986 {
8080- char* opts;
8181-8282- createDir(dprefix);
8383- setupWorkdir(dprefix);
8484-8585- // Since overlay cannot be mounted inside user namespaces, we have to setup a new mount namespace
8686- // and do the mount while we can be root
8787- //seteuid(0);
8888- if (unshare(CLONE_NEWNS) != 0)
8787+ setupWorkdir();
8888+ pidInit = spawnInitProcess();
8989+ putInitPid(pidInit);
9090+ }
9191+9292+ if (strcmp(argv[1], "shell") != 0)
9393+ {
9494+ const char *argv_child[argc + 1];
9595+9696+ argv_child[0] = "dyld";
9797+ for (int i = 1; i < argc; i++)
9898+ argv_child[i] = argv[i];
9999+ argv_child[argc] = NULL;
100100+101101+ pidChild = spawnChild(pidInit, DYLD_PATH, argv_child);
102102+ }
103103+ else
104104+ {
105105+ // Spawn the shell
106106+ snprintf(path, sizeof(path), "%s/bin/bash", prefix);
107107+ if (argc > 2)
89108 {
9090- fprintf(stderr, "Cannot unshare(CLONE_NEWNS): %s\n", strerror(errno));
9191- return 1;
109109+ size_t total_len = 0;
110110+ for (int i = 2; i < argc; i++)
111111+ total_len += strlen(argv[i]);
112112+113113+ char buffer[total_len + argc];
114114+115115+ char *to = buffer;
116116+ for (int i = 2; i < argc; i++)
117117+ to = stpcpy(stpcpy(to, argv[i]), " ");
118118+ // Overwrite the last whitespace
119119+ *(to - 1) = '\0';
120120+121121+ pidChild = spawnChild(pidInit, DYLD_PATH,
122122+ (const char *[5]) {"dyld", path, "-c", buffer, NULL});
92123 }
9393-9494- // Because IDIOTIC systemd marks / as MS_SHARED and we would inherit this into the overlay mount,
9595- // causing it not to be unmounted once the init process dies.
9696- if (mount(NULL, "/", NULL, MS_REC | MS_PRIVATE, NULL) != 0)
124124+ else
125125+ pidChild = spawnChild(pidInit, DYLD_PATH,
126126+ (const char *[3]) {"dyld", path, NULL});
127127+ }
128128+129129+ // Drop the privileges so that we can be killed, etc by the user
130130+ seteuid(g_originalUid);
131131+132132+ waitpid(pidChild, &wstatus, 0);
133133+134134+ // Should we unloadKernelModule() here? Others may be still using it
135135+ if (WIFEXITED(wstatus))
136136+ return WEXITSTATUS(wstatus);
137137+ if (WIFSIGNALED(wstatus))
138138+ return WTERMSIG(wstatus);
139139+ return 0;
140140+}
141141+142142+pid_t spawnChild(int pidInit, const char *path, const char *const argv[])
143143+{
144144+ int fdNS;
145145+ pid_t pidChild;
146146+ char pathNS[4096], curPath[4096];
147147+148148+ if (getcwd(curPath, sizeof(curPath)) == NULL)
149149+ {
150150+ fprintf(stderr, "Cannot get current directory: %s\n", strerror(errno));
151151+ exit(1);
152152+ }
153153+154154+ snprintf(pathNS, sizeof(pathNS), "/proc/%d/ns/pid", pidInit);
155155+156156+ fdNS = open(pathNS, O_RDONLY);
157157+158158+ if (fdNS < 0)
159159+ {
160160+ fprintf(stderr, "Cannot open PID namespace file: %s\n", strerror(errno));
161161+ exit(1);
162162+ }
163163+164164+ // Calling setns() with a PID namespace doesn't move our process into it,
165165+ // but our child process will be spawned inside the namespace
166166+ if (setns(fdNS, CLONE_NEWPID) != 0)
167167+ {
168168+ fprintf(stderr, "Cannot join PID namespace: %s\n", strerror(errno));
169169+ exit(1);
170170+ }
171171+ close(fdNS);
172172+173173+ pidChild = fork();
174174+ if (pidChild < 0)
175175+ {
176176+ fprintf(stderr, "Cannot spawn a child process: %s\n", strerror(errno));
177177+ exit(1);
178178+ }
179179+180180+ if (pidChild == 0)
181181+ {
182182+ // This is the child process
183183+184184+ // We still have the outside PIDs in /proc
185185+ snprintf(pathNS, sizeof(pathNS), "/proc/%d/ns/mnt", pidInit);
186186+ fdNS = open(pathNS, O_RDONLY);
187187+ if (fdNS < 0)
97188 {
9898- fprintf(stderr, "Cannot remount / as private: %s\n", strerror(errno));
9999- return 1;
189189+ fprintf(stderr, "Cannot open mount namespace file: %s\n", strerror(errno));
190190+ exit(1);
100191 }
101101-102102- opts = (char*) malloc(strlen(dprefix)*2 + sizeof(LIBEXEC_PATH) + 50);
103103- sprintf(opts, "lowerdir=%s,upperdir=%s,workdir=%s.workdir", LIBEXEC_PATH, dprefix, dprefix);
104104-105105- // Mount overlay onto our prefix
106106- if (mount("overlay", dprefix, "overlay", 0, opts) != 0)
192192+193193+ if (setns(fdNS, CLONE_NEWNS) != 0)
194194+ {
195195+ fprintf(stderr, "Cannot join mount namespace: %s\n", strerror(errno));
196196+ exit(1);
197197+ }
198198+ close(fdNS);
199199+200200+ snprintf(pathNS, sizeof(pathNS), "/proc/%d/ns/user", pidInit);
201201+ fdNS = open(pathNS, O_RDONLY);
202202+ if (fdNS < 0)
203203+ {
204204+ fprintf(stderr, "Cannot open user namespace file: %s\n", strerror(errno));
205205+ exit(1);
206206+ }
207207+208208+ setresuid(g_originalUid, g_originalUid, g_originalUid);
209209+ setresgid(g_originalGid, g_originalGid, g_originalGid);
210210+211211+ if (setns(fdNS, CLONE_NEWUSER) != 0)
107212 {
108108- fprintf(stderr, "Cannot mount overlay: %s\n", strerror(errno));
109109- return 1;
213213+ fprintf(stderr, "Cannot join user namespace: %s\n", strerror(errno));
214214+ exit(1);
110215 }
111111-112112- free(opts);
113113- //seteuid(getuid());
114114-115115- pidInit = spawnInitProcess(dprefix);
216216+ close(fdNS);
217217+218218+ setupChild(curPath);
219219+220220+ execv(path, (char * const *) argv);
221221+222222+ fprintf(stderr, "Cannot exec the target program: %s\n", strerror(errno));
223223+ exit(1);
116224 }
117117-118118- // TODO: Spawn the executable in the namespace, wait for it and return its exit code
119119- unloadKernelModule();
120120- return 0;
225225+226226+ return pidChild;
227227+}
228228+229229+void setupChild(const char *curPath)
230230+{
231231+ char buffer1[4096];
232232+ char buffer2[4096];
233233+234234+ setenv("PATH", "/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin", 1);
235235+236236+ sscanf(getenv("HOME"), "/home/%4096s", buffer1);
237237+ snprintf(buffer2, sizeof(buffer2), "/Users/%s", buffer1);
238238+ setenv("HOME", buffer2, 1);
239239+240240+ if (sscanf(curPath, "/home/%4096s", buffer1) == 1)
241241+ {
242242+ // We're currently inside our home directory
243243+ snprintf(buffer2, sizeof(buffer2), "/Users/%s", buffer1);
244244+ setenv("PWD", buffer2, 1);
245245+246246+ snprintf(buffer2, sizeof(buffer2), "%s/Users/%s", prefix, buffer1);
247247+ chdir(buffer2);
248248+ }
249249+ else
250250+ {
251251+ snprintf(buffer2, sizeof(buffer2), SYSTEM_ROOT "%s", curPath);
252252+ setenv("PWD", buffer2, 1);
253253+254254+ snprintf(buffer2, sizeof(buffer2), "%s" SYSTEM_ROOT "%s", prefix, curPath);
255255+ chdir(buffer2);
256256+ }
121257}
122258123259void showHelp(const char* argv0)
···125261 fprintf(stderr, "This is Darling, translation layer for macOS software.\n\n");
126262 fprintf(stderr, "Copyright (C) 2012-2016 Lubos Dolezel\n\n");
127263128128- fprintf(stderr, "Usage: %s program-path [arguments...]\n\n", argv0);
264264+ fprintf(stderr, "Usage:\n");
265265+ fprintf(stderr, "\t%s program-path [arguments...]\n", argv0);
266266+ fprintf(stderr, "\t%s shell [arguments...]\n", argv0);
267267+ fprintf(stderr, "\n");
129268 fprintf(stderr, "Environment variables:\n"
130269 "DPREFIX - specifies the location of Darling prefix, defaults to ~/.darling\n");
131270}
···134273{
135274 char path[4096];
136275 int len;
137137-276276+138277 len = readlink("/proc/self/exe", path, sizeof(path)-1);
139278 if (len < 0)
140279 strcpy(path, "darling");
141280 else
142281 path[len] = '\0';
143143-282282+144283 fprintf(stderr, "Sorry, the `%s' binary is not setuid root, which is mandatory.\n", path);
145284 fprintf(stderr, "Darling needs this in order to create mount and PID namespaces and to perform mounts.\n");
146285}
147286148148-int spawnInitProcess(const char* prefix)
287287+pid_t spawnInitProcess(void)
149288{
150150- char* childStack;
151151- int pid;
152152- char uidmap[100];
153153-154154- childStack = (char*) malloc(16*1024);
155155- childStack += 16*1024;
156156-157157- //setuid(0);
158158- pid = clone(darlingPreInit, childStack, /*CLONE_NEWPID |*/ CLONE_NEWUSER, (void*) prefix);
159159-160160- if (pid <= 0)
289289+ pid_t pid;
290290+ int pipefd[2];
291291+ char idmap[100];
292292+ char buffer[1];
293293+ FILE *file;
294294+295295+ if (pipe(pipefd) == -1)
296296+ {
297297+ fprintf(stderr, "Cannot create a pipe for synchronization: %s\n", strerror(errno));
298298+ exit(1);
299299+ }
300300+301301+ if (unshare(CLONE_NEWPID) != 0)
302302+ {
303303+ fprintf(stderr, "Cannot unshare pid namespace to create darling-init: %s\n", strerror(errno));
304304+ exit(1);
305305+ }
306306+307307+ pid = fork();
308308+309309+ if (pid < 0)
161310 {
162162- fprintf(stderr, "Cannot clone() to create darling-init: %s\n", strerror(errno));
311311+ fprintf(stderr, "Cannot fork() to create darling-init: %s\n", strerror(errno));
163312 exit(1);
164313 }
165165-166166- sprintf(uidmap, "/proc/%d/uid_map", pid);
167167-168168- FILE* file = fopen(uidmap, "w");
314314+315315+ if (pid == 0)
316316+ {
317317+ // The child
318318+319319+ char *opts;
320320+321321+ // Since overlay cannot be mounted inside user namespaces, we have to setup a new mount namespace
322322+ // and do the mount while we can be root
323323+ if (unshare(CLONE_NEWNS) != 0)
324324+ {
325325+ fprintf(stderr, "Cannot unshare mount namespace: %s\n", strerror(errno));
326326+ exit(1);
327327+ }
328328+329329+ // Because systemd marks / as MS_SHARED and we would inherit this into the overlay mount,
330330+ // causing it not to be unmounted once the init process dies.
331331+ if (mount(NULL, "/", NULL, MS_REC | MS_SLAVE, NULL) != 0)
332332+ {
333333+ fprintf(stderr, "Cannot remount / as slave: %s\n", strerror(errno));
334334+ exit(1);
335335+ }
336336+337337+ opts = (char*) malloc(strlen(prefix)*2 + sizeof(LIBEXEC_PATH) + 50);
338338+ sprintf(opts, "lowerdir=%s,upperdir=%s,workdir=%s.workdir", LIBEXEC_PATH, prefix, prefix);
339339+340340+ // Mount overlay onto our prefix
341341+ if (mount("overlay", prefix, "overlay", 0, opts) != 0)
342342+ {
343343+ fprintf(stderr, "Cannot mount overlay: %s\n", strerror(errno));
344344+ exit(1);
345345+ }
346346+347347+ free(opts);
348348+349349+ // Drop the privileges
350350+ setresuid(g_originalUid, g_originalUid, g_originalUid);
351351+ setresgid(g_originalGid, g_originalGid, g_originalGid);
352352+ prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
353353+354354+ prctl(PR_SET_NAME, DARLING_INIT_COMM, 0, 0);
355355+356356+ if (unshare(CLONE_NEWUSER) != 0)
357357+ {
358358+ fprintf(stderr, "Cannot unshare user namespace: %s\n", strerror(errno));
359359+ exit(1);
360360+ }
361361+362362+ // Tell the parent we're ready for it to set up UID/GID mappings
363363+ write(pipefd[1], buffer, 1);
364364+ close(pipefd[1]);
365365+ // And wait for it to do it
366366+ read(pipefd[0], buffer, 1);
367367+ close(pipefd[0]);
368368+369369+ darlingPreInit();
370370+ // Never returns
371371+ }
372372+373373+ // Wait for the child to drop UID/GIDs and unshare stuff
374374+ read(pipefd[0], buffer, 1);
375375+ close(pipefd[0]);
376376+377377+ snprintf(idmap, sizeof(idmap), "/proc/%d/uid_map", pid);
378378+379379+ file = fopen(idmap, "w");
169380 if (file != NULL)
170381 {
171171- fprintf(file, "0 %d 1\n", getuid()); // all users map to our user on the outside
382382+ fprintf(file, "0 %d 1\n", g_originalUid); // all users map to our user on the outside
172383 fclose(file);
173384 }
174385 else
175386 {
176176- fprintf(stderr, "Failure setting uid_map in init process\n");
387387+ fprintf(stderr, "Cannot set uid_map for the init process: %s\n", strerror(errno));
177388 }
178178-389389+390390+ snprintf(idmap, sizeof(idmap), "/proc/%d/gid_map", pid);
391391+392392+ file = fopen(idmap, "w");
393393+ if (file != NULL)
394394+ {
395395+ fprintf(file, "0 %d 1\n", g_originalGid); // all groups map to our group on the outside
396396+ fclose(file);
397397+ }
398398+ else
399399+ {
400400+ fprintf(stderr, "Cannot set gid_map for the init process: %s\n", strerror(errno));
401401+ }
402402+403403+ // Resume the child
404404+ write(pipefd[1], buffer, 1);
405405+ close(pipefd[1]);
406406+407407+ return pid;
408408+}
409409+410410+void putInitPid(pid_t pidInit)
411411+{
412412+ const char pidFile[] = "/.init.pid";
413413+ char* pidPath;
414414+ FILE *fp;
415415+416416+ pidPath = (char*) alloca(strlen(prefix) + sizeof(pidFile));
417417+ strcpy(pidPath, prefix);
418418+ strcat(pidPath, pidFile);
419419+179420 seteuid(g_originalUid);
180180- setuid(g_originalUid);
181181-182182- return pid;
421421+ setegid(g_originalGid);
422422+423423+ fp = fopen(pidPath, "w");
424424+425425+ seteuid(0);
426426+ setegid(0);
427427+428428+ if (fp == NULL)
429429+ {
430430+ fprintf(stderr, "Cannot write out PID of the init process: %s\n", strerror(errno));
431431+ return;
432432+ }
433433+ fprintf(fp, "%d", (int) pidInit);
434434+ fclose(fp);
183435}
184436185185-int darlingPreInit(void* arg)
437437+void darlingPreInit(void)
186438{
187187- const char* prefix = (const char*) arg;
188188-189189- prctl(PR_SET_NAME, DARLING_INIT_COMM, 0, 0);
190190-191191- // Wait until the parent sets our uid_map
192192- while (getuid() == 65534);
193193-194439 // TODO: Run /usr/libexec/makewhatis
195195-440440+196441 // TODO: this is where we will exec() launchd in future.
197442 // Instead, we just reap zombies.
198443 while (1)
199444 {
200445 int status, sig;
201446 sigset_t chld;
202202-447447+203448 sigemptyset(&chld);
204449 sigaddset(&chld, SIGCHLD);
205450 sigwait(&chld, &sig);
206206-451451+207452 while (waitpid(-1, &status, 0) != -1);
208453 }
209209-210210- return 0;
211454}
212455213456char* defaultPrefixPath(void)
···215458 const char defaultPath[] = "/.darling";
216459 const char* home = getenv("HOME");
217460 char* buf;
218218-461461+219462 if (!home)
220463 {
221464 fprintf(stderr, "Cannot detect your home directory!\n");
222465 return NULL;
223466 }
224224-467467+225468 buf = (char*) malloc(strlen(home) + sizeof(defaultPath));
226469 strcpy(buf, home);
227470 strcat(buf, defaultPath);
228228-471471+229472 return buf;
230473}
231474232475void createDir(const char* path)
233476{
234477 struct stat st;
235235-478478+236479 if (stat(path, &st) == 0)
237480 {
238481 if (!S_ISDIR(st.st_mode))
···253496 }
254497 else
255498 {
256256- fprintf(stderr, "Problem accessing %s: %s\n", path, strerror(errno));
499499+ fprintf(stderr, "Cannot access %s: %s\n", path, strerror(errno));
257500 exit(1);
258501 }
259502 }
260503}
261504262262-void setupWorkdir(const char* prefix)
505505+void setupWorkdir()
263506{
264507 char* workdir;
265508 const char suffix[] = ".workdir";
266509 size_t len;
267267-510510+268511 len = strlen(prefix);
269512 workdir = (char*) alloca(len + sizeof(suffix));
270513 strcpy(workdir, prefix);
271271-514514+272515 // Remove trailing /
273516 while (workdir[len-1] == '/')
274517 len--;
275518 workdir[len] = '\0';
276276-519519+277520 strcat(workdir, suffix);
278278-521521+279522 createDir(workdir);
280523}
281524282282-int getInitProcess(const char* prefix)
525525+int checkPrefixDir()
526526+{
527527+ struct stat st;
528528+529529+ if (stat(prefix, &st) == 0)
530530+ {
531531+ if (!S_ISDIR(st.st_mode))
532532+ {
533533+ fprintf(stderr, "%s is a file. Remove the file.\n", prefix);
534534+ exit(1);
535535+ }
536536+ return 1; // OK
537537+ }
538538+ if (errno == ENOENT)
539539+ return 0; // not found
540540+ fprintf(stderr, "Cannot access %s: %s\n", prefix, strerror(errno));
541541+ exit(1);
542542+}
543543+544544+void setupPrefix()
545545+{
546546+ char path[4096];
547547+548548+ fprintf(stderr, "Setting up a new Darling prefix at %s\n", prefix);
549549+550550+ seteuid(g_originalUid);
551551+ setegid(g_originalGid);
552552+553553+ createDir(prefix);
554554+555555+ snprintf(path, sizeof(path), "%s" SYSTEM_ROOT, prefix);
556556+ if (symlink("/", path) != 0)
557557+ {
558558+ fprintf(stderr, "Cannot symlink %s: %s\n", path, strerror(errno));
559559+ exit(1);
560560+ }
561561+562562+ snprintf(path, sizeof(path), "%s/dev", prefix);
563563+ if (symlink(SYSTEM_ROOT "/dev" + 1, path) != 0)
564564+ {
565565+ fprintf(stderr, "Cannot symlink %s: %s\n", path, strerror(errno));
566566+ exit(1);
567567+ }
568568+569569+ snprintf(path, sizeof(path), "%s/tmp", prefix);
570570+ if (symlink(SYSTEM_ROOT "/tmp" + 1, path) != 0)
571571+ {
572572+ fprintf(stderr, "Cannot symlink %s: %s\n", path, strerror(errno));
573573+ exit(1);
574574+ }
575575+576576+ snprintf(path, sizeof(path), "%s/Users", prefix);
577577+ if (symlink(SYSTEM_ROOT "/home" + 1, path) != 0)
578578+ {
579579+ fprintf(stderr, "Cannot symlink %s: %s\n", path, strerror(errno));
580580+ exit(1);
581581+ }
582582+583583+ snprintf(path, sizeof(path), "%s/Volumes", prefix);
584584+ createDir(path);
585585+ snprintf(path, sizeof(path), "%s/Applications", prefix);
586586+ createDir(path);
587587+588588+ snprintf(path, sizeof(path), "%s/var", prefix);
589589+ createDir(path);
590590+ snprintf(path, sizeof(path), "%s/var/root", prefix);
591591+ createDir(path);
592592+ snprintf(path, sizeof(path), "%s/var/run", prefix);
593593+ createDir(path);
594594+595595+ snprintf(path, sizeof(path), "%s/var/run/syslog", prefix);
596596+ if (symlink("../.." SYSTEM_ROOT "/dev/log", path) != 0)
597597+ {
598598+ fprintf(stderr, "Cannot symlink %s: %s\n", path, strerror(errno));
599599+ exit(1);
600600+ }
601601+602602+ seteuid(0);
603603+ setegid(0);
604604+}
605605+606606+pid_t getInitProcess()
283607{
284608 const char pidFile[] = "/.init.pid";
285609 char* pidPath;
286286- int fd, rd, pid;
287287- char pidBuf[10];
288288- char exeBuf[17], procBuf[100];
289289-610610+ pid_t pid;
611611+ int pid_i;
612612+ FILE *fp;
613613+ char procBuf[100];
614614+ char *exeBuf, *statusBuf;
615615+ int uidMatch = 0, gidMatch = 0;
616616+290617 pidPath = (char*) alloca(strlen(prefix) + sizeof(pidFile));
291618 strcpy(pidPath, prefix);
292619 strcat(pidPath, pidFile);
293293-294294- fd = open(pidPath, O_RDONLY);
295295- if (fd == -1)
620620+621621+ fp = fopen(pidPath, "r");
622622+ if (fp == NULL)
296623 return 0;
297297-298298- rd = read(fd, pidBuf, sizeof(pidBuf)-1);
299299- close(fd);
300300-301301- if (rd <= 0)
624624+625625+ if (fscanf(fp, "%d", &pid_i) != 1)
626626+ {
627627+ fclose(fp);
628628+ unlink(pidPath);
302629 return 0;
303303-304304- pidBuf[rd-1] = '\0';
305305- pid = atoi(pidBuf);
630630+ }
631631+ fclose(fp);
632632+ pid = (pid_t) pid_i;
306633307634 // Does the process exist?
308635 if (kill(pid, 0) == -1)
···310637 unlink(pidPath);
311638 return 0;
312639 }
313313-640640+314641 // Is it actually an init process?
315315- sprintf(procBuf, "/proc/%d/comm", pid);
316316- fd = open(procBuf, O_RDONLY);
317317- if (fd == -1)
642642+ snprintf(procBuf, sizeof(procBuf), "/proc/%d/comm", pid);
643643+ fp = fopen(procBuf, "r");
644644+ if (fp == NULL)
318645 {
319646 unlink(pidPath);
320647 return 0;
321648 }
322322-323323- rd = read(fd, exeBuf, sizeof(exeBuf)-1);
324324- close(fd);
325325-326326- if (rd <= 0)
649649+650650+ if (fscanf(fp, "%ms", &exeBuf) != 1)
327651 {
652652+ fclose(fp);
328653 unlink(pidPath);
329654 return 0;
330655 }
331331-332332- exeBuf[rd] = '\0';
656656+ fclose(fp);
657657+333658 if (strcmp(exeBuf, DARLING_INIT_COMM) != 0)
334659 {
335660 unlink(pidPath);
336661 return 0;
337662 }
338338-663663+ free(exeBuf);
664664+665665+ // Is it owned by the current user?
666666+ if (g_originalUid != 0)
667667+ {
668668+ snprintf(procBuf, sizeof(procBuf), "/proc/%d/status", pid);
669669+ fp = fopen(procBuf, "r");
670670+ if (fp == NULL)
671671+ {
672672+ unlink(pidPath);
673673+ return 0;
674674+ }
675675+676676+ while (1)
677677+ {
678678+ statusBuf = NULL;
679679+ size_t len;
680680+ if (getline(&statusBuf, &len, fp) == -1)
681681+ break;
682682+ int rid, eid, sid, fid;
683683+ if (sscanf(statusBuf, "Uid: %d %d %d %d", &rid, &eid, &sid, &fid) == 4)
684684+ {
685685+ uidMatch = 1;
686686+ uidMatch &= rid == g_originalUid;
687687+ uidMatch &= eid == g_originalUid;
688688+ uidMatch &= sid == g_originalUid;
689689+ uidMatch &= fid == g_originalUid;
690690+ }
691691+ if (sscanf(statusBuf, "Gid: %d %d %d %d", &rid, &eid, &sid, &fid) == 4)
692692+ {
693693+ gidMatch = 1;
694694+ gidMatch &= rid == g_originalGid;
695695+ gidMatch &= eid == g_originalGid;
696696+ gidMatch &= sid == g_originalGid;
697697+ gidMatch &= fid == g_originalGid;
698698+ }
699699+ free(statusBuf);
700700+ }
701701+ fclose(fp);
702702+703703+ if (!uidMatch || !gidMatch)
704704+ {
705705+ unlink(pidPath);
706706+ return 0;
707707+ }
708708+ }
709709+339710 return pid;
340711}
341712342342-void checkPrefixOwner(const char* prefix)
713713+void checkPrefixOwner()
343714{
344715 struct stat st;
345345-716716+346717 if (stat(prefix, &st) == 0)
347718 {
348348- if (st.st_uid != getuid())
719719+ if (g_originalUid != 0 && st.st_uid != g_originalUid)
349720 {
350721 fprintf(stderr, "You do not own the prefix directory.\n");
351722 exit(1);
···360731361732int isModuleLoaded()
362733{
363363- size_t len = 0;
734734+ size_t len = 0;
364735 ssize_t read = 0;
365365- char * line = NULL;
366366- FILE *fp = NULL;
736736+ char * line = NULL;
737737+ FILE *fp = NULL;
367738368739 if ((fp = fopen("/proc/modules", "r")) == NULL)
369740 {
370741 fprintf(stderr, "Failure opening /proc/modules: %s\n", strerror(errno));
742742+ fclose(fp);
371743 return 0;
372744 }
373745···375747 {
376748 read = getline(&line, &len, fp);
377749 if (read > 0 && strstr(line, "darling_mach") != NULL)
750750+ {
751751+ fclose(fp);
378752 return 1;
753753+ }
379754 }
380755756756+ fclose(fp);
381757 return 0;
382758}
383759···391767 return 0;
392768393769 uname(&name);
394394- sprintf(path, "/lib/modules/%s/kernel/misc/darling-mach.ko", name.release);
770770+ snprintf(path, sizeof(path), "/lib/modules/%s/kernel/misc/darling-mach.ko", name.release);
395771 if (access(path, F_OK))
396772 {
397773 fprintf(stderr, "Cannot find kernel module at %s: %s\n", path, strerror(errno));
+25-6
src/dyld/darling.h
···1717along with Darling. If not, see <http://www.gnu.org/licenses/>.
1818*/
19192020+#include <sys/types.h>
2121+2022#ifndef _DARLING_H_
2123#define _DARLING_H_
2224···27292830// Returns ~/.darling with ~ expanded
2931char* defaultPrefixPath(void);
3030-void setupWorkdir(const char* prefix);
3232+3333+void setupWorkdir(void);
3434+3535+void setupPrefix(void);
3636+3737+int checkPrefixDir(void);
31383239// Creates the given directory, exit()ing if not possible
3340void createDir(const char* path);
34413535-// Return the PID of the init process in prefix (in our namespace)
4242+// Spawn the specified proceess inside the namespaces that PID 1 is in
4343+// Returns the PID of the child
4444+// exit()s on error
4545+pid_t spawnChild(int pidInit, const char *path, const char *const argv[]);
4646+4747+// Set up some environment variables
4848+// As well as the working directory
4949+// Called in the child process
5050+void setupChild(const char *curPath);
5151+5252+// Returns the PID of the init process in prefix (in our namespace)
3653// Returns 0 if no init is running
3737-int getInitProcess(const char* prefix);
5454+pid_t getInitProcess(void);
5555+5656+pid_t spawnInitProcess(void);
38573939-int spawnInitProcess(const char* prefix);
5858+void putInitPid(pid_t pidInit);
40594141-int darlingPreInit(void* arg);
6060+void darlingPreInit(void);
42614343-void checkPrefixOwner(const char* prefix);
6262+void checkPrefixOwner(void);
44634564int isModuleLoaded(void);
4665
+15-15
src/dyld/dirstructure.cpp
···29293030static std::string GetUserLibrary()
3131{
3232- const char* home;
3232+ const char *home, *prefix;
3333 std::stringstream ss;
3434 std::string path;
3535-3535+3636+ prefix = getenv("DPREFIX");
3637 home = getenv("HOME");
3737- if (!home)
3838+ if (!prefix || !home)
3839 return std::string(); // give up on this user
3939-4040- ss << home << '/' << "Library" << '/';
4040+4141+ ss << prefix << home << '/' << "Library" << '/';
4142 return ss.str();
4243}
43444445bool HasUserDirectoryStructure()
4546{
4647 std::string path = GetUserLibrary();
4747-4848+4849 if (path.empty())
4950 return true; // give up on this user
5050-5151+5152 if (::access(path.c_str(), F_OK) == -1)
5253 return false;
5354 else
···9091 "Spelling",
9192 "Voices",
9293 };
9393-9494+9495 std::string path = GetUserLibrary();
9595-9696+9697 if (path.empty())
9798 return;
9898-9999+99100 std::cerr << "Darling: Creating Library structure at " << path << std::endl;
100100-101101+101102 if (::mkdir(path.c_str(), 0777) == -1)
102103 std::cerr << "Darling: Cannot mkdir(" << path << "): " << strerror(errno) << std::endl;
103103-104104+104105 for (const char* dir : dirs)
105106 {
106107 std::string s = path;
107107-108108+108109 s += dir;
109109-110110+110111 if (::mkdir(s.c_str(), 0777) == -1)
111112 std::cerr << "Darling: Cannot mkdir(" << s << "): " << strerror(errno) << std::endl;
112113 }
113114}
114114-