aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/pid.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/pid.c')
-rw-r--r--src/lib/pid.c392
1 files changed, 392 insertions, 0 deletions
diff --git a/src/lib/pid.c b/src/lib/pid.c
new file mode 100644
index 000000000..a0261ead2
--- /dev/null
+++ b/src/lib/pid.c
@@ -0,0 +1,392 @@
1/*
2 * Copyright (C) 2014, 2015 netblue30 (netblue30@yahoo.com)
3 *
4 * This file is part of firejail project
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19*/
20#include "../include/common.h"
21#include "../include/pid.h"
22#include <string.h>
23#include <sys/types.h>
24#include <pwd.h>
25#include <sys/ioctl.h>
26#include <dirent.h>
27
28#define PIDS_BUFLEN 4096
29//Process pids[max_pids];
30Process *pids = NULL;
31int max_pids=32769;
32#define PIDS_BUFLEN 4096
33
34// get the memory associated with this pid
35void pid_getmem(unsigned pid, unsigned *rss, unsigned *shared) {
36 // open stat file
37 char *file;
38 if (asprintf(&file, "/proc/%u/statm", pid) == -1) {
39 perror("asprintf");
40 exit(1);
41 }
42 FILE *fp = fopen(file, "r");
43 if (!fp) {
44 free(file);
45 return;
46 }
47 free(file);
48
49 unsigned a, b, c;
50 if (3 != fscanf(fp, "%u %u %u", &a, &b, &c)) {
51 fclose(fp);
52 return;
53 }
54 *rss += b;
55 *shared += c;
56 fclose(fp);
57}
58
59
60void pid_get_cpu_time(unsigned pid, unsigned *utime, unsigned *stime) {
61 // open stat file
62 char *file;
63 if (asprintf(&file, "/proc/%u/stat", pid) == -1) {
64 perror("asprintf");
65 exit(1);
66 }
67 FILE *fp = fopen(file, "r");
68 if (!fp) {
69 free(file);
70 return;
71 }
72 free(file);
73
74 char line[PIDS_BUFLEN];
75 if (fgets(line, PIDS_BUFLEN - 1, fp)) {
76 char *ptr = line;
77 // jump 13 fields
78 int i;
79 for (i = 0; i < 13; i++) {
80 while (*ptr != ' ' && *ptr != '\t' && *ptr != '\0')
81 ptr++;
82 if (*ptr == '\0')
83 goto myexit;
84 ptr++;
85 }
86 if (2 != sscanf(ptr, "%u %u", utime, stime))
87 goto myexit;
88 }
89
90myexit:
91 fclose(fp);
92}
93
94unsigned long long pid_get_start_time(unsigned pid) {
95 // open stat file
96 char *file;
97 if (asprintf(&file, "/proc/%u/stat", pid) == -1) {
98 perror("asprintf");
99 exit(1);
100 }
101 FILE *fp = fopen(file, "r");
102 if (!fp) {
103 free(file);
104 return 0;
105 }
106 free(file);
107
108 char line[PIDS_BUFLEN];
109 unsigned long long retval = 0;
110 if (fgets(line, PIDS_BUFLEN - 1, fp)) {
111 char *ptr = line;
112 // jump 21 fields
113 int i;
114 for (i = 0; i < 21; i++) {
115 while (*ptr != ' ' && *ptr != '\t' && *ptr != '\0')
116 ptr++;
117 if (*ptr == '\0')
118 goto myexit;
119 ptr++;
120 }
121 if (1 != sscanf(ptr, "%llu", &retval))
122 goto myexit;
123 }
124
125myexit:
126 fclose(fp);
127 return retval;
128}
129
130char *pid_get_user_name(uid_t uid) {
131 struct passwd *pw = getpwuid(uid);
132 if (pw)
133 return strdup(pw->pw_name);
134 return NULL;
135}
136
137uid_t pid_get_uid(pid_t pid) {
138 uid_t rv = 0;
139
140 // open stat file
141 char *file;
142 if (asprintf(&file, "/proc/%u/status", pid) == -1) {
143 perror("asprintf");
144 exit(1);
145 }
146 FILE *fp = fopen(file, "r");
147 if (!fp) {
148 free(file);
149 return 0;
150 }
151
152 // look for firejail executable name
153 char buf[PIDS_BUFLEN];
154 while (fgets(buf, PIDS_BUFLEN - 1, fp)) {
155 if (strncmp(buf, "Uid:", 4) == 0) {
156 char *ptr = buf + 5;
157 while (*ptr != '\0' && (*ptr == ' ' || *ptr == '\t')) {
158 ptr++;
159 }
160 if (*ptr == '\0')
161 goto doexit;
162
163 rv = atoi(ptr);
164 break; // break regardless!
165 }
166 }
167doexit:
168 fclose(fp);
169 free(file);
170 return rv;
171}
172
173static void print_elem(unsigned index, int nowrap) {
174 // get terminal size
175 struct winsize sz;
176 int col = 0;
177 if (isatty(STDIN_FILENO)) {
178 if (!ioctl(0, TIOCGWINSZ, &sz))
179 col = sz.ws_col;
180 }
181
182 // indent
183 char indent[(pids[index].level - 1) * 2 + 1];
184 memset(indent, ' ', sizeof(indent));
185 indent[(pids[index].level - 1) * 2] = '\0';
186
187 // get data
188 uid_t uid = pids[index].uid;
189 char *cmd = pid_proc_cmdline(index);
190 char *user = pid_get_user_name(uid);
191 char *allocated = user;
192 if (user ==NULL)
193 user = "";
194 if (cmd) {
195 if (col < 4 || nowrap)
196 printf("%s%u:%s:%s\n", indent, index, user, cmd);
197 else {
198 char *out;
199 if (asprintf(&out, "%s%u:%s:%s\n", indent, index, user, cmd) == -1)
200 errExit("asprintf");
201 int len = strlen(out);
202 if (len > col) {
203 out[col] = '\0';
204 out[col - 1] = '\n';
205 }
206 printf("%s", out);
207 free(out);
208 }
209
210 free(cmd);
211 }
212 else {
213 if (pids[index].zombie)
214 printf("%s%u: (zombie)\n", indent, index);
215 else
216 printf("%s%u:\n", indent, index);
217 }
218 if (allocated)
219 free(allocated);
220}
221
222// recursivity!!!
223void pid_print_tree(unsigned index, unsigned parent, int nowrap) {
224 print_elem(index, nowrap);
225
226 int i;
227 for (i = index + 1; i < max_pids; i++) {
228 if (pids[i].parent == index)
229 pid_print_tree(i, index, nowrap);
230 }
231
232 for (i = 0; i < index; i++) {
233 if (pids[i].parent == index)
234 pid_print_tree(i, index, nowrap);
235 }
236}
237
238void pid_print_list(unsigned index, int nowrap) {
239 print_elem(index, nowrap);
240}
241
242// recursivity!!!
243void pid_store_cpu(unsigned index, unsigned parent, unsigned *utime, unsigned *stime) {
244 if (pids[index].level == 1) {
245 *utime = 0;
246 *stime = 0;
247 }
248
249 unsigned utmp = 0;
250 unsigned stmp = 0;
251 pid_get_cpu_time(index, &utmp, &stmp);
252 *utime += utmp;
253 *stime += stmp;
254
255 int i;
256 for (i = index + 1; i < max_pids; i++) {
257 if (pids[i].parent == index)
258 pid_store_cpu(i, index, utime, stime);
259 }
260
261 if (pids[index].level == 1) {
262 pids[index].utime = *utime;
263 pids[index].stime = *stime;
264 }
265}
266
267// mon_pid: pid of sandbox to be monitored, 0 if all sandboxes are included
268void pid_read(pid_t mon_pid) {
269 if (pids == NULL) {
270 FILE *fp = fopen("/proc/sys/kernel/pid_max", "r");
271 if (fp) {
272 int val;
273 if (fscanf(fp, "%d", &val) == 1) {
274 if (val >= max_pids)
275 max_pids = val + 1;
276 }
277 fclose(fp);
278 }
279 pids = malloc(sizeof(Process) * max_pids);
280 if (pids == NULL)
281 errExit("malloc");
282 }
283 memset(pids, 0, sizeof(Process) * max_pids);
284 pid_t mypid = getpid();
285
286 DIR *dir;
287 if (!(dir = opendir("/proc"))) {
288 // sleep 2 seconds and try again
289 sleep(2);
290 if (!(dir = opendir("/proc"))) {
291 fprintf(stderr, "Error: cannot open /proc directory\n");
292 exit(1);
293 }
294 }
295
296 pid_t child = -1;
297 struct dirent *entry;
298 char *end;
299 while (child < 0 && (entry = readdir(dir))) {
300 pid_t pid = strtol(entry->d_name, &end, 10);
301 pid %= max_pids;
302 if (end == entry->d_name || *end)
303 continue;
304 if (pid == mypid)
305 continue;
306
307 // open stat file
308 char *file;
309 if (asprintf(&file, "/proc/%u/status", pid) == -1) {
310 perror("asprintf");
311 exit(1);
312 }
313 FILE *fp = fopen(file, "r");
314 if (!fp) {
315 free(file);
316 continue;
317 }
318
319 // look for firejail executable name
320 char buf[PIDS_BUFLEN];
321 while (fgets(buf, PIDS_BUFLEN - 1, fp)) {
322 if (strncmp(buf, "Name:", 5) == 0) {
323 char *ptr = buf + 5;
324 while (*ptr != '\0' && (*ptr == ' ' || *ptr == '\t')) {
325 ptr++;
326 }
327 if (*ptr == '\0') {
328 fprintf(stderr, "Error: cannot read /proc file\n");
329 exit(1);
330 }
331
332 if (mon_pid == 0 && strncmp(ptr, "firejail", 8) == 0) {
333 pids[pid].level = 1;
334 }
335 else if (mon_pid == pid && strncmp(ptr, "firejail", 8) == 0) {
336 pids[pid].level = 1;
337 }
338// else if (mon_pid == 0 && strncmp(ptr, "lxc-execute", 11) == 0) {
339// pids[pid].level = 1;
340// }
341// else if (mon_pid == pid && strncmp(ptr, "lxc-execute", 11) == 0) {
342// pids[pid].level = 1;
343// }
344 else
345 pids[pid].level = -1;
346 }
347 if (strncmp(buf, "State:", 6) == 0) {
348 if (strstr(buf, "(zombie)"))
349 pids[pid].zombie = 1;
350 }
351 else if (strncmp(buf, "PPid:", 5) == 0) {
352 char *ptr = buf + 5;
353 while (*ptr != '\0' && (*ptr == ' ' || *ptr == '\t')) {
354 ptr++;
355 }
356 if (*ptr == '\0') {
357 fprintf(stderr, "Error: cannot read /proc file\n");
358 exit(1);
359 }
360 unsigned parent = atoi(ptr);
361 parent %= max_pids;
362 if (pids[parent].level > 0) {
363 pids[pid].level = pids[parent].level + 1;
364 }
365 pids[pid].parent = parent;
366 }
367 else if (strncmp(buf, "Uid:", 4) == 0) {
368 char *ptr = buf + 5;
369 while (*ptr != '\0' && (*ptr == ' ' || *ptr == '\t')) {
370 ptr++;
371 }
372 if (*ptr == '\0') {
373 fprintf(stderr, "Error: cannot read /proc file\n");
374 exit(1);
375 }
376 pids[pid].uid = atoi(ptr);
377 break;
378 }
379 }
380 fclose(fp);
381 free(file);
382 }
383 closedir(dir);
384
385 pid_t pid;
386 for (pid = 0; pid < max_pids; pid++) {
387 int parent = pids[pid].parent;
388 if (pids[parent].level > 0) {
389 pids[pid].level = pids[parent].level + 1;
390 }
391 }
392}