Skip to content

Commit 5ae433b

Browse files
committed
ssl: refactor session_{get,new,remove}_cb
Prepare the argument array object inside rb_protect(). The callback proc is already called in it, but the array allocation can also potentially fail and needs to be done there.
1 parent 62e1ad1 commit 5ae433b

1 file changed

Lines changed: 66 additions & 60 deletions

File tree

‎ext/openssl/ossl_ssl.c‎

Lines changed: 66 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -273,80 +273,87 @@ ossl_ssl_verify_callback(int preverify_ok, X509_STORE_CTX *ctx)
273273
return ossl_verify_cb_call(cb, preverify_ok, ctx);
274274
}
275275

276+
struct sess_get_cb_args {
277+
VALUE ssl_obj;
278+
const unsigned char *data;
279+
int len;
280+
};
281+
276282
static VALUE
277-
ossl_call_session_get_cb(VALUE ary)
283+
ossl_call_sess_get_cb(VALUE args_)
278284
{
279-
VALUE ssl_obj, sslctx_obj, cb;
285+
struct sess_get_cb_args *args = (struct sess_get_cb_args *)args_;
286+
VALUE ssl_obj = args->ssl_obj, sslctx_obj, cb;
280287

281-
Check_Type(ary, T_ARRAY);
282-
ssl_obj = rb_ary_entry(ary, 0);
283288
sslctx_obj = rb_attr_get(ssl_obj, id_i_context);
284289
cb = rb_attr_get(sslctx_obj, id_i_session_get_cb);
285290
if (NIL_P(cb)) return Qnil;
286291

287-
return rb_funcallv(cb, id_call, 1, &ary);
292+
VALUE session_id = rb_str_new((const char *)args->data, args->len);
293+
VALUE ret_obj = rb_funcall(cb, id_call, 1, rb_assoc_new(ssl_obj, session_id));
294+
// XXX: Should we raise if ret is neither SSLSession nor nil?
295+
if (!rb_obj_is_instance_of(ret_obj, cSSLSession))
296+
return (VALUE)NULL;
297+
298+
SSL_SESSION *sess;
299+
GetSSLSession(ret_obj, sess);
300+
return (VALUE)sess;
288301
}
289302

290303
static SSL_SESSION *
291304
ossl_sslctx_session_get_cb(SSL *ssl, const unsigned char *buf, int len, int *copy)
292305
{
293306
struct ossl_ssl_data *p = ssl_data(ssl);
294-
VALUE ary, ret_obj;
295-
SSL_SESSION *sess;
296-
int state = 0;
307+
if (p->cb_state)
308+
return NULL;
297309

298310
OSSL_Debug("SSL SESSION get callback entered");
299-
ary = rb_ary_new2(2);
300-
rb_ary_push(ary, p->self);
301-
rb_ary_push(ary, rb_str_new((const char *)buf, len));
302-
303-
ret_obj = rb_protect(ossl_call_session_get_cb, ary, &state);
311+
struct sess_get_cb_args args = { p->self, buf, len };
312+
int state;
313+
VALUE ret = rb_protect(ossl_call_sess_get_cb, (VALUE)&args, &state);
304314
if (state) {
305315
p->cb_state = state;
306316
return NULL;
307317
}
308-
if (!rb_obj_is_instance_of(ret_obj, cSSLSession))
309-
return NULL;
310-
311-
GetSSLSession(ret_obj, sess);
312318
*copy = 1;
313-
314-
return sess;
319+
return (SSL_SESSION *)ret;
315320
}
316321

322+
struct sess_new_cb_args {
323+
VALUE ssl_obj;
324+
SSL_SESSION *sess;
325+
};
326+
317327
static VALUE
318-
ossl_call_session_new_cb(VALUE ary)
328+
ossl_call_session_new_cb(VALUE args_)
319329
{
320-
VALUE ssl_obj, sslctx_obj, cb;
330+
struct sess_new_cb_args *args = (struct sess_new_cb_args *)args_;
331+
VALUE ssl_obj = args->ssl_obj, sslctx_obj, cb;
321332

322-
Check_Type(ary, T_ARRAY);
323-
ssl_obj = rb_ary_entry(ary, 0);
324333
sslctx_obj = rb_attr_get(ssl_obj, id_i_context);
325334
cb = rb_attr_get(sslctx_obj, id_i_session_new_cb);
326335
if (NIL_P(cb)) return Qnil;
327336

328-
return rb_funcallv(cb, id_call, 1, &ary);
337+
VALUE sess_obj = rb_obj_alloc(cSSLSession);
338+
if (!SSL_SESSION_up_ref(args->sess))
339+
ossl_raise(eSSLError, "SSL_SESSION_up_ref");
340+
RTYPEDDATA_DATA(sess_obj) = args->sess;
341+
342+
return rb_funcall(cb, id_call, 1, rb_assoc_new(ssl_obj, sess_obj));
329343
}
330344

