Problem: ws_engine uses unsafe strcpy

Solution: use strcpy_s instead (define custom if not available)
This commit is contained in:
Simon Giesecke 2019-12-11 13:33:00 +01:00 committed by Simon Giesecke
parent 2256bd5b0b
commit 334e837b88
4 changed files with 39 additions and 4 deletions

View File

@ -460,6 +460,7 @@ if(NOT MSVC)
check_cxx_symbol_exists(mkdtemp stdlib.h HAVE_MKDTEMP) check_cxx_symbol_exists(mkdtemp stdlib.h HAVE_MKDTEMP)
check_cxx_symbol_exists(accept4 sys/socket.h HAVE_ACCEPT4) check_cxx_symbol_exists(accept4 sys/socket.h HAVE_ACCEPT4)
check_cxx_symbol_exists(strnlen string.h HAVE_STRNLEN) check_cxx_symbol_exists(strnlen string.h HAVE_STRNLEN)
check_cxx_symbol_exists(strlcpy string.h ZMQ_HAVE_STRLCPY)
else() else()
set(HAVE_STRNLEN 1) set(HAVE_STRNLEN 1)
endif() endif()

View File

@ -51,6 +51,7 @@
#cmakedefine ZMQ_HAVE_PTHREAD_SET_AFFINITY #cmakedefine ZMQ_HAVE_PTHREAD_SET_AFFINITY
#cmakedefine HAVE_ACCEPT4 #cmakedefine HAVE_ACCEPT4
#cmakedefine HAVE_STRNLEN #cmakedefine HAVE_STRNLEN
#cmakedefine ZMQ_HAVE_STRLCPY
#cmakedefine ZMQ_HAVE_IPC #cmakedefine ZMQ_HAVE_IPC

View File

@ -751,6 +751,20 @@ AC_COMPILE_IFELSE(
AC_MSG_RESULT([no]) AC_MSG_RESULT([no])
]) ])
# string.h doesn't seem to be included by default in Fedora 30
AC_MSG_CHECKING([whether strlcpy is available])
AC_COMPILE_IFELSE(
[AC_LANG_PROGRAM(
[[#include <string.h>]],
[[char buf [100]; size_t bar = strlcpy (buf, "foo", 100); (void)bar; return 0;]])
],[
AC_MSG_RESULT([yes])
AC_DEFINE(ZMQ_HAVE_STRLCPY, [1],
[strlcpy is available])
],[
AC_MSG_RESULT([no])
])
# pthread_setname is non-posix, and there are at least 4 different implementations # pthread_setname is non-posix, and there are at least 4 different implementations
AC_MSG_CHECKING([whether signature of pthread_setname_np() has 1 argument]) AC_MSG_CHECKING([whether signature of pthread_setname_np() has 1 argument])
AC_COMPILE_IFELSE( AC_COMPILE_IFELSE(

View File

@ -52,6 +52,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#endif #endif
#endif #endif
#include <cstring>
#include "tcp.hpp" #include "tcp.hpp"
#include "ws_engine.hpp" #include "ws_engine.hpp"
#include "session_base.hpp" #include "session_base.hpp"
@ -71,6 +73,23 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifdef ZMQ_HAVE_WINDOWS #ifdef ZMQ_HAVE_WINDOWS
#define strcasecmp _stricmp #define strcasecmp _stricmp
#else
#ifndef ZMQ_HAVE_STRLCPY
static size_t strlcpy (char *dest_, const char *src_, const size_t dest_size_)
{
size_t remain = dest_size_;
for (; remain && *src_; --remain, ++src_, ++dest_) {
*dest_ = *src_;
}
return dest_size_ - remain;
}
#endif
template <size_t size>
static int strcpy_s (char (&dest_)[size], const char *const src_)
{
const size_t res = strlcpy (dest_, src_, size);
return res >= size ? ERANGE : 0;
}
#endif #endif
// OSX uses a different name for this socket option // OSX uses a different name for this socket option
@ -440,7 +459,7 @@ bool zmq::ws_engine_t::server_handshake ()
strcasecmp ("upgrade", _header_value) == 0; strcasecmp ("upgrade", _header_value) == 0;
else if (strcasecmp ("Sec-WebSocket-Key", _header_name) else if (strcasecmp ("Sec-WebSocket-Key", _header_name)
== 0) == 0)
strcpy (_websocket_key, _header_value); strcpy_s (_websocket_key, _header_value);
else if (strcasecmp ("Sec-WebSocket-Protocol", _header_name) else if (strcasecmp ("Sec-WebSocket-Protocol", _header_name)
== 0) { == 0) {
// Currently only the ZWS2.0 is supported // Currently only the ZWS2.0 is supported
@ -453,7 +472,7 @@ bool zmq::ws_engine_t::server_handshake ()
p++; p++;
if (select_protocol (p)) { if (select_protocol (p)) {
strcpy (_websocket_protocol, p); strcpy_s (_websocket_protocol, p);
break; break;
} }
@ -820,11 +839,11 @@ bool zmq::ws_engine_t::client_handshake ()
strcasecmp ("upgrade", _header_value) == 0; strcasecmp ("upgrade", _header_value) == 0;
else if (strcasecmp ("Sec-WebSocket-Accept", _header_name) else if (strcasecmp ("Sec-WebSocket-Accept", _header_name)
== 0) == 0)
strcpy (_websocket_accept, _header_value); strcpy_s (_websocket_accept, _header_value);
else if (strcasecmp ("Sec-WebSocket-Protocol", _header_name) else if (strcasecmp ("Sec-WebSocket-Protocol", _header_name)
== 0) { == 0) {
if (select_protocol (_header_value)) if (select_protocol (_header_value))
strcpy (_websocket_protocol, _header_value); strcpy_s (_websocket_protocol, _header_value);
} }
_client_handshake_state = client_header_field_cr; _client_handshake_state = client_header_field_cr;
} else if (_header_value_position + 1 > MAX_HEADER_VALUE_LENGTH) } else if (_header_value_position + 1 > MAX_HEADER_VALUE_LENGTH)