aboutsummaryrefslogtreecommitdiff
path: root/ios-bootstrap/unrestrict.c
blob: d8d14dd30513342345df17facfc03b88c4300d1f (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
#define IB_LOG_NAME "unrestrict"
#include "ib-log.h"
#include "substitute.h"
#include "substitute-internal.h"
#include <stdlib.h>
#include <syslog.h>
#include <signal.h>
#include <errno.h>
#include <stdio.h>

#define PROC_PIDFDVNODEINFO 1
#define PROC_PIDFDVNODEINFO_SIZE 176
int proc_pidfdinfo(int, int, int, void *, int);

int main(int argc, char **argv) {
    if (argc != 4) {
        ib_log("unrestrict: wrong number of args");
        return 1;
    }

    const char *pids = argv[1];
    char *end;
    long pid = strtol(pids, &end, 10);
    if (!pids[0] || *end) {
        ib_log("unrestrict: pid not an integer");
        return 1;
    }

    const char *should_resume = argv[2];
    if (strcmp(should_resume, "0") && strcmp(should_resume, "1")) {
        ib_log("unrestrict: should_resume not 0 or 1");
        return 1;
    }

    const char *is_exec = argv[3];
    if (strcmp(is_exec, "0") && strcmp(is_exec, "1")) {
        ib_log("unrestrict: is_exec not 0 or 1");
        return 1;
    }

    /* double fork to avoid zombies */
    int ret = fork();
    if (ret == -1) {
        ib_log("unrestrict: fork: %s", strerror(errno));
        return 1;
    } else if (ret) {
        return 0;
    }

    ib_log("unrestrict: unrestricting %ld (sr=%s, ie=%s)", pid,
           should_resume, is_exec);

    int ec = 1;

    mach_port_t task;
    kern_return_t kr = task_for_pid(mach_task_self(), (pid_t) pid, &task);
    if (kr) {
        ib_log("unrestrict: TFP fail: %d", kr);
        goto fail;
    }

    if (is_exec[0] == '1') {
        int retries = 0;
        int wait_us = 1;
        while (1) {
            /* The process might not have transitioned yet.  We set up a dummy fd
             * 255 in the parent process which was marked CLOEXEC, so test if that
             * still exists.  AFAICT, Substrate's equivalent to this is not
             * actually correct.
             * TODO cleanup
             */
            char buf[PROC_PIDFDVNODEINFO_SIZE];
            int ret = proc_pidfdinfo(pid, 255, PROC_PIDFDVNODEINFO,
                                     buf, sizeof(buf));
            if (ret == -1 && errno == EBADF) {
                break;
            } else if (ret == -1) {
                ib_log("proc_pidfdinfo: %s", strerror(errno));
                goto fail;
            }

            if (retries++ == 20) {
                ib_log("still in parent process after 20 retries");
                goto fail;
            }
            wait_us *= 2;
            if (wait_us > 200000)
                wait_us = 200000;
            while (usleep(wait_us))
                ;
        }
    }

    char *err = NULL;
    int sret = substitute_ios_unrestrict(task, &err);
    if (sret) {
        ib_log("unrestrict: substitute_ios_unrestrict => %d (%s)",
               sret, err);
        ec = 1;
    }

    ec = 0;
fail:
    if (should_resume[0] == '1') {
        if ((kill(pid, SIGCONT))) {
            ib_log("unrestrict: kill SIGCONT: %s", strerror(errno));
            return 1;
        }
    }

    return ec;
}