Повторное SSL_connect в C вызывает SIGSEGV - PullRequest
0 голосов
/ 20 мая 2018

У меня есть следующий код, и я получаю SIGSEGV на линии:

if ( SSL_connect(ssl) == FAIL )

Ошибка, которую я получаю:

Program received signal SIGSEGV, Segmentation fault.
0x00007ffffe5a41e0 in __GI___libc_malloc (bytes=104) at malloc.c:2926
2926    malloc.c: No such file or directory.

Программа в основном предназначена для загрузкиданных и поместите их в базу данных.

Первый элемент - проверка того, зарегистрированы ли мы, следующий бит - регистрация.

Возвращаясь к основам программы, у нас есть следующий начальный гамбит:

int main(int argc, char *argv[]) {
    int iRegistered = checkRegistered();
    int result = registerCar();
}

Если мы поменяем эти две строки, поэтому мы регистрируемся перед проверкой регистрации, тогда мы неполучить SIGSEGV.

Вот функция checkRegistration:

int checkRegistered() {
    int firebaseRegistered = 0;

    char *carId;
    carId = (char *) malloc(256);

    strcpy(carId, "aabbccddeeffgg" );

    char *payload;
    payload = (char *) malloc(1024);
    sprintf(payload, "{ \"carid\": \"%s\" }", carId);

    char *response;
    response = (char *) malloc(1024);

    int result = firebase("isCarRegistered", payload, &response);

    if (result == 0) {
        // Process JSON Response
        cJSON *json = cJSON_Parse(response);

        if (json == NULL) {
            //
        } else {
            cJSON *json_registered = NULL;
            json_registered = cJSON_GetObjectItemCaseSensitive(json, "registered");
            firebaseRegistered = json_registered->valueint;
        }
    }
    free(response);
    free(payload);
    free(carId);
    return firebaseRegistered;
}

И функция registerCar.

Они в основном одинакового формата - создайте сообщение, отправьте его в firebase, обработайтеответ JSON.Мы используем cJSON для декомпиляции данных, возвращаемых из Firebase, хотя потенциально мы можем использовать его и для компиляции.Но одна вещь за один раз.

Вы увидите несколько операторов free () - я пытался выяснить, как лучше всего это выполнить - то есть сгенерировать char * локально, передать по ссылке** для функции, пусть функция выполняет malloc / realloc на основе размеров, которые она может вычислить, а затем мы можем освободить ее от вызывающего кода, как только мы разберемся с данными.Хотя я также получаю SIGSEGV от этого.

int registerCar() {
    int iResponse = 0;

    char *carId;
    carId = (char *) malloc(256);

    char *authCode;
    authCode = (char *) malloc(12);

    char *payload;
    payload = (char *) malloc(1024);
    sprintf(payload, "{ }");

    char *response;
    response = (char *) malloc(1024);

    int result = firebase("registerCar", payload, &response);
    if (result == 0) {
        // Process JSON Response
        cJSON *json = cJSON_Parse(response);

        if (json == NULL) {
            //
        } else {
            cJSON *json_auth = NULL;
            cJSON *json_car = NULL;

            json_auth = cJSON_GetObjectItemCaseSensitive(json, "authcode");
            json_car = cJSON_GetObjectItemCaseSensitive(json, "carid");
            iResponse = 1;
        }
    }
    free(response);
    free(payload);
    return iResponse;
}

Вот процедура firebase, она принимает функцию, полезную нагрузку и генерирует ответ.Интересно, что char firebaseLocal и char firebaseMessage не всегда равны нулю перед начальным malloc.

int firebase(char *firebaseFunction, char *firebasePayload, char **firebaseResponse) {
    char buf[1024];
    char *firebaseLocal;
    char *firebaseMessage;
    firebaseMessage = (char *) malloc(1024);

    SSL_CTX *ctx;
    int server;
    SSL *ssl;

    int bytes;

    ctx = InitCTX();
    server = OpenConnection(HOST, atoi(PORT));
    ssl = SSL_new(ctx);      /* create new SSL connection state */
    SSL_set_fd(ssl, server);    /* attach the socket descriptor */
    if ( SSL_connect(ssl) == FAIL )   /* perform the connection */
        ERR_print_errors_fp(stderr);
    else {
        ShowCerts(ssl);        /* get any certs */

        char *firebasePost;
        generatePostMessage(firebaseFunction, firebasePayload, &firebasePost);
        SSL_write(ssl, firebasePost, strlen(firebasePost));

        bytes = SSL_read(ssl, buf, sizeof(buf)); /* get reply & decrypt */
        buf[bytes] = 0;
        //SSL_free(ssl);        /* release connection state */

        strcpy(firebaseMessage, buf);
        firebaseLocal = strstr(firebaseMessage, "\r\n\r\n");
        if (firebaseLocal != NULL) {
            firebaseLocal +=4;
        }
        strcpy(*firebaseResponse, firebaseLocal);
    }

    free(firebaseMessage);

    close(server);         /* close socket */
    SSL_CTX_free(ctx);        /* release context */
    return 0;
}

