diff options
author | Kazuki Yamaguchi <k@rhe.jp> | 2021-08-30 18:55:10 +0900 |
---|---|---|
committer | Kazuki Yamaguchi <k@rhe.jp> | 2021-09-27 00:15:30 +0900 |
commit | d38274949f4a504c046a00a76ec33aff006e12a8 (patch) | |
tree | 72e2b96bf0a7f32aa8f6b3426e8aab5d3927af97 | |
parent | aea874bc6eae69a74c5832b499eb9e3132175d2f (diff) | |
download | ruby-openssl-d38274949f4a504c046a00a76ec33aff006e12a8.tar.gz |
ssl: temporary lock string buffer while readingky/ssl-sysread-syswrite-protect-buffer
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.
-rw-r--r-- | ext/openssl/ossl_ssl.c | 21 |
1 files changed, 16 insertions, 5 deletions
diff --git a/ext/openssl/ossl_ssl.c b/ext/openssl/ossl_ssl.c index 5d2c1e83..fcc2218c 100644 --- a/ext/openssl/ossl_ssl.c +++ b/ext/openssl/ossl_ssl.c @@ -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 { @@ -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"); } } |