(root)/
strace-6.5/
tests/
msg_name.c
       1  /*
       2   * Check decoding of struct msghdr.msg_name* arguments of recvmsg syscall.
       3   *
       4   * Copyright (c) 2016 Dmitry V. Levin <ldv@strace.io>
       5   * Copyright (c) 2016-2021 The strace developers.
       6   * All rights reserved.
       7   *
       8   * SPDX-License-Identifier: GPL-2.0-or-later
       9   */
      10  
      11  #include "tests.h"
      12  #include <stddef.h>
      13  #include <stdio.h>
      14  #include <string.h>
      15  #include <unistd.h>
      16  #include <sys/socket.h>
      17  #include <sys/un.h>
      18  
      19  #undef TEST_RECVMSG_BOGUS_ADDR
      20  
      21  /*
      22   * Sadly, musl recvmsg wrapper blindly dereferences the 2nd argument,
      23   * so limit these tests to glibc that hopefully doesn't.
      24   */
      25  #ifndef __GLIBC__
      26  # define TEST_RECVMSG_BOGUS_ADDR 0
      27  #endif
      28  
      29  /*
      30   * Sadly, starting with commit
      31   * glibc-2.33.9000-707-g13c51549e2077f2f3bf84e8fd0b46d8b0c615912, on every
      32   * 32-bit architecture where 32-bit time_t support is enabled, glibc blindly
      33   * dereferences the 2nd argument of recvmsg call.
      34   */
      35  #if GLIBC_PREREQ_GE(2, 33) && defined __TIMESIZE && __TIMESIZE != 64
      36  # define TEST_RECVMSG_BOGUS_ADDR 0
      37  #endif
      38  
      39  #ifndef TEST_RECVMSG_BOGUS_ADDR
      40  # define TEST_RECVMSG_BOGUS_ADDR 1
      41  #endif
      42  
      43  static int
      44  send_recv(const int send_fd, const int recv_fd,
      45  	 struct msghdr *const msg, const int flags)
      46  {
      47  	if (send(send_fd, "A", 1, 0) != 1)
      48  		perror_msg_and_skip("send");
      49  	return recvmsg(recv_fd, msg, flags);
      50  }
      51  
      52  static void
      53  test_msg_name(const int send_fd, const int recv_fd)
      54  {
      55  	TAIL_ALLOC_OBJECT_CONST_PTR(char, recv_buf);
      56  	TAIL_ALLOC_OBJECT_CONST_PTR(struct iovec, iov);
      57  	iov->iov_base = recv_buf;
      58  	iov->iov_len = sizeof(*recv_buf);
      59  
      60  	TAIL_ALLOC_OBJECT_CONST_PTR(struct sockaddr_un, addr);
      61  	TAIL_ALLOC_OBJECT_CONST_PTR(struct msghdr, msg);
      62  	msg->msg_name = addr;
      63  	msg->msg_namelen = sizeof(*addr);
      64  	msg->msg_iov = iov;
      65  	msg->msg_iovlen = 1;
      66  	msg->msg_control = 0;
      67  	msg->msg_controllen = 0;
      68  	msg->msg_flags = 0;
      69  
      70  	int rc = send_recv(send_fd, recv_fd, msg, MSG_DONTWAIT);
      71  	if (rc < 0)
      72  		perror_msg_and_skip("recvmsg");
      73  	printf("recvmsg(%d, {msg_name={sa_family=AF_UNIX, sun_path=\"%s\"}"
      74  	       ", msg_namelen=%d => %d, msg_iov=[{iov_base=\"A\", iov_len=1}]"
      75  	       ", msg_iovlen=1, msg_controllen=0, msg_flags=0}, MSG_DONTWAIT)"
      76  	       " = %d\n",
      77  	       recv_fd, addr->sun_path, (int) sizeof(struct sockaddr_un),
      78  	       (int) msg->msg_namelen, rc);
      79  
      80  	memset(addr, 0, sizeof(*addr));
      81  	rc = send_recv(send_fd, recv_fd, msg, MSG_DONTWAIT);
      82  	printf("recvmsg(%d, {msg_name={sa_family=AF_UNIX, sun_path=\"%s\"}"
      83  	       ", msg_namelen=%d, msg_iov=[{iov_base=\"A\", iov_len=1}]"
      84  	       ", msg_iovlen=1, msg_controllen=0, msg_flags=0}, MSG_DONTWAIT)"
      85  	       " = %d\n",
      86  	       recv_fd, addr->sun_path, (int) msg->msg_namelen, rc);
      87  
      88  	msg->msg_name = 0;
      89  	rc = send_recv(send_fd, recv_fd, msg, MSG_DONTWAIT);
      90  	printf("recvmsg(%d, {msg_name=NULL, msg_namelen=%d"
      91  	       ", msg_iov=[{iov_base=\"A\", iov_len=1}], msg_iovlen=1"
      92  	       ", msg_controllen=0, msg_flags=0}, MSG_DONTWAIT) = %d\n",
      93  	       recv_fd, (int) msg->msg_namelen, rc);
      94  
      95  	const size_t offsetof_sun_path = offsetof(struct sockaddr_un, sun_path);
      96  	msg->msg_name = addr;
      97  	msg->msg_namelen = offsetof_sun_path;
      98  	memset(addr->sun_path, 'A', sizeof(addr->sun_path));
      99  
     100  	rc = send_recv(send_fd, recv_fd, msg, MSG_DONTWAIT);
     101  	printf("recvmsg(%d, {msg_name={sa_family=AF_UNIX}, msg_namelen=%d => %d"
     102  	       ", msg_iov=[{iov_base=\"A\", iov_len=1}], msg_iovlen=1"
     103  	       ", msg_controllen=0, msg_flags=0}, MSG_DONTWAIT) = %d\n",
     104  	       recv_fd, (int) offsetof_sun_path, (int) msg->msg_namelen, rc);
     105  
     106  	msg->msg_namelen = sizeof(struct sockaddr);
     107  	msg->msg_name = ((void *) (addr + 1)) - msg->msg_namelen;
     108  	rc = send_recv(send_fd, recv_fd, msg, MSG_DONTWAIT);
     109  	printf("recvmsg(%d, {msg_name={sa_family=AF_UNIX, sun_path=\"%.*s\"}"
     110  	       ", msg_namelen=%d => %d, msg_iov=[{iov_base=\"A\", iov_len=1}]"
     111  	       ", msg_iovlen=1, msg_controllen=0, msg_flags=0}, MSG_DONTWAIT)"
     112  	       " = %d\n",
     113  	       recv_fd, (int) (sizeof(struct sockaddr) - offsetof_sun_path),
     114  	       ((struct sockaddr_un *) msg->msg_name)->sun_path,
     115  	       (int) sizeof(struct sockaddr), (int) msg->msg_namelen, rc);
     116  
     117  	rc = send_recv(send_fd, recv_fd, msg, MSG_DONTWAIT);
     118  	printf("recvmsg(%d, {msg_namelen=%d}, MSG_DONTWAIT) = %d %s (%m)\n",
     119  	       recv_fd, (int) msg->msg_namelen, rc, errno2name());
     120  
     121  #if TEST_RECVMSG_BOGUS_ADDR
     122  	/*
     123  	 * When recvmsg is called with a valid descriptor
     124  	 * but inaccessible memory, it causes segfaults on some architectures.
     125  	 * As in these cases we test decoding of failed recvmsg calls,
     126  	 * it's ok to fail recvmsg with any reason as long as
     127  	 * it doesn't read that inaccessible memory.
     128  	 */
     129  	rc = send_recv(send_fd, -1, msg + 1, 0);
     130  	printf("recvmsg(-1, %p, 0) = %d %s (%m)\n",
     131  	       msg + 1, rc, errno2name());
     132  
     133  	rc = send_recv(send_fd, -1, 0, 0);
     134  	printf("recvmsg(-1, NULL, 0) = %d %s (%m)\n",
     135  	       rc, errno2name());
     136  #endif
     137  }
     138  
     139  int
     140  main(void)
     141  {
     142  	int fds[2];
     143  	if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds))
     144  		perror_msg_and_skip("socketpair");
     145  
     146  	const struct sockaddr_un un = {
     147  		.sun_family = AF_UNIX,
     148  		.sun_path = "msg_name-recvmsg.test.send.socket"
     149  	};
     150  
     151  	(void) unlink(un.sun_path);
     152  	if (bind(fds[1], (const void *) &un, sizeof(un)))
     153  		perror_msg_and_skip("bind");
     154  	(void) unlink(un.sun_path);
     155  
     156  	test_msg_name(fds[1], fds[0]);
     157  
     158  	puts("+++ exited with 0 +++");
     159  	return 0;
     160  }