1 /* 2 * Check decoding of netlink attribute. 3 * 4 * Copyright (c) 2017 JingPiao Chen <chenjingpiao (at) gmail.com> 5 * Copyright (c) 2017-2018 The strace developers. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. The name of the author may not be used to endorse or promote products 17 * derived from this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include "tests.h" 32 33 #include <stdio.h> 34 #include <stdint.h> 35 #include <string.h> 36 #include <unistd.h> 37 #include <sys/socket.h> 38 #include <netinet/tcp.h> 39 #include "netlink.h" 40 #include <linux/rtnetlink.h> 41 #include <linux/sock_diag.h> 42 #include <linux/unix_diag.h> 43 44 static void 45 test_nlattr(const int fd) 46 { 47 static const struct msg { 48 struct nlmsghdr nlh; 49 struct unix_diag_msg udm; 50 } c_msg = { 51 .nlh = { 52 .nlmsg_len = sizeof(struct msg), 53 .nlmsg_type = SOCK_DIAG_BY_FAMILY, 54 .nlmsg_flags = NLM_F_DUMP 55 }, 56 .udm = { 57 .udiag_family = AF_UNIX, 58 .udiag_type = SOCK_STREAM, 59 .udiag_state = TCP_FIN_WAIT1 60 } 61 }; 62 struct msg *msg; 63 struct nlattr *nla; 64 unsigned int msg_len; 65 long rc; 66 67 /* fetch fail: len < sizeof(struct nlattr) */ 68 msg_len = NLMSG_SPACE(sizeof(msg->udm)) + 2; 69 msg = tail_memdup(&c_msg, msg_len); 70 memcpy(&msg->nlh.nlmsg_len, &msg_len, sizeof(msg_len)); 71 nla = NLMSG_ATTR(msg, sizeof(msg->udm)); 72 memcpy(nla, "12", 2); 73 rc = sendto(fd, msg, msg_len, MSG_DONTWAIT, NULL, 0); 74 printf("sendto(%d, {{len=%u, type=SOCK_DIAG_BY_FAMILY" 75 ", flags=NLM_F_DUMP, seq=0, pid=0}, {udiag_family=AF_UNIX" 76 ", udiag_type=SOCK_STREAM, udiag_state=TCP_FIN_WAIT1" 77 ", udiag_ino=0, udiag_cookie=[0, 0]}, \"\\x31\\x32\"}, %u" 78 ", MSG_DONTWAIT, NULL, 0) = %s\n", 79 fd, msg_len, msg_len, sprintrc(rc)); 80 81 /* fetch fail: short read */ 82 msg_len = NLMSG_SPACE(sizeof(msg->udm)) + sizeof(*nla); 83 msg = tail_memdup(&c_msg, msg_len - 1); 84 memcpy(&msg->nlh.nlmsg_len, &msg_len, sizeof(msg_len)); 85 rc = sendto(fd, msg, msg_len, MSG_DONTWAIT, NULL, 0); 86 printf("sendto(%d, {{len=%u, type=SOCK_DIAG_BY_FAMILY" 87 ", flags=NLM_F_DUMP, seq=0, pid=0}, {udiag_family=AF_UNIX" 88 ", udiag_type=SOCK_STREAM, udiag_state=TCP_FIN_WAIT1" 89 ", udiag_ino=0, udiag_cookie=[0, 0]}, %p}, %u" 90 ", MSG_DONTWAIT, NULL, 0) = %s\n", 91 fd, msg_len, (void *) msg + NLMSG_SPACE(sizeof(msg->udm)), 92 msg_len, sprintrc(rc)); 93 94 /* print one struct nlattr */ 95 msg_len = NLMSG_SPACE(sizeof(msg->udm)) + sizeof(*nla); 96 msg = tail_memdup(&c_msg, msg_len); 97 memcpy(&msg->nlh.nlmsg_len, &msg_len, sizeof(msg_len)); 98 nla = NLMSG_ATTR(msg, sizeof(msg->udm)); 99 *nla = (struct nlattr) { 100 .nla_len = sizeof(*nla), 101 .nla_type = UNIX_DIAG_NAME 102 }; 103 rc = sendto(fd, msg, msg_len, MSG_DONTWAIT, NULL, 0); 104 printf("sendto(%d, {{len=%u, type=SOCK_DIAG_BY_FAMILY" 105 ", flags=NLM_F_DUMP, seq=0, pid=0}, {udiag_family=AF_UNIX" 106 ", udiag_type=SOCK_STREAM, udiag_state=TCP_FIN_WAIT1" 107 ", udiag_ino=0, udiag_cookie=[0, 0]}, {nla_len=%u" 108 ", nla_type=UNIX_DIAG_NAME}}, %u, MSG_DONTWAIT, NULL, 0) = %s\n", 109 fd, msg_len, nla->nla_len, msg_len, sprintrc(rc)); 110 111 /* print one struct nlattr with nla_len out of msg_len bounds */ 112 nla->nla_len += 8; 113 rc = sendto(fd, msg, msg_len, MSG_DONTWAIT, NULL, 0); 114 printf("sendto(%d, {{len=%u, type=SOCK_DIAG_BY_FAMILY" 115 ", flags=NLM_F_DUMP, seq=0, pid=0}, {udiag_family=AF_UNIX" 116 ", udiag_type=SOCK_STREAM, udiag_state=TCP_FIN_WAIT1" 117 ", udiag_ino=0, udiag_cookie=[0, 0]}, {nla_len=%u" 118 ", nla_type=UNIX_DIAG_NAME}}, %u, MSG_DONTWAIT, NULL, 0) = %s\n", 119 fd, msg_len, nla->nla_len, msg_len, sprintrc(rc)); 120 121 /* print one struct nlattr and some data */ 122 msg_len = NLMSG_SPACE(sizeof(msg->udm)) + NLA_HDRLEN + 4; 123 msg = tail_memdup(&c_msg, msg_len); 124 memcpy(&msg->nlh.nlmsg_len, &msg_len, sizeof(msg_len)); 125 nla = NLMSG_ATTR(msg, sizeof(msg->udm)); 126 *nla = (struct nlattr) { 127 .nla_len = NLA_HDRLEN + 4, 128 .nla_type = UNIX_DIAG_SHUTDOWN + 1 129 }; 130 memcpy(RTA_DATA(nla), "1234", 4); 131 rc = sendto(fd, msg, msg_len, MSG_DONTWAIT, NULL, 0); 132 printf("sendto(%d, {{len=%u, type=SOCK_DIAG_BY_FAMILY" 133 ", flags=NLM_F_DUMP, seq=0, pid=0}, {udiag_family=AF_UNIX" 134 ", udiag_type=SOCK_STREAM, udiag_state=TCP_FIN_WAIT1" 135 ", udiag_ino=0, udiag_cookie=[0, 0]}, {{nla_len=%u" 136 ", nla_type=%#x /* UNIX_DIAG_??? */}" 137 ", \"\\x31\\x32\\x33\\x34\"}}" 138 ", %u, MSG_DONTWAIT, NULL, 0) = %s\n", 139 fd, msg_len, nla->nla_len, UNIX_DIAG_SHUTDOWN + 1, 140 msg_len, sprintrc(rc)); 141 142 /* print one struct nlattr and fetch fail second struct nlattr */ 143 msg_len = NLMSG_SPACE(sizeof(msg->udm)) + NLA_HDRLEN + 2; 144 msg = tail_memdup(&c_msg, msg_len); 145 memcpy(&msg->nlh.nlmsg_len, &msg_len, sizeof(msg_len)); 146 nla = NLMSG_ATTR(msg, sizeof(msg->udm)); 147 SET_STRUCT(struct nlattr, nla, 148 .nla_len = NLA_HDRLEN, 149 .nla_type = UNIX_DIAG_NAME 150 ); 151 memcpy(nla + 1, "12", 2); 152 rc = sendto(fd, msg, msg_len, MSG_DONTWAIT, NULL, 0); 153 printf("sendto(%d, {{len=%u, type=SOCK_DIAG_BY_FAMILY" 154 ", flags=NLM_F_DUMP, seq=0, pid=0}, {udiag_family=AF_UNIX" 155 ", udiag_type=SOCK_STREAM, udiag_state=TCP_FIN_WAIT1" 156 ", udiag_ino=0, udiag_cookie=[0, 0]}, [{nla_len=%u" 157 ", nla_type=UNIX_DIAG_NAME}, \"\\x31\\x32\"]}, %u" 158 ", MSG_DONTWAIT, NULL, 0) = %s\n", 159 fd, msg_len, NLA_HDRLEN, msg_len, sprintrc(rc)); 160 161 /* print one struct nlattr and short read of second struct nlattr */ 162 msg_len = NLMSG_SPACE(sizeof(msg->udm)) + NLA_HDRLEN * 2; 163 msg = tail_memdup(&c_msg, msg_len - 1); 164 memcpy(&msg->nlh.nlmsg_len, &msg_len, sizeof(msg_len)); 165 nla = NLMSG_ATTR(msg, sizeof(msg->udm)); 166 SET_STRUCT(struct nlattr, nla, 167 .nla_len = NLA_HDRLEN, 168 .nla_type = UNIX_DIAG_NAME 169 ); 170 rc = sendto(fd, msg, msg_len, MSG_DONTWAIT, NULL, 0); 171 printf("sendto(%d, {{len=%u, type=SOCK_DIAG_BY_FAMILY" 172 ", flags=NLM_F_DUMP, seq=0, pid=0}, {udiag_family=AF_UNIX" 173 ", udiag_type=SOCK_STREAM, udiag_state=TCP_FIN_WAIT1" 174 ", udiag_ino=0, udiag_cookie=[0, 0]}, [{nla_len=%u" 175 ", nla_type=UNIX_DIAG_NAME}, ... /* %p */]}, %u" 176 ", MSG_DONTWAIT, NULL, 0) = %s\n", 177 fd, msg_len, NLA_HDRLEN, nla + 1, msg_len, sprintrc(rc)); 178 179 /* print two struct nlattr */ 180 msg_len = NLMSG_SPACE(sizeof(msg->udm)) + NLA_HDRLEN * 2; 181 msg = tail_memdup(&c_msg, msg_len); 182 memcpy(&msg->nlh.nlmsg_len, &msg_len, sizeof(msg_len)); 183 nla = NLMSG_ATTR(msg, sizeof(msg->udm)); 184 *nla = (struct nlattr) { 185 .nla_len = NLA_HDRLEN, 186 .nla_type = UNIX_DIAG_NAME 187 }; 188 *(nla + 1) = (struct nlattr) { 189 .nla_len = NLA_HDRLEN, 190 .nla_type = UNIX_DIAG_PEER 191 }; 192 rc = sendto(fd, msg, msg_len, MSG_DONTWAIT, NULL, 0); 193 printf("sendto(%d, {{len=%u, type=SOCK_DIAG_BY_FAMILY" 194 ", flags=NLM_F_DUMP, seq=0, pid=0}, {udiag_family=AF_UNIX" 195 ", udiag_type=SOCK_STREAM, udiag_state=TCP_FIN_WAIT1" 196 ", udiag_ino=0, udiag_cookie=[0, 0]}, [{nla_len=%u" 197 ", nla_type=UNIX_DIAG_NAME}, {nla_len=%u" 198 ", nla_type=UNIX_DIAG_PEER}]}, %u" 199 ", MSG_DONTWAIT, NULL, 0) = %s\n", 200 fd, msg_len, nla->nla_len, nla->nla_len, 201 msg_len, sprintrc(rc)); 202 203 /* print first nlattr only when its nla_len is less than NLA_HDRLEN */ 204 nla->nla_len = NLA_HDRLEN - 1; 205 rc = sendto(fd, msg, msg_len, MSG_DONTWAIT, NULL, 0); 206 printf("sendto(%d, {{len=%u, type=SOCK_DIAG_BY_FAMILY" 207 ", flags=NLM_F_DUMP, seq=0, pid=0}, {udiag_family=AF_UNIX" 208 ", udiag_type=SOCK_STREAM, udiag_state=TCP_FIN_WAIT1" 209 ", udiag_ino=0, udiag_cookie=[0, 0]}, {nla_len=%u" 210 ", nla_type=UNIX_DIAG_NAME}}, %u, MSG_DONTWAIT, NULL, 0) = %s\n", 211 fd, msg_len, nla->nla_len, msg_len, sprintrc(rc)); 212 213 /* unrecognized attribute data, abbreviated output */ 214 #define ABBREV_LEN (DEFAULT_STRLEN + 1) 215 msg_len = NLMSG_SPACE(sizeof(msg->udm)) + NLA_HDRLEN * ABBREV_LEN * 2; 216 msg = tail_alloc(msg_len); 217 memcpy(msg, &c_msg, sizeof(c_msg)); 218 msg->nlh.nlmsg_len = msg_len; 219 unsigned int i; 220 nla = NLMSG_ATTR(msg, sizeof(msg->udm)); 221 for (i = 0; i < ABBREV_LEN; ++i) { 222 nla[i * 2] = (struct nlattr) { 223 .nla_len = NLA_HDRLEN * 2 - 1, 224 .nla_type = UNIX_DIAG_SHUTDOWN + 1 + i 225 }; 226 fill_memory_ex(&nla[i * 2 + 1], NLA_HDRLEN, 227 '0' + i, '~' - '0' - i); 228 } 229 230 rc = sendto(fd, msg, msg_len, MSG_DONTWAIT, NULL, 0); 231 printf("sendto(%d, {{len=%u, type=SOCK_DIAG_BY_FAMILY" 232 ", flags=NLM_F_DUMP, seq=0, pid=0}" 233 ", {udiag_family=AF_UNIX, udiag_type=SOCK_STREAM" 234 ", udiag_state=TCP_FIN_WAIT1, udiag_ino=0" 235 ", udiag_cookie=[0, 0]}, [", 236 fd, msg_len); 237 for (i = 0; i < DEFAULT_STRLEN; ++i) { 238 if (i) 239 printf(", "); 240 printf("{{nla_len=%u, nla_type=%#x /* UNIX_DIAG_??? */}, ", 241 nla->nla_len, UNIX_DIAG_SHUTDOWN + 1 + i); 242 print_quoted_hex(&nla[i * 2 + 1], NLA_HDRLEN - 1); 243 printf("}"); 244 } 245 printf(", ...]}, %u, MSG_DONTWAIT, NULL, 0) = %s\n", 246 msg_len, sprintrc(rc)); 247 } 248 249 static void 250 test_nla_type(const int fd) 251 { 252 static const struct msg { 253 struct nlmsghdr nlh; 254 struct unix_diag_msg udm; 255 } c_msg = { 256 .nlh = { 257 .nlmsg_len = sizeof(struct msg), 258 .nlmsg_type = SOCK_DIAG_BY_FAMILY, 259 .nlmsg_flags = NLM_F_DUMP 260 }, 261 .udm = { 262 .udiag_family = AF_UNIX, 263 .udiag_type = SOCK_STREAM, 264 .udiag_state = TCP_FIN_WAIT1 265 } 266 }; 267 struct msg *msg; 268 struct nlattr *nla; 269 unsigned int msg_len; 270 long rc; 271 272 msg_len = NLMSG_SPACE(sizeof(msg->udm)) + sizeof(*nla); 273 msg = tail_memdup(&c_msg, msg_len); 274 memcpy(&msg->nlh.nlmsg_len, &msg_len, sizeof(msg_len)); 275 nla = NLMSG_ATTR(msg, sizeof(msg->udm)); 276 *nla = (struct nlattr) { 277 .nla_len = sizeof(*nla), 278 .nla_type = NLA_F_NESTED | UNIX_DIAG_NAME 279 }; 280 rc = sendto(fd, msg, msg_len, MSG_DONTWAIT, NULL, 0); 281 printf("sendto(%d, {{len=%u, type=SOCK_DIAG_BY_FAMILY" 282 ", flags=NLM_F_DUMP, seq=0, pid=0}, {udiag_family=AF_UNIX" 283 ", udiag_type=SOCK_STREAM, udiag_state=TCP_FIN_WAIT1" 284 ", udiag_ino=0, udiag_cookie=[0, 0]}, {nla_len=%u" 285 ", nla_type=NLA_F_NESTED|UNIX_DIAG_NAME}}" 286 ", %u, MSG_DONTWAIT, NULL, 0) = %s\n", 287 fd, msg_len, nla->nla_len, msg_len, sprintrc(rc)); 288 289 nla->nla_type = NLA_F_NET_BYTEORDER | UNIX_DIAG_NAME; 290 rc = sendto(fd, msg, msg_len, MSG_DONTWAIT, NULL, 0); 291 printf("sendto(%d, {{len=%u, type=SOCK_DIAG_BY_FAMILY" 292 ", flags=NLM_F_DUMP, seq=0, pid=0}, {udiag_family=AF_UNIX" 293 ", udiag_type=SOCK_STREAM, udiag_state=TCP_FIN_WAIT1" 294 ", udiag_ino=0, udiag_cookie=[0, 0]}, {nla_len=%u" 295 ", nla_type=NLA_F_NET_BYTEORDER|UNIX_DIAG_NAME}}" 296 ", %u, MSG_DONTWAIT, NULL, 0) = %s\n", 297 fd, msg_len, nla->nla_len, msg_len, sprintrc(rc)); 298 299 nla->nla_type = NLA_F_NESTED | NLA_F_NET_BYTEORDER | UNIX_DIAG_NAME; 300 rc = sendto(fd, msg, msg_len, MSG_DONTWAIT, NULL, 0); 301 printf("sendto(%d, {{len=%u, type=SOCK_DIAG_BY_FAMILY" 302 ", flags=NLM_F_DUMP, seq=0, pid=0}, {udiag_family=AF_UNIX" 303 ", udiag_type=SOCK_STREAM, udiag_state=TCP_FIN_WAIT1" 304 ", udiag_ino=0, udiag_cookie=[0, 0]}, {nla_len=%u" 305 ", nla_type=NLA_F_NESTED|NLA_F_NET_BYTEORDER|UNIX_DIAG_NAME}}" 306 ", %u, MSG_DONTWAIT, NULL, 0) = %s\n", 307 fd, msg_len, nla->nla_len, msg_len, sprintrc(rc)); 308 309 nla->nla_type = NLA_F_NESTED | (UNIX_DIAG_SHUTDOWN + 1); 310 rc = sendto(fd, msg, msg->nlh.nlmsg_len, MSG_DONTWAIT, NULL, 0); 311 printf("sendto(%d, {{len=%u, type=SOCK_DIAG_BY_FAMILY" 312 ", flags=NLM_F_DUMP, seq=0, pid=0}, {udiag_family=AF_UNIX" 313 ", udiag_type=SOCK_STREAM, udiag_state=TCP_FIN_WAIT1" 314 ", udiag_ino=0, udiag_cookie=[0, 0]}, {nla_len=%u" 315 ", nla_type=NLA_F_NESTED|%#x /* UNIX_DIAG_??? */}}" 316 ", %u, MSG_DONTWAIT, NULL, 0) = %s\n", 317 fd, msg->nlh.nlmsg_len, nla->nla_len, UNIX_DIAG_SHUTDOWN + 1, 318 msg->nlh.nlmsg_len, sprintrc(rc)); 319 } 320 321 int main(void) 322 { 323 skip_if_unavailable("/proc/self/fd/"); 324 325 const int fd = create_nl_socket(NETLINK_SOCK_DIAG); 326 327 test_nlattr(fd); 328 test_nla_type(fd); 329 330 puts("+++ exited with 0 +++"); 331 332 return 0; 333 } 334