From 9c3259ca065cd3331e627607b73bda96ed460524ba3f3eb9400bbbcac1fcb996 Mon Sep 17 00:00:00 2001 From: Marius Tomaschewski Date: Thu, 27 Apr 2017 09:50:39 +0000 Subject: [PATCH] Accepting request 489820 from home:ndas:branches:network:vpn - Preform deferred authentication in the background to not cause main daemon processing delays when the underlying pam mechanism (e.g. ldap) needs longer to response (bsc#959511). [+ 0001-preform-deferred-authentication-in-the-background.patch] - Added fix for possible heap overflow on read accessing getaddrinfo result (bsc#959714). [+openvpn-2.3.9-Fix-heap-overflow-on-getaddrinfo-result.patch] - Added a patch to fix multiple low severity issues (bsc#934237). [+openvpn-2.3.x-fixed-multiple-low-severity-issues.patch] OBS-URL: https://build.opensuse.org/request/show/489820 OBS-URL: https://build.opensuse.org/package/show/network:vpn/openvpn?expand=0&rev=115 --- ...red-authentication-in-the-background.patch | 163 ++++++++++++ ...-heap-overflow-on-getaddrinfo-result.patch | 66 +++++ ...x-fixed-multiple-low-severity-issues.patch | 238 ++++++++++++++++++ openvpn.changes | 13 + openvpn.spec | 6 + 5 files changed, 486 insertions(+) create mode 100644 0001-preform-deferred-authentication-in-the-background.patch create mode 100644 openvpn-2.3.9-Fix-heap-overflow-on-getaddrinfo-result.patch create mode 100644 openvpn-2.3.x-fixed-multiple-low-severity-issues.patch diff --git a/0001-preform-deferred-authentication-in-the-background.patch b/0001-preform-deferred-authentication-in-the-background.patch new file mode 100644 index 0000000..018a8e8 --- /dev/null +++ b/0001-preform-deferred-authentication-in-the-background.patch @@ -0,0 +1,163 @@ +From 8c39dbd45d3551e838310732a73e05f6d2d2e784 Mon Sep 17 00:00:00 2001 +From: Nirmoy Das +Date: Thu, 12 May 2016 12:08:56 +0200 +Subject: [PATCH] preform deferred authentication in the background to not + cause main daemon processing delays when the underlying pam mechanism (e.g. + ldap) needs longer to response. +References: bsc#959511 + + +diff --git a/src/plugins/auth-pam/auth-pam.c b/src/plugins/auth-pam/auth-pam.c +index bd71792..119fc31 100644 +--- a/src/plugins/auth-pam/auth-pam.c ++++ b/src/plugins/auth-pam/auth-pam.c +@@ -55,6 +55,7 @@ + /* Command codes for foreground -> background communication */ + #define COMMAND_VERIFY 0 + #define COMMAND_EXIT 1 ++#define COMMAND_VERIFY_V2 2 + + /* Response codes for background -> foreground communication */ + #define RESPONSE_INIT_SUCCEEDED 10 +@@ -108,6 +109,7 @@ struct user_pass { + char username[128]; + char password[128]; + char common_name[128]; ++ char auth_control_file[PATH_MAX]; + + const struct name_value_list *name_value_list; + }; +@@ -687,6 +689,21 @@ pam_auth (const char *service, const struct user_pass *up) + return ret; + } + ++static int handle_auth_control_file(char *auth_control_file, int status) ++{ ++ FILE *fp = fopen(auth_control_file, "w"); ++ ++ if (fp) { ++ if (fprintf (fp, "%d\n", status) < 0) { ++ fclose(fp); ++ return -1; ++ } ++ fclose(fp); ++ return 0; ++ } ++ return -1; ++} ++ + /* + * Background process -- runs with privilege. + */ +@@ -781,6 +798,41 @@ pam_server (int fd, const char *service, int verb, const struct name_value_list + } + break; + ++ case COMMAND_VERIFY_V2: ++ if (recv_string (fd, up.username, sizeof (up.username)) == -1 ++ || recv_string (fd, up.password, sizeof (up.password)) == -1 ++ || recv_string (fd, up.common_name, sizeof (up.common_name)) == -1 ++ || recv_string (fd, up.auth_control_file, sizeof (up.auth_control_file)) == -1) ++ { ++ fprintf (stderr, "AUTH-PAM: BACKGROUND: read error on command channel: code=%d, exiting\n", ++ command); ++ goto done; ++ } ++ ++ if (DEBUG (verb)) ++ { ++#if 0 ++ fprintf (stderr, "AUTH-PAM: BACKGROUND: USER/PASS: %s/%s\n", ++ up.username, up.password); ++#else ++ fprintf (stderr, "AUTH-PAM: BACKGROUND: USER: %s\n", up.username); ++#endif ++ } ++ ++ if (pam_auth (service, &up)) /* Succeeded */ ++ { ++ if (handle_auth_control_file(up.auth_control_file, 1) == -1) { ++ fprintf (stderr, "AUTH-PAM: BACKGROUND: write error on control file\n"); ++ } ++ } ++ else /* Failed */ ++ { ++ if (handle_auth_control_file(up.auth_control_file, 0) == -1) { ++ fprintf (stderr, "AUTH-PAM: BACKGROUND: write error on control file\n"); ++ } ++ } ++ break; ++ + case COMMAND_EXIT: + goto done; + +@@ -804,3 +856,56 @@ pam_server (int fd, const char *service, int verb, const struct name_value_list + + return; + } ++ ++int ++handle_auth_pass_verify_v2(struct auth_pam_context *context, const char *argv[], const char *envp[]) ++{ ++ ++ /* get username/password from envp string array */ ++ const char *username = get_env ("username", envp); ++ const char *password = get_env ("password", envp); ++ const char *common_name = get_env ("common_name", envp) ? get_env ("common_name", envp) : ""; ++ const char *auth_control_file = get_env ("auth_control_file", envp); ++ ++ if (!username || !*username || !password) ++ return OPENVPN_PLUGIN_FUNC_ERROR; ++ ++ if (!auth_control_file || !*auth_control_file || access( auth_control_file, F_OK ) == -1) ++ return OPENVPN_PLUGIN_FUNC_ERROR; ++ ++ if (send_control (context->foreground_fd, COMMAND_VERIFY_V2) == -1 ++ || send_string (context->foreground_fd, username) == -1 ++ || send_string (context->foreground_fd, password) == -1 ++ || send_string (context->foreground_fd, common_name) == -1 ++ || send_string (context->foreground_fd, auth_control_file) == -1) ++ { ++ fprintf (stderr, "AUTH-PAM: Error sending auth info to background process\n"); ++ } ++ else ++ { ++ return OPENVPN_PLUGIN_FUNC_DEFERRED; ++ } ++ ++ return OPENVPN_PLUGIN_FUNC_ERROR; ++} ++ ++OPENVPN_EXPORT int ++openvpn_plugin_func_v2 (openvpn_plugin_handle_t handle, ++ const int type, ++ const char *argv[], ++ const char *envp[], ++ void *per_client_context, ++ struct openvpn_plugin_string_list **return_list) ++{ ++ struct auth_pam_context *context = (struct auth_pam_context *) handle; ++ ++ switch (type) ++ { ++ case OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY: ++ printf ("OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY\n"); ++ return handle_auth_pass_verify_v2 (context, argv, envp); ++ default: ++ printf ("OPENVPN_PLUGIN_?\n"); ++ return OPENVPN_PLUGIN_FUNC_ERROR; ++ } ++} +diff --git a/src/plugins/auth-pam/auth-pam.exports b/src/plugins/auth-pam/auth-pam.exports +index b07937c..11a80f1 100644 +--- a/src/plugins/auth-pam/auth-pam.exports ++++ b/src/plugins/auth-pam/auth-pam.exports +@@ -1,4 +1,5 @@ + openvpn_plugin_open_v1 + openvpn_plugin_func_v1 ++openvpn_plugin_func_v2 + openvpn_plugin_close_v1 + openvpn_plugin_abort_v1 +-- +2.6.2 + diff --git a/openvpn-2.3.9-Fix-heap-overflow-on-getaddrinfo-result.patch b/openvpn-2.3.9-Fix-heap-overflow-on-getaddrinfo-result.patch new file mode 100644 index 0000000..ec4eaa8 --- /dev/null +++ b/openvpn-2.3.9-Fix-heap-overflow-on-getaddrinfo-result.patch @@ -0,0 +1,66 @@ +Author: Gert Doering +Date: Tue Nov 10 22:58:39 2015 +0100 + + Fix possible heap overflow on read accessing getaddrinfo() result. + + The code always tried to copy-out a "struct sockaddr_in6" even for IPv4 + results, which reads more bytes than getaddrinfo() is guaranteed to + allocate. + + Now, look at ai->ai_family and only copy "struct sockaddr" for IPv4. + + Also, reformat this block of code to comply to coding style. + + This is a specific 2.3 bug as the code in master (to be 2.4) has been + completely rewritten to properly handle dual-stack and multiple responses + from getaddrinfo() proper. + + Bug found by Daniel Hirche using "gcc -fsanitize=address". No possible + exploits are known. + + Signed-off-by: Gert Doering + Acked-by: Arne Schwabe + Message-Id: <1447192719-31381-1-git-send-email-gert@greenie.muc.de> + URL: http://article.gmane.org/gmane.network.openvpn.devel/10479 + +References: bsc#959714 + +diff --git a/src/openvpn/socket.c b/src/openvpn/socket.c +index a143853..0f46bad 100644 +--- a/src/openvpn/socket.c ++++ b/src/openvpn/socket.c + -1259,20 +1259,24 resolve_remote (struct link_socket *sock, + ASSERT (0); + } + +- /* Temporary fix, this need to be changed for dual stack */ +- status = openvpn_getaddrinfo(flags, sock->remote_host, retry, +- signal_received, af, &ai); +- if(status == 0) { +- sock->info.lsa->remote.addr.in6 = *((struct sockaddr_in6*)(ai->ai_addr)); +- freeaddrinfo(ai); ++ /* Temporary fix, this need to be changed for dual stack */ ++ status = openvpn_getaddrinfo(flags, sock->remote_host, retry, ++ signal_received, af, &ai); ++ if(status == 0) ++ { ++ if ( ai->ai_family == AF_INET6 ) ++ sock->info.lsa->remote.addr.in6 = *((struct sockaddr_in6*)(ai->ai_addr)); ++ else ++ sock->info.lsa->remote.addr.in4 = *((struct sockaddr_in*)(ai->ai_addr)); ++ freeaddrinfo(ai); + +- dmsg (D_SOCKET_DEBUG, "RESOLVE_REMOTE flags=0x%04x phase=%d rrs=%d sig=%d status=%d", ++ dmsg (D_SOCKET_DEBUG, "RESOLVE_REMOTE flags=0x%04x phase=%d rrs=%d sig=%d status=%d", + flags, + phase, + retry, + signal_received ? *signal_received : -1, + status); +- } ++ } + if (signal_received) + { + if (*signal_received) +-- +2.4.9 diff --git a/openvpn-2.3.x-fixed-multiple-low-severity-issues.patch b/openvpn-2.3.x-fixed-multiple-low-severity-issues.patch new file mode 100644 index 0000000..77c469d --- /dev/null +++ b/openvpn-2.3.x-fixed-multiple-low-severity-issues.patch @@ -0,0 +1,238 @@ +diff --git a/src/openvpn/crypto.c b/src/openvpn/crypto.c +index 4261795..44c1f9e 100644 +--- a/src/openvpn/crypto.c ++++ b/src/openvpn/crypto.c +@@ -151,7 +151,7 @@ openvpn_encrypt (struct buffer *buf, struct buffer work, + ASSERT (cipher_ctx_reset(ctx->cipher, iv_buf)); + + /* Buffer overflow check */ +- if (!buf_safe (&work, buf->len + cipher_ctx_block_size(ctx->cipher))) ++ if (!buf_safe (&work, buf->len + OPENVPN_MAX_BLOCK_LENGTH)) + { + msg (D_CRYPT_ERRORS, "ENCRYPT: buffer size error, bc=%d bo=%d bl=%d wc=%d wo=%d wl=%d cbs=%d", + buf->capacity, +@@ -278,7 +278,7 @@ openvpn_decrypt (struct buffer *buf, struct buffer work, + const int iv_size = cipher_ctx_iv_length (ctx->cipher); + const cipher_kt_t *cipher_kt = cipher_ctx_get_cipher_kt (ctx->cipher); + uint8_t iv_buf[OPENVPN_MAX_IV_LENGTH]; +- int outlen; ++ int outlen = 0; + + /* initialize work buffer with FRAME_HEADROOM bytes of prepend capacity */ + ASSERT (buf_init (&work, FRAME_HEADROOM_ADJ (frame, FRAME_HEADROOM_MARKER_DECRYPT))); +@@ -305,7 +305,7 @@ openvpn_decrypt (struct buffer *buf, struct buffer work, + CRYPT_ERROR ("cipher init failed"); + + /* Buffer overflow check (should never happen) */ +- if (!buf_safe (&work, buf->len + cipher_ctx_block_size(ctx->cipher))) ++ if (!buf_safe (&work, buf->len + OPENVPN_MAX_BLOCK_LENGTH)) + CRYPT_ERROR ("potential buffer overflow"); + + /* Decrypt packet ID, payload */ +diff --git a/src/openvpn/crypto_openssl.h b/src/openvpn/crypto_openssl.h +index 2ed0bef..ae9f24d 100644 +--- a/src/openvpn/crypto_openssl.h ++++ b/src/openvpn/crypto_openssl.h +@@ -53,6 +53,9 @@ typedef HMAC_CTX hmac_ctx_t; + /** Maximum length of an IV */ + #define OPENVPN_MAX_IV_LENGTH EVP_MAX_IV_LENGTH + ++/** Maximum length of a cipher block */ ++#define OPENVPN_MAX_BLOCK_LENGTH EVP_MAX_BLOCK_LENGTH ++ + /** Cipher is in CBC mode */ + #define OPENVPN_MODE_CBC EVP_CIPH_CBC_MODE + +diff --git a/src/openvpn/init.c b/src/openvpn/init.c +index 089e3c4..e03a3e6 100644 +--- a/src/openvpn/init.c ++++ b/src/openvpn/init.c +@@ -2614,8 +2614,8 @@ init_context_buffers (const struct frame *frame) + b->aux_buf = alloc_buf (BUF_SIZE (frame)); + + #ifdef ENABLE_CRYPTO +- b->encrypt_buf = alloc_buf (BUF_SIZE (frame)); +- b->decrypt_buf = alloc_buf (BUF_SIZE (frame)); ++ b->encrypt_buf = alloc_buf (BUF_SIZE (frame) + OPENVPN_MAX_BLOCK_LENGTH); ++ b->decrypt_buf = alloc_buf (BUF_SIZE (frame) + OPENVPN_MAX_BLOCK_LENGTH); + #endif + + #ifdef ENABLE_LZO +diff --git a/src/openvpn/proxy.c b/src/openvpn/proxy.c +index 89989d1..5809daa 100644 +--- a/src/openvpn/proxy.c ++++ b/src/openvpn/proxy.c +@@ -76,6 +76,9 @@ recv_line (socket_descriptor_t sd, + struct buffer la; + int lastc = 0; + ++ if (sd >= FD_SETSIZE) ++ return false; ++ + CLEAR (la); + if (lookahead) + la = *lookahead; +@@ -283,11 +286,11 @@ get_proxy_authenticate (socket_descriptor_t sd, + struct gc_arena *gc, + volatile int *signal_received) + { +- char buf[256]; ++ char buf[256] = {0}; + int ret = HTTP_AUTH_NONE; + while (true) + { +- if (!recv_line (sd, buf, sizeof (buf), timeout, true, NULL, signal_received)) ++ if (!recv_line (sd, buf, sizeof (buf) - 1, timeout, true, NULL, signal_received)) + { + *data = NULL; + return HTTP_AUTH_NONE; +@@ -498,9 +501,9 @@ establish_http_proxy_passthru (struct http_proxy_info *p, + volatile int *signal_received) + { + struct gc_arena gc = gc_new (); +- char buf[512]; +- char buf2[129]; +- char get[80]; ++ char buf[512] = {0}; ++ char buf2[129] = {0}; ++ char get[80] = {0}; + int status; + int nparms; + bool ret = false; +@@ -586,7 +589,8 @@ establish_http_proxy_passthru (struct http_proxy_info *p, + goto error; + + /* receive reply from proxy */ +- if (!recv_line (sd, buf, sizeof(buf), p->options.timeout, true, NULL, signal_received)) ++ memset(buf, 0, sizeof(buf)); ++ if (!recv_line (sd, buf, sizeof(buf) - 1 , p->options.timeout, true, NULL, signal_received)) + goto error; + + /* remove trailing CR, LF */ +@@ -615,7 +619,8 @@ establish_http_proxy_passthru (struct http_proxy_info *p, + + while (true) + { +- if (!recv_line (sd, buf, sizeof(buf), p->options.timeout, true, NULL, signal_received)) ++ memset(buf, 0, sizeof(buf)); ++ if (!recv_line (sd, buf, sizeof(buf) - 1, p->options.timeout, true, NULL, signal_received)) + goto error; + chomp (buf); + msg (D_PROXY, "HTTP proxy returned: '%s'", buf); +@@ -685,7 +690,8 @@ establish_http_proxy_passthru (struct http_proxy_info *p, + goto error; + + /* receive reply from proxy */ +- if (!recv_line (sd, buf, sizeof(buf), p->options.timeout, true, NULL, signal_received)) ++ memset(buf, 0, sizeof(buf)); ++ if (!recv_line (sd, buf, sizeof(buf) - 1, p->options.timeout, true, NULL, signal_received)) + goto error; + + /* remove trailing CR, LF */ +@@ -795,7 +801,8 @@ establish_http_proxy_passthru (struct http_proxy_info *p, + goto error; + + /* receive reply from proxy */ +- if (!recv_line (sd, buf, sizeof(buf), p->options.timeout, true, NULL, signal_received)) ++ memset(buf, 0, sizeof(buf)); ++ if (!recv_line (sd, buf, sizeof(buf) - 1, p->options.timeout, true, NULL, signal_received)) + goto error; + + /* remove trailing CR, LF */ +diff --git a/src/openvpn/socket.c b/src/openvpn/socket.c +index 3474f18..dfd9d6c 100644 +--- a/src/openvpn/socket.c ++++ b/src/openvpn/socket.c +@@ -832,6 +832,9 @@ socket_listen_accept (socket_descriptor_t sd, + struct openvpn_sockaddr remote_verify = act->dest; + int new_sd = SOCKET_UNDEFINED; + ++ if (sd >= FD_SETSIZE) ++ return -1; ++ + CLEAR (*act); + socket_do_listen (sd, local, do_listen, true); + +@@ -919,6 +922,9 @@ openvpn_connect (socket_descriptor_t sd, + { + int status = 0; + ++ if (sd >= FD_SETSIZE) ++ return -1; ++ + #ifdef CONNECT_NONBLOCK + set_nonblock (sd); + status = connect (sd, &remote->addr.sa, af_addr_size(remote->addr.sa.sa_family)); +diff --git a/src/openvpn/socks.c b/src/openvpn/socks.c +index 57dc02a..8954e91 100644 +--- a/src/openvpn/socks.c ++++ b/src/openvpn/socks.c +@@ -97,13 +97,16 @@ socks_username_password_auth (struct socks_proxy_info *p, + socket_descriptor_t sd, + volatile int *signal_received) + { +- char to_send[516]; +- char buf[2]; ++ char to_send[516] = {0}; ++ char buf[2] = {0}; + int len = 0; + const int timeout_sec = 5; + struct user_pass creds; + ssize_t size; + ++ if (sd >= FD_SETSIZE) ++ return false; ++ + creds.defined = 0; + if (!get_user_pass (&creds, p->authfile, UP_TYPE_SOCKS, GET_USER_PASS_MANAGEMENT)) + { +@@ -189,7 +192,7 @@ socks_handshake (struct socks_proxy_info *p, + socket_descriptor_t sd, + volatile int *signal_received) + { +- char buf[2]; ++ char buf[2] = {0}; + int len = 0; + const int timeout_sec = 5; + ssize_t size; +@@ -198,6 +201,8 @@ socks_handshake (struct socks_proxy_info *p, + char method_sel[3] = { 0x05, 0x01, 0x00 }; + if (p->authfile[0]) + method_sel[2] = 0x02; /* METHODS = [2 (plain login)] */ ++ if (sd >= FD_SETSIZE) ++ return false; + + size = send (sd, method_sel, sizeof (method_sel), MSG_NOSIGNAL); + if (size != sizeof (method_sel)) +@@ -302,9 +307,12 @@ recv_socks_reply (socket_descriptor_t sd, + char atyp = '\0'; + int alen = 0; + int len = 0; +- char buf[22]; ++ char buf[22] = {0}; + const int timeout_sec = 5; + ++ if (sd >= FD_SETSIZE) ++ return false; ++ + if (addr != NULL) + { + addr->addr.in4.sin_family = AF_INET; +@@ -381,7 +389,7 @@ recv_socks_reply (socket_descriptor_t sd, + } + + /* store char in buffer */ +- if (len < (int)sizeof(buf)) ++ if (len < (int)sizeof(buf) && len >= 0) + buf[len] = c; + ++len; + } +@@ -411,7 +419,7 @@ establish_socks_proxy_passthru (struct socks_proxy_info *p, + const int port, /* openvpn server port */ + volatile int *signal_received) + { +- char buf[128]; ++ char buf[128] = {0}; + size_t len; + + if (!socks_handshake (p, sd, signal_received)) diff --git a/openvpn.changes b/openvpn.changes index e0fd8ef..1b590a8 100644 --- a/openvpn.changes +++ b/openvpn.changes @@ -1,3 +1,16 @@ +------------------------------------------------------------------- +Fri Apr 21 14:55:09 CEST 2017 - ndas@suse.de + +- Preform deferred authentication in the background to not + cause main daemon processing delays when the underlying pam mechanism (e.g. + ldap) needs longer to response (bsc#959511). + [+ 0001-preform-deferred-authentication-in-the-background.patch] +- Added fix for possible heap overflow on read accessing getaddrinfo + result (bsc#959714). + [+openvpn-2.3.9-Fix-heap-overflow-on-getaddrinfo-result.patch] +- Added a patch to fix multiple low severity issues (bsc#934237). + [+openvpn-2.3.x-fixed-multiple-low-severity-issues.patch] + ------------------------------------------------------------------- Sun Jan 22 15:21:17 UTC 2017 - mrueckert@suse.de diff --git a/openvpn.spec b/openvpn.spec index 31b7949..9f2de3e 100644 --- a/openvpn.spec +++ b/openvpn.spec @@ -51,6 +51,9 @@ Source10: %{name}-tmpfile.conf Source11: rc%{name} Patch1: %{name}-2.3-plugin-man.dif Patch6: %{name}-fips140-2.3.2.patch +Patch7: openvpn-2.3.9-Fix-heap-overflow-on-getaddrinfo-result.patch +Patch8: openvpn-2.3.x-fixed-multiple-low-severity-issues.patch +Patch9: 0001-preform-deferred-authentication-in-the-background.patch BuildRoot: %{_tmppath}/%{name}-%{version}-build BuildRequires: iproute2 BuildRequires: lzo-devel @@ -135,6 +138,9 @@ This package provides the header file to build external plugins. %setup -q -n %{name}-%{version} %patch1 -p0 %patch6 -p1 +%patch7 -p1 +%patch8 -p1 +%patch9 -p1 sed -e "s|\" __DATE__|$(date '+%b %e %Y' -r version.m4)\"|g" \ -i src/openvpn/options.c