Home | History | Annotate | Download | only in tests
      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