331345
/* return 1 normal. return 0 removes the session */
332346
static int
333347
ossl_sslctx_session_new_cb(SSL *ssl, SSL_SESSION *sess)
334348
{
335349
struct ossl_ssl_data *p = ssl_data(ssl);
336-
VALUE ary, sess_obj;
337-
int state = 0;
350+
if (p->cb_state)
351+
return 0;
338352

339353
OSSL_Debug("SSL SESSION new callback entered");
340-
341-
sess_obj = rb_obj_alloc(cSSLSession);
342-
SSL_SESSION_up_ref(sess);
343-
DATA_PTR(sess_obj) = sess;
344-
345-
ary = rb_ary_new2(2);
346-
rb_ary_push(ary, p->self);
347-
rb_ary_push(ary, sess_obj);
348-
349-
rb_protect(ossl_call_session_new_cb, ary, &state);
354+
struct sess_new_cb_args args = { p->self, sess };
355+
int state;
356+
rb_protect(ossl_call_session_new_cb, (VALUE)&args, &state);
350357
if (state) {
351358
p->cb_state = state;
352359
}
@@ -407,26 +414,32 @@ ossl_sslctx_keylog_cb(const SSL *ssl, const char *line)
407414
}
408415
#endif
409416

417+
struct sess_remove_cb_args {
418+
SSL_CTX *ctx;
419+
SSL_SESSION *sess;
420+
};
421+
410422
static VALUE
411-
ossl_call_session_remove_cb(VALUE ary)
423+
ossl_call_session_remove_cb(VALUE args_)
412424
{
425+
struct sess_remove_cb_args *args = (struct sess_remove_cb_args *)args_;
413426
VALUE sslctx_obj, cb;
414427

415-
Check_Type(ary, T_ARRAY);
416-
sslctx_obj = rb_ary_entry(ary, 0);
417-
428+
sslctx_obj = (VALUE)SSL_CTX_get_ex_data(args->ctx, ossl_sslctx_ex_ptr_idx);
418429
cb = rb_attr_get(sslctx_obj, id_i_session_remove_cb);
419430
if (NIL_P(cb)) return Qnil;
420431

421-
return rb_funcallv(cb, id_call, 1, &ary);
432+
VALUE sess_obj = rb_obj_alloc(cSSLSession);
433+
if (!SSL_SESSION_up_ref(args->sess))
434+
ossl_raise(eSSLError, "SSL_SESSION_up_ref");
435+
RTYPEDDATA_DATA(sess_obj) = args->sess;
436+
437+
return rb_funcall(cb, id_call, 1, rb_assoc_new(sslctx_obj, sess_obj));
422438
}
423439

424440
static void
425441
ossl_sslctx_session_remove_cb(SSL_CTX *ctx, SSL_SESSION *sess)
426442
{
427-
VALUE ary, sslctx_obj, sess_obj;
428-
int state = 0;
429-
430443
/*
431444
* This callback is also called for all sessions in the internal store
432445
* when SSL_CTX_free() is called.
@@ -435,23 +448,16 @@ ossl_sslctx_session_remove_cb(SSL_CTX *ctx, SSL_SESSION *sess)
435448
return;
436449

437450
OSSL_Debug("SSL SESSION remove callback entered");
438-
439-
sslctx_obj = (VALUE)SSL_CTX_get_ex_data(ctx, ossl_sslctx_ex_ptr_idx);
440-
sess_obj = rb_obj_alloc(cSSLSession);
441-
SSL_SESSION_up_ref(sess);
442-
DATA_PTR(sess_obj) = sess;
443-
444-
ary = rb_ary_new2(2);
445-
rb_ary_push(ary, sslctx_obj);
446-
rb_ary_push(ary, sess_obj);
447-
448-
rb_protect(ossl_call_session_remove_cb, ary, &state);
451+
struct sess_remove_cb_args args = { ctx, sess };
452+
int state;
453+
rb_protect(ossl_call_session_remove_cb, (VALUE)&args, &state);
449454
if (state) {
450-
/*
451-
the SSL_CTX is frozen, nowhere to save state.
452-
there is no common accessor method to check it either.
453-
rb_ivar_set(sslctx_obj, ID_callback_state, INT2NUM(state));
454-
*/
455+
/*
456+
* the SSL_CTX is frozen, nowhere to save state.
457+
* there is no common accessor method to check it either.
458+
*/
459+
rb_warn("exception in session_remove_cb is ignored");
460+
rb_set_errinfo(Qnil);
455461
}
456462
}
457463

0 commit comments

Comments
 (0)