Branch data Line data Source code
1 : : #include <linux/if_packet.h>
2 : : #include <sys/socket.h>
3 : : #include <linux/netlink.h>
4 : : #include <linux/rtnetlink.h>
5 : : #include <unistd.h>
6 : : #include <string.h>
7 : : #include "asm/types.h"
8 : : #include "fdset.h"
9 : : #include "files.h"
10 : : #include "sockets.h"
11 : : #include "libnetlink.h"
12 : : #include "sk-packet.h"
13 : : #include "packet_diag.h"
14 : : #include "vma.h"
15 : :
16 : : #include "protobuf.h"
17 : : #include "protobuf/packet-sock.pb-c.h"
18 : : #include "protobuf/fdinfo.pb-c.h"
19 : :
20 : : struct packet_sock_info {
21 : : PacketSockEntry *pse;
22 : : struct file_desc d;
23 : : };
24 : :
25 : : struct packet_mreq_max {
26 : : int mr_ifindex;
27 : : unsigned short mr_type;
28 : : unsigned short mr_alen;
29 : : unsigned char mr_address[MAX_ADDR_LEN];
30 : : };
31 : :
32 : : struct packet_sock_desc {
33 : : struct socket_desc sd;
34 : : unsigned int file_id;
35 : : unsigned int type;
36 : : unsigned short proto;
37 : : struct packet_diag_info nli;
38 : : int mreq_n;
39 : : struct packet_diag_mclist *mreqs;
40 : : unsigned int fanout;
41 : : struct packet_diag_ring *rx, *tx;
42 : : };
43 : :
44 : : #define NO_FANOUT ((unsigned int)-1)
45 : :
46 : 8 : static int dump_mreqs(PacketSockEntry *psk, struct packet_sock_desc *sd)
47 : : {
48 : : int i;
49 : :
50 [ + - ]: 8 : if (!sd->mreq_n)
51 : : return 0;
52 : :
53 : 8 : pr_debug("\tdumping %d mreqs\n", sd->mreq_n);
54 [ - + ]: 8 : psk->mclist = xmalloc(sd->mreq_n * sizeof(psk->mclist[0]));
55 [ + - ]: 8 : if (!psk->mclist)
56 : : return -1;
57 : :
58 [ + + ]: 16 : for (i = 0; i < sd->mreq_n; i++) {
59 : 8 : struct packet_diag_mclist *m = &sd->mreqs[i];
60 : : PacketMclist *im;
61 : :
62 [ - + ]: 8 : if (m->pdmc_count != 1) {
63 : 0 : pr_err("Multiple MC membership not supported (but can be)\n");
64 : : goto err;
65 : : }
66 : :
67 : 8 : pr_debug("\tmr%d: idx %d type %d\n", i,
68 : : m->pdmc_index, m->pdmc_type);
69 : :
70 [ - + ]: 8 : im = xmalloc(sizeof(*im));
71 [ + - ]: 8 : if (!im)
72 : : goto err;
73 : :
74 : 8 : packet_mclist__init(im);
75 : 8 : psk->mclist[i] = im;
76 : 8 : psk->n_mclist++;
77 : :
78 : 8 : im->index = m->pdmc_index;
79 : 8 : im->type = m->pdmc_type;
80 : :
81 [ + - + ]: 8 : switch (m->pdmc_type) {
82 : : case PACKET_MR_MULTICAST:
83 : : case PACKET_MR_UNICAST:
84 : 4 : im->addr.len = m->pdmc_alen;
85 [ - + ]: 4 : im->addr.data = xmalloc(m->pdmc_alen);
86 [ + - ]: 4 : if (!im->addr.data)
87 : : goto err;
88 : :
89 : 4 : memcpy(im->addr.data, m->pdmc_addr, m->pdmc_alen);
90 : : break;
91 : : case PACKET_MR_PROMISC:
92 : : case PACKET_MR_ALLMULTI:
93 : : break;
94 : : default:
95 : 0 : pr_err("Unknown mc membership type %d\n", m->pdmc_type);
96 : : goto err;
97 : : }
98 : : }
99 : :
100 : : return 0;
101 : : err:
102 : : return -1;
103 : : }
104 : :
105 : 8 : static PacketRing *dump_ring(struct packet_diag_ring *dr)
106 : : {
107 : : PacketRing *ring;
108 : :
109 [ - + ]: 8 : ring = xmalloc(sizeof(*ring));
110 [ + - ]: 8 : if (!ring)
111 : : return NULL;
112 : :
113 : 8 : packet_ring__init(ring);
114 : :
115 : 8 : ring->block_size = dr->pdr_block_size;
116 : 8 : ring->block_nr = dr->pdr_block_nr;
117 : 8 : ring->frame_size = dr->pdr_frame_size;
118 : 8 : ring->frame_nr = dr->pdr_frame_nr;
119 : 8 : ring->retire_tmo = dr->pdr_retire_tmo;
120 : 8 : ring->sizeof_priv = dr->pdr_sizeof_priv;
121 : 8 : ring->features = dr->pdr_features;
122 : :
123 : 8 : return ring;
124 : : }
125 : :
126 : 16 : static int dump_rings(PacketSockEntry *psk, struct packet_sock_desc *sd)
127 : : {
128 [ + + ]: 8 : if (sd->rx) {
129 : 4 : psk->rx_ring = dump_ring(sd->rx);
130 [ + - ]: 4 : if (!psk->rx_ring)
131 : : return -1;
132 : : }
133 : :
134 [ + + ]: 8 : if (sd->tx) {
135 : 4 : psk->tx_ring = dump_ring(sd->tx);
136 [ + - ]: 4 : if (!psk->tx_ring)
137 : : return -1;
138 : : }
139 : :
140 : : return 0;
141 : : }
142 : :
143 : 8 : static int dump_one_packet_fd(int lfd, u32 id, const struct fd_parms *p)
144 : : {
145 : 8 : PacketSockEntry psk = PACKET_SOCK_ENTRY__INIT;
146 : 8 : SkOptsEntry skopts = SK_OPTS_ENTRY__INIT;
147 : 8 : struct packet_sock_desc *sd;
148 : : int i, ret;
149 : :
150 : 8 : sd = (struct packet_sock_desc *)lookup_socket(p->stat.st_ino, PF_PACKET, 0);
151 [ - + ]: 8 : if (IS_ERR_OR_NULL(sd)) {
152 : 0 : pr_err("Can't find packet socket %"PRIu64"\n", p->stat.st_ino);
153 : 0 : return -1;
154 : : }
155 : :
156 : 8 : pr_info("Dumping packet socket fd %d id %#x\n", lfd, id);
157 [ - + ]: 8 : BUG_ON(sd->sd.already_dumped);
158 : 8 : sd->sd.already_dumped = 1;
159 : :
160 : 8 : psk.id = sd->file_id = id;
161 : 8 : psk.type = sd->type;
162 : 8 : psk.flags = p->flags;
163 : 8 : psk.fown = (FownEntry *)&p->fown;
164 : 8 : psk.opts = &skopts;
165 : :
166 [ + - ]: 8 : if (dump_socket_opts(lfd, &skopts))
167 : : return -1;
168 : :
169 : 8 : psk.protocol = sd->proto;
170 : 8 : psk.ifindex = sd->nli.pdi_index;
171 : 8 : psk.version = sd->nli.pdi_version;
172 : 8 : psk.reserve = sd->nli.pdi_reserve;
173 : 8 : psk.timestamp = sd->nli.pdi_tstamp;
174 : 8 : psk.copy_thresh = sd->nli.pdi_copy_thresh;
175 : 8 : psk.aux_data = (sd->nli.pdi_flags & PDI_AUXDATA ? true : false);
176 : 8 : psk.orig_dev = (sd->nli.pdi_flags & PDI_ORIGDEV ? true : false);
177 : 8 : psk.vnet_hdr = (sd->nli.pdi_flags & PDI_VNETHDR ? true : false);
178 : 8 : psk.loss = (sd->nli.pdi_flags & PDI_LOSS ? true : false);
179 : :
180 : 8 : ret = dump_mreqs(&psk, sd);
181 [ + - ]: 8 : if (ret)
182 : : goto out;
183 : :
184 [ + + ]: 8 : if (sd->fanout != NO_FANOUT) {
185 : 4 : psk.has_fanout = true;
186 : 4 : psk.fanout = sd->fanout;
187 : : }
188 : :
189 : 8 : ret = dump_rings(&psk, sd);
190 [ + - ]: 8 : if (ret)
191 : : goto out;
192 : :
193 : 8 : ret = pb_write_one(fdset_fd(glob_fdset, CR_FD_PACKETSK), &psk, PB_PACKET_SOCK);
194 : : out:
195 : 8 : release_skopts(&skopts);
196 [ + + ]: 8 : xfree(psk.rx_ring);
197 [ + + ]: 8 : xfree(psk.tx_ring);
198 [ + + ]: 16 : for (i = 0; i < psk.n_mclist; i++)
199 [ + + ]: 8 : xfree(psk.mclist[i]->addr.data);
200 [ + - ]: 8 : xfree(psk.mclist);
201 : 8 : return ret;
202 : : }
203 : :
204 : : const struct fdtype_ops packet_dump_ops = {
205 : : .type = FD_TYPES__PACKETSK,
206 : : .dump = dump_one_packet_fd,
207 : : };
208 : :
209 : 0 : int dump_socket_map(struct vma_area *vma)
210 : : {
211 : : struct packet_sock_desc *sd;
212 : :
213 : 0 : sd = (struct packet_sock_desc *)lookup_socket(vma->vm_socket_id, PF_PACKET, 0);
214 [ # # ]: 0 : if (IS_ERR_OR_NULL(sd)) {
215 : 0 : pr_err("Can't find packet socket %u to mmap\n", vma->vm_socket_id);
216 : 0 : return -1;
217 : : }
218 : :
219 [ # # ]: 0 : if (!sd->file_id) {
220 : 0 : pr_err("Mmap-ed socket %u not open\n", vma->vm_socket_id);
221 : 0 : return -1;
222 : : }
223 : :
224 : 0 : pr_info("Dumping socket map %x -> %"PRIx64"\n", sd->file_id, vma->e->start);
225 : 0 : vma->e->shmid = sd->file_id;
226 : 0 : return 0;
227 : : }
228 : :
229 : 952 : static int packet_save_mreqs(struct packet_sock_desc *sd, struct rtattr *mc)
230 : : {
231 : 952 : sd->mreq_n = RTA_PAYLOAD(mc) / sizeof(struct packet_diag_mclist);
232 : 952 : pr_debug("\tGot %d mreqs\n", sd->mreq_n);
233 [ - + ]: 952 : sd->mreqs = xmalloc(RTA_PAYLOAD(mc));
234 [ + - ]: 952 : if (!sd->mreqs)
235 : : return -1;
236 : :
237 : 952 : memcpy(sd->mreqs, RTA_DATA(mc), RTA_PAYLOAD(mc));
238 : : return 0;
239 : : }
240 : :
241 : 952 : int packet_receive_one(struct nlmsghdr *hdr, void *arg)
242 : : {
243 : : struct packet_diag_msg *m;
244 : : struct rtattr *tb[PACKET_DIAG_MAX + 1];
245 : : struct packet_sock_desc *sd;
246 : :
247 : : m = NLMSG_DATA(hdr);
248 : 952 : parse_rtattr(tb, PACKET_DIAG_MAX, (struct rtattr *)(m + 1),
249 : 952 : hdr->nlmsg_len - NLMSG_LENGTH(sizeof(*m)));
250 : 952 : pr_info("Collect packet sock %u %u\n", m->pdiag_ino, (unsigned int)m->pdiag_num);
251 : :
252 [ - + ]: 952 : if (!tb[PACKET_DIAG_INFO]) {
253 : 0 : pr_err("No packet sock info in nlm\n");
254 : 0 : return -1;
255 : : }
256 : :
257 [ - + ]: 952 : if (!tb[PACKET_DIAG_MCLIST]) {
258 : 0 : pr_err("No packet sock mclist in nlm\n");
259 : 0 : return -1;
260 : : }
261 : :
262 [ - + ]: 952 : sd = xmalloc(sizeof(*sd));
263 [ + - ]: 952 : if (!sd)
264 : : return -1;
265 : :
266 : 952 : sd->file_id = 0;
267 : 952 : sd->type = m->pdiag_type;
268 [ - + ]: 952 : sd->proto = htons(m->pdiag_num);
269 : 952 : sd->rx = NULL;
270 : 952 : sd->tx = NULL;
271 : 952 : memcpy(&sd->nli, RTA_DATA(tb[PACKET_DIAG_INFO]), sizeof(sd->nli));
272 : :
273 [ + - ]: 952 : if (packet_save_mreqs(sd, tb[PACKET_DIAG_MCLIST]))
274 : : goto err;
275 : :
276 [ + + ]: 952 : if (tb[PACKET_DIAG_FANOUT])
277 : 4 : sd->fanout = *(__u32 *)RTA_DATA(tb[PACKET_DIAG_FANOUT]);
278 : : else
279 : 948 : sd->fanout = NO_FANOUT;
280 : :
281 [ + + ]: 952 : if (tb[PACKET_DIAG_RX_RING]) {
282 [ - + ]: 4 : sd->rx = xmalloc(sizeof(*sd->rx));
283 [ + - ]: 4 : if (sd->rx == NULL)
284 : : goto err;
285 : 4 : memcpy(sd->rx, RTA_DATA(tb[PACKET_DIAG_RX_RING]), sizeof(*sd->rx));
286 : : }
287 : :
288 [ + + ]: 952 : if (tb[PACKET_DIAG_TX_RING]) {
289 [ - + ]: 4 : sd->tx = xmalloc(sizeof(*sd->tx));
290 [ + - ]: 4 : if (sd->tx == NULL)
291 : : goto err;
292 : 4 : memcpy(sd->tx, RTA_DATA(tb[PACKET_DIAG_TX_RING]), sizeof(*sd->tx));
293 : : }
294 : :
295 : 952 : return sk_collect_one(m->pdiag_ino, PF_PACKET, &sd->sd);
296 : : err:
297 [ # # ]: 0 : xfree(sd->tx);
298 [ # # ]: 0 : xfree(sd->rx);
299 [ # # ]: 0 : xfree(sd);
300 : : return -1;
301 : : }
302 : :
303 : 0 : int get_socket_fd(int pid, VmaEntry *vma)
304 : : {
305 : : struct file_desc *fd;
306 : : struct fdinfo_list_entry *le;
307 : :
308 : 0 : pr_info("Getting packet socket fd for %d:%x\n",
309 : : pid, (int)vma->shmid);
310 : 0 : fd = find_file_desc_raw(FD_TYPES__PACKETSK, vma->shmid);
311 [ # # ]: 0 : if (!fd) {
312 : 0 : pr_err("No packet socket %x\n", (int)vma->shmid);
313 : 0 : return -1;
314 : : }
315 : :
316 [ # # ]: 0 : list_for_each_entry(le, &fd->fd_info_head, desc_list)
317 [ # # ]: 0 : if (le->pid == pid) {
318 : : int fd;
319 : :
320 : : /*
321 : : * Restorer will close the mmap-ed fd
322 : : */
323 : :
324 : 0 : fd = dup(le->fe->fd);
325 [ # # ]: 0 : if (!fd) {
326 : 0 : pr_perror("Can't dup packet sk");
327 : 0 : return -1;
328 : : }
329 : :
330 : : return fd;
331 : : }
332 : :
333 : 0 : pr_err("No open packet socket %x by %d\n", (int)vma->shmid, pid);
334 : 0 : return -1;
335 : : }
336 : :
337 : 8 : static int restore_mreqs(int sk, PacketSockEntry *pse)
338 : : {
339 : : int i;
340 : :
341 [ + + ]: 8 : for (i = 0; i < pse->n_mclist; i++) {
342 : : PacketMclist *ml;
343 : : struct packet_mreq_max mreq;
344 : :
345 : 4 : ml = pse->mclist[i];
346 : 4 : pr_info("Restoring mreq type %d\n", ml->type);
347 : :
348 [ - + ]: 4 : if (ml->addr.len > sizeof(mreq.mr_address)) {
349 : 0 : pr_err("To big mcaddr %zu\n", ml->addr.len);
350 : 0 : return -1;
351 : : }
352 : :
353 : 4 : mreq.mr_ifindex = ml->index;
354 : 4 : mreq.mr_type = ml->type;
355 : 4 : mreq.mr_alen = ml->addr.len;
356 : 4 : memcpy(mreq.mr_address, ml->addr.data, ml->addr.len);
357 : :
358 [ + - ]: 4 : if (restore_opt(sk, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq))
359 : : return -1;
360 : : }
361 : :
362 : : return 0;
363 : : }
364 : :
365 : 8 : static int restore_ring(int sk, int type, PacketRing *ring)
366 : : {
367 : : struct tpacket_req3 req;
368 : :
369 [ + + ]: 8 : if (!ring)
370 : : return 0;
371 : :
372 : 4 : pr_debug("\tRestoring %d ring\n", type);
373 : :
374 : 4 : req.tp_block_size = ring->block_size;
375 : 4 : req.tp_block_nr = ring->block_nr;
376 : 4 : req.tp_frame_size = ring->frame_size;
377 : 4 : req.tp_frame_nr = ring->frame_nr;
378 : 4 : req.tp_retire_blk_tov = ring->retire_tmo;
379 : 4 : req.tp_sizeof_priv = ring->sizeof_priv;
380 : 4 : req.tp_feature_req_word = ring->features;
381 : :
382 : 4 : return restore_opt(sk, SOL_PACKET, type, &req);
383 : : }
384 : :
385 : 8 : static int restore_rings(int sk, PacketSockEntry *psk)
386 : : {
387 [ + - ]: 4 : if (restore_ring(sk, PACKET_RX_RING, psk->rx_ring))
388 : : return -1;
389 : :
390 [ + - ]: 4 : if (restore_ring(sk, PACKET_TX_RING, psk->tx_ring))
391 : : return -1;
392 : :
393 : : return 0;
394 : : }
395 : :
396 : 4 : static int open_packet_sk(struct file_desc *d)
397 : : {
398 : : struct packet_sock_info *psi;
399 : 4 : PacketSockEntry *pse;
400 : : struct sockaddr_ll addr;
401 : : int sk, yes;
402 : :
403 : : psi = container_of(d, struct packet_sock_info, d);
404 : 4 : pse = psi->pse;
405 : :
406 : 4 : pr_info("Opening packet socket id %#x\n", pse->id);
407 : :
408 : 4 : sk = socket(PF_PACKET, pse->type, pse->protocol);
409 [ - + ]: 4 : if (sk < 0) {
410 : 0 : pr_perror("Can't create packet sock");
411 : 0 : goto err;
412 : : }
413 : :
414 : : memset(&addr, 0, sizeof(addr));
415 : 4 : addr.sll_family = AF_PACKET;
416 : 4 : addr.sll_ifindex = pse->ifindex;
417 : :
418 [ - + ]: 4 : if (bind(sk, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
419 : 0 : pr_perror("Can't bind packet socket");
420 : 0 : goto err_cl;
421 : : }
422 : :
423 [ + - ]: 4 : if (restore_opt(sk, SOL_PACKET, PACKET_VERSION, &pse->version))
424 : : goto err_cl;
425 : :
426 [ + - ]: 4 : if (restore_opt(sk, SOL_PACKET, PACKET_RESERVE, &pse->reserve))
427 : : goto err_cl;
428 : :
429 [ + - ]: 4 : if (restore_opt(sk, SOL_PACKET, PACKET_TIMESTAMP, &pse->timestamp))
430 : : goto err_cl;
431 : :
432 [ + - ]: 4 : if (restore_opt(sk, SOL_PACKET, PACKET_COPY_THRESH, &pse->copy_thresh))
433 : : goto err_cl;
434 : :
435 [ + + ]: 4 : if (pse->aux_data) {
436 : 2 : yes = 1;
437 [ + - ]: 2 : if (restore_opt(sk, SOL_PACKET, PACKET_AUXDATA, &yes))
438 : : goto err_cl;
439 : : }
440 : :
441 [ + + ]: 4 : if (pse->orig_dev) {
442 : 2 : yes = 1;
443 [ + - ]: 2 : if (restore_opt(sk, SOL_PACKET, PACKET_ORIGDEV, &yes))
444 : : goto err_cl;
445 : : }
446 : :
447 [ - + ]: 4 : if (pse->vnet_hdr) {
448 : 0 : yes = 1;
449 [ # # ]: 0 : if (restore_opt(sk, SOL_PACKET, PACKET_VNET_HDR, &yes))
450 : : goto err_cl;
451 : : }
452 : :
453 [ - + ]: 4 : if (pse->loss) {
454 : 0 : yes = 1;
455 [ # # ]: 0 : if (restore_opt(sk, SOL_PACKET, PACKET_LOSS, &yes))
456 : : goto err_cl;
457 : : }
458 : :
459 [ + - ]: 4 : if (restore_mreqs(sk, pse))
460 : : goto err_cl;
461 : :
462 [ + - ]: 4 : if (restore_rings(sk, pse))
463 : : goto err_cl;
464 : :
465 [ + + ]: 4 : if (pse->has_fanout) {
466 : 2 : pr_info("Restoring fanout %x\n", pse->fanout);
467 [ + - ]: 2 : if (restore_opt(sk, SOL_PACKET, PACKET_FANOUT, &pse->fanout))
468 : : goto err_cl;
469 : : }
470 : :
471 [ + - ]: 4 : if (rst_file_params(sk, pse->fown, pse->flags))
472 : : goto err_cl;
473 : :
474 [ - + ]: 4 : if (restore_socket_opts(sk, pse->opts))
475 : : goto err_cl;
476 : :
477 : : return sk;
478 : :
479 : : err_cl:
480 : 0 : close(sk);
481 : : err:
482 : : return -1;
483 : : }
484 : :
485 : : static struct file_desc_ops packet_sock_desc_ops = {
486 : : .type = FD_TYPES__PACKETSK,
487 : : .open = open_packet_sk,
488 : : };
489 : :
490 : 4 : static int collect_one_packet_sk(void *o, ProtobufCMessage *base)
491 : : {
492 : : struct packet_sock_info *si = o;
493 : :
494 : 4 : si->pse = pb_msg(base, PacketSockEntry);
495 : 4 : return file_desc_add(&si->d, si->pse->id, &packet_sock_desc_ops);
496 : : }
497 : :
498 : : struct collect_image_info packet_sk_cinfo = {
499 : : .fd_type = CR_FD_PACKETSK,
500 : : .pb_type = PB_PACKET_SOCK,
501 : : .priv_size = sizeof(struct packet_sock_info),
502 : : .collect = collect_one_packet_sk,
503 : : .flags = COLLECT_OPTIONAL,
504 : : };
|