1/* 2 * Check decoding of netlink attribute. 3 * 4 * Copyright (c) 2017 JingPiao Chen <chenjingpiao@gmail.com> 5 * Copyright (c) 2017 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 44static void 45test_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]}, \"12\"}, %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_??? */}, \"1234\"}}" 137 ", %u, MSG_DONTWAIT, NULL, 0) = %s\n", 138 fd, msg_len, nla->nla_len, UNIX_DIAG_SHUTDOWN + 1, 139 msg_len, sprintrc(rc)); 140 141 /* print one struct nlattr and fetch fail second struct nlattr */ 142 msg_len = NLMSG_SPACE(sizeof(msg->udm)) + NLA_HDRLEN + 2; 143 msg = tail_memdup(&c_msg, msg_len); 144 memcpy(&msg->nlh.nlmsg_len, &msg_len, sizeof(msg_len)); 145 nla = NLMSG_ATTR(msg, sizeof(msg->udm)); 146 *nla = (struct nlattr) { 147 .nla_len = NLA_HDRLEN, 148 .nla_type = UNIX_DIAG_NAME 149 }; 150 memcpy(nla + 1, "12", 2); 151 rc = sendto(fd, msg, msg_len, MSG_DONTWAIT, NULL, 0); 152 printf("sendto(%d, {{len=%u, type=SOCK_DIAG_BY_FAMILY" 153 ", flags=NLM_F_DUMP, seq=0, pid=0}, {udiag_family=AF_UNIX" 154 ", udiag_type=SOCK_STREAM, udiag_state=TCP_FIN_WAIT1" 155 ", udiag_ino=0, udiag_cookie=[0, 0]}, [{nla_len=%u" 156 ", nla_type=UNIX_DIAG_NAME}, \"12\"]}, %u" 157 ", MSG_DONTWAIT, NULL, 0) = %s\n", 158 fd, msg_len, nla->nla_len, msg_len, sprintrc(rc)); 159 160 /* print one struct nlattr and short read of second struct nlattr */ 161 msg_len = NLMSG_SPACE(sizeof(msg->udm)) + NLA_HDRLEN * 2; 162 msg = tail_memdup(&c_msg, msg_len - 1); 163 memcpy(&msg->nlh.nlmsg_len, &msg_len, sizeof(msg_len)); 164 nla = NLMSG_ATTR(msg, sizeof(msg->udm)); 165 *nla = (struct nlattr) { 166 .nla_len = NLA_HDRLEN, 167 .nla_type = UNIX_DIAG_NAME 168 }; 169 rc = sendto(fd, msg, msg_len, MSG_DONTWAIT, NULL, 0); 170 printf("sendto(%d, {{len=%u, type=SOCK_DIAG_BY_FAMILY" 171 ", flags=NLM_F_DUMP, seq=0, pid=0}, {udiag_family=AF_UNIX" 172 ", udiag_type=SOCK_STREAM, udiag_state=TCP_FIN_WAIT1" 173 ", udiag_ino=0, udiag_cookie=[0, 0]}, [{nla_len=%u" 174 ", nla_type=UNIX_DIAG_NAME}, %p]}, %u" 175 ", MSG_DONTWAIT, NULL, 0) = %s\n", 176 fd, msg_len, nla->nla_len, nla + 1, msg_len, sprintrc(rc)); 177 178 /* print two struct nlattr */ 179 msg_len = NLMSG_SPACE(sizeof(msg->udm)) + NLA_HDRLEN * 2; 180 msg = tail_memdup(&c_msg, msg_len); 181 memcpy(&msg->nlh.nlmsg_len, &msg_len, sizeof(msg_len)); 182 nla = NLMSG_ATTR(msg, sizeof(msg->udm)); 183 *nla = (struct nlattr) { 184 .nla_len = NLA_HDRLEN, 185 .nla_type = UNIX_DIAG_NAME 186 }; 187 *(nla + 1) = (struct nlattr) { 188 .nla_len = NLA_HDRLEN, 189 .nla_type = UNIX_DIAG_PEER 190 }; 191 rc = sendto(fd, msg, msg_len, MSG_DONTWAIT, NULL, 0); 192 printf("sendto(%d, {{len=%u, type=SOCK_DIAG_BY_FAMILY" 193 ", flags=NLM_F_DUMP, seq=0, pid=0}, {udiag_family=AF_UNIX" 194 ", udiag_type=SOCK_STREAM, udiag_state=TCP_FIN_WAIT1" 195 ", udiag_ino=0, udiag_cookie=[0, 0]}, [{nla_len=%u" 196 ", nla_type=UNIX_DIAG_NAME}, {nla_len=%u" 197 ", nla_type=UNIX_DIAG_PEER}]}, %u" 198 ", MSG_DONTWAIT, NULL, 0) = %s\n", 199 fd, msg_len, nla->nla_len, nla->nla_len, 200 msg_len, sprintrc(rc)); 201 202 /* print first nlattr only when its nla_len is less than NLA_HDRLEN */ 203 nla->nla_len = NLA_HDRLEN - 1; 204 rc = sendto(fd, msg, msg_len, MSG_DONTWAIT, NULL, 0); 205 printf("sendto(%d, {{len=%u, type=SOCK_DIAG_BY_FAMILY" 206 ", flags=NLM_F_DUMP, seq=0, pid=0}, {udiag_family=AF_UNIX" 207 ", udiag_type=SOCK_STREAM, udiag_state=TCP_FIN_WAIT1" 208 ", udiag_ino=0, udiag_cookie=[0, 0]}, {nla_len=%u" 209 ", nla_type=UNIX_DIAG_NAME}}, %u, MSG_DONTWAIT, NULL, 0) = %s\n", 210 fd, msg_len, nla->nla_len, msg_len, sprintrc(rc)); 211 212 /* abbreviated output */ 213#define ABBREV_LEN (DEFAULT_STRLEN + 1) 214 msg_len = NLA_HDRLEN * ABBREV_LEN + NLMSG_SPACE(sizeof(msg->udm)); 215 msg = tail_memdup(&c_msg, msg_len); 216 memcpy(&msg->nlh.nlmsg_len, &msg_len, sizeof(msg_len)); 217 unsigned int i; 218 nla = NLMSG_ATTR(msg, sizeof(msg->udm)); 219 for (i = 0; i < ABBREV_LEN; ++i) 220 nla[i] = (struct nlattr) { 221 .nla_len = NLA_HDRLEN, 222 .nla_type = UNIX_DIAG_SHUTDOWN + 1 + i 223 }; 224 225 rc = sendto(fd, msg, msg_len, MSG_DONTWAIT, NULL, 0); 226 printf("sendto(%d, {{len=%u, type=SOCK_DIAG_BY_FAMILY" 227 ", flags=NLM_F_DUMP, seq=0, pid=0}" 228 ", {udiag_family=AF_UNIX, udiag_type=SOCK_STREAM" 229 ", udiag_state=TCP_FIN_WAIT1, udiag_ino=0" 230 ", udiag_cookie=[0, 0]}, [", 231 fd, msg_len); 232 for (i = 0; i < DEFAULT_STRLEN; ++i) { 233 if (i) 234 printf(", "); 235 printf("{nla_len=%u, nla_type=%#x /* UNIX_DIAG_??? */}", 236 nla->nla_len, UNIX_DIAG_SHUTDOWN + 1 + i); 237 } 238 printf(", ...]}, %u, MSG_DONTWAIT, NULL, 0) = %s\n", 239 msg_len, sprintrc(rc)); 240} 241 242static void 243test_nla_type(const int fd) 244{ 245 static const struct msg { 246 struct nlmsghdr nlh; 247 struct unix_diag_msg udm; 248 } c_msg = { 249 .nlh = { 250 .nlmsg_len = sizeof(struct msg), 251 .nlmsg_type = SOCK_DIAG_BY_FAMILY, 252 .nlmsg_flags = NLM_F_DUMP 253 }, 254 .udm = { 255 .udiag_family = AF_UNIX, 256 .udiag_type = SOCK_STREAM, 257 .udiag_state = TCP_FIN_WAIT1 258 } 259 }; 260 struct msg *msg; 261 struct nlattr *nla; 262 unsigned int msg_len; 263 long rc; 264 265 msg_len = NLMSG_SPACE(sizeof(msg->udm)) + sizeof(*nla); 266 msg = tail_memdup(&c_msg, msg_len); 267 memcpy(&msg->nlh.nlmsg_len, &msg_len, sizeof(msg_len)); 268 nla = NLMSG_ATTR(msg, sizeof(msg->udm)); 269 *nla = (struct nlattr) { 270 .nla_len = sizeof(*nla), 271 .nla_type = NLA_F_NESTED | UNIX_DIAG_NAME 272 }; 273 rc = sendto(fd, msg, msg_len, MSG_DONTWAIT, NULL, 0); 274 printf("sendto(%d, {{len=%u, type=SOCK_DIAG_BY_FAMILY" 275 ", flags=NLM_F_DUMP, seq=0, pid=0}, {udiag_family=AF_UNIX" 276 ", udiag_type=SOCK_STREAM, udiag_state=TCP_FIN_WAIT1" 277 ", udiag_ino=0, udiag_cookie=[0, 0]}, {nla_len=%u" 278 ", nla_type=NLA_F_NESTED|UNIX_DIAG_NAME}}" 279 ", %u, MSG_DONTWAIT, NULL, 0) = %s\n", 280 fd, msg_len, nla->nla_len, msg_len, sprintrc(rc)); 281 282 nla->nla_type = NLA_F_NET_BYTEORDER | UNIX_DIAG_NAME; 283 rc = sendto(fd, msg, msg_len, MSG_DONTWAIT, NULL, 0); 284 printf("sendto(%d, {{len=%u, type=SOCK_DIAG_BY_FAMILY" 285 ", flags=NLM_F_DUMP, seq=0, pid=0}, {udiag_family=AF_UNIX" 286 ", udiag_type=SOCK_STREAM, udiag_state=TCP_FIN_WAIT1" 287 ", udiag_ino=0, udiag_cookie=[0, 0]}, {nla_len=%u" 288 ", nla_type=NLA_F_NET_BYTEORDER|UNIX_DIAG_NAME}}" 289 ", %u, MSG_DONTWAIT, NULL, 0) = %s\n", 290 fd, msg_len, nla->nla_len, msg_len, sprintrc(rc)); 291 292 nla->nla_type = NLA_F_NESTED | NLA_F_NET_BYTEORDER | UNIX_DIAG_NAME; 293 rc = sendto(fd, msg, msg_len, MSG_DONTWAIT, NULL, 0); 294 printf("sendto(%d, {{len=%u, type=SOCK_DIAG_BY_FAMILY" 295 ", flags=NLM_F_DUMP, seq=0, pid=0}, {udiag_family=AF_UNIX" 296 ", udiag_type=SOCK_STREAM, udiag_state=TCP_FIN_WAIT1" 297 ", udiag_ino=0, udiag_cookie=[0, 0]}, {nla_len=%u" 298 ", nla_type=NLA_F_NESTED|NLA_F_NET_BYTEORDER|UNIX_DIAG_NAME}}" 299 ", %u, MSG_DONTWAIT, NULL, 0) = %s\n", 300 fd, msg_len, nla->nla_len, msg_len, sprintrc(rc)); 301 302 nla->nla_type = NLA_F_NESTED | (UNIX_DIAG_SHUTDOWN + 1); 303 rc = sendto(fd, msg, msg->nlh.nlmsg_len, MSG_DONTWAIT, NULL, 0); 304 printf("sendto(%d, {{len=%u, type=SOCK_DIAG_BY_FAMILY" 305 ", flags=NLM_F_DUMP, seq=0, pid=0}, {udiag_family=AF_UNIX" 306 ", udiag_type=SOCK_STREAM, udiag_state=TCP_FIN_WAIT1" 307 ", udiag_ino=0, udiag_cookie=[0, 0]}, {nla_len=%u" 308 ", nla_type=NLA_F_NESTED|%#x /* UNIX_DIAG_??? */}}" 309 ", %u, MSG_DONTWAIT, NULL, 0) = %s\n", 310 fd, msg->nlh.nlmsg_len, nla->nla_len, UNIX_DIAG_SHUTDOWN + 1, 311 msg->nlh.nlmsg_len, sprintrc(rc)); 312} 313 314int main(void) 315{ 316 skip_if_unavailable("/proc/self/fd/"); 317 318 const int fd = create_nl_socket(NETLINK_SOCK_DIAG); 319 320 test_nlattr(fd); 321 test_nla_type(fd); 322 323 puts("+++ exited with 0 +++"); 324 325 return 0; 326} 327