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