Branch data Line data Source code
1 : : #include <stdlib.h>
2 : : #include <stdio.h>
3 : : #include <stdarg.h>
4 : : #include <string.h>
5 : : #include <errno.h>
6 : : #include <unistd.h>
7 : : #include <stdbool.h>
8 : : #include <limits.h>
9 : : #include <signal.h>
10 : : #include <limits.h>
11 : : #include <unistd.h>
12 : : #include <errno.h>
13 : : #include <string.h>
14 : : #include <dirent.h>
15 : : #include <sys/sendfile.h>
16 : : #include <fcntl.h>
17 : :
18 : : #include <sys/param.h>
19 : : #include <sys/types.h>
20 : : #include <sys/ptrace.h>
21 : : #include <sys/types.h>
22 : : #include <sys/time.h>
23 : : #include <sys/resource.h>
24 : : #include <sys/stat.h>
25 : : #include <sys/mman.h>
26 : : #include <sys/vfs.h>
27 : : #include <sys/ptrace.h>
28 : : #include <sys/wait.h>
29 : : #include <sys/resource.h>
30 : : #include <sys/wait.h>
31 : :
32 : : #include "compiler.h"
33 : : #include "types.h"
34 : : #include "list.h"
35 : : #include "util.h"
36 : :
37 : : #include "crtools.h"
38 : :
39 : : /* /proc/PID/maps can contain not up to date information about stack */
40 : 698 : void mark_stack_vma(unsigned long sp, struct list_head *vma_area_list)
41 : : {
42 : : struct vma_area *vma_area;
43 [ + - ]: 24484 : list_for_each_entry(vma_area, vma_area_list, list) {
44 [ + + ]: 24484 : if (in_vma_area(vma_area, sp)) {
45 : 698 : vma_area->vma.status |= VMA_AREA_STACK;
46 : 698 : vma_area->vma.flags |= MAP_GROWSDOWN;
47 : :
48 : : /*
49 : : * The kernel doesn't show stack guard pages on
50 : : * proc output, so add pages here by hands.
51 : : */
52 : 698 : vma_area->vma.start -= PAGE_SIZE;
53 : 698 : return;
54 : : }
55 : : }
56 : 0 : BUG();
57 : : }
58 : :
59 : : #define VMA_OPT_LEN 128
60 : :
61 : 12110 : static void vma_opt_str(const struct vma_area *v, char *opt)
62 : : {
63 : 12110 : int p = 0;
64 : :
65 : : #define opt2s(_o, _s) do { \
66 : : if (v->vma.status & _o) \
67 : : p += sprintf(opt + p, _s " "); \
68 : : } while (0)
69 : :
70 : 12110 : opt[p] = '\0';
71 [ + + ]: 12110 : opt2s(VMA_AREA_REGULAR, "reg");
72 [ + + ]: 12110 : opt2s(VMA_AREA_STACK, "stk");
73 [ + + ]: 12110 : opt2s(VMA_AREA_VSYSCALL, "vsys");
74 [ + + ]: 12110 : opt2s(VMA_AREA_VDSO, "vdso");
75 [ - + ]: 12110 : opt2s(VMA_FORCE_READ, "frd");
76 [ + + ]: 12110 : opt2s(VMA_AREA_HEAP, "heap");
77 [ + + ]: 12110 : opt2s(VMA_FILE_PRIVATE, "fp");
78 [ + + ]: 12110 : opt2s(VMA_FILE_SHARED, "fs");
79 [ + + ]: 12110 : opt2s(VMA_ANON_SHARED, "as");
80 [ + + ]: 12110 : opt2s(VMA_ANON_PRIVATE, "ap");
81 [ + + ]: 12110 : opt2s(VMA_AREA_SYSVIPC, "sysv");
82 [ - + ]: 12110 : opt2s(VMA_AREA_SOCKET, "sk");
83 : :
84 : : #undef opt2s
85 : 12110 : }
86 : :
87 : 12110 : void pr_vma(unsigned int loglevel, const struct vma_area *vma_area)
88 : : {
89 : : char opt[VMA_OPT_LEN];
90 : :
91 [ + - ]: 12110 : if (!vma_area)
92 : 12110 : return;
93 : :
94 : 12110 : vma_opt_str(vma_area, opt);
95 : 12110 : print_on_level(loglevel, "%#lx-%#lx (%liK) prot %#x flags %#x off %#lx "
96 : : "%s shmid: %#lx\n",
97 : : vma_area->vma.start, vma_area->vma.end,
98 : 12110 : KBYTES(vma_area_len(vma_area)),
99 : : vma_area->vma.prot,
100 : : vma_area->vma.flags,
101 : : vma_area->vma.pgoff,
102 : : opt, vma_area->vma.shmid);
103 : : }
104 : :
105 : 15671 : int close_safe(int *fd)
106 : : {
107 : 15671 : int ret = 0;
108 [ + + ]: 15671 : if (*fd > -1) {
109 : 15491 : ret = close(*fd);
110 [ + - ]: 15491 : if (!ret)
111 : 15491 : *fd = -1;
112 : : else
113 : 0 : pr_perror("Unable to close fd %d", *fd);
114 : : }
115 : :
116 : 15671 : return ret;
117 : : }
118 : :
119 : 4188 : int reopen_fd_as_safe(char *file, int line, int new_fd, int old_fd, bool allow_reuse_fd)
120 : : {
121 : : int tmp;
122 : :
123 [ + + ]: 4188 : if (old_fd != new_fd) {
124 : :
125 [ + + ]: 3025 : if (!allow_reuse_fd) {
126 [ + - ][ - + ]: 2260 : if (fcntl(new_fd, F_GETFD) != -1 || errno != EBADF) {
127 [ # # ]: 0 : if (new_fd < 3) {
128 : : /*
129 : : * Standard descriptors.
130 : : */
131 : 0 : pr_warn("fd %d already in use (called at %s:%d)\n",
132 : : new_fd, file, line);
133 : : } else {
134 : 0 : pr_err("fd %d already in use (called at %s:%d)\n",
135 : : new_fd, file, line);
136 : 0 : return -1;
137 : : }
138 : : }
139 : : }
140 : :
141 : 3025 : tmp = dup2(old_fd, new_fd);
142 [ - + ]: 3025 : if (tmp < 0) {
143 : 0 : pr_perror("Dup %d -> %d failed (called at %s:%d)",
144 : : old_fd, new_fd, file, line);
145 : 0 : return tmp;
146 : : }
147 : :
148 : : /* Just to have error message if failed */
149 : 4188 : close_safe(&old_fd);
150 : : }
151 : :
152 : : return 0;
153 : : }
154 : :
155 : 867 : int move_img_fd(int *img_fd, int want_fd)
156 : : {
157 [ + + ]: 867 : if (*img_fd == want_fd) {
158 : : int tmp;
159 : :
160 : 248 : tmp = dup(*img_fd);
161 [ - + ]: 248 : if (tmp < 0) {
162 : 0 : pr_perror("Can't dup file");
163 : 0 : return -1;
164 : : }
165 : :
166 : 248 : close(*img_fd);
167 : :
168 : 867 : *img_fd = tmp;
169 : : }
170 : :
171 : : return 0;
172 : : }
173 : :
174 : : static pid_t open_proc_pid = 0;
175 : : static int open_proc_fd = -1;
176 : : static int proc_dir_fd = -1;
177 : :
178 : 4030 : int close_pid_proc(void)
179 : : {
180 : 4030 : int ret = 0;
181 : :
182 [ + + ]: 4030 : if (open_proc_fd >= 0)
183 : 1838 : ret = close(open_proc_fd);
184 : :
185 : 4030 : open_proc_fd = -1;
186 : 4030 : open_proc_pid = 0;
187 : :
188 : 4030 : return ret;
189 : : }
190 : :
191 : 953 : void close_proc()
192 : : {
193 : 953 : close_pid_proc();
194 [ + + ]: 953 : if (proc_dir_fd > 0)
195 : 425 : close(proc_dir_fd);
196 : 953 : proc_dir_fd = -1;
197 : 953 : }
198 : :
199 : 76 : int set_proc_fd(int fd)
200 : : {
201 : 76 : int sfd = get_service_fd(PROC_FD_OFF);
202 : :
203 : 76 : sfd = dup2(fd, sfd);
204 [ - + ]: 76 : if (sfd < 0) {
205 : 0 : pr_perror("Can't set proc fd\n");
206 : 0 : return -1;
207 : : }
208 : :
209 : 76 : proc_dir_fd = sfd;
210 : :
211 : 76 : return 0;
212 : : }
213 : :
214 : 528 : int set_proc_mountpoint(char *path)
215 : : {
216 : 528 : int sfd = get_service_fd(PROC_FD_OFF), fd;
217 : :
218 : 528 : close_proc();
219 : :
220 : 528 : fd = open(path, O_DIRECTORY | O_RDONLY);
221 [ - + ]: 528 : if (fd == -1) {
222 : 0 : pr_err("Can't open %s\n", path);
223 : 0 : return -1;
224 : : }
225 : :
226 : 528 : sfd = dup2(fd, sfd);
227 : 528 : close(fd);
228 [ - + ]: 528 : if (sfd < 0) {
229 : 0 : pr_err("Can't set proc fd\n");
230 : 0 : return -1;
231 : : }
232 : :
233 : 528 : proc_dir_fd = sfd;
234 : :
235 : 528 : return 0;
236 : : }
237 : :
238 : 7539 : inline int open_pid_proc(pid_t pid)
239 : : {
240 : : char path[18];
241 : : int fd;
242 : :
243 [ + + ]: 7539 : if (pid == open_proc_pid)
244 : 5686 : return open_proc_fd;
245 : :
246 : 1853 : close_pid_proc();
247 : :
248 [ + + ]: 1853 : if (proc_dir_fd == -1) {
249 : 173 : fd = set_proc_mountpoint("/proc");
250 [ + - ]: 173 : if (fd < 0)
251 : : return fd;
252 : : }
253 : :
254 : 1853 : snprintf(path, sizeof(path), "%d", pid);
255 : 1853 : fd = openat(proc_dir_fd, path, O_RDONLY);
256 [ - + ]: 1853 : if (fd < 0)
257 : 0 : pr_perror("Can't open %s", path);
258 : : else {
259 : 1853 : open_proc_fd = fd;
260 : 7539 : open_proc_pid = pid;
261 : : }
262 : :
263 : : return fd;
264 : : }
265 : :
266 : 7372 : int do_open_proc(pid_t pid, int flags, const char *fmt, ...)
267 : : {
268 : : char path[128];
269 : : va_list args;
270 : 7372 : int dirfd = open_pid_proc(pid);
271 : :
272 [ + - ]: 7372 : if (dirfd < 0)
273 : : return -1;
274 : :
275 : 7372 : va_start(args, fmt);
276 : 7372 : vsnprintf(path, sizeof(path), fmt, args);
277 : 7372 : va_end(args);
278 : :
279 : 7372 : return openat(dirfd, path, flags);
280 : : }
281 : :
282 : : static int service_fd_rlim_cur;
283 : :
284 : 547 : int init_service_fd(void)
285 : : {
286 : : struct rlimit rlimit;
287 : :
288 : : /*
289 : : * Service FDs are thouse that most likely won't
290 : : * conflict with any 'real-life' ones
291 : : */
292 : :
293 [ - + ]: 547 : if (getrlimit(RLIMIT_NOFILE, &rlimit)) {
294 : 0 : pr_perror("Can't get rlimit");
295 : : return -1;
296 : : }
297 : :
298 : 547 : service_fd_rlim_cur = (int)rlimit.rlim_cur;
299 [ - + ]: 547 : BUG_ON(service_fd_rlim_cur < SERVICE_FD_MAX);
300 : :
301 : : return 0;
302 : : }
303 : :
304 : : static int __get_service_fd(enum sfd_type type)
305 : : {
306 : 6274 : return service_fd_rlim_cur - type;
307 : : }
308 : :
309 : 2784 : int get_service_fd(enum sfd_type type)
310 : : {
311 [ - + ]: 2784 : BUG_ON((int)type <= SERVICE_FD_MIN || (int)type >= SERVICE_FD_MAX);
312 : 2784 : return __get_service_fd(type);
313 : : }
314 : :
315 : 3490 : bool is_any_service_fd(int fd)
316 : : {
317 [ + + ][ - + ]: 3490 : return fd > __get_service_fd(SERVICE_FD_MAX) &&
318 : : fd < __get_service_fd(SERVICE_FD_MIN);
319 : : }
320 : :
321 : 149 : bool is_service_fd(int fd, enum sfd_type type)
322 : : {
323 : 149 : return fd == get_service_fd(type);
324 : : }
325 : :
326 : 22 : int copy_file(int fd_in, int fd_out, size_t bytes)
327 : : {
328 : 22 : ssize_t written = 0;
329 [ + + ]: 22 : size_t chunk = bytes ? bytes : 4096;
330 : :
331 : : while (1) {
332 : : ssize_t ret;
333 : :
334 : 32 : ret = sendfile(fd_out, fd_in, NULL, chunk);
335 [ - + ]: 32 : if (ret < 0) {
336 : 0 : pr_perror("Can't send data to ghost file");
337 : 22 : return -1;
338 : : }
339 : :
340 [ + + ]: 32 : if (ret == 0) {
341 [ - + ]: 22 : if (bytes && (written != bytes)) {
342 : 0 : pr_err("Ghost file size mismatch %lu/%lu\n",
343 : : written, bytes);
344 : 0 : return -1;
345 : : }
346 : : break;
347 : : }
348 : :
349 : 10 : written += ret;
350 : 10 : }
351 : :
352 : : return 0;
353 : : }
354 : :
355 : : #ifndef ANON_INODE_FS_MAGIC
356 : : # define ANON_INODE_FS_MAGIC 0x09041934
357 : : #endif
358 : :
359 : 1038 : bool is_anon_inode(struct statfs *statfs)
360 : : {
361 : 1038 : return statfs->f_type == ANON_INODE_FS_MAGIC;
362 : : }
363 : :
364 : 20 : int is_anon_link_type(int lfd, char *type)
365 : : {
366 : : char link[32], aux[32];
367 : : ssize_t ret;
368 : :
369 : 20 : snprintf(aux, sizeof(aux), "/proc/self/fd/%d", lfd);
370 : 20 : ret = readlink(aux, link, sizeof(link));
371 [ - + ]: 20 : if (ret < 0) {
372 : 0 : pr_perror("Can't read link of fd %d\n", lfd);
373 : : return 0;
374 : : }
375 : 20 : link[ret] = 0;
376 : 20 : snprintf(aux, sizeof(aux), "anon_inode:%s", type);
377 : 20 : return !strcmp(link, aux);
378 : : }
379 : :
380 : : static void *sh_buf;
381 : : static unsigned int sh_bytes_left;
382 : : static size_t sh_last_size;
383 : : #define SH_BUF_CHUNK 4096
384 : :
385 : 7126 : void *shmalloc(size_t bytes)
386 : : {
387 : : void *ret;
388 : :
389 [ - + ]: 7126 : if (bytes > SH_BUF_CHUNK) {
390 : 0 : pr_err("Too big shared buffer requested %lu\n", bytes);
391 : 0 : return NULL;
392 : : }
393 : :
394 [ + + ]: 7126 : if (sh_bytes_left < bytes) {
395 : 370 : sh_buf = mmap(NULL, SH_BUF_CHUNK, PROT_READ | PROT_WRITE,
396 : : MAP_SHARED | MAP_ANON, 0, 0);
397 [ - + ]: 370 : if (sh_buf == MAP_FAILED) {
398 : 0 : pr_perror("Can't alloc shared buffer");
399 : 0 : return NULL;
400 : : }
401 : :
402 : 370 : sh_bytes_left = SH_BUF_CHUNK;
403 : : }
404 : :
405 : 7126 : ret = sh_buf;
406 : 7126 : sh_buf += bytes;
407 : 7126 : sh_bytes_left -= bytes;
408 : 7126 : sh_last_size = bytes;
409 : :
410 : 7126 : return ret;
411 : : }
412 : :
413 : : /* Only last chunk can be released */
414 : 355 : void shfree_last(void *ptr)
415 : : {
416 [ - + ]: 355 : BUG_ON(sh_buf - sh_last_size != ptr);
417 : 355 : sh_buf -= sh_last_size;
418 : 355 : sh_bytes_left += sh_last_size;
419 : 355 : sh_last_size = 0;
420 : 355 : }
421 : :
422 : 152 : int run_scripts(char *action)
423 : : {
424 : : struct script *script;
425 : 152 : int ret = 0;
426 : :
427 [ - + ]: 152 : if (setenv("CRTOOLS_SCRIPT_ACTION", action, 1)) {
428 : 0 : pr_perror("Can't set CRTOOL_SCRIPT_ACTION=%s\n", action);
429 : 0 : return -1;
430 : : }
431 : :
432 [ - + ]: 152 : list_for_each_entry(script, &opts.scripts, node)
433 : 0 : ret |= system(script->path);
434 : :
435 : 152 : unsetenv("CRTOOLS_SCRIPT_ACTION");
436 : 152 : return ret;
437 : : }
438 : :
439 : : #define DUP_SAFE(fd, out) \
440 : : ({ \
441 : : int ret__; \
442 : : ret__ = dup(fd); \
443 : : if (ret__ == -1) { \
444 : : pr_perror("dup(%d) failed", fd); \
445 : : goto out; \
446 : : } \
447 : : ret__; \
448 : : })
449 : :
450 : : /*
451 : : * If "in" is negative, stdin will be closed.
452 : : * If "out" or "err" are negative, a log file descriptor will be used.
453 : : */
454 : 306 : int cr_system(int in, int out, int err, char *cmd, char *const argv[])
455 : : {
456 : : sigset_t blockmask, oldmask;
457 : 306 : int ret = -1, status;
458 : : pid_t pid;
459 : :
460 : 306 : sigemptyset(&blockmask);
461 : 306 : sigaddset(&blockmask, SIGCHLD);
462 [ - + ]: 306 : if (sigprocmask(SIG_BLOCK, &blockmask, &oldmask) == -1) {
463 : 0 : pr_perror("Can not set mask of blocked signals");
464 : : return -1;
465 : : }
466 : :
467 : 306 : pid = fork();
468 [ - + ]: 753 : if (pid == -1) {
469 : 0 : pr_perror("fork() failed\n");
470 : 0 : goto out;
471 [ + + ]: 753 : } else if (pid == 0) {
472 [ + + ]: 306 : if (out < 0)
473 : 153 : out = log_get_fd();
474 [ + - ]: 306 : if (err < 0)
475 : 306 : err = log_get_fd();
476 : :
477 : : /*
478 : : * out, err, in should be a separate fds,
479 : : * because reopen_fd_as() closes an old fd
480 : : */
481 [ + + ]: 306 : if (err == out || err == in)
482 [ - + ]: 153 : err = DUP_SAFE(err, out_chld);
483 : :
484 [ - + ]: 306 : if (out == in)
485 [ # # ]: 0 : out = DUP_SAFE(out, out_chld);
486 : :
487 [ + + ]: 306 : if (in < 0) {
488 : 153 : close(STDIN_FILENO);
489 : : } else {
490 [ + - + - ]: 306 : if (move_img_fd(&out, STDIN_FILENO) ||
491 : 153 : move_img_fd(&err, STDIN_FILENO))
492 : : goto out_chld;
493 : :
494 [ + - ]: 153 : if (reopen_fd_as_nocheck(STDIN_FILENO, in))
495 : : goto out_chld;
496 : : }
497 : :
498 [ + - ]: 306 : if (move_img_fd(&err, STDOUT_FILENO))
499 : : goto out_chld;
500 : :
501 [ + - ]: 306 : if (reopen_fd_as_nocheck(STDOUT_FILENO, out))
502 : : goto out_chld;
503 : :
504 [ + - ]: 306 : if (reopen_fd_as_nocheck(STDERR_FILENO, err))
505 : : goto out_chld;
506 : :
507 : 306 : execvp(cmd, argv);
508 : :
509 : 306 : pr_perror("exec failed");
510 : : out_chld:
511 : 0 : _exit(1);
512 : : }
513 : :
514 : : while (1) {
515 : 447 : ret = waitpid(pid, &status, 0);
516 [ - + ]: 447 : if (ret == -1) {
517 : 0 : pr_perror("waitpid() failed");
518 : 0 : goto out;
519 : : }
520 : :
521 [ + - ]: 447 : if (WIFEXITED(status)) {
522 [ - + ]: 447 : if (WEXITSTATUS(status))
523 : 0 : pr_err("exited, status=%d\n", WEXITSTATUS(status));
524 : : break;
525 [ # # ]: 0 : } else if (WIFSIGNALED(status)) {
526 : 0 : pr_err("killed by signal %d\n", WTERMSIG(status));
527 : 0 : break;
528 [ # # ]: 0 : } else if (WIFSTOPPED(status)) {
529 : 0 : pr_err("stopped by signal %d\n", WSTOPSIG(status));
530 [ # # ]: 0 : } else if (WIFCONTINUED(status)) {
531 : 0 : pr_err("continued\n");
532 : : }
533 : : }
534 : :
535 [ + - ]: 447 : ret = status ? -1 : 0;
536 : : out:
537 [ - + ]: 447 : if (sigprocmask(SIG_SETMASK, &oldmask, NULL) == -1) {
538 : 0 : pr_perror("Can not unset mask of blocked signals");
539 : 447 : BUG();
540 : : }
541 : :
542 : : return ret;
543 : 36594 : }
|