]> granicus.if.org Git - strace/blob - netlink_sock_diag.c
netlink: add a basic socket diag parser of AF_UNIX messages
[strace] / netlink_sock_diag.c
1 /*
2  * Copyright (c) 2016 Fabien Siron <fabien.siron@epita.fr>
3  * Copyright (c) 2017 JingPiao Chen <chenjingpiao@gmail.com>
4  * Copyright (c) 2017 The strace developers.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. The name of the author may not be used to endorse or promote products
16  *    derived from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #include "defs.h"
31
32 #include <sys/socket.h>
33 #include <linux/netlink.h>
34 #include <linux/unix_diag.h>
35
36 #include "xlat/tcp_states.h"
37 #include "xlat/tcp_state_flags.h"
38
39 #include "xlat/unix_diag_show.h"
40
41 static void
42 decode_family(struct tcb *const tcp, const uint8_t family,
43               const kernel_ulong_t addr, const kernel_ulong_t len)
44 {
45         tprints("{family=");
46         printxval(addrfams, family, "AF_???");
47         if (len > sizeof(family)) {
48                 tprints(", ");
49                 printstrn(tcp, addr + sizeof(family),
50                           len - sizeof(family));
51         }
52         tprints("}");
53 }
54
55 static void
56 decode_unix_diag_req(struct tcb *const tcp,
57                      const struct nlmsghdr *const nlmsghdr,
58                      const uint8_t family,
59                      const kernel_ulong_t addr,
60                      const kernel_ulong_t len)
61 {
62         struct unix_diag_req req = { .sdiag_family = family };
63         const size_t offset = sizeof(req.sdiag_family);
64
65         tprints("{sdiag_family=");
66         printxval(addrfams, req.sdiag_family, "AF_???");
67
68         tprints(", ");
69         if (len >= sizeof(req)) {
70                 if (!umoven_or_printaddr(tcp, addr + offset,
71                                          sizeof(req) - offset,
72                                          (void *) &req + offset)) {
73                         tprintf("sdiag_protocol=%" PRIu8 ", udiag_states=",
74                                 req.sdiag_protocol);
75                         printflags(tcp_state_flags, req.udiag_states,
76                                    "1<<TCP_???");
77                         tprintf(", udiag_ino=%" PRIu32 ", udiag_show=",
78                                 req.udiag_ino);
79                         printflags(unix_diag_show, req.udiag_show,
80                                    "UDIAG_SHOW_???");
81                         tprintf(", udiag_cookie=[%" PRIu32 ", %" PRIu32 "]",
82                                 req.udiag_cookie[0], req.udiag_cookie[1]);
83                 }
84         } else
85                 tprints("...");
86         tprints("}");
87 }
88
89 static void
90 decode_unix_diag_msg(struct tcb *const tcp,
91                      const struct nlmsghdr *const nlmsghdr,
92                      const uint8_t family,
93                      const kernel_ulong_t addr,
94                      const kernel_ulong_t len)
95 {
96         struct unix_diag_msg msg = { .udiag_family = family };
97         const size_t offset = sizeof(msg.udiag_family);
98
99         tprints("{udiag_family=");
100         printxval(addrfams, msg.udiag_family, "AF_???");
101
102         tprints(", ");
103         if (len >= sizeof(msg)) {
104                 if (!umoven_or_printaddr(tcp, addr + offset,
105                                          sizeof(msg) - offset,
106                                          (void *) &msg + offset)) {
107                         tprints("udiag_type=");
108                         printxval(socktypes, msg.udiag_type, "SOCK_???");
109                         tprintf(", udiag_state=");
110                         printxval(tcp_states, msg.udiag_state, "TCP_???");
111                         tprintf(", udiag_ino=%" PRIu32
112                                 ", udiag_cookie=[%" PRIu32 ", %" PRIu32 "]",
113                                 msg.udiag_ino,
114                                 msg.udiag_cookie[0], msg.udiag_cookie[1]);
115                 }
116         } else
117                 tprints("...");
118         tprints("}");
119 }
120
121 typedef void (*netlink_diag_decoder_t)(struct tcb *,
122                                        const struct nlmsghdr *,
123                                        uint8_t family,
124                                        kernel_ulong_t addr,
125                                        kernel_ulong_t len);
126
127 static const struct {
128         const netlink_diag_decoder_t request, response;
129 } diag_decoders[] = {
130         [AF_UNIX] = { decode_unix_diag_req, decode_unix_diag_msg }
131 };
132
133 bool
134 decode_netlink_sock_diag(struct tcb *const tcp,
135                          const struct nlmsghdr *const nlmsghdr,
136                          const kernel_ulong_t addr,
137                          const kernel_ulong_t len)
138 {
139         uint8_t family;
140
141         if (!umove_or_printaddr(tcp, addr, &family)) {
142                 if (family < ARRAY_SIZE(diag_decoders)
143                     && len > sizeof(family)) {
144                         const netlink_diag_decoder_t decoder =
145                                 (nlmsghdr->nlmsg_flags & NLM_F_REQUEST)
146                                 ? diag_decoders[family].request
147                                 : diag_decoders[family].response;
148
149                         if (decoder) {
150                                 decoder(tcp, nlmsghdr, family, addr, len);
151                                 return true;
152                         }
153                 }
154
155                 decode_family(tcp, family, addr, len);
156         }
157
158         return true;
159 }