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
113
114
115
116
117
118
119
120
121
122
123
124
|
#include "jailtest.h"
#include <errno.h>
#include <pwd.h>
#include <dirent.h>
#define BUFLEN 4096
char *get_sudo_user(void) {
char *user = getenv("SUDO_USER");
if (!user) {
user = getpwuid(getuid())->pw_name;
if (!user) {
fprintf(stderr, "Error: cannot detect login user\n");
exit(1);
}
}
return user;
}
char *get_homedir(const char *user, uid_t *uid, gid_t *gid) {
// find home directory
struct passwd *pw = getpwnam(user);
if (!pw)
goto errexit;
char *home = pw->pw_dir;
if (!home)
goto errexit;
*uid = pw->pw_uid;
*gid = pw->pw_gid;
return home;
errexit:
fprintf(stderr, "Error: cannot find home directory for user %s\n", user);
exit(1);
}
int find_child(pid_t parent, pid_t *child) {
*child = 0; // use it to flag a found child
DIR *dir;
if (!(dir = opendir("/proc"))) {
// sleep 2 seconds and try again
sleep(2);
if (!(dir = opendir("/proc"))) {
fprintf(stderr, "Error: cannot open /proc directory\n");
exit(1);
}
}
struct dirent *entry;
char *end;
while (*child == 0 && (entry = readdir(dir))) {
pid_t pid = strtol(entry->d_name, &end, 10);
if (end == entry->d_name || *end)
continue;
if (pid == parent)
continue;
// open stat file
char *file;
if (asprintf(&file, "/proc/%u/status", pid) == -1) {
perror("asprintf");
exit(1);
}
FILE *fp = fopen(file, "r");
if (!fp) {
free(file);
continue;
}
// look for firejail executable name
char buf[BUFLEN];
while (fgets(buf, BUFLEN - 1, fp)) {
if (strncmp(buf, "PPid:", 5) == 0) {
char *ptr = buf + 5;
while (*ptr != '\0' && (*ptr == ' ' || *ptr == '\t')) {
ptr++;
}
if (*ptr == '\0') {
fprintf(stderr, "Error: cannot read /proc file\n");
exit(1);
}
if (parent == atoi(ptr)) {
// we don't want /usr/bin/xdg-dbus-proxy!
char *cmdline = pid_proc_cmdline(pid);
if (strncmp(cmdline, XDG_DBUS_PROXY_PATH, strlen(XDG_DBUS_PROXY_PATH)) != 0)
*child = pid;
free(cmdline);
}
break; // stop reading the file
}
}
fclose(fp);
free(file);
}
closedir(dir);
return (*child)? 0:1; // 0 = found, 1 = not found
}
pid_t switch_to_child(pid_t pid) {
pid_t rv = pid;
errno = 0;
char *comm = pid_proc_comm(pid);
if (!comm) {
if (errno == ENOENT)
fprintf(stderr, "Error: cannot find process with pid %d\n", pid);
else
fprintf(stderr, "Error: cannot read /proc file\n");
exit(1);
}
if (strcmp(comm, "firejail") == 0) {
if (find_child(pid, &rv) == 1) {
fprintf(stderr, "Error: no valid sandbox\n");
exit(1);
}
}
free(comm);
return rv;
}
|