1/* 2 * Check decoding of netlink protocol. 3 * 4 * Copyright (c) 2014-2017 Dmitry V. Levin <ldv@altlinux.org> 5 * Copyright (c) 2016 Fabien Siron <fabien.siron@epita.fr> 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#ifdef HAVE_SYS_XATTR_H 34 35# include <stdio.h> 36# include <stdlib.h> 37# include <string.h> 38# include <unistd.h> 39# include <sys/xattr.h> 40# include <netinet/in.h> 41# include "netlink.h" 42# include <linux/sock_diag.h> 43# include <linux/netlink_diag.h> 44 45static void 46send_query(const int fd) 47{ 48 static const struct req { 49 struct nlmsghdr nlh; 50 const char magic[4]; 51 } c_req = { 52 .nlh = { 53 .nlmsg_len = sizeof(struct req), 54 .nlmsg_type = NLMSG_NOOP, 55 .nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST 56 }, 57 .magic = "abcd" 58 }; 59 struct req *const req = tail_memdup(&c_req, sizeof(c_req)); 60 long rc; 61 const char *errstr; 62 63 /* zero address */ 64 rc = sendto(fd, NULL, sizeof(*req), MSG_DONTWAIT, NULL, 0); 65 printf("sendto(%d, NULL, %u, MSG_DONTWAIT, NULL, 0) = %s\n", 66 fd, (unsigned) sizeof(*req), sprintrc(rc)); 67 68 /* zero length */ 69 rc = sendto(fd, req, 0, MSG_DONTWAIT, NULL, 0); 70 printf("sendto(%d, \"\", 0, MSG_DONTWAIT, NULL, 0) = %s\n", 71 fd, sprintrc(rc)); 72 73 /* zero address and length */ 74 rc = sendto(fd, NULL, 0, MSG_DONTWAIT, NULL, 0); 75 printf("sendto(%d, NULL, 0, MSG_DONTWAIT, NULL, 0) = %s\n", 76 fd, sprintrc(rc)); 77 78 /* unfetchable struct nlmsghdr */ 79 const void *const efault = tail_alloc(sizeof(struct nlmsghdr) - 1); 80 rc = sendto(fd, efault, sizeof(struct nlmsghdr), MSG_DONTWAIT, NULL, 0); 81 printf("sendto(%d, %p, %u, MSG_DONTWAIT, NULL, 0) = %s\n", 82 fd, efault, (unsigned) sizeof(struct nlmsghdr), sprintrc(rc)); 83 84 /* whole message length < sizeof(struct nlmsghdr) */ 85 rc = sendto(fd, req->magic, sizeof(req->magic), MSG_DONTWAIT, NULL, 0); 86 printf("sendto(%d, \"abcd\", %u, MSG_DONTWAIT, NULL, 0) = %s\n", 87 fd, (unsigned) sizeof(req->magic), sprintrc(rc)); 88 89 /* a single message with some data */ 90 rc = sendto(fd, req, sizeof(*req), MSG_DONTWAIT, NULL, 0); 91 printf("sendto(%d, {{len=%u, type=NLMSG_NOOP, flags=NLM_F_REQUEST|0x%x" 92 ", seq=0, pid=0}, \"abcd\"}, %u, MSG_DONTWAIT, NULL, 0) = %s\n", 93 fd, req->nlh.nlmsg_len, NLM_F_DUMP, 94 (unsigned) sizeof(*req), sprintrc(rc)); 95 96 /* a single message without data */ 97 req->nlh.nlmsg_len = sizeof(req->nlh); 98 rc = sendto(fd, &req->nlh, sizeof(req->nlh), MSG_DONTWAIT, NULL, 0); 99 printf("sendto(%d, {len=%u, type=NLMSG_NOOP, flags=NLM_F_REQUEST|0x%x" 100 ", seq=0, pid=0}, %u, MSG_DONTWAIT, NULL, 0) = %s\n", 101 fd, req->nlh.nlmsg_len, NLM_F_DUMP, 102 (unsigned) sizeof(req->nlh), sprintrc(rc)); 103 104 /* nlmsg_len > whole message length */ 105 req->nlh.nlmsg_len = sizeof(*req) + 8; 106 rc = sendto(fd, req, sizeof(*req), MSG_DONTWAIT, NULL, 0); 107 printf("sendto(%d, {{len=%u, type=NLMSG_NOOP, flags=NLM_F_REQUEST|0x%x" 108 ", seq=0, pid=0}, \"abcd\"}, %u, MSG_DONTWAIT, NULL, 0) = %s\n", 109 fd, req->nlh.nlmsg_len, NLM_F_DUMP, 110 (unsigned) sizeof(*req), sprintrc(rc)); 111 112 /* nlmsg_len < sizeof(struct nlmsghdr) */ 113 req->nlh.nlmsg_len = 8; 114 rc = sendto(fd, req, sizeof(*req), MSG_DONTWAIT, NULL, 0); 115 printf("sendto(%d, {len=%u, type=NLMSG_NOOP, flags=NLM_F_REQUEST|0x%x" 116 ", seq=0, pid=0}, %u, MSG_DONTWAIT, NULL, 0) = %s\n", 117 fd, req->nlh.nlmsg_len, NLM_F_DUMP, 118 (unsigned) sizeof(*req), sprintrc(rc)); 119 120 /* a sequence of two nlmsg objects */ 121 struct reqs { 122 struct req req1; 123 char padding[NLMSG_ALIGN(sizeof(struct req)) - sizeof(struct req)]; 124 struct req req2; 125 } *const reqs = tail_alloc(sizeof(*reqs)); 126 memcpy(&reqs->req1, &c_req, sizeof(c_req)); 127 memcpy(&reqs->req2, &c_req, sizeof(c_req)); 128 129 rc = sendto(fd, reqs, sizeof(*reqs), MSG_DONTWAIT, NULL, 0); 130 printf("sendto(%d, [{{len=%u, type=NLMSG_NOOP, flags=NLM_F_REQUEST|0x%x" 131 ", seq=0, pid=0}, \"abcd\"}, {{len=%u, type=NLMSG_NOOP" 132 ", flags=NLM_F_REQUEST|0x%x, seq=0, pid=0}, \"abcd\"}]" 133 ", %u, MSG_DONTWAIT, NULL, 0) = %s\n", 134 fd, reqs->req1.nlh.nlmsg_len, NLM_F_DUMP, 135 reqs->req2.nlh.nlmsg_len, NLM_F_DUMP, 136 (unsigned) sizeof(*reqs), sprintrc(rc)); 137 138 /* unfetchable second struct nlmsghdr */ 139 void *const efault2 = tail_memdup(&reqs->req1, sizeof(reqs->req1)); 140 rc = sendto(fd, efault2, sizeof(*reqs), MSG_DONTWAIT, NULL, 0); 141 printf("sendto(%d, [{{len=%u, type=NLMSG_NOOP, flags=NLM_F_REQUEST|0x%x" 142 ", seq=0, pid=0}, \"abcd\"}, %p], %u, MSG_DONTWAIT, NULL, 0)" 143 " = %s\n", 144 fd, reqs->req1.nlh.nlmsg_len, NLM_F_DUMP, 145 &((struct reqs *) efault2)->req2, (unsigned) sizeof(*reqs), 146 sprintrc(rc)); 147 148 /* message length is not enough for the second struct nlmsghdr */ 149 rc = sendto(fd, reqs, sizeof(*reqs) - sizeof(req->nlh), MSG_DONTWAIT, 150 NULL, 0); 151 errstr = sprintrc(rc); 152 printf("sendto(%d, [{{len=%u, type=NLMSG_NOOP, flags=NLM_F_REQUEST|0x%x" 153 ", seq=0, pid=0}, \"abcd\"}, \"", 154 fd, reqs->req1.nlh.nlmsg_len, NLM_F_DUMP); 155 print_quoted_memory((void *) &reqs->req2.nlh, 156 sizeof(reqs->req2) - sizeof(req->nlh)); 157 printf("\"], %u, MSG_DONTWAIT, NULL, 0) = %s\n", 158 (unsigned) (sizeof(*reqs) - sizeof(req->nlh)), errstr); 159 160 /* second nlmsg_len < sizeof(struct nlmsghdr) */ 161 reqs->req2.nlh.nlmsg_len = 4; 162 rc = sendto(fd, reqs, sizeof(*reqs), MSG_DONTWAIT, NULL, 0); 163 printf("sendto(%d, [{{len=%u, type=NLMSG_NOOP, flags=NLM_F_REQUEST|0x%x" 164 ", seq=0, pid=0}, \"abcd\"}, {len=%u, type=NLMSG_NOOP" 165 ", flags=NLM_F_REQUEST|0x%x, seq=0, pid=0}], %u" 166 ", MSG_DONTWAIT, NULL, 0) = %s\n", 167 fd, reqs->req1.nlh.nlmsg_len, NLM_F_DUMP, 168 reqs->req2.nlh.nlmsg_len, NLM_F_DUMP, 169 (unsigned) sizeof(*reqs), sprintrc(rc)); 170 171 /* abbreviated output */ 172# define ABBREV_LEN (DEFAULT_STRLEN + 1) 173 const unsigned int msg_len = sizeof(struct nlmsghdr) * ABBREV_LEN; 174 struct nlmsghdr *const msgs = tail_alloc(msg_len); 175 unsigned int i; 176 for (i = 0; i < ABBREV_LEN; ++i) { 177 msgs[i].nlmsg_len = sizeof(*msgs); 178 msgs[i].nlmsg_type = NLMSG_NOOP; 179 msgs[i].nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST; 180 msgs[i].nlmsg_seq = i; 181 msgs[i].nlmsg_pid = 0; 182 } 183 184 rc = sendto(fd, msgs, msg_len, MSG_DONTWAIT, NULL, 0); 185 errstr = sprintrc(rc); 186 printf("sendto(%d, [", fd); 187 for (i = 0; i < DEFAULT_STRLEN; ++i) { 188 if (i) 189 printf(", "); 190 printf("{len=%u, type=NLMSG_NOOP, flags=NLM_F_REQUEST|0x%x" 191 ", seq=%u, pid=0}", 192 msgs[i].nlmsg_len, NLM_F_DUMP, msgs[i].nlmsg_seq); 193 } 194 printf(", ...], %u, MSG_DONTWAIT, NULL, 0) = %s\n", msg_len, errstr); 195} 196 197static void 198test_nlmsgerr(const int fd) 199{ 200 struct nlmsgerr *err; 201 struct nlmsghdr *nlh; 202 void *const nlh0 = tail_alloc(NLMSG_HDRLEN); 203 long rc; 204 205 /* error message without enough room for the error code */ 206 nlh = nlh0; 207 nlh->nlmsg_len = NLMSG_HDRLEN + 4; 208 nlh->nlmsg_type = NLMSG_ERROR; 209 nlh->nlmsg_flags = NLM_F_REQUEST; 210 nlh->nlmsg_seq = 0; 211 nlh->nlmsg_pid = 0; 212 213 rc = sendto(fd, nlh, nlh->nlmsg_len, MSG_DONTWAIT, NULL, 0); 214 printf("sendto(%d, {{len=%u, type=NLMSG_ERROR, flags=NLM_F_REQUEST" 215 ", seq=0, pid=0}, %p}, %u, MSG_DONTWAIT, NULL, 0) = %s\n", 216 fd, nlh->nlmsg_len, nlh0 + NLMSG_HDRLEN, 217 nlh->nlmsg_len, sprintrc(rc)); 218 219 nlh->nlmsg_len = NLMSG_HDRLEN + 2; 220 nlh = nlh0 - 2; 221 memmove(nlh, nlh0, sizeof(*nlh)); 222 memcpy(NLMSG_DATA(nlh), "42", 2); 223 224 rc = sendto(fd, nlh, NLMSG_HDRLEN + 2, MSG_DONTWAIT, NULL, 0); 225 printf("sendto(%d, {{len=%u, type=NLMSG_ERROR, flags=NLM_F_REQUEST" 226 ", seq=0, pid=0}, \"42\"}, %u, MSG_DONTWAIT, NULL, 0) = %s\n", 227 fd, NLMSG_HDRLEN + 2, NLMSG_HDRLEN + 2, sprintrc(rc)); 228 229 /* error message with room for the error code only */ 230 nlh = nlh0 - sizeof(err->error); 231 nlh->nlmsg_len = NLMSG_HDRLEN + sizeof(err->error); 232 nlh->nlmsg_type = NLMSG_ERROR; 233 nlh->nlmsg_flags = NLM_F_REQUEST; 234 nlh->nlmsg_seq = 0; 235 nlh->nlmsg_pid = 0; 236 err = NLMSG_DATA(nlh); 237 err->error = 42; 238 239 rc = sendto(fd, nlh, nlh->nlmsg_len, MSG_DONTWAIT, NULL, 0); 240 printf("sendto(%d, {{len=%u, type=NLMSG_ERROR, flags=NLM_F_REQUEST" 241 ", seq=0, pid=0}, {error=42}}, %u, MSG_DONTWAIT, NULL, 0)" 242 " = %s\n", fd, nlh->nlmsg_len, nlh->nlmsg_len, sprintrc(rc)); 243 244 err->error = -1; 245 246 rc = sendto(fd, nlh, nlh->nlmsg_len, MSG_DONTWAIT, NULL, 0); 247 printf("sendto(%d, {{len=%u, type=NLMSG_ERROR, flags=NLM_F_REQUEST" 248 ", seq=0, pid=0}, {error=-EPERM}}, %u, MSG_DONTWAIT, NULL, 0)" 249 " = %s\n", fd, nlh->nlmsg_len, nlh->nlmsg_len, sprintrc(rc)); 250 251 err->error = -32767; 252 nlh->nlmsg_len += sizeof(err->msg.nlmsg_len); 253 254 rc = sendto(fd, nlh, nlh->nlmsg_len, MSG_DONTWAIT, NULL, 0); 255 printf("sendto(%d, {{len=%u, type=NLMSG_ERROR, flags=NLM_F_REQUEST" 256 ", seq=0, pid=0}, {error=-32767, msg=%p}}" 257 ", %u, MSG_DONTWAIT, NULL, 0) = %s\n", 258 fd, nlh->nlmsg_len, nlh0 + NLMSG_HDRLEN, 259 nlh->nlmsg_len, sprintrc(rc)); 260 261 /* error message with room for the error code and a header */ 262 nlh = nlh0 - sizeof(*err); 263 nlh->nlmsg_len = NLMSG_HDRLEN + sizeof(*err); 264 nlh->nlmsg_type = NLMSG_ERROR; 265 nlh->nlmsg_flags = NLM_F_REQUEST; 266 nlh->nlmsg_seq = 0; 267 nlh->nlmsg_pid = 0; 268 err = NLMSG_DATA(nlh); 269 err->error = -13; 270 err->msg.nlmsg_len = NLMSG_HDRLEN; 271 err->msg.nlmsg_type = NLMSG_NOOP; 272 err->msg.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST; 273 err->msg.nlmsg_seq = 42; 274 err->msg.nlmsg_pid = 1234; 275 276 rc = sendto(fd, nlh, nlh->nlmsg_len, MSG_DONTWAIT, NULL, 0); 277 printf("sendto(%d, {{len=%u, type=NLMSG_ERROR, flags=NLM_F_REQUEST" 278 ", seq=0, pid=0}, {error=-EACCES" 279 ", msg={len=%u, type=NLMSG_NOOP, flags=NLM_F_REQUEST|0x%x" 280 ", seq=%u, pid=%u}}}, %u, MSG_DONTWAIT, NULL, 0) = %s\n", 281 fd, nlh->nlmsg_len, err->msg.nlmsg_len, NLM_F_DUMP, 282 err->msg.nlmsg_seq, err->msg.nlmsg_pid, 283 nlh->nlmsg_len, sprintrc(rc)); 284 285 /* error message with room for the error code, a header, and some data */ 286 nlh = nlh0 - sizeof(*err) - 4; 287 nlh->nlmsg_len = NLMSG_HDRLEN + sizeof(*err) + 4; 288 nlh->nlmsg_type = NLMSG_ERROR; 289 nlh->nlmsg_flags = NLM_F_REQUEST; 290 nlh->nlmsg_seq = 0; 291 nlh->nlmsg_pid = 0; 292 err = NLMSG_DATA(nlh); 293 err->error = -13; 294 err->msg.nlmsg_len = NLMSG_HDRLEN + 4; 295 err->msg.nlmsg_type = NLMSG_NOOP; 296 err->msg.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST; 297 err->msg.nlmsg_seq = 421; 298 err->msg.nlmsg_pid = 12345; 299 memcpy(NLMSG_DATA(&err->msg), "abcd", 4); 300 301 rc = sendto(fd, nlh, nlh->nlmsg_len, MSG_DONTWAIT, NULL, 0); 302 printf("sendto(%d, {{len=%u, type=NLMSG_ERROR, flags=NLM_F_REQUEST" 303 ", seq=0, pid=0}, {error=-EACCES" 304 ", msg={{len=%u, type=NLMSG_NOOP, flags=NLM_F_REQUEST|0x%x" 305 ", seq=%u, pid=%u}, \"abcd\"}}}, %u, MSG_DONTWAIT, NULL, 0)" 306 " = %s\n", 307 fd, nlh->nlmsg_len, err->msg.nlmsg_len, NLM_F_DUMP, 308 err->msg.nlmsg_seq, err->msg.nlmsg_pid, 309 nlh->nlmsg_len, sprintrc(rc)); 310} 311 312static void 313test_nlmsg_done(const int fd) 314{ 315 struct nlmsghdr *nlh; 316 void *const nlh0 = tail_alloc(NLMSG_HDRLEN); 317 long rc; 318 const int num = 0xfacefeed; 319 320 /* NLMSG_DONE message without enough room for an integer payload */ 321 nlh = nlh0; 322 *nlh = (struct nlmsghdr) { 323 .nlmsg_len = NLMSG_HDRLEN + sizeof(num), 324 .nlmsg_type = NLMSG_DONE, 325 .nlmsg_flags = NLM_F_MULTI 326 }; 327 328 rc = sendto(fd, nlh, nlh->nlmsg_len, MSG_DONTWAIT, NULL, 0); 329 printf("sendto(%d, {{len=%u, type=NLMSG_DONE, flags=NLM_F_MULTI" 330 ", seq=0, pid=0}, %p}, %u, MSG_DONTWAIT, NULL, 0) = %s\n", 331 fd, nlh->nlmsg_len, nlh0 + NLMSG_HDRLEN, 332 nlh->nlmsg_len, sprintrc(rc)); 333 334 /* NLMSG_DONE message with enough room for an oddly short payload */ 335 nlh->nlmsg_len = NLMSG_HDRLEN + 2; 336 nlh = nlh0 - 2; 337 /* Beware of unaligned access to nlh members. */ 338 memmove(nlh, nlh0, sizeof(*nlh)); 339 memcpy(NLMSG_DATA(nlh), "42", 2); 340 341 rc = sendto(fd, nlh, NLMSG_HDRLEN + 2, MSG_DONTWAIT, NULL, 0); 342 printf("sendto(%d, {{len=%u, type=NLMSG_DONE, flags=NLM_F_MULTI" 343 ", seq=0, pid=0}, \"42\"}, %u, MSG_DONTWAIT, NULL, 0) = %s\n", 344 fd, NLMSG_HDRLEN + 2, NLMSG_HDRLEN + 2, sprintrc(rc)); 345 346 /* NLMSG_DONE message with enough room for an integer payload */ 347 nlh = nlh0 - sizeof(num); 348 *nlh = (struct nlmsghdr) { 349 .nlmsg_len = NLMSG_HDRLEN + sizeof(num), 350 .nlmsg_type = NLMSG_DONE, 351 .nlmsg_flags = NLM_F_MULTI 352 }; 353 memcpy(NLMSG_DATA(nlh), &num, sizeof(num)); 354 355 rc = sendto(fd, nlh, nlh->nlmsg_len, MSG_DONTWAIT, NULL, 0); 356 printf("sendto(%d, {{len=%u, type=NLMSG_DONE, flags=NLM_F_MULTI" 357 ", seq=0, pid=0}, %d}, %u, MSG_DONTWAIT, NULL, 0) = %s\n", 358 fd, nlh->nlmsg_len, num, nlh->nlmsg_len, sprintrc(rc)); 359} 360 361int main(void) 362{ 363 const int fd = create_nl_socket(NETLINK_SOCK_DIAG); 364 365 char *path; 366 if (asprintf(&path, "/proc/self/fd/%u", fd) < 0) 367 perror_msg_and_fail("asprintf"); 368 char buf[256]; 369 if (getxattr(path, "system.sockprotoname", buf, sizeof(buf) - 1) < 0) 370 perror_msg_and_skip("getxattr"); 371 free(path); 372 373 send_query(fd); 374 test_nlmsgerr(fd); 375 test_nlmsg_done(fd); 376 377 puts("+++ exited with 0 +++"); 378 return 0; 379} 380 381#else 382 383SKIP_MAIN_UNDEFINED("HAVE_SYS_XATTR_H") 384 385#endif 386