diff --git a/man/sd_notify.xml b/man/sd_notify.xml index 5e6c9d6dbc..0c993e31f7 100644 --- a/man/sd_notify.xml +++ b/man/sd_notify.xml @@ -499,6 +499,26 @@ successfully. Specifically, no error is returned when a file descriptor is attempted to be stored using FDSTORE=1 but the service is not actually configured to permit storing of file descriptors (see above). + + + Errors + + Returned errors may indicate the following problems: + + + + -E2BIG + + More file descriptors passed at once than the system allows. On Linux the number of + file descriptors that may be passed across AF_UNIX sockets at once is 253, see + unix7 for + details. + + + + + diff --git a/src/basic/missing_socket.h b/src/basic/missing_socket.h index 55de40a321..8460ce13bf 100644 --- a/src/basic/missing_socket.h +++ b/src/basic/missing_socket.h @@ -68,3 +68,10 @@ #ifndef IPV6_RECVFRAGSIZE #define IPV6_RECVFRAGSIZE 77 #endif + +/* The maximum number of fds that SCM_RIGHTS accepts. This is an internal kernel constant, but very much + * useful for userspace too. It's documented in unix(7) these days, hence should be fairly reliable to define + * here. */ +#ifndef SCM_MAX_FD +#define SCM_MAX_FD 253U +#endif diff --git a/src/libsystemd/sd-daemon/sd-daemon.c b/src/libsystemd/sd-daemon/sd-daemon.c index faf45c2750..4d3d678cb4 100644 --- a/src/libsystemd/sd-daemon/sd-daemon.c +++ b/src/libsystemd/sd-daemon/sd-daemon.c @@ -472,6 +472,12 @@ static int pid_notify_with_fds_internal( assert_return(state, -EINVAL); assert_return(fds || n_fds == 0, -EINVAL); + /* Let's make sure the multiplications below don't overflow, and also return a recognizable error in + * case the caller tries to send more fds than the kernel limit. The kernel would return EINVAL which + * is not too useful I'd say. */ + if (n_fds > SCM_MAX_FD) + return -E2BIG; + const char *e = getenv("NOTIFY_SOCKET"); if (!e) return 0; diff --git a/src/notify/notify.c b/src/notify/notify.c index 8937457ec9..6afb9560c6 100644 --- a/src/notify/notify.c +++ b/src/notify/notify.c @@ -453,6 +453,8 @@ static int run(int argc, char* argv[]) { r = sd_pid_notify_with_fds(arg_pid.pid, /* unset_environment= */ false, msg, a, k); } + if (r == -E2BIG) + return log_error_errno(r, "Too many file descriptors passed."); if (r < 0) return log_error_errno(r, "Failed to notify init system: %m"); if (r == 0)