Skip to content

Commit

Permalink
ssl: temporary lock string buffer while reading
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
rhenium committed Sep 26, 2021
1 parent aea874b commit d382749
Showing 1 changed file with 16 additions and 5 deletions.
21 changes: 16 additions & 5 deletions ext/openssl/ossl_ssl.c
Expand Up @@ -1848,26 +1848,36 @@ ossl_ssl_read_internal(int argc, VALUE *argv, VALUE self, int nonblock)
io = rb_attr_get(self, id_i_io);
GetOpenFile(io, fptr);
if (ssl_started(ssl)) {
for (;;){
rb_str_locktmp(str);
for (;;) {
nread = SSL_read(ssl, RSTRING_PTR(str), ilen);
switch(ssl_get_error(ssl, nread)){
case SSL_ERROR_NONE:
rb_str_unlocktmp(str);
goto end;
case SSL_ERROR_ZERO_RETURN:
rb_str_unlocktmp(str);
if (no_exception_p(opts)) { return Qnil; }
rb_eof_error();
case SSL_ERROR_WANT_WRITE:
if (no_exception_p(opts)) { return sym_wait_writable; }
write_would_block(nonblock);
if (nonblock) {
rb_str_unlocktmp(str);
if (no_exception_p(opts)) { return sym_wait_writable; }
write_would_block(nonblock);
}
rb_io_wait_writable(fptr->fd);
continue;
case SSL_ERROR_WANT_READ:
if (no_exception_p(opts)) { return sym_wait_readable; }
read_would_block(nonblock);
if (nonblock) {
rb_str_unlocktmp(str);
if (no_exception_p(opts)) { return sym_wait_readable; }
read_would_block(nonblock);
}
rb_io_wait_readable(fptr->fd);
continue;
case SSL_ERROR_SYSCALL:
if (!ERR_peek_error()) {
rb_str_unlocktmp(str);
if (errno)
rb_sys_fail(0);
else {
Expand All @@ -1884,6 +1894,7 @@ ossl_ssl_read_internal(int argc, VALUE *argv, VALUE self, int nonblock)
}
/* fall through */
default:
rb_str_unlocktmp(str);
ossl_raise(eSSLError, "SSL_read");
}
}
Expand Down

0 comments on commit d382749

Please sign in to comment.