]>
Commit | Line | Data |
---|---|---|
1d81c6a6 CB |
1 | #define __STDC_FORMAT_MACROS |
2 | #include <errno.h> | |
3 | #include <fcntl.h> | |
4 | #include <inttypes.h> | |
5 | #include <sched.h> | |
6 | #include <stdarg.h> | |
7 | #include <stdbool.h> | |
8 | #include <stdint.h> | |
9 | #include <stdio.h> | |
10 | #include <stdlib.h> | |
11 | #include <string.h> | |
12 | #include <sys/stat.h> | |
13 | #include <sys/types.h> | |
14 | #include <unistd.h> | |
15 | ||
16 | #include "config.h" | |
17 | #include "macro.h" | |
18 | #include "memory_utils.h" | |
19 | #include "utils.h" | |
20 | ||
21 | /* | |
22 | * append the given formatted string to *src. | |
23 | * src: a pointer to a char* in which to append the formatted string. | |
24 | * sz: the number of characters printed so far, minus trailing \0. | |
25 | * asz: the allocated size so far | |
26 | * format: string format. See printf for details. | |
27 | * ...: varargs. See printf for details. | |
28 | */ | |
29 | void must_strcat(char **src, size_t *sz, size_t *asz, const char *format, ...) | |
30 | { | |
31 | char tmp[BUF_RESERVE_SIZE]; | |
32 | va_list args; | |
33 | ||
34 | va_start (args, format); | |
35 | int tmplen = vsnprintf(tmp, BUF_RESERVE_SIZE, format, args); | |
36 | va_end(args); | |
37 | ||
38 | if (!*src || tmplen + *sz + 1 >= *asz) { | |
39 | char *tmp; | |
40 | do { | |
41 | tmp = realloc(*src, *asz + BUF_RESERVE_SIZE); | |
42 | } while (!tmp); | |
43 | *src = tmp; | |
44 | *asz += BUF_RESERVE_SIZE; | |
45 | } | |
46 | memcpy((*src) +*sz , tmp, tmplen+1); /* include the \0 */ | |
47 | *sz += tmplen; | |
48 | } | |
49 | ||
50 | /** | |
51 | * in_same_namespace - Check whether two processes are in the same namespace. | |
52 | * @pid1 - PID of the first process. | |
53 | * @pid2 - PID of the second process. | |
54 | * @ns - Name of the namespace to check. Must correspond to one of the names | |
55 | * for the namespaces as shown in /proc/<pid/ns/ | |
56 | * | |
57 | * If the two processes are not in the same namespace returns an fd to the | |
58 | * namespace of the second process identified by @pid2. If the two processes are | |
59 | * in the same namespace returns -EINVAL, -1 if an error occurred. | |
60 | */ | |
61 | static int in_same_namespace(pid_t pid1, pid_t pid2, const char *ns) | |
62 | { | |
63 | __do_close_prot_errno int ns_fd1 = -1, ns_fd2 = -1; | |
64 | int ret = -1; | |
65 | struct stat ns_st1, ns_st2; | |
66 | ||
67 | ns_fd1 = preserve_ns(pid1, ns); | |
68 | if (ns_fd1 < 0) { | |
69 | /* The kernel does not support this namespace. This is not an | |
70 | * error. | |
71 | */ | |
72 | if (errno == ENOENT) | |
73 | return -EINVAL; | |
74 | ||
75 | return -1; | |
76 | } | |
77 | ||
78 | ns_fd2 = preserve_ns(pid2, ns); | |
79 | if (ns_fd2 < 0) | |
80 | return -1; | |
81 | ||
82 | ret = fstat(ns_fd1, &ns_st1); | |
83 | if (ret < 0) | |
84 | return -1; | |
85 | ||
86 | ret = fstat(ns_fd2, &ns_st2); | |
87 | if (ret < 0) | |
88 | return -1; | |
89 | ||
90 | /* processes are in the same namespace */ | |
91 | if ((ns_st1.st_dev == ns_st2.st_dev) && (ns_st1.st_ino == ns_st2.st_ino)) | |
92 | return -EINVAL; | |
93 | ||
94 | /* processes are in different namespaces */ | |
95 | return move_fd(ns_fd2); | |
96 | } | |
97 | ||
98 | bool is_shared_pidns(pid_t pid) | |
99 | { | |
100 | if (pid != 1) | |
101 | return false; | |
102 | ||
103 | if (in_same_namespace(pid, getpid(), "pid") == -EINVAL) | |
104 | return true; | |
105 | ||
106 | return false; | |
107 | } | |
108 | ||
109 | int preserve_ns(const int pid, const char *ns) | |
110 | { | |
111 | int ret; | |
112 | /* 5 /proc + 21 /int_as_str + 3 /ns + 20 /NS_NAME + 1 \0 */ | |
113 | #define __NS_PATH_LEN 50 | |
114 | char path[__NS_PATH_LEN]; | |
115 | ||
116 | /* This way we can use this function to also check whether namespaces | |
117 | * are supported by the kernel by passing in the NULL or the empty | |
118 | * string. | |
119 | */ | |
120 | ret = snprintf(path, __NS_PATH_LEN, "/proc/%d/ns%s%s", pid, | |
121 | !ns || strcmp(ns, "") == 0 ? "" : "/", | |
122 | !ns || strcmp(ns, "") == 0 ? "" : ns); | |
123 | if (ret < 0 || (size_t)ret >= __NS_PATH_LEN) { | |
124 | errno = EFBIG; | |
125 | return -1; | |
126 | } | |
127 | ||
128 | return open(path, O_RDONLY | O_CLOEXEC); | |
129 | } |