Branch data Line data Source code
1 : : #include <unistd.h>
2 : : #include <stdlib.h>
3 : : #include <string.h>
4 : : #include <fcntl.h>
5 : : #include <sys/wait.h>
6 : : #include <sys/msg.h>
7 : : #include <sys/sem.h>
8 : : #include <sys/shm.h>
9 : :
10 : : #include "util.h"
11 : : #include "cr_options.h"
12 : : #include "fdset.h"
13 : : #include "syscall.h"
14 : : #include "namespaces.h"
15 : : #include "sysctl.h"
16 : : #include "ipc_ns.h"
17 : :
18 : : #include "protobuf.h"
19 : : #include "protobuf/ipc-var.pb-c.h"
20 : : #include "protobuf/ipc-shm.pb-c.h"
21 : : #include "protobuf/ipc-sem.pb-c.h"
22 : : #include "protobuf/ipc-msg.pb-c.h"
23 : :
24 : : #if defined (__GLIBC__) && __GLIBC__ >= 2
25 : : #define KEY __key
26 : : #else
27 : : #define KEY key
28 : : #endif
29 : :
30 : : #ifndef MSGMAX
31 : : #define MSGMAX 8192
32 : : #endif
33 : :
34 : : #ifndef MSG_COPY
35 : : #define MSG_COPY 040000
36 : : #endif
37 : :
38 : 30 : static void pr_ipc_desc_entry(unsigned int loglevel, const IpcDescEntry *desc)
39 : : {
40 : 30 : print_on_level(loglevel, "id: %-10d key: 0x%08x ", desc->id, desc->key);
41 : 30 : print_on_level(loglevel, "uid: %-10d gid: %-10d ", desc->uid, desc->gid);
42 : 30 : print_on_level(loglevel, "cuid: %-10d cgid: %-10d ", desc->cuid, desc->cgid);
43 : 30 : print_on_level(loglevel, "mode: %-10o ", desc->mode);
44 : 30 : }
45 : :
46 : : static void fill_ipc_desc(int id, IpcDescEntry *desc, const struct ipc_perm *ipcp)
47 : : {
48 : 10 : desc->id = id;
49 : 10 : desc->key = ipcp->KEY;
50 : 10 : desc->uid = ipcp->uid;
51 : 10 : desc->gid = ipcp->gid;
52 : 10 : desc->cuid = ipcp->cuid;
53 : 10 : desc->cgid = ipcp->cgid;
54 : 10 : desc->mode = ipcp->mode;
55 : : }
56 : :
57 : 12 : static void pr_ipc_sem_array(unsigned int loglevel, int nr, u16 *values)
58 : : {
59 [ + + ]: 24 : while (nr--)
60 : 12 : print_on_level(loglevel, " %-5d", values[nr]);
61 : 12 : print_on_level(loglevel, "\n");
62 : 12 : }
63 : :
64 : : #define pr_info_ipc_sem_array(nr, values) pr_ipc_sem_array(LOG_INFO, nr, values)
65 : : #define pr_msg_ipc_sem_array(nr, values) pr_ipc_sem_array(LOG_MSG, nr, values)
66 : :
67 : 24 : static void pr_info_ipc_sem_entry(const IpcSemEntry *sem)
68 : : {
69 : 12 : pr_ipc_desc_entry(LOG_INFO, sem->desc);
70 : 12 : print_on_level(LOG_INFO, "nsems: %-10d\n", sem->nsems);
71 : 12 : }
72 : :
73 : 4 : static int dump_ipc_sem_set(int fd, const IpcSemEntry *sem)
74 : : {
75 : : size_t rounded;
76 : : int ret, size;
77 : : u16 *values;
78 : :
79 : 4 : size = sizeof(u16) * sem->nsems;
80 : 4 : rounded = round_up(size, sizeof(u64));
81 [ - + ]: 4 : values = xmalloc(rounded);
82 [ - + ]: 4 : if (values == NULL) {
83 : 0 : pr_err("Failed to allocate memory for semaphore set values\n");
84 : : ret = -ENOMEM;
85 : : goto out;
86 : : }
87 : 4 : ret = semctl(sem->desc->id, 0, GETALL, values);
88 [ - + ]: 4 : if (ret < 0) {
89 : 0 : pr_perror("Failed to get semaphore set values");
90 : 0 : ret = -errno;
91 : : goto out;
92 : : }
93 : 4 : pr_info_ipc_sem_array(sem->nsems, values);
94 : :
95 : 4 : memzero((void *)values + size, rounded - size);
96 : 4 : ret = write_img_buf(fd, values, rounded);
97 [ - + ]: 4 : if (ret < 0) {
98 : 0 : pr_err("Failed to write IPC message data\n");
99 : : goto out;
100 : : }
101 : : out:
102 [ + - ]: 4 : xfree(values);
103 : 4 : return ret;
104 : : }
105 : :
106 : 4 : static int dump_ipc_sem_desc(int fd, int id, const struct semid_ds *ds)
107 : : {
108 : 4 : IpcSemEntry sem = IPC_SEM_ENTRY__INIT;
109 : 4 : IpcDescEntry desc = IPC_DESC_ENTRY__INIT;
110 : : int ret;
111 : :
112 : 4 : sem.desc = &desc;
113 : 4 : sem.nsems = ds->sem_nsems;
114 : :
115 : : fill_ipc_desc(id, sem.desc, &ds->sem_perm);
116 : 4 : pr_info_ipc_sem_entry(&sem);
117 : :
118 : 4 : ret = pb_write_one(fd, &sem, PB_IPC_SEM);
119 [ - + ]: 4 : if (ret < 0) {
120 : 0 : pr_err("Failed to write IPC semaphores set\n");
121 : 0 : return ret;
122 : : }
123 : 4 : return dump_ipc_sem_set(fd, &sem);
124 : : }
125 : :
126 : 220 : static int dump_ipc_sem(int fd)
127 : : {
128 : : int i, maxid;
129 : : struct seminfo info;
130 : : int slot;
131 : :
132 : 220 : maxid = semctl(0, 0, SEM_INFO, &info);
133 [ - + ]: 220 : if (maxid < 0) {
134 : 0 : pr_perror("semctl failed");
135 : 0 : return -errno;
136 : : }
137 : :
138 : 220 : pr_info("IPC semaphore sets: %d\n", info.semusz);
139 [ + + ]: 440 : for (i = 0, slot = 0; i <= maxid; i++) {
140 : : struct semid_ds ds;
141 : : int id, ret;
142 : :
143 : 220 : id = semctl(i, 0, SEM_STAT, &ds);
144 [ + + ]: 220 : if (id < 0) {
145 [ + - ]: 216 : if (errno == EINVAL)
146 : 216 : continue;
147 : 0 : pr_perror("Failed to get stats for IPC semaphore set");
148 : 0 : break;
149 : : }
150 : 4 : ret = dump_ipc_sem_desc(fd, id, &ds);
151 [ + - ]: 4 : if (!ret)
152 : 4 : slot++;
153 : : }
154 [ - + ]: 220 : if (slot != info.semusz) {
155 : 0 : pr_err("Failed to collect %d (only %d succeeded)\n", info.semusz, slot);
156 : 0 : return -EFAULT;
157 : : }
158 : : return info.semusz;
159 : : }
160 : :
161 : : static void pr_info_ipc_msg(int nr, const IpcMsg *msg)
162 : : {
163 : 12 : print_on_level(LOG_INFO, " %-5d: type: %-20"PRId64" size: %-10d\n",
164 : : nr++, msg->mtype, msg->msize);
165 : : }
166 : :
167 : 6 : static void pr_info_ipc_msg_entry(const IpcMsgEntry *msg)
168 : : {
169 : 6 : pr_ipc_desc_entry(LOG_INFO, msg->desc);
170 : 6 : print_on_level(LOG_INFO, "qbytes: %-10d qnum: %-10d\n",
171 : : msg->qbytes, msg->qnum);
172 : 6 : }
173 : :
174 : 2 : static int dump_ipc_msg_queue_messages(int fd, const IpcMsgEntry *msq,
175 : : unsigned int msg_nr)
176 : : {
177 : : struct msgbuf *message = NULL;
178 : : unsigned int msgmax;
179 : : int ret, msg_cnt = 0;
180 : 2 : struct sysctl_req req[] = {
181 : : { "kernel/msgmax", &msgmax, CTL_U32 },
182 : : { },
183 : : };
184 : :
185 : 2 : ret = sysctl_op(req, CTL_READ);
186 [ - + ]: 2 : if (ret < 0) {
187 : 0 : pr_err("Failed to read max IPC message size\n");
188 : : goto err;
189 : : }
190 : :
191 : 2 : msgmax += sizeof(struct msgbuf);
192 [ - + ]: 2 : message = xmalloc(round_up(msgmax, sizeof(u64)));
193 [ + - ]: 2 : if (message == NULL) {
194 : 0 : pr_err("Failed to allocate memory for IPC message\n");
195 : : return -ENOMEM;
196 : : }
197 : :
198 [ + + ]: 6 : for (msg_cnt = 0; msg_cnt < msg_nr; msg_cnt++) {
199 : 4 : IpcMsg msg = IPC_MSG__INIT;
200 : : size_t rounded;
201 : :
202 : 4 : ret = msgrcv(msq->desc->id, message, msgmax, msg_cnt, IPC_NOWAIT | MSG_COPY);
203 [ - + ]: 4 : if (ret < 0) {
204 : 0 : pr_perror("Failed to copy IPC message");
205 : 0 : goto err;
206 : : }
207 : :
208 : 4 : msg.msize = ret;
209 : 4 : msg.mtype = message->mtype;
210 : :
211 : : pr_info_ipc_msg(msg_cnt, &msg);
212 : :
213 : 4 : ret = pb_write_one(fd, &msg, PB_IPCNS_MSG);
214 [ - + ]: 4 : if (ret < 0) {
215 : 0 : pr_err("Failed to write IPC message header\n");
216 : 0 : break;
217 : : }
218 : :
219 : 4 : rounded = round_up(msg.msize, sizeof(u64));
220 : 4 : memzero(((void *)message->mtext + msg.msize), rounded - msg.msize);
221 : 4 : ret = write_img_buf(fd, message->mtext, rounded);
222 [ - + ]: 4 : if (ret < 0) {
223 : 0 : pr_err("Failed to write IPC message data\n");
224 : : break;
225 : : }
226 : : }
227 : : ret = 0;
228 : : err:
229 [ + - ]: 2 : xfree(message);
230 : : return ret;
231 : : }
232 : :
233 : 2 : static int dump_ipc_msg_queue(int fd, int id, const struct msqid_ds *ds)
234 : : {
235 : 2 : IpcMsgEntry msg = IPC_MSG_ENTRY__INIT;
236 : 2 : IpcDescEntry desc = IPC_DESC_ENTRY__INIT;
237 : : int ret;
238 : :
239 : 2 : msg.desc = &desc;
240 : : fill_ipc_desc(id, msg.desc, &ds->msg_perm);
241 : 2 : msg.qbytes = ds->msg_qbytes;
242 : 2 : msg.qnum = ds->msg_qnum;
243 : :
244 : 2 : pr_info_ipc_msg_entry(&msg);
245 : :
246 : 2 : ret = pb_write_one(fd, &msg, PB_IPCNS_MSG_ENT);
247 [ - + ]: 2 : if (ret < 0) {
248 : 0 : pr_err("Failed to write IPC message queue\n");
249 : 0 : return ret;
250 : : }
251 : 2 : return dump_ipc_msg_queue_messages(fd, &msg, ds->msg_qnum);
252 : : }
253 : :
254 : 220 : static int dump_ipc_msg(int fd)
255 : : {
256 : : int i, maxid;
257 : : struct msginfo info;
258 : : int slot;
259 : :
260 : 220 : maxid = msgctl(0, MSG_INFO, (struct msqid_ds *)&info);
261 [ - + ]: 220 : if (maxid < 0) {
262 : 0 : pr_perror("msgctl failed");
263 : 0 : return -errno;
264 : : }
265 : :
266 : 220 : pr_info("IPC message queues: %d\n", info.msgpool);
267 [ + + ]: 440 : for (i = 0, slot = 0; i <= maxid; i++) {
268 : : struct msqid_ds ds;
269 : : int id, ret;
270 : :
271 : 220 : id = msgctl(i, MSG_STAT, &ds);
272 [ + + ]: 220 : if (id < 0) {
273 [ + - ]: 218 : if (errno == EINVAL)
274 : 218 : continue;
275 : 0 : pr_perror("Failed to get stats for IPC message queue");
276 : 0 : break;
277 : : }
278 : 2 : ret = dump_ipc_msg_queue(fd, id, &ds);
279 [ + - ]: 2 : if (!ret)
280 : 2 : slot++;
281 : : }
282 [ - + ]: 220 : if (slot != info.msgpool) {
283 : 0 : pr_err("Failed to collect %d message queues (only %d succeeded)\n", info.msgpool, slot);
284 : 0 : return -EFAULT;
285 : : }
286 : : return info.msgpool;
287 : : }
288 : :
289 : 24 : static void pr_info_ipc_shm(const IpcShmEntry *shm)
290 : : {
291 : 12 : pr_ipc_desc_entry(LOG_INFO, shm->desc);
292 : 12 : print_on_level(LOG_INFO, "size: %-10"PRIu64"\n", shm->size);
293 : 12 : }
294 : :
295 : 256 : static int ipc_sysctl_req(IpcVarEntry *e, int op)
296 : : {
297 : 2816 : struct sysctl_req req[] = {
298 : 512 : { "kernel/sem", e->sem_ctls, CTL_U32A(e->n_sem_ctls) },
299 : 256 : { "kernel/msgmax", &e->msg_ctlmax, CTL_U32 },
300 : 256 : { "kernel/msgmnb", &e->msg_ctlmnb, CTL_U32 },
301 : 256 : { "kernel/msgmni", &e->msg_ctlmni, CTL_U32 },
302 : 256 : { "kernel/auto_msgmni", &e->auto_msgmni, CTL_U32 },
303 : 256 : { "kernel/shmmax", &e->shm_ctlmax, CTL_U64 },
304 : 256 : { "kernel/shmall", &e->shm_ctlall, CTL_U64 },
305 : 256 : { "kernel/shmmni", &e->shm_ctlmni, CTL_U32 },
306 : 256 : { "kernel/shm_rmid_forced", &e->shm_rmid_forced, CTL_U32 },
307 : : { },
308 : : };
309 : :
310 : 1024 : struct sysctl_req req_mq[] = {
311 : 256 : { "fs/mqueue/queues_max", &e->mq_queues_max, CTL_U32 },
312 : 256 : { "fs/mqueue/msg_max", &e->mq_msg_max, CTL_U32 },
313 : 256 : { "fs/mqueue/msgsize_max", &e->mq_msgsize_max, CTL_U32 },
314 : : { },
315 : : };
316 : :
317 : : int ret;
318 : :
319 : 256 : ret = sysctl_op(req, op);
320 [ + - ]: 256 : if (ret)
321 : : return ret;
322 : :
323 [ - + ]: 256 : if (access("/proc/sys/fs/mqueue", X_OK)) {
324 : 0 : pr_info("Mqueue sysctls are missing\n");
325 : 0 : return 0;
326 : : }
327 : :
328 : 256 : return sysctl_op(req_mq, op);
329 : : }
330 : :
331 : : /*
332 : : * TODO: Function below should be later improved to locate and dump only dirty
333 : : * pages via updated sys_mincore().
334 : : */
335 : 4 : static int dump_ipc_shm_pages(int fd, const IpcShmEntry *shm)
336 : : {
337 : : void *data;
338 : : int ret;
339 : :
340 : 4 : data = shmat(shm->desc->id, NULL, SHM_RDONLY);
341 [ - + ]: 4 : if (data == (void *)-1) {
342 : 0 : pr_perror("Failed to attach IPC shared memory");
343 : 0 : return -errno;
344 : : }
345 : 4 : ret = write_img_buf(fd, data, round_up(shm->size, sizeof(u32)));
346 [ - + ]: 4 : if (ret < 0) {
347 : 0 : pr_err("Failed to write IPC shared memory data\n");
348 : : return ret;
349 : : }
350 [ - + ]: 4 : if (shmdt(data)) {
351 : 0 : pr_perror("Failed to detach IPC shared memory");
352 : 0 : return -errno;
353 : : }
354 : : return 0;
355 : : }
356 : :
357 : 4 : static int dump_ipc_shm_seg(int fd, int id, const struct shmid_ds *ds)
358 : : {
359 : 4 : IpcShmEntry shm = IPC_SHM_ENTRY__INIT;
360 : 4 : IpcDescEntry desc = IPC_DESC_ENTRY__INIT;
361 : : int ret;
362 : :
363 : 4 : shm.desc = &desc;
364 : 4 : shm.size = ds->shm_segsz;
365 : : fill_ipc_desc(id, shm.desc, &ds->shm_perm);
366 : 4 : pr_info_ipc_shm(&shm);
367 : :
368 : 4 : ret = pb_write_one(fd, &shm, PB_IPC_SHM);
369 [ - + ]: 4 : if (ret < 0) {
370 : 0 : pr_err("Failed to write IPC shared memory segment\n");
371 : 0 : return ret;
372 : : }
373 : 4 : return dump_ipc_shm_pages(fd, &shm);
374 : : }
375 : :
376 : 220 : static int dump_ipc_shm(int fd)
377 : : {
378 : : int i, maxid, slot;
379 : : struct shm_info info;
380 : :
381 : 220 : maxid = shmctl(0, SHM_INFO, (void *)&info);
382 [ - + ]: 220 : if (maxid < 0) {
383 : 0 : pr_perror("shmctl(SHM_INFO) failed");
384 : 0 : return -errno;
385 : : }
386 : :
387 : 220 : pr_info("IPC shared memory segments: %d\n", info.used_ids);
388 [ + + ]: 440 : for (i = 0, slot = 0; i <= maxid; i++) {
389 : : struct shmid_ds ds;
390 : : int id, ret;
391 : :
392 : 220 : id = shmctl(i, SHM_STAT, &ds);
393 [ + + ]: 220 : if (id < 0) {
394 [ + - ]: 216 : if (errno == EINVAL)
395 : 216 : continue;
396 : 0 : pr_perror("Failed to get stats for IPC shared memory");
397 : 0 : break;
398 : : }
399 : :
400 : 4 : ret = dump_ipc_shm_seg(fd, id, &ds);
401 [ - + ]: 4 : if (ret < 0)
402 : 0 : return ret;
403 : 4 : slot++;
404 : : }
405 [ - + ]: 220 : if (slot != info.used_ids) {
406 : 0 : pr_err("Failed to collect %d (only %d succeeded)\n",
407 : : info.used_ids, slot);
408 : 0 : return -EFAULT;
409 : : }
410 : : return 0;
411 : : }
412 : :
413 : 220 : static int dump_ipc_var(int fd)
414 : : {
415 : 220 : IpcVarEntry var = IPC_VAR_ENTRY__INIT;
416 : : int ret = -1;
417 : :
418 : 220 : var.n_sem_ctls = 4;
419 [ - + ]: 220 : var.sem_ctls = xmalloc(pb_repeated_size(&var, sem_ctls));
420 [ + - ]: 220 : if (!var.sem_ctls)
421 : : goto err;
422 : :
423 : 220 : ret = ipc_sysctl_req(&var, CTL_READ);
424 [ - + ]: 220 : if (ret < 0) {
425 : 0 : pr_err("Failed to read IPC variables\n");
426 : 0 : goto err;
427 : : }
428 : :
429 : 220 : ret = pb_write_one(fd, &var, PB_IPC_VAR);
430 [ - + ]: 220 : if (ret < 0) {
431 : 0 : pr_err("Failed to write IPC variables\n");
432 : 0 : goto err;
433 : : }
434 : :
435 : : err:
436 [ + - ]: 220 : xfree(var.sem_ctls);
437 : 220 : return ret;
438 : : }
439 : :
440 : 220 : static int dump_ipc_data(const struct cr_fdset *fdset)
441 : : {
442 : : int ret;
443 : :
444 : 220 : ret = dump_ipc_var(fdset_fd(fdset, CR_FD_IPC_VAR));
445 [ + - ]: 220 : if (ret < 0)
446 : : return ret;
447 : 220 : ret = dump_ipc_shm(fdset_fd(fdset, CR_FD_IPCNS_SHM));
448 [ + - ]: 220 : if (ret < 0)
449 : : return ret;
450 : 220 : ret = dump_ipc_msg(fdset_fd(fdset, CR_FD_IPCNS_MSG));
451 [ + - ]: 220 : if (ret < 0)
452 : : return ret;
453 : 220 : ret = dump_ipc_sem(fdset_fd(fdset, CR_FD_IPCNS_SEM));
454 [ - + ]: 220 : if (ret < 0)
455 : 0 : return ret;
456 : : return 0;
457 : : }
458 : :
459 : 220 : int dump_ipc_ns(int ns_pid, int ns_id)
460 : : {
461 : : int ret;
462 : : struct cr_fdset *fdset;
463 : :
464 : 220 : fdset = cr_fdset_open(ns_id, IPCNS, O_DUMP);
465 [ + - ]: 220 : if (fdset == NULL)
466 : : return -1;
467 : :
468 : 220 : ret = switch_ns(ns_pid, &ipc_ns_desc, NULL);
469 [ + - ]: 220 : if (ret < 0)
470 : : goto err;
471 : :
472 : 220 : ret = dump_ipc_data(fdset);
473 [ - + ]: 220 : if (ret < 0) {
474 : 0 : pr_err("Failed to write IPC namespace data\n");
475 : 0 : goto err;
476 : : }
477 : :
478 : : err:
479 : 220 : close_cr_fdset(&fdset);
480 [ + - ]: 220 : return ret < 0 ? -1 : 0;
481 : : }
482 : :
483 : 0 : void ipc_sem_handler(int fd, void *obj)
484 : : {
485 : : IpcSemEntry *e = obj;
486 : : u16 *values;
487 : : int size;
488 : :
489 : 0 : pr_msg("\n");
490 : 0 : size = round_up(sizeof(u16) * e->nsems, sizeof(u64));
491 [ # # ]: 0 : values = xmalloc(size);
492 [ # # ]: 0 : if (values == NULL)
493 : : return;
494 [ # # ]: 0 : if (read_img_buf(fd, values, size) <= 0) {
495 [ # # ]: 0 : xfree(values);
496 : : return;
497 : : }
498 : 0 : pr_msg_ipc_sem_array(e->nsems, values);
499 : : }
500 : :
501 : 0 : static void ipc_msg_data_handler(int fd, void *obj)
502 : : {
503 : : IpcMsg *e = obj;
504 : 0 : print_image_data(fd, round_up(e->msize, sizeof(u64)), opts.show_pages_content);
505 : 0 : }
506 : :
507 : 0 : void ipc_msg_handler(int fd, void *obj)
508 : : {
509 : : IpcMsgEntry *e = obj;
510 : : int msg_nr = 0;
511 : :
512 : 0 : pr_msg("\n");
513 [ # # ]: 0 : while (msg_nr++ < e->qnum)
514 : 0 : pb_show_plain_payload(fd, PB_IPCNS_MSG, ipc_msg_data_handler);
515 : :
516 : 0 : }
517 : :
518 : 0 : void ipc_shm_handler(int fd, void *obj)
519 : : {
520 : : IpcShmEntry *e = obj;
521 : 0 : print_image_data(fd, round_up(e->size, sizeof(u32)), opts.show_pages_content);
522 : 0 : }
523 : :
524 : 8 : static int prepare_ipc_sem_values(int fd, const IpcSemEntry *sem)
525 : : {
526 : : int ret, size;
527 : : u16 *values;
528 : :
529 : 8 : size = round_up(sizeof(u16) * sem->nsems, sizeof(u64));
530 [ - + ]: 8 : values = xmalloc(size);
531 [ - + ]: 8 : if (values == NULL) {
532 : 0 : pr_err("Failed to allocate memory for semaphores set values\n");
533 : : ret = -ENOMEM;
534 : : goto out;
535 : : }
536 : :
537 : 8 : ret = read_img_buf(fd, values, size);
538 [ - + ]: 8 : if (ret < 0) {
539 : 0 : pr_err("Failed to allocate memory for semaphores set values\n");
540 : : ret = -ENOMEM;
541 : : goto out;
542 : : }
543 : :
544 : 8 : pr_info_ipc_sem_array(sem->nsems, values);
545 : :
546 : 8 : ret = semctl(sem->desc->id, 0, SETALL, values);
547 [ - + ]: 8 : if (ret < 0) {
548 : 0 : pr_perror("Failed to set semaphores set values");
549 : 0 : ret = -errno;
550 : : }
551 : : out:
552 [ + - ]: 8 : xfree(values);
553 : 8 : return ret;
554 : : }
555 : :
556 : 8 : static int prepare_ipc_sem_desc(int fd, const IpcSemEntry *sem)
557 : : {
558 : : int ret, id;
559 : 16 : struct sysctl_req req[] = {
560 : 8 : { "kernel/sem_next_id", &sem->desc->id, CTL_U32 },
561 : : { },
562 : : };
563 : : struct semid_ds semid;
564 : :
565 : 8 : ret = sysctl_op(req, CTL_WRITE);
566 [ - + ]: 8 : if (ret < 0) {
567 : 0 : pr_err("Failed to set desired IPC sem ID\n");
568 : 0 : return ret;
569 : : }
570 : :
571 : 8 : id = semget(sem->desc->key, sem->nsems,
572 : 8 : sem->desc->mode | IPC_CREAT | IPC_EXCL);
573 [ - + ]: 8 : if (id == -1) {
574 : 0 : pr_perror("Failed to create sem set");
575 : 0 : return -errno;
576 : : }
577 : :
578 [ - + ]: 8 : if (id != sem->desc->id) {
579 : 0 : pr_err("Failed to restore sem id (%d instead of %d)\n",
580 : : id, sem->desc->id);
581 : 0 : return -EFAULT;
582 : : }
583 : :
584 : 8 : ret = semctl(id, sem->nsems, IPC_STAT, &semid);
585 [ - + ]: 8 : if (ret == -1) {
586 : 0 : pr_err("Failed to get sem stat structure\n");
587 : 0 : return -EFAULT;
588 : : }
589 : :
590 : 8 : semid.sem_perm.uid = sem->desc->uid;
591 : 8 : semid.sem_perm.gid = sem->desc->gid;
592 : :
593 : 8 : ret = semctl(id, sem->nsems, IPC_SET, &semid);
594 [ - + ]: 8 : if (ret == -1) {
595 : 0 : pr_err("Failed to set sem uid and gid\n");
596 : 0 : return -EFAULT;
597 : : }
598 : :
599 : 8 : ret = prepare_ipc_sem_values(fd, sem);
600 [ - + ]: 8 : if (ret < 0) {
601 : 0 : pr_err("Failed to update sem pages\n");
602 : 0 : return ret;
603 : : }
604 : : return 0;
605 : : }
606 : :
607 : 18 : static int prepare_ipc_sem(int pid)
608 : : {
609 : : int fd, ret;
610 : :
611 : 18 : pr_info("Restoring IPC semaphores sets\n");
612 : 18 : fd = open_image(CR_FD_IPCNS_SEM, O_RSTR, pid);
613 [ + - ]: 18 : if (fd < 0)
614 : : return -1;
615 : :
616 : : while (1) {
617 : : IpcSemEntry *sem;
618 : :
619 : 26 : ret = pb_read_one_eof(fd, &sem, PB_IPC_SEM);
620 [ + - ]: 26 : if (ret < 0) {
621 : : ret = -EIO;
622 : 0 : goto err;
623 : : }
624 [ + + ]: 26 : if (ret == 0)
625 : : break;
626 : :
627 : 8 : pr_info_ipc_sem_entry(sem);
628 : :
629 : 8 : ret = prepare_ipc_sem_desc(fd, sem);
630 : 8 : ipc_sem_entry__free_unpacked(sem, NULL);
631 : :
632 [ - + ]: 8 : if (ret < 0) {
633 : 0 : pr_err("Failed to prepare semaphores set\n");
634 : 0 : goto err;
635 : : }
636 : 8 : }
637 : :
638 : 18 : return close_safe(&fd);
639 : : err:
640 : 0 : close_safe(&fd);
641 : 0 : return ret;
642 : : }
643 : :
644 : 4 : static int prepare_ipc_msg_queue_messages(int fd, const IpcMsgEntry *msq)
645 : : {
646 : 4 : IpcMsg *msg = NULL;
647 : : int msg_nr = 0;
648 : : int ret = 0;
649 : :
650 [ + + ]: 12 : while (msg_nr < msq->qnum) {
651 : : struct msgbuf {
652 : : long mtype;
653 : : char mtext[MSGMAX];
654 : : } data;
655 : :
656 : 8 : ret = pb_read_one(fd, &msg, PB_IPCNS_MSG);
657 [ - + ]: 8 : if (ret <= 0)
658 : 0 : return -EIO;
659 : :
660 : 8 : pr_info_ipc_msg(msg_nr, msg);
661 : :
662 [ - + ]: 8 : if (msg->msize > MSGMAX) {
663 : : ret = -1;
664 : 0 : pr_err("Unsupported message size: %d (MAX: %d)\n",
665 : : msg->msize, MSGMAX);
666 : 0 : break;
667 : : }
668 : :
669 : 8 : ret = read_img_buf(fd, data.mtext, round_up(msg->msize, sizeof(u64)));
670 [ - + ]: 8 : if (ret < 0) {
671 : 0 : pr_err("Failed to read IPC message data\n");
672 : : break;
673 : : }
674 : :
675 : 8 : data.mtype = msg->mtype;
676 : 8 : ret = msgsnd(msq->desc->id, &data, msg->msize, IPC_NOWAIT);
677 [ - + ]: 8 : if (ret < 0) {
678 : 0 : pr_perror("Failed to send IPC message");
679 : 0 : ret = -errno;
680 : : break;
681 : : }
682 : 8 : msg_nr++;
683 : : }
684 : :
685 [ + - ]: 4 : if (msg)
686 : 4 : ipc_msg__free_unpacked(msg, NULL);
687 : : return ret;
688 : : }
689 : :
690 : 4 : static int prepare_ipc_msg_queue(int fd, const IpcMsgEntry *msq)
691 : : {
692 : : int ret, id;
693 : 8 : struct sysctl_req req[] = {
694 : 4 : { "kernel/msg_next_id", &msq->desc->id, CTL_U32 },
695 : : { },
696 : : };
697 : : struct msqid_ds msqid;
698 : :
699 : 4 : ret = sysctl_op(req, CTL_WRITE);
700 [ - + ]: 4 : if (ret < 0) {
701 : 0 : pr_err("Failed to set desired IPC msg ID\n");
702 : 0 : return ret;
703 : : }
704 : :
705 : 4 : id = msgget(msq->desc->key, msq->desc->mode | IPC_CREAT | IPC_EXCL);
706 [ - + ]: 4 : if (id == -1) {
707 : 0 : pr_perror("Failed to create msg set");
708 : 0 : return -errno;
709 : : }
710 : :
711 [ - + ]: 4 : if (id != msq->desc->id) {
712 : 0 : pr_err("Failed to restore msg id (%d instead of %d)\n",
713 : : id, msq->desc->id);
714 : 0 : return -EFAULT;
715 : : }
716 : :
717 : 4 : ret = msgctl(id, IPC_STAT, &msqid);
718 [ - + ]: 4 : if (ret == -1) {
719 : 0 : pr_err("Failed to get msq stat structure\n");
720 : 0 : return -EFAULT;
721 : : }
722 : :
723 : 4 : msqid.msg_perm.uid = msq->desc->uid;
724 : 4 : msqid.msg_perm.gid = msq->desc->gid;
725 : :
726 : 4 : ret = msgctl(id, IPC_SET, &msqid);
727 [ - + ]: 4 : if (ret == -1) {
728 : 0 : pr_err("Failed to set msq queue uid and gid\n");
729 : 0 : return -EFAULT;
730 : : }
731 : :
732 : 4 : ret = prepare_ipc_msg_queue_messages(fd, msq);
733 [ - + ]: 4 : if (ret < 0) {
734 : 0 : pr_err("Failed to update message queue messages\n");
735 : 0 : return ret;
736 : : }
737 : : return 0;
738 : : }
739 : :
740 : 18 : static int prepare_ipc_msg(int pid)
741 : : {
742 : : int fd, ret;
743 : :
744 : 18 : pr_info("Restoring IPC message queues\n");
745 : 18 : fd = open_image(CR_FD_IPCNS_MSG, O_RSTR, pid);
746 [ + - ]: 18 : if (fd < 0)
747 : : return -1;
748 : :
749 : : while (1) {
750 : : IpcMsgEntry *msq;
751 : :
752 : 22 : ret = pb_read_one_eof(fd, &msq, PB_IPCNS_MSG_ENT);
753 [ - + ]: 22 : if (ret < 0) {
754 : 0 : pr_err("Failed to read IPC messages queue\n");
755 : : ret = -EIO;
756 : 0 : goto err;
757 : : }
758 [ + + ]: 22 : if (ret == 0)
759 : : break;
760 : :
761 : 4 : pr_info_ipc_msg_entry(msq);
762 : :
763 : 4 : ret = prepare_ipc_msg_queue(fd, msq);
764 : 4 : ipc_msg_entry__free_unpacked(msq, NULL);
765 : :
766 [ - + ]: 4 : if (ret < 0) {
767 : 0 : pr_err("Failed to prepare messages queue\n");
768 : 0 : goto err;
769 : : }
770 : 4 : }
771 : 18 : return close_safe(&fd);
772 : : err:
773 : 0 : close_safe(&fd);
774 : 0 : return ret;
775 : : }
776 : :
777 : 8 : static int prepare_ipc_shm_pages(int fd, const IpcShmEntry *shm)
778 : : {
779 : : int ret;
780 : : void *data;
781 : :
782 : 8 : data = shmat(shm->desc->id, NULL, 0);
783 [ - + ]: 8 : if (data == (void *)-1) {
784 : 0 : pr_perror("Failed to attach IPC shared memory");
785 : 0 : return -errno;
786 : : }
787 : 8 : ret = read_img_buf(fd, data, round_up(shm->size, sizeof(u32)));
788 [ - + ]: 8 : if (ret < 0) {
789 : 0 : pr_err("Failed to read IPC shared memory data\n");
790 : : return ret;
791 : : }
792 [ - + ]: 8 : if (shmdt(data)) {
793 : 0 : pr_perror("Failed to detach IPC shared memory");
794 : 0 : return -errno;
795 : : }
796 : : return 0;
797 : : }
798 : :
799 : 8 : static int prepare_ipc_shm_seg(int fd, const IpcShmEntry *shm)
800 : : {
801 : : int ret, id;
802 : 16 : struct sysctl_req req[] = {
803 : 8 : { "kernel/shm_next_id", &shm->desc->id, CTL_U32 },
804 : : { },
805 : : };
806 : : struct shmid_ds shmid;
807 : :
808 : 8 : ret = sysctl_op(req, CTL_WRITE);
809 [ - + ]: 8 : if (ret < 0) {
810 : 0 : pr_err("Failed to set desired IPC shm ID\n");
811 : 0 : return ret;
812 : : }
813 : :
814 : 8 : id = shmget(shm->desc->key, shm->size,
815 : 8 : shm->desc->mode | IPC_CREAT | IPC_EXCL);
816 [ - + ]: 8 : if (id == -1) {
817 : 0 : pr_perror("Failed to create shm set");
818 : 0 : return -errno;
819 : : }
820 : :
821 [ - + ]: 8 : if (id != shm->desc->id) {
822 : 0 : pr_err("Failed to restore shm id (%d instead of %d)\n",
823 : : id, shm->desc->id);
824 : 0 : return -EFAULT;
825 : : }
826 : :
827 : 8 : ret = shmctl(id, IPC_STAT, &shmid);
828 [ - + ]: 8 : if (ret == -1) {
829 : 0 : pr_err("Failed to get shm stat structure\n");
830 : 0 : return -EFAULT;
831 : : }
832 : :
833 : 8 : shmid.shm_perm.uid = shm->desc->uid;
834 : 8 : shmid.shm_perm.gid = shm->desc->gid;
835 : :
836 : 8 : ret = shmctl(id, IPC_SET, &shmid);
837 [ - + ]: 8 : if (ret == -1) {
838 : 0 : pr_err("Failed to set shm uid and gid\n");
839 : 0 : return -EFAULT;
840 : : }
841 : :
842 : 8 : ret = prepare_ipc_shm_pages(fd, shm);
843 [ - + ]: 8 : if (ret < 0) {
844 : 0 : pr_err("Failed to update shm pages\n");
845 : 0 : return ret;
846 : : }
847 : : return 0;
848 : : }
849 : :
850 : 18 : static int prepare_ipc_shm(int pid)
851 : : {
852 : : int fd, ret;
853 : :
854 : 18 : pr_info("Restoring IPC shared memory\n");
855 : 18 : fd = open_image(CR_FD_IPCNS_SHM, O_RSTR, pid);
856 [ + - ]: 18 : if (fd < 0)
857 : : return -1;
858 : :
859 : : while (1) {
860 : : IpcShmEntry *shm;
861 : :
862 : 26 : ret = pb_read_one_eof(fd, &shm, PB_IPC_SHM);
863 [ - + ]: 26 : if (ret < 0) {
864 : 0 : pr_err("Failed to read IPC shared memory segment\n");
865 : : ret = -EIO;
866 : 0 : goto err;
867 : : }
868 [ + + ]: 26 : if (ret == 0)
869 : : break;
870 : :
871 : 8 : pr_info_ipc_shm(shm);
872 : :
873 : 8 : ret = prepare_ipc_shm_seg(fd, shm);
874 : 8 : ipc_shm_entry__free_unpacked(shm, NULL);
875 : :
876 [ - + ]: 8 : if (ret < 0) {
877 : 0 : pr_err("Failed to prepare shm segment\n");
878 : 0 : goto err;
879 : : }
880 : 8 : }
881 : 18 : return close_safe(&fd);
882 : : err:
883 : 0 : close_safe(&fd);
884 : 0 : return ret;
885 : : }
886 : :
887 : 18 : static int prepare_ipc_var(int pid)
888 : : {
889 : : int fd, ret;
890 : : IpcVarEntry *var;
891 : :
892 : 18 : pr_info("Restoring IPC variables\n");
893 : 18 : fd = open_image(CR_FD_IPC_VAR, O_RSTR, pid);
894 [ + - ]: 18 : if (fd < 0)
895 : : return -1;
896 : :
897 : 18 : ret = pb_read_one(fd, &var, PB_IPC_VAR);
898 : 18 : close_safe(&fd);
899 [ - + ]: 18 : if (ret <= 0) {
900 : 0 : pr_err("Failed to read IPC namespace variables\n");
901 : 0 : return -EFAULT;
902 : : }
903 : :
904 : 18 : ipc_sysctl_req(var, CTL_PRINT);
905 : :
906 : 18 : ret = ipc_sysctl_req(var, CTL_WRITE);
907 : 18 : ipc_var_entry__free_unpacked(var, NULL);
908 : :
909 [ - + ]: 18 : if (ret < 0) {
910 : 0 : pr_err("Failed to prepare IPC namespace variables\n");
911 : 0 : return -EFAULT;
912 : : }
913 : :
914 : : return 0;
915 : : }
916 : :
917 : 18 : int prepare_ipc_ns(int pid)
918 : : {
919 : : int ret;
920 : :
921 : 18 : pr_info("Restoring IPC namespace\n");
922 : 18 : ret = prepare_ipc_var(pid);
923 [ + - ]: 18 : if (ret < 0)
924 : : return ret;
925 : 18 : ret = prepare_ipc_shm(pid);
926 [ + - ]: 18 : if (ret < 0)
927 : : return ret;
928 : 18 : ret = prepare_ipc_msg(pid);
929 [ + - ]: 18 : if (ret < 0)
930 : : return ret;
931 : 18 : ret = prepare_ipc_sem(pid);
932 [ - + ]: 18 : if (ret < 0)
933 : 0 : return ret;
934 : : return 0;
935 : : }
936 : :
937 : : struct ns_desc ipc_ns_desc = NS_DESC_ENTRY(CLONE_NEWIPC, "ipc");
|