Fix possible buffer overrun in \d command: substr(..., 128) produces

a result of at most 128 chars, but that could be more than 128 bytes.
Also ensure we don't try to pfree uninitialized pointers during error
cleanup.
This commit is contained in:
Tom Lane 2002-12-21 01:07:07 +00:00
parent e2ad5816e2
commit f1f5978603
1 changed files with 41 additions and 24 deletions

View File

@ -3,7 +3,7 @@
* *
* Copyright 2000-2002 by PostgreSQL Global Development Group * Copyright 2000-2002 by PostgreSQL Global Development Group
* *
* $Header: /cvsroot/pgsql/src/bin/psql/describe.c,v 1.72 2002/12/12 21:02:24 momjian Exp $ * $Header: /cvsroot/pgsql/src/bin/psql/describe.c,v 1.73 2002/12/21 01:07:07 tgl Exp $
*/ */
#include "postgres_fe.h" #include "postgres_fe.h"
#include "describe.h" #include "describe.h"
@ -44,6 +44,16 @@ xmalloc(size_t size)
return tmp; return tmp;
} }
static void *
xmalloczero(size_t size)
{
void *tmp;
tmp = xmalloc(size);
memset(tmp, 0, size);
return tmp;
}
/*---------------- /*----------------
* Handlers for various slash commands displaying some sort of list * Handlers for various slash commands displaying some sort of list
@ -635,7 +645,9 @@ describeOneTableDetails(const char *schemaname,
char **footers = NULL; char **footers = NULL;
char **ptr; char **ptr;
PQExpBufferData title; PQExpBufferData title;
unsigned int cols = 0; PQExpBufferData tmpbuf;
int cols = 0;
int numrows = 0;
struct struct
{ {
bool hasindex; bool hasindex;
@ -644,12 +656,14 @@ describeOneTableDetails(const char *schemaname,
int16 triggers; int16 triggers;
bool hasrules; bool hasrules;
} tableinfo; } tableinfo;
bool show_modifiers = false;
bool retval; bool retval;
retval = false; retval = false;
initPQExpBuffer(&buf); initPQExpBuffer(&buf);
initPQExpBuffer(&title); initPQExpBuffer(&title);
initPQExpBuffer(&tmpbuf);
/* Get general table info */ /* Get general table info */
printfPQExpBuffer(&buf, printfPQExpBuffer(&buf,
@ -683,6 +697,7 @@ describeOneTableDetails(const char *schemaname,
if (tableinfo.relkind == 'r' || tableinfo.relkind == 'v') if (tableinfo.relkind == 'r' || tableinfo.relkind == 'v')
{ {
show_modifiers = true;
cols++; cols++;
headers[cols - 1] = _("Modifiers"); headers[cols - 1] = _("Modifiers");
} }
@ -715,6 +730,7 @@ describeOneTableDetails(const char *schemaname,
res = PSQLexec(buf.data, false); res = PSQLexec(buf.data, false);
if (!res) if (!res)
goto error_return; goto error_return;
numrows = PQntuples(res);
/* Check if table is a view */ /* Check if table is a view */
if (tableinfo.relkind == 'v') if (tableinfo.relkind == 'v')
@ -733,10 +749,10 @@ describeOneTableDetails(const char *schemaname,
} }
/* Generate table cells to be printed */ /* Generate table cells to be printed */
cells = xmalloc((PQntuples(res) * cols + 1) * sizeof(*cells)); /* note: initialize all cells[] to NULL in case of error exit */
cells[PQntuples(res) * cols] = NULL; /* end of list */ cells = xmalloczero((numrows * cols + 1) * sizeof(*cells));
for (i = 0; i < PQntuples(res); i++) for (i = 0; i < numrows; i++)
{ {
/* Name */ /* Name */
cells[i * cols + 0] = PQgetvalue(res, i, 0); /* don't free this cells[i * cols + 0] = PQgetvalue(res, i, 0); /* don't free this
@ -747,12 +763,11 @@ describeOneTableDetails(const char *schemaname,
/* Extra: not null and default */ /* Extra: not null and default */
/* (I'm cutting off the 'default' string at 128) */ /* (I'm cutting off the 'default' string at 128) */
if (tableinfo.relkind == 'r' || tableinfo.relkind == 'v') if (show_modifiers)
{ {
cells[i * cols + 2] = xmalloc(128 + 128); resetPQExpBuffer(&tmpbuf);
cells[i * cols + 2][0] = '\0';
if (strcmp(PQgetvalue(res, i, 2), "t") == 0) if (strcmp(PQgetvalue(res, i, 2), "t") == 0)
strcat(cells[i * cols + 2], "not null"); appendPQExpBufferStr(&tmpbuf, "not null");
/* handle "default" here */ /* handle "default" here */
if (strcmp(PQgetvalue(res, i, 3), "t") == 0) if (strcmp(PQgetvalue(res, i, 3), "t") == 0)
@ -761,18 +776,21 @@ describeOneTableDetails(const char *schemaname,
printfPQExpBuffer(&buf, printfPQExpBuffer(&buf,
"SELECT substring(d.adsrc for 128) FROM pg_catalog.pg_attrdef d\n" "SELECT substring(d.adsrc for 128) FROM pg_catalog.pg_attrdef d\n"
"WHERE d.adrelid = '%s' AND d.adnum = %s", "WHERE d.adrelid = '%s' AND d.adnum = %s",
oid, PQgetvalue(res, i, 4)); oid, PQgetvalue(res, i, 4));
result = PSQLexec(buf.data, false); result = PSQLexec(buf.data, false);
if (cells[i * cols + 2][0]) if (tmpbuf.len > 0)
strcat(cells[i * cols + 2], " "); appendPQExpBufferStr(&tmpbuf, " ");
strcat(cells[i * cols + 2], "default ");
strcat(cells[i * cols + 2], result ? PQgetvalue(result, 0, 0) : "?"); appendPQExpBuffer(&tmpbuf, "default %s",
result ? PQgetvalue(result, 0, 0) : "?");
PQclear(result); PQclear(result);
} }
cells[i * cols + 2] = xstrdup(tmpbuf.data);
} }
/* Description */ /* Description */
@ -841,15 +859,12 @@ describeOneTableDetails(const char *schemaname,
} }
else else
{ {
PQExpBufferData tmpbuf;
char *indisunique = PQgetvalue(result, 0, 0); char *indisunique = PQgetvalue(result, 0, 0);
char *indisprimary = PQgetvalue(result, 0, 1); char *indisprimary = PQgetvalue(result, 0, 1);
char *indamname = PQgetvalue(result, 0, 2); char *indamname = PQgetvalue(result, 0, 2);
char *indtable = PQgetvalue(result, 0, 3); char *indtable = PQgetvalue(result, 0, 3);
char *indpred = PQgetvalue(result, 0, 4); char *indpred = PQgetvalue(result, 0, 4);
initPQExpBuffer(&tmpbuf);
if (strcmp(indisprimary, "t") == 0) if (strcmp(indisprimary, "t") == 0)
printfPQExpBuffer(&tmpbuf, _("primary key, ")); printfPQExpBuffer(&tmpbuf, _("primary key, "));
else if (strcmp(indisunique, "t") == 0) else if (strcmp(indisunique, "t") == 0)
@ -865,10 +880,9 @@ describeOneTableDetails(const char *schemaname,
if (strlen(indpred)) if (strlen(indpred))
appendPQExpBuffer(&tmpbuf, ", predicate %s", indpred); appendPQExpBuffer(&tmpbuf, ", predicate %s", indpred);
footers = xmalloc(2 * sizeof(*footers)); footers = xmalloczero(2 * sizeof(*footers));
footers[0] = xstrdup(tmpbuf.data); footers[0] = xstrdup(tmpbuf.data);
footers[1] = NULL; footers[1] = NULL;
termPQExpBuffer(&tmpbuf);
} }
PQclear(result); PQclear(result);
@ -895,7 +909,7 @@ describeOneTableDetails(const char *schemaname,
} }
/* Footer information about a view */ /* Footer information about a view */
footers = xmalloc((rule_count + 2) * sizeof(*footers)); footers = xmalloczero((rule_count + 2) * sizeof(*footers));
footers[count_footers] = xmalloc(64 + strlen(view_def)); footers[count_footers] = xmalloc(64 + strlen(view_def));
snprintf(footers[count_footers], 64 + strlen(view_def), snprintf(footers[count_footers], 64 + strlen(view_def),
_("View definition: %s"), view_def); _("View definition: %s"), view_def);
@ -1018,8 +1032,8 @@ describeOneTableDetails(const char *schemaname,
foreignkey_count = PQntuples(result5); foreignkey_count = PQntuples(result5);
} }
footers = xmalloc((index_count + check_count + rule_count + trigger_count + foreignkey_count + 1) footers = xmalloczero((index_count + check_count + rule_count + trigger_count + foreignkey_count + 1)
* sizeof(*footers)); * sizeof(*footers));
/* print indexes */ /* print indexes */
for (i = 0; i < index_count; i++) for (i = 0; i < index_count; i++)
@ -1148,12 +1162,15 @@ error_return:
/* clean up */ /* clean up */
termPQExpBuffer(&buf); termPQExpBuffer(&buf);
termPQExpBuffer(&title); termPQExpBuffer(&title);
termPQExpBuffer(&tmpbuf);
if (cells) if (cells)
{ {
for (i = 0; i < PQntuples(res); i++) for (i = 0; i < numrows; i++)
if (tableinfo.relkind == 'r' || tableinfo.relkind == 'v') {
if (show_modifiers)
free(cells[i * cols + 2]); free(cells[i * cols + 2]);
}
free(cells); free(cells);
} }