Это из реализации, которую я нашел в безопасных сокетах.

int OpenConnection(const char *hostname, int port)
{   int sd;
  struct hostent *host;
  struct sockaddr_in addr;

  if ( (host = gethostbyname(hostname)) == NULL )
  {
    perror(hostname);
    abort();
  }
  sd = socket(PF_INET, SOCK_STREAM, 0);
  bzero(&addr, sizeof(addr));
  addr.sin_family = AF_INET;
  addr.sin_port = htons(port);
  addr.sin_addr.s_addr = *(long*)(host->h_addr);
  if ( connect(sd, (struct sockaddr*)&addr, sizeof(addr)) != 0 )
  {
    close(sd);
    perror(hostname);
    abort();
  }
  return sd;
}

Это от реализации, которую я нашел на безопасных сокетах.

SSL_CTX* InitCTX(void)
{
  SSL_METHOD *method;
  SSL_CTX *ctx;
  SSL_library_init();

  OpenSSL_add_all_algorithms();  /* Load cryptos, et.al. */
  SSL_load_error_strings();   /* Bring in and register error messages */
  method = TLSv1_2_client_method();  /* Create new client-method instance */
  ctx = SSL_CTX_new(method);   /* Create new context */
  if ( ctx == NULL )
  {
    ERR_print_errors_fp(stderr);
    abort();
  }
  return ctx;
}

Это от реализации, которую я нашел на безопасных сокетах.

void ShowCerts(SSL* ssl)
{   X509 *cert;
  char *line;

  cert = SSL_get_peer_certificate(ssl); /* get the server's certificate */
  if ( cert != NULL )
  {
    printf("Server certificates:\n");
    line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
    printf("Subject: %s\n", line);
    free(line);       /* free the malloc'ed string */
    line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
    printf("Issuer: %s\n", line);
    free(line);       /* free the malloc'ed string */
    X509_free(cert);     /* free the malloc'ed certificate copy */
  }
  else
    printf("Info: No client certificates configured.\n");
}

Это то, что я написал для генерациисообщение из сообщения

void generatePostMessage(char *firebaseFunction, char *firebaseMessage, char **response) {
    int intPayloadSize = strlen(firebaseMessage);
    char *charPayloadSize;
    charPayloadSize = (char *) malloc(8);
    sprintf(charPayloadSize, "%d", intPayloadSize);

    char *postmessage = "POST /%s HTTP/1.1\r\n"
                         "Host: us-central1-carconnect-e763e.cloudfunctions.net\r\n"
                         "User-Agent: USER_AGENT\r\n"
                         "Content-Type: application/json\r\n"
                         "Accept: text/plain\r\n"
                         "Content-Length: %d\r\n\r\n"
                         "%s";

    // Allocate size of postmessage less the inserts, plus the payload size, plus the payload size digits, plus null
    int responseLength = (strlen(postmessage) - 4) + intPayloadSize + strlen(charPayloadSize)+1;
    // Round up Four Bytes.
    int responseIncrease = responseLength % 4;
    if (responseIncrease > 0) {
        responseLength += (4 - responseIncrease);
    }
    *response = (char *) malloc(responseLength);
    sprintf(*response, postmessage, firebaseFunction, intPayloadSize, firebaseMessage);
}

Как указано, сначала вызывается проверка регистрации или регистрации, первый вызов работает нормально.

Если я выполню регистрацию перед проверкой, то обе команды работают нормально.Дальнейшее тестирование также подтверждает, что проблема заключается в проверке регистрации.Я могу выполнить регистрацию несколько раз в обязательном порядке.Проверка регистрации и любые последующие вызовы завершаются неудачно в строке SSL_connect.Я не знаю почему.

Команда SSL_free в соединении с firebase всегда терпит неудачу.Я также получаю SIGSEGV, если я пытаюсь освободить (firebasePost) после SSL_Write - это говорит о том, что я не могу освободить указатель, который был передан по ссылке и размещен в функции.

Часть меня интересует, есть ли что-нибудь из этоговызвано тем, что я отлаживаю в Windows.У меня всегда были проблемы с malloc () в Windows, просто не работала так, как я ожидал.

1 Ответ

0 голосов
/ 20 мая 2018

Проблема, или хотя бы один из них, находится в generatePostMessage.Недостаточно буфера для response.sprintf будет затем запускаться с конца выделенного буфера и вызывать повреждение кучи, что проявляется при следующем вызове malloc.Попробуйте:

int responseLength = strlen(firebaseFunction) + (strlen(postmessage) - 4) + intPayloadSize + strlen(charPayloadSize)+1;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...