SSL_write возвращает SSL_ERR_SYSCALL, а ERR_get_error и errno оба равны 0 - PullRequest
0 голосов
/ 27 февраля 2020

У меня странная проблема, и обработка ошибок openssl и документация не помогли. Я использую SSL_dup (после SSL_new), SSL_set_fd и SSL_connect, чтобы начать сеанс SSL. Но затем, когда я использую SSL_write, он возвращает 0. Документация openssl говорит о проверке SSL_get_error. Я сделал, и это дало мне SSL_ERROR_SYSCALL. В docs также предлагается проверять очередь ошибок и ошибаться. Но они оба равны нулю. Теперь все становится интересным. В документации сказано:

SSL_ERROR_SYSCALL

Произошла неустранимая фатальная ошибка ввода-вывода. Очередь ошибок OpenSSL может содержать больше информации об ошибке. Для сокетов ввода / вывода в системах Unix обратитесь к errno для получения подробной информации. Если эта ошибка возникает, дальнейшие операции ввода-вывода не должны выполняться для соединения, и SSL_shutdown () не должен вызываться.

Это значение также может быть возвращено для других ошибок, подробности смотрите в очереди ошибок.

Там написано, что это невозможно восстановить, но когда я снова вызываю SSL_write с теми же параметрами, он работает успешно. Но, очевидно, я не могу оставить такой код, игнорируя код ошибки первого вызова. Вот то, что я попытался устранить проблему из того, что я нашел на Inte rnet.

  • Я использовал select, чтобы дождаться, пока базовый сокет не будет готов к записи.
  • Я проверил EOF на SSL_get_rbio и SSL_get_wbio. BIO_eof возвращает 0 для них обоих.
  • Я пытался SSL_do_handshake перед вызовом SSL_write. В любом случае это может быть ненужным, потому что согласно openssl он вызывается, когда я SSL_connect.
  • Я пытался проверить SSL_is_init_finished, но он возвращает 1 и не указывает на проблему здесь .

Моя версия openssl 1.1.1 и я на Ubuntu 18.04.3

Почему возникает эта проблема? Как я могу найти причину и устранить ее?

1 Ответ

0 голосов
/ 28 февраля 2020

Я отвечаю на свой вопрос, когда обнаружил, в чем проблема. Это была даже не проблема OpenSSL.

Сначала просмотрите проблему GitHub: SSL_write () возвращает SSL_ERROR_SYSCALL, если размер равен 0

Мой код выглядит следующим образом:

SSL_write(ssl, foo(), var);

foo создает полезную нагрузку и возвращает const char *, а var - длину этих данных. Дело в том, что они на самом деле являются функциями-членами и переменными-членами класса C ++, а var устанавливается foo. Согласно стандарту C ++ порядок вычисления аргументов функции не указан. Начиная с 5.2.2,

Порядок оценки аргументов не определен. Все побочные эффекты при оценке выражений аргументов вступают в силу до ввода функции.

Таким образом, третий параметр (var) может быть оценен перед вторым параметром (foo()) , Действительно, это то, что происходило в соответствии с результатами сборки программы. Ниже приведен пример.

class myclass {
  public:
    int l;
    const char *foo(){
      l = 10;
      return "mystring";
    }
};

int main()
{
  SSL *ssl;
  myclass instance;
  SSL_write(ssl, instance.foo(), instance.l);
}

и сборка,

_ZN7myclass3fooEv:
.LFB1778:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    movq    %rdi, -8(%rbp)
    movq    -8(%rbp), %rax
    movl    $10, (%rax)
    leaq    .LC0(%rip), %rax
    popq    %rbp
    .cfi_def_cfa 7, 8
    ret
    .cfi_endproc
.LFE1778:
    .size   _ZN7myclass3fooEv, .-_ZN7myclass3fooEv
    .text
    .globl  main
    .type   main, @function
main:
.LFB1779:
    .cfi_startproc
    pushq   %rbp
    .cfi_def_cfa_offset 16
    .cfi_offset 6, -16
    movq    %rsp, %rbp
    .cfi_def_cfa_register 6
    pushq   %rbx
    subq    $40, %rsp
    .cfi_offset 3, -24
    movq    %fs:40, %rax
    movq    %rax, -24(%rbp)
    xorl    %eax, %eax
    movl    -36(%rbp), %ebx
    leaq    -36(%rbp), %rax
    movq    %rax, %rdi
    call    _ZN7myclass3fooEv
    movq    %rax, %rcx
    movq    -32(%rbp), %rax
    movl    %ebx, %edx ; rdx is the third parameter, var. ebx was set before the foo() call
    movq    %rcx, %rsi ; rsi is the second parameter, return value of foo()
    movq    %rax, %rdi ; rdi is the first parameter, ssl
    call    SSL_write@PLT
    movl    $0, %eax
    movq    -24(%rbp), %rdx

После SSL_write гарантированно будет выполнено foo() и для var установлено правильное значение Вот почему SSL_write работал во второй раз, я полагаю. Более того, в документах на SSL_write написано

Вы не должны вызывать SSL_write () с num = 0, это вернет ошибку. SSL_write_ex () может быть вызван с num = 0, но не будет отправлять данные приложения на одноранговый узел.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...