1/* Check recvmsg results for netlink sockets.
2 Copyright (C) 2015-2022 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <https://www.gnu.org/licenses/>. */
18
19#include <errno.h>
20#include <fcntl.h>
21#include <stdio.h>
22#include <stdbool.h>
23#include <sys/socket.h>
24
25#include "netlinkaccess.h"
26
27static int
28get_address_family (int fd)
29{
30 struct sockaddr_storage sa;
31 socklen_t sa_len = sizeof (sa);
32 if (__getsockname (fd: fd, addr: (struct sockaddr *) &sa, len: &sa_len) < 0)
33 return -1;
34 /* Check that the socket family number is preserved despite in-band
35 signaling. */
36 _Static_assert (sizeof (sa.ss_family) < sizeof (int), "address family size");
37 _Static_assert (0 < (__typeof__ (sa.ss_family)) -1,
38 "address family unsigned");
39 return sa.ss_family;
40}
41
42void
43__netlink_assert_response (int fd, ssize_t result)
44{
45 if (result < 0)
46 {
47 /* Check if the error is unexpected. */
48 bool terminate = false;
49 int error_code = errno;
50 int family = get_address_family (fd);
51 if (family != AF_NETLINK)
52 /* If the address family does not match (or getsockname
53 failed), report the original error. */
54 terminate = true;
55 else if (error_code == EBADF
56 || error_code == ENOTCONN
57 || error_code == ENOTSOCK
58 || error_code == ECONNREFUSED)
59 /* These errors indicate that the descriptor is not a
60 connected socket. */
61 terminate = true;
62 else if (error_code == EAGAIN || error_code == EWOULDBLOCK)
63 {
64 /* The kernel might return EAGAIN for other reasons than a
65 non-blocking socket. But if the socket is not blocking,
66 it is not ours, so report the error. */
67 int mode = __fcntl (fd, F_GETFL, 0);
68 if (mode < 0 || (mode & O_NONBLOCK) != 0)
69 terminate = true;
70 }
71 if (terminate)
72 {
73 char message[200];
74 if (family < 0)
75 __snprintf (message, sizeof (message),
76 "Unexpected error %d on netlink descriptor %d.\n",
77 error_code, fd);
78 else
79 __snprintf (message, sizeof (message),
80 "Unexpected error %d on netlink descriptor %d"
81 " (address family %d).\n",
82 error_code, fd, family);
83 __libc_fatal (message);
84 }
85 else
86 /* Restore orignal errno value. */
87 __set_errno (error_code);
88 }
89 else if (result < sizeof (struct nlmsghdr))
90 {
91 char message[200];
92 int family = get_address_family (fd);
93 if (family < 0)
94 __snprintf (message, sizeof (message),
95 "Unexpected netlink response of size %zd"
96 " on descriptor %d\n",
97 result, fd);
98 else
99 __snprintf (message, sizeof (message),
100 "Unexpected netlink response of size %zd"
101 " on descriptor %d (address family %d)\n",
102 result, fd, family);
103 __libc_fatal (message);
104 }
105}
106libc_hidden_def (__netlink_assert_response)
107

source code of glibc/sysdeps/unix/sysv/linux/netlink_assert_response.c