意外,Openssl出現死循環的問題

  最近調研和研發關於c++支持ws和wss協議的網絡底層,意外發現了Openssl內部出現死循環的情況。網絡底層採用boost::asio和Openssl的方式支持wss協議。

  平時使用都是正常,等到最近壓測的時候發現,一段時間後會出現死循環的情況,經過一段時間的調查發現竟然是Openssl底層導致的死循環,死循環的堆棧的信息如下:

19:40:03.441 d:\tddownload\code\openssl-1.1.0i_test\crypto\bio\bss_bio.c (325): bio_write
19:40:03.441 d:\tddownload\code\openssl-1.1.0i_test\crypto\bio\bio_lib.c (232): BIO_write
19:40:03.441 d:\tddownload\code\openssl-1.1.0i_test\ssl\record\rec_layer_s3.c (930): ssl3_write_pending
19:40:03.441 d:\tddownload\code\openssl-1.1.0i_test\ssl\record\rec_layer_s3.c (881): do_ssl3_write

  後來又寫了一些測試代碼,發現實際上是無符號整形溢出。溢出的接口名稱:bio_write
  源碼如下:

static int bio_write(BIO *bio, const char *buf, int num_)
{
    size_t num = num_;
    size_t rest;
    struct bio_bio_st *b;

    BIO_clear_retry_flags(bio);

    if (!bio->init || buf == NULL || num == 0)
        return 0;

    b = bio->ptr;
    assert(b != NULL);
    assert(b->peer != NULL);
    assert(b->buf != NULL);

    b->request = 0;
    if (b->closed) {
        /* we already closed */
        BIOerr(BIO_F_BIO_WRITE, BIO_R_BROKEN_PIPE);
        return -1;
    }

    assert(b->len <= b->size);

    if (b->len == b->size) {
        BIO_set_retry_write(bio); /* buffer is full */
        return -1;
    }

    /* we can write */
    if (num > b->size - b->len)
        num = b->size - b->len;

    /* now write "num" bytes */

    rest = num;

    assert(rest > 0);
    do {                        /* one or two iterations */
        size_t write_offset;
        size_t chunk;

        assert(b->len + rest <= b->size);

        write_offset = b->offset + b->len;
        if (write_offset >= b->size)
            write_offset -= b->size;
        /* b->buf[write_offset] is the first byte we can write to. */

        if (write_offset + rest <= b->size)
            chunk = rest;
        else
            /* wrap around ring buffer */
            chunk = b->size - write_offset;

        memcpy(b->buf + write_offset, buf, chunk);

        b->len += chunk;

        assert(b->len <= b->size);

        rest -= chunk;
        buf += chunk;
    }
    while (rest);

    return num;
}

  死循環是因爲,chunk會大於rest,然後導致rest溢出,然後chunk的值一直爲0,導致死循環。
  剛接觸Openssl不確定是否是因爲使用上的問題導致的,不過代碼確實有不夠健壯的地方。

  目前該問題已經反饋到Openssl的github的issues上,希望官方組織能及時修復該問題。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章