From: Sean Bright Date: Thu, 30 Mar 2017 13:11:46 +0000 (-0400) Subject: cdr_pgsql: Fix buffer overflow calling libpq X-Git-Tag: 14.5.0-rc1~67^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c9707febe3b41ffd17741254084c9a26f9039935;p=thirdparty%2Fasterisk.git cdr_pgsql: Fix buffer overflow calling libpq Implement the same buffer size checking done in cel_pgsql. ASTERISK-26896 #close Reported by: twisted Change-Id: Iaacfa1f1de7cb1e9414d121850d2d8c2888f3f48 --- diff --git a/cdr/cdr_pgsql.c b/cdr/cdr_pgsql.c index ea38cc9837..a0f0ce71c0 100644 --- a/cdr/cdr_pgsql.c +++ b/cdr/cdr_pgsql.c @@ -204,6 +204,7 @@ static int pgsql_log(struct ast_cdr *cdr) struct ast_tm tm; char *pgerror; PGresult *result; + int res = -1; ast_mutex_lock(&pgsql_lock); @@ -233,13 +234,14 @@ static int pgsql_log(struct ast_cdr *cdr) if (connected) { struct columns *cur; struct ast_str *sql = ast_str_create(maxsize), *sql2 = ast_str_create(maxsize2); - char buf[257], escapebuf[513], *value; + char buf[257]; + char *escapebuf = NULL, *value; char *separator = ""; + size_t bufsize = 513; - if (!sql || !sql2) { - ast_free(sql); - ast_free(sql2); - return -1; + escapebuf = ast_malloc(bufsize); + if (!escapebuf || !sql || !sql2) { + goto ast_log_cleanup; } ast_str_set(&sql, 0, "INSERT INTO %s (", table); @@ -360,10 +362,28 @@ static int pgsql_log(struct ast_cdr *cdr) } /* XXX Might want to handle dates, times, and other misc fields here XXX */ } else { - if (value) + if (value) { + size_t required_size = strlen(value) * 2 + 1; + + /* If our argument size exceeds our buffer, grow it, + * as PQescapeStringConn() expects the buffer to be + * adequitely sized and does *NOT* do size checking. + */ + if (required_size > bufsize) { + char *tmpbuf = ast_realloc(escapebuf, required_size); + + if (!tmpbuf) { + AST_RWLIST_UNLOCK(&psql_columns); + goto ast_log_cleanup; + } + + escapebuf = tmpbuf; + bufsize = required_size; + } PQescapeStringConn(conn, escapebuf, value, strlen(value), NULL); - else + } else { escapebuf[0] = '\0'; + } LENGTHEN_BUF2(strlen(escapebuf) + 3); ast_str_append(&sql2, 0, "%s'%s'", separator, escapebuf); } @@ -397,10 +417,7 @@ static int pgsql_log(struct ast_cdr *cdr) PQfinish(conn); conn = NULL; connected = 0; - ast_mutex_unlock(&pgsql_lock); - ast_free(sql); - ast_free(sql2); - return -1; + goto ast_log_cleanup; } } result = PQexec(conn, ast_str_buffer(sql)); @@ -421,23 +438,17 @@ static int pgsql_log(struct ast_cdr *cdr) pgerror = PQresultErrorMessage(result); ast_log(LOG_ERROR, "HARD ERROR! Attempted reconnection failed. DROPPING CALL RECORD!\n"); ast_log(LOG_ERROR, "Reason: %s\n", pgerror); - } else { + } else { /* Second try worked out ok */ totalrecords++; records++; - ast_mutex_unlock(&pgsql_lock); - PQclear(result); - return 0; + res = 0; } } - ast_mutex_unlock(&pgsql_lock); - PQclear(result); - ast_free(sql); - ast_free(sql2); - return -1; } else { totalrecords++; records++; + res = 0; } PQclear(result); @@ -449,11 +460,14 @@ static int pgsql_log(struct ast_cdr *cdr) maxsize2 = ast_str_strlen(sql2); } +ast_log_cleanup: + ast_free(escapebuf); ast_free(sql); ast_free(sql2); } + ast_mutex_unlock(&pgsql_lock); - return 0; + return res; } /* This function should be called without holding the pgsql_columns lock */ diff --git a/cel/cel_pgsql.c b/cel/cel_pgsql.c index 7ce76d2980..4d61709d3a 100644 --- a/cel/cel_pgsql.c +++ b/cel/cel_pgsql.c @@ -322,6 +322,7 @@ static void pgsql_log(struct ast_event *event) char *tmpbuf = ast_realloc(escapebuf, required_size); if (!tmpbuf) { + AST_RWLIST_UNLOCK(&psql_columns); goto ast_log_cleanup; } @@ -382,8 +383,6 @@ static void pgsql_log(struct ast_event *event) ast_log(LOG_ERROR, "Reason: %s\n", pgerror); } } - PQclear(result); - goto ast_log_cleanup; } PQclear(result);