C中重复的SSL_connect导致SIGSEGV

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C中重复的SSL_connect导致SIGSEGV相关的知识,希望对你有一定的参考价值。

我有以下代码,我在线上获得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和charfirebaseMessage在初始malloc之前并不总是为null。

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, "

");
        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:
");
    line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
    printf("Subject: %s
", line);
    free(line);       /* free the malloc'ed string */
    line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
    printf("Issuer: %s
", line);
    free(line);       /* free the malloc'ed string */
    X509_free(cert);     /* free the malloc'ed certificate copy */
  }
  else
    printf("Info: No client certificates configured.
");
}

这是我编写的用于从消息生成帖子消息的内容

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
"
                         "Host: us-central1-carconnect-e763e.cloudfunctions.net
"
                         "User-Agent: USER_AGENT
"
                         "Content-Type: application/json
"
                         "Accept: text/plain
"
                         "Content-Length: %d

"
                         "%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()问题,但是没有像我期望的那样工作。

答案

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

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

以上是关于C中重复的SSL_connect导致SIGSEGV的主要内容,如果未能解决你的问题,请参考以下文章

什么导致 SIGSEGV

QResizeEvent 导致 SIGSEGV

通过向量迭代(使用迭代器)会导致 SIGSEGV 但在索引中使用时有效 - 那怎么样?

std::map 到 std::list 导致 SIGSEGV

是否可以在 Linux 上预测 C 中的堆栈溢出?

SIGBUS 和 SIGSEGV