C中重复的SSL_connect导致SIGSEGV

时间:2018-05-20 14:10:53

标签: c openssl malloc

我有以下代码,我在线上获得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.

该程序主要用于处理大量数据并将其推入firebase。

第一个元素,是检查我们是否已注册,下一位是实际进行注册。

将程序切换回基础,我们有以下开场白:

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线路上完全失败。我不知道为什么。

firebase连接中的SSL_free命令始终失败。如果我在SSL_Write之后尝试释放(firebasePost),我也会得到一个SIGSEGV - 这表明我无法释放已通过引用传递的指针和函数中的mallocced。

我的一部分想知道这是否是由于我在Windows上调试这一事实造成的。我总是遇到Windows上的malloc()问题,但是没有按照我预期的方式工作。

1 个答案:

答案 0 :(得分:1)

问题或至少其中一个问题出现在generatePostMessage中。没有为response分配足够的缓冲区。然后,sprintf将在分配的缓冲区的末尾运行并导致堆损坏,这会在下一次调用malloc时显示出来。尝试:

int responseLength = strlen(firebaseFunction) + (strlen(postmessage) - 4) + intPayloadSize + strlen(charPayloadSize)+1;