mirror of
https://github.com/ruby/ruby.git
synced 2026-01-26 20:19:19 +00:00
[ruby/openssl] ssl: fix errno display in exception messages
The errno reported in an OpenSSL::SSL::SSLError raised by
SSLSocket#accept and #connect sometimes does not match what SSL_accept()
or SSL_connect() actually encountered. Depending on the evaluation order
of arguments passed to ossl_raise(), errno may be overwritten by
peeraddr_ip_str().
While we could just fix peeraddr_ip_str(), we should avoid passing
around errno since it is error-prone. Replace rb_sys_fail() and
rb_io_{maybe_,}wait_{read,writ}able() with equivalents that do not read
errno.
https://github.com/ruby/openssl/commit/bfc7df860f
This commit is contained in:
parent
05b85fc1ab
commit
0379aab6c0
@ -1714,11 +1714,15 @@ ossl_ssl_setup(VALUE self)
|
||||
return Qtrue;
|
||||
}
|
||||
|
||||
static int
|
||||
errno_mapped(void)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
#define ssl_get_error(ssl, ret) (errno = rb_w32_map_errno(WSAGetLastError()), SSL_get_error((ssl), (ret)))
|
||||
return rb_w32_map_errno(WSAGetLastError());
|
||||
#else
|
||||
#define ssl_get_error(ssl, ret) SSL_get_error((ssl), (ret))
|
||||
return errno;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
write_would_block(int nonblock)
|
||||
@ -1759,13 +1763,13 @@ static void
|
||||
io_wait_writable(VALUE io)
|
||||
{
|
||||
#ifdef HAVE_RB_IO_MAYBE_WAIT
|
||||
if (!rb_io_maybe_wait_writable(errno, io, RUBY_IO_TIMEOUT_DEFAULT)) {
|
||||
if (!rb_io_wait(io, INT2NUM(RUBY_IO_WRITABLE), RUBY_IO_TIMEOUT_DEFAULT)) {
|
||||
rb_raise(IO_TIMEOUT_ERROR, "Timed out while waiting to become writable!");
|
||||
}
|
||||
#else
|
||||
rb_io_t *fptr;
|
||||
GetOpenFile(io, fptr);
|
||||
rb_io_wait_writable(fptr->fd);
|
||||
rb_thread_fd_writable(fptr->fd);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -1773,13 +1777,13 @@ static void
|
||||
io_wait_readable(VALUE io)
|
||||
{
|
||||
#ifdef HAVE_RB_IO_MAYBE_WAIT
|
||||
if (!rb_io_maybe_wait_readable(errno, io, RUBY_IO_TIMEOUT_DEFAULT)) {
|
||||
if (!rb_io_wait(io, INT2NUM(RUBY_IO_READABLE), RUBY_IO_TIMEOUT_DEFAULT)) {
|
||||
rb_raise(IO_TIMEOUT_ERROR, "Timed out while waiting to become readable!");
|
||||
}
|
||||
#else
|
||||
rb_io_t *fptr;
|
||||
GetOpenFile(io, fptr);
|
||||
rb_io_wait_readable(fptr->fd);
|
||||
rb_thread_wait_fd(fptr->fd);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -1787,7 +1791,6 @@ static VALUE
|
||||
ossl_start_ssl(VALUE self, int (*func)(SSL *), const char *funcname, VALUE opts)
|
||||
{
|
||||
SSL *ssl;
|
||||
int ret, ret2;
|
||||
VALUE cb_state;
|
||||
int nonblock = opts != Qfalse;
|
||||
|
||||
@ -1797,7 +1800,8 @@ ossl_start_ssl(VALUE self, int (*func)(SSL *), const char *funcname, VALUE opts)
|
||||
|
||||
VALUE io = rb_attr_get(self, id_i_io);
|
||||
for (;;) {
|
||||
ret = func(ssl);
|
||||
int ret = func(ssl);
|
||||
int saved_errno = errno_mapped();
|
||||
|
||||
cb_state = rb_attr_get(self, ID_callback_state);
|
||||
if (!NIL_P(cb_state)) {
|
||||
@ -1809,7 +1813,8 @@ ossl_start_ssl(VALUE self, int (*func)(SSL *), const char *funcname, VALUE opts)
|
||||
if (ret > 0)
|
||||
break;
|
||||
|
||||
switch ((ret2 = ssl_get_error(ssl, ret))) {
|
||||
int code = SSL_get_error(ssl, ret);
|
||||
switch (code) {
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
if (no_exception_p(opts)) { return sym_wait_writable; }
|
||||
write_would_block(nonblock);
|
||||
@ -1823,10 +1828,11 @@ ossl_start_ssl(VALUE self, int (*func)(SSL *), const char *funcname, VALUE opts)
|
||||
case SSL_ERROR_SYSCALL:
|
||||
#ifdef __APPLE__
|
||||
/* See ossl_ssl_write_internal() */
|
||||
if (errno == EPROTOTYPE)
|
||||
if (saved_errno == EPROTOTYPE)
|
||||
continue;
|
||||
#endif
|
||||
if (errno) rb_sys_fail(funcname);
|
||||
if (saved_errno)
|
||||
rb_exc_raise(rb_syserr_new(saved_errno, funcname));
|
||||
/* fallthrough */
|
||||
default: {
|
||||
VALUE error_append = Qnil;
|
||||
@ -1847,9 +1853,9 @@ ossl_start_ssl(VALUE self, int (*func)(SSL *), const char *funcname, VALUE opts)
|
||||
ossl_raise(eSSLError,
|
||||
"%s%s returned=%d errno=%d peeraddr=%"PRIsVALUE" state=%s%"PRIsVALUE,
|
||||
funcname,
|
||||
ret2 == SSL_ERROR_SYSCALL ? " SYSCALL" : "",
|
||||
ret2,
|
||||
errno,
|
||||
code == SSL_ERROR_SYSCALL ? " SYSCALL" : "",
|
||||
code,
|
||||
saved_errno,
|
||||
peeraddr_ip_str(self),
|
||||
SSL_state_string_long(ssl),
|
||||
error_append);
|
||||
@ -1992,6 +1998,7 @@ ossl_ssl_read_internal(int argc, VALUE *argv, VALUE self, int nonblock)
|
||||
for (;;) {
|
||||
rb_str_locktmp(str);
|
||||
int nread = SSL_read(ssl, RSTRING_PTR(str), ilen);
|
||||
int saved_errno = errno_mapped();
|
||||
rb_str_unlocktmp(str);
|
||||
|
||||
cb_state = rb_attr_get(self, ID_callback_state);
|
||||
@ -2001,7 +2008,7 @@ ossl_ssl_read_internal(int argc, VALUE *argv, VALUE self, int nonblock)
|
||||
rb_jump_tag(NUM2INT(cb_state));
|
||||
}
|
||||
|
||||
switch (ssl_get_error(ssl, nread)) {
|
||||
switch (SSL_get_error(ssl, nread)) {
|
||||
case SSL_ERROR_NONE:
|
||||
rb_str_set_len(str, nread);
|
||||
return str;
|
||||
@ -2024,8 +2031,8 @@ ossl_ssl_read_internal(int argc, VALUE *argv, VALUE self, int nonblock)
|
||||
break;
|
||||
case SSL_ERROR_SYSCALL:
|
||||
if (!ERR_peek_error()) {
|
||||
if (errno)
|
||||
rb_sys_fail(0);
|
||||
if (saved_errno)
|
||||
rb_exc_raise(rb_syserr_new(saved_errno, "SSL_read"));
|
||||
else {
|
||||
/*
|
||||
* The underlying BIO returned 0. This is actually a
|
||||
@ -2110,6 +2117,7 @@ ossl_ssl_write_internal_safe(VALUE _args)
|
||||
|
||||
for (;;) {
|
||||
int nwritten = SSL_write(ssl, RSTRING_PTR(str), num);
|
||||
int saved_errno = errno_mapped();
|
||||
|
||||
cb_state = rb_attr_get(self, ID_callback_state);
|
||||
if (!NIL_P(cb_state)) {
|
||||
@ -2118,7 +2126,7 @@ ossl_ssl_write_internal_safe(VALUE _args)
|
||||
rb_jump_tag(NUM2INT(cb_state));
|
||||
}
|
||||
|
||||
switch (ssl_get_error(ssl, nwritten)) {
|
||||
switch (SSL_get_error(ssl, nwritten)) {
|
||||
case SSL_ERROR_NONE:
|
||||
return INT2NUM(nwritten);
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
@ -2139,10 +2147,11 @@ ossl_ssl_write_internal_safe(VALUE _args)
|
||||
* make the error handling in line with the socket library.
|
||||
* [Bug #14713] https://bugs.ruby-lang.org/issues/14713
|
||||
*/
|
||||
if (errno == EPROTOTYPE)
|
||||
if (saved_errno == EPROTOTYPE)
|
||||
continue;
|
||||
#endif
|
||||
if (errno) rb_sys_fail(0);
|
||||
if (saved_errno)
|
||||
rb_exc_raise(rb_syserr_new(saved_errno, "SSL_write"));
|
||||
/* fallthrough */
|
||||
default:
|
||||
ossl_raise(eSSLError, "SSL_write");
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user