Set CLOEXEC flag on sockets

If SOCK_CLOEXEC exists, then set the flag on socket creation.

Otherwise, use fcntl() (or SetHandleInformation() on Windows) to set the
flag afterwards.

This avoids the sockets to be inherited in child processes.

Refs #2783 <https://github.com/Genymobile/scrcpy/pull/2783>
This commit is contained in:
Romain Vimont 2021-11-26 08:10:37 +01:00
parent 904f0ae61e
commit b90c89766b
2 changed files with 55 additions and 1 deletions

View file

@ -149,6 +149,9 @@ foreach f : check_functions
endif endif
endforeach endforeach
conf.set('HAVE_SOCK_CLOEXEC', host_machine.system() != 'windows' and
cc.has_header_symbol('sys/socket.h', 'SOCK_CLOEXEC'))
# the version, updated on release # the version, updated on release
conf.set_quoted('SCRCPY_VERSION', meson.project_version()) conf.set_quoted('SCRCPY_VERSION', meson.project_version())

View file

@ -1,6 +1,7 @@
#include "net.h" #include "net.h"
#include <assert.h> #include <assert.h>
#include <errno.h>
#include <stdio.h> #include <stdio.h>
#include <SDL2/SDL_platform.h> #include <SDL2/SDL_platform.h>
@ -10,17 +11,20 @@
# include <ws2tcpip.h> # include <ws2tcpip.h>
typedef int socklen_t; typedef int socklen_t;
typedef SOCKET sc_raw_socket; typedef SOCKET sc_raw_socket;
# define SC_RAW_SOCKET_NONE INVALID_SOCKET
#else #else
# include <sys/types.h> # include <sys/types.h>
# include <sys/socket.h> # include <sys/socket.h>
# include <netinet/in.h> # include <netinet/in.h>
# include <arpa/inet.h> # include <arpa/inet.h>
# include <unistd.h> # include <unistd.h>
# include <fcntl.h>
# define SOCKET_ERROR -1 # define SOCKET_ERROR -1
typedef struct sockaddr_in SOCKADDR_IN; typedef struct sockaddr_in SOCKADDR_IN;
typedef struct sockaddr SOCKADDR; typedef struct sockaddr SOCKADDR;
typedef struct in_addr IN_ADDR; typedef struct in_addr IN_ADDR;
typedef int sc_raw_socket; typedef int sc_raw_socket;
# define SC_RAW_SOCKET_NONE -1
#endif #endif
bool bool
@ -79,6 +83,35 @@ unwrap(sc_socket socket) {
#endif #endif
} }
static inline bool
sc_raw_socket_close(sc_raw_socket raw_sock) {
#ifndef _WIN32
return !close(raw_sock);
#else
return !closesocket(raw_sock);
#endif
}
#ifndef HAVE_SOCK_CLOEXEC
// If SOCK_CLOEXEC does not exist, the flag must be set manually once the
// socket is created
static bool
set_cloexec_flag(sc_raw_socket raw_sock) {
#ifndef _WIN32
if (fcntl(raw_sock, F_SETFD, FD_CLOEXEC) == -1) {
perror("fcntl F_SETFD");
return false;
}
#else
if (!SetHandleInformation((HANDLE) raw_sock, HANDLE_FLAG_INHERIT, 0)) {
LOGE("SetHandleInformation socket failed");
return false;
}
#endif
return true;
}
#endif
static void static void
net_perror(const char *s) { net_perror(const char *s) {
#ifdef _WIN32 #ifdef _WIN32
@ -97,7 +130,16 @@ net_perror(const char *s) {
sc_socket sc_socket
net_socket(void) { net_socket(void) {
#ifdef HAVE_SOCK_CLOEXEC
sc_raw_socket raw_sock = socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, 0);
#else
sc_raw_socket raw_sock = socket(AF_INET, SOCK_STREAM, 0); sc_raw_socket raw_sock = socket(AF_INET, SOCK_STREAM, 0);
if (raw_sock != SC_RAW_SOCKET_NONE && !set_cloexec_flag(raw_sock)) {
sc_raw_socket_close(raw_sock);
return SC_SOCKET_NONE;
}
#endif
sc_socket sock = wrap(raw_sock); sc_socket sock = wrap(raw_sock);
if (sock == SC_SOCKET_NONE) { if (sock == SC_SOCKET_NONE) {
net_perror("socket"); net_perror("socket");
@ -156,8 +198,18 @@ net_accept(sc_socket server_socket) {
SOCKADDR_IN csin; SOCKADDR_IN csin;
socklen_t sinsize = sizeof(csin); socklen_t sinsize = sizeof(csin);
#ifdef HAVE_SOCK_CLOEXEC
sc_raw_socket raw_sock =
accept4(raw_server_socket, (SOCKADDR *) &csin, &sinsize, SOCK_CLOEXEC);
#else
sc_raw_socket raw_sock = sc_raw_socket raw_sock =
accept(raw_server_socket, (SOCKADDR *) &csin, &sinsize); accept(raw_server_socket, (SOCKADDR *) &csin, &sinsize);
if (raw_sock != SC_RAW_SOCKET_NONE && !set_cloexec_flag(raw_sock)) {
sc_raw_socket_close(raw_sock);
return SC_SOCKET_NONE;
}
#endif
return wrap(raw_sock); return wrap(raw_sock);
} }
@ -211,7 +263,6 @@ net_interrupt(sc_socket socket) {
#endif #endif
} }
#include <errno.h>
bool bool
net_close(sc_socket socket) { net_close(sc_socket socket) {
sc_raw_socket raw_sock = unwrap(socket); sc_raw_socket raw_sock = unwrap(socket);