diff options
author | Evgeny Grin (Karlson2k) <k2k@narod.ru> | 2021-04-15 18:58:58 +0300 |
---|---|---|
committer | Christian Grothoff <christian@grothoff.org> | 2021-04-16 10:25:37 +0200 |
commit | fadba1133cc4e67ce8dd9d9709edd76f9285c704 (patch) | |
tree | a13f8e74e7e8314d3da7a41d50b6edb5d1fd4bfa | |
parent | ddf368bb6d1093657ab29cb5af894bdc2b93788f (diff) | |
download | libmicrohttpd-fadba1133cc4e67ce8dd9d9709edd76f9285c704.tar.gz libmicrohttpd-fadba1133cc4e67ce8dd9d9709edd76f9285c704.zip |
fix #6768: do not use TCP-specific syscalls on UNIX domain sockets
-rw-r--r-- | ChangeLog | 10 | ||||
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | src/microhttpd/daemon.c | 60 | ||||
-rw-r--r-- | src/microhttpd/internal.h | 13 | ||||
-rw-r--r-- | src/microhttpd/mhd_send.c | 13 |
5 files changed, 84 insertions, 14 deletions
@@ -1,3 +1,13 @@ | |||
1 | Fri 16 Apr 2021 10:23:39 AM CEST | ||
2 | Thu 15 Apr 2021 18:56:00 MSK | ||
3 | Fixed configure '--enable-sanitizer' paramenter. | ||
4 | Stopped pushing of patrial responses when limited by system maximum size | ||
5 | for sendmsg(). -EG | ||
6 | Fri 16 Apr 2021 10:23:39 AM CEST | ||
7 | Detect if a socket is a UNIX domain socket and do not try to play | ||
8 | with TCP corking options in this case (avoids useless failed | ||
9 | syscalls). -CG | ||
10 | |||
1 | Web 14 Apr 2021 22:20:00 MSK | 11 | Web 14 Apr 2021 22:20:00 MSK |
2 | Fixed: use sendmsg() in POSIX-compatible way, do not try to send more | 12 | Fixed: use sendmsg() in POSIX-compatible way, do not try to send more |
3 | than IOV_MAX elements per single call. -EG | 13 | than IOV_MAX elements per single call. -EG |
diff --git a/configure.ac b/configure.ac index e6cc7214..e9c1e03b 100644 --- a/configure.ac +++ b/configure.ac | |||
@@ -117,7 +117,7 @@ AC_ARG_ENABLE([linker-hardening], | |||
117 | AC_ARG_ENABLE([sanitizer], | 117 | AC_ARG_ENABLE([sanitizer], |
118 | [AS_HELP_STRING([--enable-sanitizer], [enable Address Sanitizer and Undefined Behavior Sanitizer])], | 118 | [AS_HELP_STRING([--enable-sanitizer], [enable Address Sanitizer and Undefined Behavior Sanitizer])], |
119 | [AS_IF([test x$enableval = xyes],[ | 119 | [AS_IF([test x$enableval = xyes],[ |
120 | LDFLAGS="$CFLAGS -fsanitize=address,undefined -fno-omit-frame-pointer" | 120 | CFLAGS="$CFLAGS -fsanitize=address,undefined -fno-omit-frame-pointer" |
121 | ])]) | 121 | ])]) |
122 | 122 | ||
123 | 123 | ||
diff --git a/src/microhttpd/daemon.c b/src/microhttpd/daemon.c index 7f814ec0..d3b9958d 100644 --- a/src/microhttpd/daemon.c +++ b/src/microhttpd/daemon.c | |||
@@ -2376,6 +2376,7 @@ psk_gnutls_adapter (gnutls_session_t session, | |||
2376 | * @param non_blck indicate that socket in non-blocking mode | 2376 | * @param non_blck indicate that socket in non-blocking mode |
2377 | * @param sk_spipe_supprs indicate that the @a client_socket has | 2377 | * @param sk_spipe_supprs indicate that the @a client_socket has |
2378 | * set SIGPIPE suppression | 2378 | * set SIGPIPE suppression |
2379 | * @param sk_is_unix true if this is a UNIX domain socket (AF_UNIX) | ||
2379 | * @return pointer to the connection on success, NULL if this daemon could | 2380 | * @return pointer to the connection on success, NULL if this daemon could |
2380 | * not handle the connection (i.e. malloc failed, etc). | 2381 | * not handle the connection (i.e. malloc failed, etc). |
2381 | * The socket will be closed in case of error; 'errno' is | 2382 | * The socket will be closed in case of error; 'errno' is |
@@ -2388,7 +2389,8 @@ new_connection_prepare_ (struct MHD_Daemon *daemon, | |||
2388 | socklen_t addrlen, | 2389 | socklen_t addrlen, |
2389 | bool external_add, | 2390 | bool external_add, |
2390 | bool non_blck, | 2391 | bool non_blck, |
2391 | bool sk_spipe_supprs) | 2392 | bool sk_spipe_supprs, |
2393 | bool sk_is_unix) | ||
2392 | { | 2394 | { |
2393 | struct MHD_Connection *connection; | 2395 | struct MHD_Connection *connection; |
2394 | int eno = 0; | 2396 | int eno = 0; |
@@ -2490,6 +2492,7 @@ new_connection_prepare_ (struct MHD_Daemon *daemon, | |||
2490 | connection->addr_len = addrlen; | 2492 | connection->addr_len = addrlen; |
2491 | connection->socket_fd = client_socket; | 2493 | connection->socket_fd = client_socket; |
2492 | connection->sk_nonblck = non_blck; | 2494 | connection->sk_nonblck = non_blck; |
2495 | connection->is_unix = sk_is_unix; | ||
2493 | connection->sk_spipe_suppress = sk_spipe_supprs; | 2496 | connection->sk_spipe_suppress = sk_spipe_supprs; |
2494 | connection->daemon = daemon; | 2497 | connection->daemon = daemon; |
2495 | connection->last_activity = MHD_monotonic_sec_counter (); | 2498 | connection->last_activity = MHD_monotonic_sec_counter (); |
@@ -2860,6 +2863,7 @@ cleanup: | |||
2860 | * @param non_blck indicate that socket in non-blocking mode | 2863 | * @param non_blck indicate that socket in non-blocking mode |
2861 | * @param sk_spipe_supprs indicate that the @a client_socket has | 2864 | * @param sk_spipe_supprs indicate that the @a client_socket has |
2862 | * set SIGPIPE suppression | 2865 | * set SIGPIPE suppression |
2866 | * @param sk_is_unix true if this is a UNIX domain socket (AF_UNIX) | ||
2863 | * @return #MHD_YES on success, #MHD_NO if this daemon could | 2867 | * @return #MHD_YES on success, #MHD_NO if this daemon could |
2864 | * not handle the connection (i.e. malloc failed, etc). | 2868 | * not handle the connection (i.e. malloc failed, etc). |
2865 | * The socket will be closed in any case; 'errno' is | 2869 | * The socket will be closed in any case; 'errno' is |
@@ -2872,7 +2876,8 @@ internal_add_connection (struct MHD_Daemon *daemon, | |||
2872 | socklen_t addrlen, | 2876 | socklen_t addrlen, |
2873 | bool external_add, | 2877 | bool external_add, |
2874 | bool non_blck, | 2878 | bool non_blck, |
2875 | bool sk_spipe_supprs) | 2879 | bool sk_spipe_supprs, |
2880 | bool sk_is_unix) | ||
2876 | { | 2881 | { |
2877 | struct MHD_Connection *connection; | 2882 | struct MHD_Connection *connection; |
2878 | 2883 | ||
@@ -2912,9 +2917,13 @@ internal_add_connection (struct MHD_Daemon *daemon, | |||
2912 | return MHD_NO; | 2917 | return MHD_NO; |
2913 | } | 2918 | } |
2914 | 2919 | ||
2915 | connection = new_connection_prepare_ (daemon, client_socket, addr, addrlen, | 2920 | connection = new_connection_prepare_ (daemon, |
2916 | external_add, non_blck, | 2921 | client_socket, |
2917 | sk_spipe_supprs); | 2922 | addr, addrlen, |
2923 | external_add, | ||
2924 | non_blck, | ||
2925 | sk_spipe_supprs, | ||
2926 | sk_is_unix); | ||
2918 | if (NULL == connection) | 2927 | if (NULL == connection) |
2919 | return MHD_NO; | 2928 | return MHD_NO; |
2920 | 2929 | ||
@@ -3339,6 +3348,7 @@ MHD_add_connection (struct MHD_Daemon *daemon, | |||
3339 | { | 3348 | { |
3340 | bool sk_nonbl; | 3349 | bool sk_nonbl; |
3341 | bool sk_spipe_supprs; | 3350 | bool sk_spipe_supprs; |
3351 | bool sk_is_unix = false; | ||
3342 | 3352 | ||
3343 | /* NOT thread safe with internal thread. TODO: fix thread safety. */ | 3353 | /* NOT thread safe with internal thread. TODO: fix thread safety. */ |
3344 | if ((0 == (daemon->options & MHD_USE_INTERNAL_POLLING_THREAD)) && | 3354 | if ((0 == (daemon->options & MHD_USE_INTERNAL_POLLING_THREAD)) && |
@@ -3409,6 +3419,20 @@ MHD_add_connection (struct MHD_Daemon *daemon, | |||
3409 | _ ("Failed to set noninheritable mode on new client socket.\n")); | 3419 | _ ("Failed to set noninheritable mode on new client socket.\n")); |
3410 | #endif | 3420 | #endif |
3411 | } | 3421 | } |
3422 | #ifdef SO_DOMAIN | ||
3423 | { | ||
3424 | int af; | ||
3425 | socklen_t len = sizeof (af); | ||
3426 | |||
3427 | if ( (0 == getsockopt (daemon->listen_fd, | ||
3428 | SOL_SOCKET, | ||
3429 | SO_DOMAIN, | ||
3430 | &af, | ||
3431 | &len)) && | ||
3432 | (AF_UNIX == af) ) | ||
3433 | sk_is_unix = true; | ||
3434 | } | ||
3435 | #endif | ||
3412 | 3436 | ||
3413 | #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS) | 3437 | #if defined(MHD_USE_POSIX_THREADS) || defined(MHD_USE_W32_THREADS) |
3414 | if (NULL != daemon->worker_pool) | 3438 | if (NULL != daemon->worker_pool) |
@@ -3428,7 +3452,8 @@ MHD_add_connection (struct MHD_Daemon *daemon, | |||
3428 | addrlen, | 3452 | addrlen, |
3429 | true, | 3453 | true, |
3430 | sk_nonbl, | 3454 | sk_nonbl, |
3431 | sk_spipe_supprs); | 3455 | sk_spipe_supprs, |
3456 | sk_is_unix); | ||
3432 | } | 3457 | } |
3433 | /* all pools are at their connection limit, must refuse */ | 3458 | /* all pools are at their connection limit, must refuse */ |
3434 | MHD_socket_close_chk_ (client_socket); | 3459 | MHD_socket_close_chk_ (client_socket); |
@@ -3445,7 +3470,8 @@ MHD_add_connection (struct MHD_Daemon *daemon, | |||
3445 | addrlen, | 3470 | addrlen, |
3446 | true, | 3471 | true, |
3447 | sk_nonbl, | 3472 | sk_nonbl, |
3448 | sk_spipe_supprs); | 3473 | sk_spipe_supprs, |
3474 | sk_is_unix); | ||
3449 | } | 3475 | } |
3450 | 3476 | ||
3451 | 3477 | ||
@@ -3627,7 +3653,8 @@ MHD_accept_connection (struct MHD_Daemon *daemon) | |||
3627 | addrlen, | 3653 | addrlen, |
3628 | false, | 3654 | false, |
3629 | sk_nonbl, | 3655 | sk_nonbl, |
3630 | sk_spipe_supprs); | 3656 | sk_spipe_supprs, |
3657 | daemon->listen_is_unix); | ||
3631 | return MHD_YES; | 3658 | return MHD_YES; |
3632 | } | 3659 | } |
3633 | 3660 | ||
@@ -5810,8 +5837,24 @@ parse_options_va (struct MHD_Daemon *daemon, | |||
5810 | return MHD_NO; | 5837 | return MHD_NO; |
5811 | } | 5838 | } |
5812 | else | 5839 | else |
5840 | { | ||
5813 | daemon->listen_fd = va_arg (ap, | 5841 | daemon->listen_fd = va_arg (ap, |
5814 | MHD_socket); | 5842 | MHD_socket); |
5843 | #ifdef SO_DOMAIN | ||
5844 | { | ||
5845 | int af; | ||
5846 | socklen_t len = sizeof (af); | ||
5847 | |||
5848 | if ( (0 == getsockopt (daemon->listen_fd, | ||
5849 | SOL_SOCKET, | ||
5850 | SO_DOMAIN, | ||
5851 | &af, | ||
5852 | &len)) && | ||
5853 | (AF_UNIX == af) ) | ||
5854 | daemon->listen_is_unix = true; | ||
5855 | } | ||
5856 | #endif | ||
5857 | } | ||
5815 | break; | 5858 | break; |
5816 | case MHD_OPTION_EXTERNAL_LOGGER: | 5859 | case MHD_OPTION_EXTERNAL_LOGGER: |
5817 | #ifdef HAVE_MESSAGES | 5860 | #ifdef HAVE_MESSAGES |
@@ -6680,7 +6723,6 @@ MHD_start_daemon_va (unsigned int flags, | |||
6680 | } | 6723 | } |
6681 | } | 6724 | } |
6682 | daemon->listen_fd = listen_fd; | 6725 | daemon->listen_fd = listen_fd; |
6683 | |||
6684 | if (0 != (*pflags & MHD_USE_IPv6)) | 6726 | if (0 != (*pflags & MHD_USE_IPv6)) |
6685 | { | 6727 | { |
6686 | #ifdef IPPROTO_IPV6 | 6728 | #ifdef IPPROTO_IPV6 |
diff --git a/src/microhttpd/internal.h b/src/microhttpd/internal.h index dc38bada..c939d3e2 100644 --- a/src/microhttpd/internal.h +++ b/src/microhttpd/internal.h | |||
@@ -994,6 +994,11 @@ struct MHD_Connection | |||
994 | MHD_socket socket_fd; | 994 | MHD_socket socket_fd; |
995 | 995 | ||
996 | /** | 996 | /** |
997 | * true if #socket_fd is a UNIX domain socket, false (TCP) otherwise. | ||
998 | */ | ||
999 | bool is_unix; | ||
1000 | |||
1001 | /** | ||
997 | * true if #socket_fd is non-blocking, false otherwise. | 1002 | * true if #socket_fd is non-blocking, false otherwise. |
998 | */ | 1003 | */ |
999 | bool sk_nonblck; | 1004 | bool sk_nonblck; |
@@ -1459,11 +1464,17 @@ struct MHD_Daemon | |||
1459 | int epoll_fd; | 1464 | int epoll_fd; |
1460 | 1465 | ||
1461 | /** | 1466 | /** |
1462 | * true if the listen socket is in the 'epoll' set, | 1467 | * true if the @e listen_fd socket is in the 'epoll' set, |
1463 | * false if not. | 1468 | * false if not. |
1464 | */ | 1469 | */ |
1465 | bool listen_socket_in_epoll; | 1470 | bool listen_socket_in_epoll; |
1466 | 1471 | ||
1472 | /** | ||
1473 | * true if the @e listen_fd socket is a UNIX domain socket, | ||
1474 | * false if not. | ||
1475 | */ | ||
1476 | bool listen_is_unix; | ||
1477 | |||
1467 | #ifdef UPGRADE_SUPPORT | 1478 | #ifdef UPGRADE_SUPPORT |
1468 | #ifdef HTTPS_SUPPORT | 1479 | #ifdef HTTPS_SUPPORT |
1469 | /** | 1480 | /** |
diff --git a/src/microhttpd/mhd_send.c b/src/microhttpd/mhd_send.c index c237d469..3810e121 100644 --- a/src/microhttpd/mhd_send.c +++ b/src/microhttpd/mhd_send.c | |||
@@ -165,6 +165,7 @@ MHD_connection_set_nodelay_state_ (struct MHD_Connection *connection, | |||
165 | * Set required cork state for connection socket | 165 | * Set required cork state for connection socket |
166 | * | 166 | * |
167 | * The function automatically updates sk_corked state. | 167 | * The function automatically updates sk_corked state. |
168 | * | ||
168 | * @param connection the connection to manipulate | 169 | * @param connection the connection to manipulate |
169 | * @param cork_state the requested new state of socket | 170 | * @param cork_state the requested new state of socket |
170 | * @return true if succeed, false if failed | 171 | * @return true if succeed, false if failed |
@@ -177,6 +178,8 @@ connection_set_cork_state_ (struct MHD_Connection *connection, | |||
177 | const MHD_SCKT_OPT_BOOL_ on_val = 1; | 178 | const MHD_SCKT_OPT_BOOL_ on_val = 1; |
178 | int err_code; | 179 | int err_code; |
179 | 180 | ||
181 | if (connection->is_unix) | ||
182 | return true; | ||
180 | if (0 == setsockopt (connection->socket_fd, | 183 | if (0 == setsockopt (connection->socket_fd, |
181 | IPPROTO_TCP, | 184 | IPPROTO_TCP, |
182 | MHD_TCP_CORK_NOPUSH, | 185 | MHD_TCP_CORK_NOPUSH, |
@@ -240,6 +243,8 @@ pre_send_setopt (struct MHD_Connection *connection, | |||
240 | * Final piece is indicated by push_data == true. */ | 243 | * Final piece is indicated by push_data == true. */ |
241 | const bool buffer_data = (! push_data); | 244 | const bool buffer_data = (! push_data); |
242 | 245 | ||
246 | if (connection->is_unix) | ||
247 | return; | ||
243 | /* The goal is to minimise the total number of additional sys-calls | 248 | /* The goal is to minimise the total number of additional sys-calls |
244 | * before and after send(). | 249 | * before and after send(). |
245 | * The following tricky (over-)complicated algorithm typically use zero, | 250 | * The following tricky (over-)complicated algorithm typically use zero, |
@@ -461,14 +466,14 @@ static bool | |||
461 | zero_send_ (struct MHD_Connection *connection) | 466 | zero_send_ (struct MHD_Connection *connection) |
462 | { | 467 | { |
463 | int dummy; | 468 | int dummy; |
469 | |||
470 | if (connection->is_unix) | ||
471 | return; | ||
464 | mhd_assert (_MHD_OFF == connection->sk_corked); | 472 | mhd_assert (_MHD_OFF == connection->sk_corked); |
465 | mhd_assert (_MHD_ON == connection->sk_nodelay); | 473 | mhd_assert (_MHD_ON == connection->sk_nodelay); |
466 | |||
467 | dummy = 0; /* Mute compiler and analyzer warnings */ | 474 | dummy = 0; /* Mute compiler and analyzer warnings */ |
468 | |||
469 | if (0 == MHD_send_ (connection->socket_fd, &dummy, 0)) | 475 | if (0 == MHD_send_ (connection->socket_fd, &dummy, 0)) |
470 | return true; | 476 | return true; |
471 | |||
472 | #ifdef HAVE_MESSAGES | 477 | #ifdef HAVE_MESSAGES |
473 | MHD_DLOG (connection->daemon, | 478 | MHD_DLOG (connection->daemon, |
474 | _ ("Zero-send failed: %s\n"), | 479 | _ ("Zero-send failed: %s\n"), |
@@ -499,6 +504,8 @@ post_send_setopt (struct MHD_Connection *connection, | |||
499 | * Final piece is indicated by push_data == true. */ | 504 | * Final piece is indicated by push_data == true. */ |
500 | const bool buffer_data = (! push_data); | 505 | const bool buffer_data = (! push_data); |
501 | 506 | ||
507 | if (connection->is_unix) | ||
508 | return; | ||
502 | if (buffer_data) | 509 | if (buffer_data) |
503 | return; /* Nothing to do after send(). */ | 510 | return; /* Nothing to do after send(). */ |
504 | 511 | ||