[ruby/openssl] ssl: temporary lock string buffer while reading

Similarly to SSLSocket#syswrite, the blocking SSLSocket#sysread allows
context switches. We must prevent other threads from modifying the
string buffer.

We can use rb_str_locktmp() and rb_str_unlocktmp() to temporarily
prohibit modification of the string.

https://github.com/ruby/openssl/commit/d38274949f
This commit is contained in:
Kazuki Yamaguchi 2021-08-30 18:55:10 +09:00
parent 5828807626
commit daeb914a52

View File

@ -1806,26 +1806,36 @@ ossl_ssl_read_internal(int argc, VALUE *argv, VALUE self, int nonblock)
io = rb_attr_get(self, id_i_io); io = rb_attr_get(self, id_i_io);
GetOpenFile(io, fptr); GetOpenFile(io, fptr);
if (ssl_started(ssl)) { if (ssl_started(ssl)) {
for (;;){ rb_str_locktmp(str);
for (;;) {
nread = SSL_read(ssl, RSTRING_PTR(str), ilen); nread = SSL_read(ssl, RSTRING_PTR(str), ilen);
switch(ssl_get_error(ssl, nread)){ switch(ssl_get_error(ssl, nread)){
case SSL_ERROR_NONE: case SSL_ERROR_NONE:
rb_str_unlocktmp(str);
goto end; goto end;
case SSL_ERROR_ZERO_RETURN: case SSL_ERROR_ZERO_RETURN:
rb_str_unlocktmp(str);
if (no_exception_p(opts)) { return Qnil; } if (no_exception_p(opts)) { return Qnil; }
rb_eof_error(); rb_eof_error();
case SSL_ERROR_WANT_WRITE: case SSL_ERROR_WANT_WRITE:
if (no_exception_p(opts)) { return sym_wait_writable; } if (nonblock) {
write_would_block(nonblock); rb_str_unlocktmp(str);
if (no_exception_p(opts)) { return sym_wait_writable; }
write_would_block(nonblock);
}
io_wait_writable(fptr); io_wait_writable(fptr);
continue; continue;
case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_READ:
if (no_exception_p(opts)) { return sym_wait_readable; } if (nonblock) {
read_would_block(nonblock); rb_str_unlocktmp(str);
if (no_exception_p(opts)) { return sym_wait_readable; }
read_would_block(nonblock);
}
io_wait_readable(fptr); io_wait_readable(fptr);
continue; continue;
case SSL_ERROR_SYSCALL: case SSL_ERROR_SYSCALL:
if (!ERR_peek_error()) { if (!ERR_peek_error()) {
rb_str_unlocktmp(str);
if (errno) if (errno)
rb_sys_fail(0); rb_sys_fail(0);
else { else {
@ -1842,6 +1852,7 @@ ossl_ssl_read_internal(int argc, VALUE *argv, VALUE self, int nonblock)
} }
/* fall through */ /* fall through */
default: default:
rb_str_unlocktmp(str);
ossl_raise(eSSLError, "SSL_read"); ossl_raise(eSSLError, "SSL_read");
} }
} }