mirror of
https://github.com/systemd/systemd-stable.git
synced 2025-03-08 20:58:20 +03:00
Merge pull request #12271 from poettering/errno-accept-again
accept() errno fixes
This commit is contained in:
commit
fcd0f82e16
@ -41,6 +41,9 @@ predicate potentiallyDangerousFunction(Function f, string message) {
|
||||
) or (
|
||||
f.getQualifiedName() = "strerror" and
|
||||
message = "Call to strerror() is not thread-safe. Use strerror_r() or printf()'s %m format string instead."
|
||||
) or (
|
||||
f.getQualifiedName() = "accept" and
|
||||
message = "Call to accept() is not O_CLOEXEC-safe. Use accept4() instead."
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -271,11 +271,15 @@ static int do_accept(const char* name, char **argv, char **envp, int fd) {
|
||||
_cleanup_close_ int fd_accepted = -1;
|
||||
|
||||
fd_accepted = accept4(fd, NULL, NULL, 0);
|
||||
if (fd_accepted < 0)
|
||||
return log_error_errno(errno, "Failed to accept connection on fd:%d: %m", fd);
|
||||
if (fd_accepted < 0) {
|
||||
if (ERRNO_IS_ACCEPT_AGAIN(errno))
|
||||
return 0;
|
||||
|
||||
getsockname_pretty(fd_accepted, &local);
|
||||
getpeername_pretty(fd_accepted, true, &peer);
|
||||
return log_error_errno(errno, "Failed to accept connection on fd:%d: %m", fd);
|
||||
}
|
||||
|
||||
(void) getsockname_pretty(fd_accepted, &local);
|
||||
(void) getpeername_pretty(fd_accepted, true, &peer);
|
||||
log_info("Connection from %s to %s", strna(peer), strna(local));
|
||||
|
||||
return fork_and_exec_process(name, argv, envp, fd_accepted);
|
||||
|
@ -32,12 +32,38 @@ static inline int negative_errno(void) {
|
||||
*
|
||||
* Hint #2: The kernel sends e.g., EHOSTUNREACH or ENONET to userspace in some ICMP error cases. See the
|
||||
* icmp_err_convert[] in net/ipv4/icmp.c in the kernel sources */
|
||||
#define ERRNO_IS_DISCONNECT(r) \
|
||||
IN_SET(abs(r), \
|
||||
ENOTCONN, ECONNRESET, ECONNREFUSED, ECONNABORTED, EPIPE, \
|
||||
ENETUNREACH, EHOSTUNREACH, ENOPROTOOPT, EHOSTDOWN, \
|
||||
ENONET, ESHUTDOWN)
|
||||
static inline bool ERRNO_IS_DISCONNECT(int r) {
|
||||
return IN_SET(abs(r),
|
||||
ECONNABORTED,
|
||||
ECONNREFUSED,
|
||||
ECONNRESET,
|
||||
EHOSTDOWN,
|
||||
EHOSTUNREACH,
|
||||
ENETDOWN,
|
||||
ENETRESET,
|
||||
ENETUNREACH,
|
||||
ENONET,
|
||||
ENOPROTOOPT,
|
||||
ENOTCONN,
|
||||
EPIPE,
|
||||
EPROTO,
|
||||
ESHUTDOWN);
|
||||
}
|
||||
|
||||
/* Transient errors we might get on accept() that we should ignore. As per error handling comment in
|
||||
* the accept(2) man page. */
|
||||
static inline bool ERRNO_IS_ACCEPT_AGAIN(int r) {
|
||||
return ERRNO_IS_DISCONNECT(r) ||
|
||||
IN_SET(abs(r),
|
||||
EAGAIN,
|
||||
EINTR,
|
||||
EOPNOTSUPP);
|
||||
}
|
||||
|
||||
/* Resource exhaustion, could be our fault or general system trouble */
|
||||
#define ERRNO_IS_RESOURCE(r) \
|
||||
IN_SET(abs(r), ENOMEM, EMFILE, ENFILE)
|
||||
static inline bool ERRNO_IS_RESOURCE(int r) {
|
||||
return IN_SET(abs(r),
|
||||
EMFILE,
|
||||
ENFILE,
|
||||
ENOMEM);
|
||||
}
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include <unistd.h>
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "errno-util.h"
|
||||
#include "escape.h"
|
||||
#include "fd-util.h"
|
||||
#include "fileio.h"
|
||||
@ -1237,22 +1238,22 @@ int flush_accept(int fd) {
|
||||
continue;
|
||||
|
||||
return -errno;
|
||||
|
||||
} else if (r == 0)
|
||||
}
|
||||
if (r == 0)
|
||||
return 0;
|
||||
|
||||
cfd = accept4(fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC);
|
||||
if (cfd < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
|
||||
if (errno == EAGAIN)
|
||||
return 0;
|
||||
|
||||
if (ERRNO_IS_ACCEPT_AGAIN(errno))
|
||||
continue;
|
||||
|
||||
return -errno;
|
||||
}
|
||||
|
||||
close(cfd);
|
||||
safe_close(cfd);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -622,6 +622,9 @@ static int bus_on_connection(sd_event_source *s, int fd, uint32_t revents, void
|
||||
|
||||
nfd = accept4(fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC);
|
||||
if (nfd < 0) {
|
||||
if (ERRNO_IS_ACCEPT_AGAIN(errno))
|
||||
return 0;
|
||||
|
||||
log_warning_errno(errno, "Failed to accept private connection, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
|
@ -2856,17 +2856,10 @@ static int socket_accept_do(Socket *s, int fd) {
|
||||
assert(s);
|
||||
assert(fd >= 0);
|
||||
|
||||
for (;;) {
|
||||
cfd = accept4(fd, NULL, NULL, SOCK_NONBLOCK);
|
||||
if (cfd < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
|
||||
return -errno;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
cfd = accept4(fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC);
|
||||
if (cfd < 0)
|
||||
/* Convert transient network errors into clean and well-defined EAGAIN */
|
||||
return ERRNO_IS_ACCEPT_AGAIN(errno) ? -EAGAIN : -errno;
|
||||
|
||||
return cfd;
|
||||
}
|
||||
@ -2904,6 +2897,8 @@ static int socket_accept_in_cgroup(Socket *s, SocketPort *p, int fd) {
|
||||
pair[0] = safe_close(pair[0]);
|
||||
|
||||
cfd = socket_accept_do(s, fd);
|
||||
if (cfd == -EAGAIN) /* spurious accept() */
|
||||
_exit(EXIT_SUCCESS);
|
||||
if (cfd < 0) {
|
||||
log_unit_error_errno(UNIT(s), cfd, "Failed to accept connection socket: %m");
|
||||
_exit(EXIT_FAILURE);
|
||||
@ -2928,6 +2923,10 @@ static int socket_accept_in_cgroup(Socket *s, SocketPort *p, int fd) {
|
||||
return r;
|
||||
}
|
||||
|
||||
/* If we received no fd, we got EIO here. If this happens with a process exit code of EXIT_SUCCESS
|
||||
* this is a spurious accept(), let's convert that back to EAGAIN here. */
|
||||
if (cfd == -EIO)
|
||||
return -EAGAIN;
|
||||
if (cfd < 0)
|
||||
return log_unit_error_errno(UNIT(s), cfd, "Failed to receive connection socket: %m");
|
||||
|
||||
@ -2935,6 +2934,8 @@ static int socket_accept_in_cgroup(Socket *s, SocketPort *p, int fd) {
|
||||
|
||||
shortcut:
|
||||
cfd = socket_accept_do(s, fd);
|
||||
if (cfd == -EAGAIN) /* spurious accept(), skip it silently */
|
||||
return -EAGAIN;
|
||||
if (cfd < 0)
|
||||
return log_unit_error_errno(UNIT(s), cfd, "Failed to accept connection socket: %m");
|
||||
|
||||
@ -2954,7 +2955,6 @@ static int socket_dispatch_io(sd_event_source *source, int fd, uint32_t revents,
|
||||
log_unit_debug(UNIT(p->socket), "Incoming traffic");
|
||||
|
||||
if (revents != EPOLLIN) {
|
||||
|
||||
if (revents & EPOLLHUP)
|
||||
log_unit_error(UNIT(p->socket), "Got POLLHUP on a listening socket. The service probably invoked shutdown() on it, and should better not do that.");
|
||||
else
|
||||
@ -2967,6 +2967,8 @@ static int socket_dispatch_io(sd_event_source *source, int fd, uint32_t revents,
|
||||
socket_address_can_accept(&p->address)) {
|
||||
|
||||
cfd = socket_accept_in_cgroup(p->socket, p, fd);
|
||||
if (cfd == -EAGAIN) /* Spurious accept() */
|
||||
return 0;
|
||||
if (cfd < 0)
|
||||
goto fail;
|
||||
|
||||
|
@ -13,6 +13,7 @@
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "def.h"
|
||||
#include "errno-util.h"
|
||||
#include "escape.h"
|
||||
#include "fd-util.h"
|
||||
#include "journal-file.h"
|
||||
@ -466,14 +467,23 @@ static int dispatch_blocking_source_event(sd_event_source *event,
|
||||
return journal_remote_handle_raw_source(event, source->importer.fd, EPOLLIN, journal_remote_server_global);
|
||||
}
|
||||
|
||||
static int accept_connection(const char* type, int fd,
|
||||
SocketAddress *addr, char **hostname) {
|
||||
int fd2, r;
|
||||
static int accept_connection(
|
||||
const char* type,
|
||||
int fd,
|
||||
SocketAddress *addr,
|
||||
char **hostname) {
|
||||
|
||||
_cleanup_close_ int fd2 = -1;
|
||||
int r;
|
||||
|
||||
log_debug("Accepting new %s connection on fd:%d", type, fd);
|
||||
fd2 = accept4(fd, &addr->sockaddr.sa, &addr->size, SOCK_NONBLOCK|SOCK_CLOEXEC);
|
||||
if (fd2 < 0)
|
||||
if (fd2 < 0) {
|
||||
if (ERRNO_IS_ACCEPT_AGAIN(errno))
|
||||
return -EAGAIN;
|
||||
|
||||
return log_error_errno(errno, "accept() on fd:%d failed: %m", fd);
|
||||
}
|
||||
|
||||
switch(socket_address_family(addr)) {
|
||||
case AF_INET:
|
||||
@ -482,18 +492,12 @@ static int accept_connection(const char* type, int fd,
|
||||
char *b;
|
||||
|
||||
r = socket_address_print(addr, &a);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "socket_address_print(): %m");
|
||||
close(fd2);
|
||||
return r;
|
||||
}
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "socket_address_print(): %m");
|
||||
|
||||
r = socknameinfo_pretty(&addr->sockaddr, addr->size, &b);
|
||||
if (r < 0) {
|
||||
log_error_errno(r, "Resolving hostname failed: %m");
|
||||
close(fd2);
|
||||
return r;
|
||||
}
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Resolving hostname failed: %m");
|
||||
|
||||
log_debug("Accepted %s %s connection from %s",
|
||||
type,
|
||||
@ -501,22 +505,22 @@ static int accept_connection(const char* type, int fd,
|
||||
a);
|
||||
|
||||
*hostname = b;
|
||||
return TAKE_FD(fd2);
|
||||
}
|
||||
|
||||
return fd2;
|
||||
};
|
||||
default:
|
||||
log_error("Rejected %s connection with unsupported family %d",
|
||||
type, socket_address_family(addr));
|
||||
close(fd2);
|
||||
|
||||
return -EINVAL;
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||
"Rejected %s connection with unsupported family %d",
|
||||
type, socket_address_family(addr));
|
||||
}
|
||||
}
|
||||
|
||||
static int dispatch_raw_connection_event(sd_event_source *event,
|
||||
int fd,
|
||||
uint32_t revents,
|
||||
void *userdata) {
|
||||
static int dispatch_raw_connection_event(
|
||||
sd_event_source *event,
|
||||
int fd,
|
||||
uint32_t revents,
|
||||
void *userdata) {
|
||||
|
||||
RemoteServer *s = userdata;
|
||||
int fd2;
|
||||
SocketAddress addr = {
|
||||
@ -526,6 +530,8 @@ static int dispatch_raw_connection_event(sd_event_source *event,
|
||||
char *hostname = NULL;
|
||||
|
||||
fd2 = accept_connection("raw", fd, &addr, &hostname);
|
||||
if (fd2 == -EAGAIN)
|
||||
return 0;
|
||||
if (fd2 < 0)
|
||||
return fd2;
|
||||
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "alloc-util.h"
|
||||
#include "dirent-util.h"
|
||||
#include "env-file.h"
|
||||
#include "errno-util.h"
|
||||
#include "escape.h"
|
||||
#include "fd-util.h"
|
||||
#include "fileio.h"
|
||||
@ -605,7 +606,7 @@ static int stdout_stream_new(sd_event_source *es, int listen_fd, uint32_t revent
|
||||
|
||||
fd = accept4(s->stdout_fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC);
|
||||
if (fd < 0) {
|
||||
if (errno == EAGAIN)
|
||||
if (ERRNO_IS_ACCEPT_AGAIN(errno))
|
||||
return 0;
|
||||
|
||||
return log_error_errno(errno, "Failed to accept stdout connection: %m");
|
||||
|
@ -1,5 +1,6 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1+ */
|
||||
|
||||
#include "errno-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "missing_network.h"
|
||||
#include "resolved-dns-stub.h"
|
||||
@ -462,7 +463,7 @@ static int on_dns_stub_stream(sd_event_source *s, int fd, uint32_t revents, void
|
||||
|
||||
cfd = accept4(fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC);
|
||||
if (cfd < 0) {
|
||||
if (IN_SET(errno, EAGAIN, EINTR))
|
||||
if (ERRNO_IS_ACCEPT_AGAIN(errno))
|
||||
return 0;
|
||||
|
||||
return -errno;
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include <netinet/in.h>
|
||||
#include <resolv.h>
|
||||
|
||||
#include "errno-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "resolved-llmnr.h"
|
||||
#include "resolved-manager.h"
|
||||
@ -289,7 +290,7 @@ static int on_llmnr_stream(sd_event_source *s, int fd, uint32_t revents, void *u
|
||||
|
||||
cfd = accept4(fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC);
|
||||
if (cfd < 0) {
|
||||
if (IN_SET(errno, EAGAIN, EINTR))
|
||||
if (ERRNO_IS_ACCEPT_AGAIN(errno))
|
||||
return 0;
|
||||
|
||||
return -errno;
|
||||
|
@ -467,10 +467,10 @@ static int accept_cb(sd_event_source *s, int fd, uint32_t revents, void *userdat
|
||||
|
||||
nfd = accept4(fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC);
|
||||
if (nfd < 0) {
|
||||
if (errno != -EAGAIN)
|
||||
if (!ERRNO_IS_ACCEPT_AGAIN(errno))
|
||||
log_warning_errno(errno, "Failed to accept() socket: %m");
|
||||
} else {
|
||||
getpeername_pretty(nfd, true, &peer);
|
||||
(void) getpeername_pretty(nfd, true, &peer);
|
||||
log_debug("New connection from %s", strna(peer));
|
||||
|
||||
r = add_connection_socket(context, nfd);
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "sd-event.h"
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "errno-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "format-util.h"
|
||||
#include "io-util.h"
|
||||
@ -261,9 +262,10 @@ static int udev_ctrl_event_handler(sd_event_source *s, int fd, uint32_t revents,
|
||||
|
||||
sock = accept4(fd, NULL, NULL, SOCK_CLOEXEC|SOCK_NONBLOCK);
|
||||
if (sock < 0) {
|
||||
if (errno != EINTR)
|
||||
log_error_errno(errno, "Failed to accept ctrl connection: %m");
|
||||
return 0;
|
||||
if (ERRNO_IS_ACCEPT_AGAIN(errno))
|
||||
return 0;
|
||||
|
||||
return log_error_errno(errno, "Failed to accept ctrl connection: %m");
|
||||
}
|
||||
|
||||
/* check peer credential of connection */
|
||||
|
Loading…
x
Reference in New Issue
Block a user