1 /*
2 * Copyright (c) 2016 Fabien Siron <fabien.siron@epita.fr>
3 * Copyright (c) 2017 JingPiao Chen <chenjingpiao@gmail.com>
4 * Copyright (c) 2017-2021 The strace developers.
5 * All rights reserved.
6 *
7 * SPDX-License-Identifier: LGPL-2.1-or-later
8 */
9
10 #include "defs.h"
11 #include "netlink.h"
12 #include "netlink_sock_diag.h"
13 #include "nlattr.h"
14
15 #include <linux/sock_diag.h>
16 #include <linux/unix_diag.h>
17
18 #include "xlat/unix_diag_attrs.h"
19 #include "xlat/unix_diag_show.h"
20
21 DECL_NETLINK_DIAG_DECODER(decode_unix_diag_req)
22 {
23 struct unix_diag_req req = { .sdiag_family = family };
24 const size_t offset = sizeof(req.sdiag_family);
25
26 tprint_struct_begin();
27 PRINT_FIELD_XVAL(req, sdiag_family, addrfams, "AF_???");
28 tprint_struct_next();
29
30 if (len >= sizeof(req)) {
31 if (!umoven_or_printaddr(tcp, addr + offset,
32 sizeof(req) - offset,
33 (char *) &req + offset)) {
34 PRINT_FIELD_U(req, sdiag_protocol);
35 tprint_struct_next();
36 PRINT_FIELD_FLAGS(req, udiag_states,
37 tcp_state_flags, "1<<TCP_???");
38 tprint_struct_next();
39 PRINT_FIELD_U(req, udiag_ino);
40 tprint_struct_next();
41 PRINT_FIELD_FLAGS(req, udiag_show,
42 unix_diag_show, "UDIAG_SHOW_???");
43 tprint_struct_next();
44 PRINT_FIELD_COOKIE(req, udiag_cookie);
45 }
46 } else
47 tprint_more_data_follows();
48 tprint_struct_end();
49 }
50
51 static bool
52 decode_unix_diag_vfs(struct tcb *const tcp,
53 const kernel_ulong_t addr,
54 const unsigned int len,
55 const void *const opaque_data)
56 {
57 struct unix_diag_vfs uv;
58
59 if (len < sizeof(uv))
60 return false;
61 if (umove_or_printaddr(tcp, addr, &uv))
62 return true;
63
64 tprint_struct_begin();
65 PRINT_FIELD_DEV(uv, udiag_vfs_dev);
66 tprint_struct_next();
67 PRINT_FIELD_U(uv, udiag_vfs_ino);
68 tprint_struct_end();
69
70 return true;
71 }
72
73 static bool
74 print_inode(struct tcb *const tcp,
75 void *const elem_buf,
76 const size_t elem_size,
77 void *const opaque_data)
78 {
79 PRINT_VAL_U(*(uint32_t *) elem_buf);
80
81 return true;
82 }
83
84 static bool
85 decode_unix_diag_inode(struct tcb *const tcp,
86 const kernel_ulong_t addr,
87 const unsigned int len,
88 const void *const opaque_data)
89 {
90 uint32_t inode;
91 const size_t nmemb = len / sizeof(inode);
92
93 if (!nmemb)
94 return false;
95
96 print_array(tcp, addr, nmemb, &inode, sizeof(inode),
97 tfetch_mem, print_inode, 0);
98
99 return true;
100 }
101
102 static bool
103 decode_unix_diag_rqlen(struct tcb *const tcp,
104 const kernel_ulong_t addr,
105 const unsigned int len,
106 const void *const opaque_data)
107 {
108 struct unix_diag_rqlen rql;
109
110 if (len < sizeof(rql))
111 return false;
112 if (umove_or_printaddr(tcp, addr, &rql))
113 return true;
114
115 tprint_struct_begin();
116 PRINT_FIELD_U(rql, udiag_rqueue);
117 tprint_struct_next();
118 PRINT_FIELD_U(rql, udiag_wqueue);
119 tprint_struct_end();
120
121 return true;
122 }
123
124 static const nla_decoder_t unix_diag_msg_nla_decoders[] = {
125 [UNIX_DIAG_NAME] = decode_nla_str,
126 [UNIX_DIAG_VFS] = decode_unix_diag_vfs,
127 [UNIX_DIAG_PEER] = decode_nla_u32,
128 [UNIX_DIAG_ICONS] = decode_unix_diag_inode,
129 [UNIX_DIAG_RQLEN] = decode_unix_diag_rqlen,
130 [UNIX_DIAG_MEMINFO] = decode_nla_meminfo,
131 [UNIX_DIAG_SHUTDOWN] = decode_nla_u8,
132 [UNIX_DIAG_UID] = decode_nla_uid
133 };
134
135 DECL_NETLINK_DIAG_DECODER(decode_unix_diag_msg)
136 {
137 struct unix_diag_msg msg = { .udiag_family = family };
138 size_t offset = sizeof(msg.udiag_family);
139 bool decode_nla = false;
140
141 tprint_struct_begin();
142 PRINT_FIELD_XVAL(msg, udiag_family, addrfams, "AF_???");
143 tprint_struct_next();
144
145 if (len >= sizeof(msg)) {
146 if (!umoven_or_printaddr(tcp, addr + offset,
147 sizeof(msg) - offset,
148 (char *) &msg + offset)) {
149 PRINT_FIELD_XVAL(msg, udiag_type,
150 socktypes, "SOCK_???");
151 tprint_struct_next();
152 PRINT_FIELD_XVAL(msg, udiag_state,
153 tcp_states, "TCP_???");
154 tprint_struct_next();
155 PRINT_FIELD_U(msg, udiag_ino);
156 tprint_struct_next();
157 PRINT_FIELD_COOKIE(msg, udiag_cookie);
158 decode_nla = true;
159 }
160 } else
161 tprint_more_data_follows();
162 tprint_struct_end();
163
164 offset = NLMSG_ALIGN(sizeof(msg));
165 if (decode_nla && len > offset) {
166 tprint_array_next();
167 decode_nlattr(tcp, addr + offset, len - offset,
168 unix_diag_attrs, "UNIX_DIAG_???",
169 unix_diag_msg_nla_decoders,
170 ARRAY_SIZE(unix_diag_msg_nla_decoders), NULL);
171 }
172 }