Thanks to visit codestin.com
Credit goes to github.com

Skip to content

gh-111178: fix UBSan failures in Modules/_ssl.c #130719

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Mar 17, 2025
74 changes: 48 additions & 26 deletions Modules/_ssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,8 @@ typedef struct {
#endif
} PySSLContext;

#define PySSLContext_CAST(op) ((PySSLContext *)(op))

typedef struct {
int ssl; /* last seen error from SSL */
int c; /* last seen error from libc */
Expand All @@ -337,18 +339,24 @@ typedef struct {
PyObject *exc;
} PySSLSocket;

#define PySSLSocket_CAST(op) ((PySSLSocket *)(op))

typedef struct {
PyObject_HEAD
BIO *bio;
int eof_written;
} PySSLMemoryBIO;

#define PySSLMemoryBIO_CAST(op) ((PySSLMemoryBIO *)(op))

typedef struct {
PyObject_HEAD
SSL_SESSION *session;
PySSLContext *ctx;
} PySSLSession;

#define PySSLSession_CAST(op) ((PySSLSession *)(op))

static inline _PySSLError _PySSL_errno(int failed, const SSL *ssl, int retcode)
{
_PySSLError err = { 0 };
Expand Down Expand Up @@ -2317,23 +2325,26 @@ _ssl__SSLSocket_owner_set_impl(PySSLSocket *self, PyObject *value)
}

static int
PySSL_traverse(PySSLSocket *self, visitproc visit, void *arg)
PySSL_traverse(PyObject *op, visitproc visit, void *arg)
{
PySSLSocket *self = PySSLSocket_CAST(op);
Py_VISIT(self->exc);
Py_VISIT(Py_TYPE(self));
return 0;
}

static int
PySSL_clear(PySSLSocket *self)
PySSL_clear(PyObject *op)
{
PySSLSocket *self = PySSLSocket_CAST(op);
Py_CLEAR(self->exc);
return 0;
}

static void
PySSL_dealloc(PySSLSocket *self)
PySSL_dealloc(PyObject *op)
{
PySSLSocket *self = PySSLSocket_CAST(op);
PyTypeObject *tp = Py_TYPE(self);
PyObject_GC_UnTrack(self);
if (self->ssl) {
Expand Down Expand Up @@ -3278,17 +3289,19 @@ _ssl__SSLContext_impl(PyTypeObject *type, int proto_version)
}

static int
context_traverse(PySSLContext *self, visitproc visit, void *arg)
context_traverse(PyObject *op, visitproc visit, void *arg)
{
PySSLContext *self = PySSLContext_CAST(op);
Py_VISIT(self->set_sni_cb);
Py_VISIT(self->msg_cb);
Py_VISIT(Py_TYPE(self));
return 0;
}

static int
context_clear(PySSLContext *self)
context_clear(PyObject *op)
{
PySSLContext *self = PySSLContext_CAST(op);
Py_CLEAR(self->set_sni_cb);
Py_CLEAR(self->msg_cb);
Py_CLEAR(self->keylog_filename);
Expand All @@ -3306,15 +3319,16 @@ context_clear(PySSLContext *self)
}

static void
context_dealloc(PySSLContext *self)
context_dealloc(PyObject *op)
{
PySSLContext *self = PySSLContext_CAST(op);
PyTypeObject *tp = Py_TYPE(self);
/* bpo-31095: UnTrack is needed before calling any callbacks */
PyObject_GC_UnTrack(self);
context_clear(self);
(void)context_clear(op);
SSL_CTX_free(self->ctx);
PyMem_FREE(self->alpn_protocols);
Py_TYPE(self)->tp_free(self);
tp->tp_free(self);
Py_DECREF(tp);
}

Expand Down Expand Up @@ -3908,7 +3922,9 @@ _ssl__SSLContext_check_hostname_set_impl(PySSLContext *self, PyObject *value)
}

static PyObject *
get_post_handshake_auth(PySSLContext *self, void *c) {
get_post_handshake_auth(PyObject *op, void *Py_UNUSED(closure))
{
PySSLContext *self = PySSLContext_CAST(op);
#if defined(PySSL_HAVE_POST_HS_AUTH)
return PyBool_FromLong(self->post_handshake_auth);
#else
Expand All @@ -3918,7 +3934,9 @@ get_post_handshake_auth(PySSLContext *self, void *c) {

#if defined(PySSL_HAVE_POST_HS_AUTH)
static int
set_post_handshake_auth(PySSLContext *self, PyObject *arg, void *c) {
set_post_handshake_auth(PyObject *op, PyObject *arg, void *Py_UNUSED(closure))
{
PySSLContext *self = PySSLContext_CAST(op);
if (arg == NULL) {
PyErr_SetString(PyExc_AttributeError, "cannot delete attribute");
return -1;
Expand Down Expand Up @@ -5197,18 +5215,18 @@ static PyGetSetDef context_getsetlist[] = {
_SSL__SSLCONTEXT__HOST_FLAGS_GETSETDEF
_SSL__SSLCONTEXT_MINIMUM_VERSION_GETSETDEF
_SSL__SSLCONTEXT_MAXIMUM_VERSION_GETSETDEF
{"keylog_filename", (getter) _PySSLContext_get_keylog_filename,
(setter) _PySSLContext_set_keylog_filename, NULL},
{"_msg_callback", (getter) _PySSLContext_get_msg_callback,
(setter) _PySSLContext_set_msg_callback, NULL},
{"keylog_filename", _PySSLContext_get_keylog_filename,
_PySSLContext_set_keylog_filename, NULL},
{"_msg_callback", _PySSLContext_get_msg_callback,
_PySSLContext_set_msg_callback, NULL},
_SSL__SSLCONTEXT_SNI_CALLBACK_GETSETDEF
#if defined(TLS1_3_VERSION) && !defined(OPENSSL_NO_TLS1_3)
_SSL__SSLCONTEXT_NUM_TICKETS_GETSETDEF
#endif
_SSL__SSLCONTEXT_OPTIONS_GETSETDEF
{"post_handshake_auth", (getter) get_post_handshake_auth,
{"post_handshake_auth", get_post_handshake_auth,
#if defined(PySSL_HAVE_POST_HS_AUTH)
(setter) set_post_handshake_auth,
set_post_handshake_auth,
#else
NULL,
#endif
Expand Down Expand Up @@ -5300,19 +5318,20 @@ _ssl_MemoryBIO_impl(PyTypeObject *type)
}

static int
memory_bio_traverse(PySSLMemoryBIO *self, visitproc visit, void *arg)
memory_bio_traverse(PyObject *self, visitproc visit, void *arg)
{
Py_VISIT(Py_TYPE(self));
return 0;
}

static void
memory_bio_dealloc(PySSLMemoryBIO *self)
memory_bio_dealloc(PyObject *op)
{
PySSLMemoryBIO *self = PySSLMemoryBIO_CAST(op);
PyTypeObject *tp = Py_TYPE(self);
PyObject_GC_UnTrack(self);
BIO_free(self->bio);
Py_TYPE(self)->tp_free(self);
(void)BIO_free(self->bio);
tp->tp_free(self);
Py_DECREF(tp);
}

Expand Down Expand Up @@ -5492,8 +5511,9 @@ static PyType_Spec PySSLMemoryBIO_spec = {
*/

static void
PySSLSession_dealloc(PySSLSession *self)
PySSLSession_dealloc(PyObject *op)
{
PySSLSession *self = PySSLSession_CAST(op);
PyTypeObject *tp = Py_TYPE(self);
/* bpo-31095: UnTrack is needed before calling any callbacks */
PyObject_GC_UnTrack(self);
Expand All @@ -5514,7 +5534,7 @@ PySSLSession_richcompare(PyObject *left, PyObject *right, int op)
}

int result;
PyTypeObject *sesstype = ((PySSLSession*)left)->ctx->state->PySSLSession_Type;
PyTypeObject *sesstype = PySSLSession_CAST(left)->ctx->state->PySSLSession_Type;

if (!Py_IS_TYPE(left, sesstype) || !Py_IS_TYPE(right, sesstype)) {
Py_RETURN_NOTIMPLEMENTED;
Expand All @@ -5525,9 +5545,9 @@ PySSLSession_richcompare(PyObject *left, PyObject *right, int op)
} else {
const unsigned char *left_id, *right_id;
unsigned int left_len, right_len;
left_id = SSL_SESSION_get_id(((PySSLSession *)left)->session,
left_id = SSL_SESSION_get_id(PySSLSession_CAST(left)->session,
&left_len);
right_id = SSL_SESSION_get_id(((PySSLSession *)right)->session,
right_id = SSL_SESSION_get_id(PySSLSession_CAST(right)->session,
&right_len);
if (left_len == right_len) {
result = memcmp(left_id, right_id, left_len);
Expand Down Expand Up @@ -5564,16 +5584,18 @@ PySSLSession_richcompare(PyObject *left, PyObject *right, int op)
}

static int
PySSLSession_traverse(PySSLSession *self, visitproc visit, void *arg)
PySSLSession_traverse(PyObject *op, visitproc visit, void *arg)
{
PySSLSession *self = PySSLSession_CAST(op);
Py_VISIT(self->ctx);
Py_VISIT(Py_TYPE(self));
return 0;
}

static int
PySSLSession_clear(PySSLSession *self)
PySSLSession_clear(PyObject *op)
{
PySSLSession *self = PySSLSession_CAST(op);
Py_CLEAR(self->ctx);
return 0;
}
Expand Down
10 changes: 5 additions & 5 deletions Modules/_ssl/cert.c
Original file line number Diff line number Diff line change
Expand Up @@ -153,13 +153,13 @@ _x509name_print(_sslmodulestate *state, X509_NAME *name, int indent, unsigned lo
* PySSLCertificate_Type
*/

#define _PySSLCertificate_CAST(op) ((PySSLCertificate *)(op))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't thinkt that this change is useful.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I myself did the change and I at that time put an underscore. But considering I used the convention "objectname+_CAST" for the series of PR and that I amended some changes I've done recently I think we can refactor this one as well (if the code is however not by me and/or is older, I can revert that change)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: it's something I've changed last month, and I thought I fixed all the UBSan issues in the SSL module but this wasn't the case. I can revert it if you don't want this additional diff.

#define PySSLCertificate_CAST(op) ((PySSLCertificate *)(op))

static PyObject *
certificate_repr(PyObject *op)
{
PyObject *osubject, *result;
PySSLCertificate *self = _PySSLCertificate_CAST(op);
PySSLCertificate *self = PySSLCertificate_CAST(op);

/* subject string is ASCII encoded, UTF-8 chars are quoted */
osubject = _x509name_print(
Expand All @@ -181,7 +181,7 @@ certificate_repr(PyObject *op)
static Py_hash_t
certificate_hash(PyObject *op)
{
PySSLCertificate *self = _PySSLCertificate_CAST(op);
PySSLCertificate *self = PySSLCertificate_CAST(op);
if (self->hash == (Py_hash_t)-1) {
unsigned long hash;
hash = X509_subject_name_hash(self->cert);
Expand All @@ -198,7 +198,7 @@ static PyObject *
certificate_richcompare(PyObject *lhs, PyObject *rhs, int op)
{
int cmp;
PySSLCertificate *self = _PySSLCertificate_CAST(lhs);
PySSLCertificate *self = PySSLCertificate_CAST(lhs);
_sslmodulestate *state = get_state_cert(self);

if (Py_TYPE(rhs) != state->PySSLCertificate_Type) {
Expand All @@ -219,7 +219,7 @@ certificate_richcompare(PyObject *lhs, PyObject *rhs, int op)
static void
certificate_dealloc(PyObject *op)
{
PySSLCertificate *self = _PySSLCertificate_CAST(op);
PySSLCertificate *self = PySSLCertificate_CAST(op);
PyTypeObject *tp = Py_TYPE(self);
X509_free(self->cert);
(void)Py_TYPE(self)->tp_free(self);
Expand Down
18 changes: 14 additions & 4 deletions Modules/_ssl/debughelpers.c
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,9 @@ _PySSL_msg_callback(int write_p, int version, int content_type,


static PyObject *
_PySSLContext_get_msg_callback(PySSLContext *self, void *c) {
_PySSLContext_get_msg_callback(PyObject *op, void *Py_UNUSED(closure))
{
PySSLContext *self = PySSLContext_CAST(op);
if (self->msg_cb != NULL) {
return Py_NewRef(self->msg_cb);
} else {
Expand All @@ -94,7 +96,10 @@ _PySSLContext_get_msg_callback(PySSLContext *self, void *c) {
}

static int
_PySSLContext_set_msg_callback(PySSLContext *self, PyObject *arg, void *c) {
_PySSLContext_set_msg_callback(PyObject *op, PyObject *arg,
void *Py_UNUSED(closure))
{
PySSLContext *self = PySSLContext_CAST(op);
Py_CLEAR(self->msg_cb);
if (arg == Py_None) {
SSL_CTX_set_msg_callback(self->ctx, NULL);
Expand Down Expand Up @@ -153,7 +158,9 @@ _PySSL_keylog_callback(const SSL *ssl, const char *line)
}

static PyObject *
_PySSLContext_get_keylog_filename(PySSLContext *self, void *c) {
_PySSLContext_get_keylog_filename(PyObject *op, void *Py_UNUSED(closure))
{
PySSLContext *self = PySSLContext_CAST(op);
if (self->keylog_filename != NULL) {
return Py_NewRef(self->keylog_filename);
} else {
Expand All @@ -162,7 +169,10 @@ _PySSLContext_get_keylog_filename(PySSLContext *self, void *c) {
}

static int
_PySSLContext_set_keylog_filename(PySSLContext *self, PyObject *arg, void *c) {
_PySSLContext_set_keylog_filename(PyObject *op, PyObject *arg,
void *Py_UNUSED(closure))
{
PySSLContext *self = PySSLContext_CAST(op);
FILE *fp;
/* Reset variables and callback first */
SSL_CTX_set_keylog_callback(self->ctx, NULL);
Expand Down
Loading