aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKazuki Yamaguchi <k@rhe.jp>2021-08-30 18:55:10 +0900
committerKazuki Yamaguchi <k@rhe.jp>2021-09-27 00:15:30 +0900
commitd38274949f4a504c046a00a76ec33aff006e12a8 (patch)
tree72e2b96bf0a7f32aa8f6b3426e8aab5d3927af97
parentaea874bc6eae69a74c5832b499eb9e3132175d2f (diff)
downloadruby-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.c21
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");
}
}