Skip to content

Commit f1f5978

Browse files
committed
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.
1 parent e2ad581 commit f1f5978

File tree

1 file changed

+41
-24
lines changed

1 file changed

+41
-24
lines changed

src/bin/psql/describe.c

Lines changed: 41 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*
44
* Copyright 2000-2002 by PostgreSQL Global Development Group
55
*
6-
* $Header: /cvsroot/pgsql/src/bin/psql/describe.c,v 1.72 2002/12/12 21:02:24 momjian Exp $
6+
* $Header: /cvsroot/pgsql/src/bin/psql/describe.c,v 1.73 2002/12/21 01:07:07 tgl Exp $
77
*/
88
#include "postgres_fe.h"
99
#include "describe.h"
@@ -44,6 +44,16 @@ xmalloc(size_t size)
4444
return tmp;
4545
}
4646

47+
static void *
48+
xmalloczero(size_t size)
49+
{
50+
void *tmp;
51+
52+
tmp = xmalloc(size);
53+
memset(tmp, 0, size);
54+
return tmp;
55+
}
56+
4757

4858
/*----------------
4959
* Handlers for various slash commands displaying some sort of list
@@ -635,7 +645,9 @@ describeOneTableDetails(const char *schemaname,
635645
char **footers = NULL;
636646
char **ptr;
637647
PQExpBufferData title;
638-
unsigned int cols = 0;
648+
PQExpBufferData tmpbuf;
649+
int cols = 0;
650+
int numrows = 0;
639651
struct
640652
{
641653
bool hasindex;
@@ -644,12 +656,14 @@ describeOneTableDetails(const char *schemaname,
644656
int16 triggers;
645657
bool hasrules;
646658
} tableinfo;
659+
bool show_modifiers = false;
647660
bool retval;
648661

649662
retval = false;
650663

651664
initPQExpBuffer(&buf);
652665
initPQExpBuffer(&title);
666+
initPQExpBuffer(&tmpbuf);
653667

654668
/* Get general table info */
655669
printfPQExpBuffer(&buf,
@@ -683,6 +697,7 @@ describeOneTableDetails(const char *schemaname,
683697

684698
if (tableinfo.relkind == 'r' || tableinfo.relkind == 'v')
685699
{
700+
show_modifiers = true;
686701
cols++;
687702
headers[cols - 1] = _("Modifiers");
688703
}
@@ -715,6 +730,7 @@ describeOneTableDetails(const char *schemaname,
715730
res = PSQLexec(buf.data, false);
716731
if (!res)
717732
goto error_return;
733+
numrows = PQntuples(res);
718734

719735
/* Check if table is a view */
720736
if (tableinfo.relkind == 'v')
@@ -733,10 +749,10 @@ describeOneTableDetails(const char *schemaname,
733749
}
734750

735751
/* Generate table cells to be printed */
736-
cells = xmalloc((PQntuples(res) * cols + 1) * sizeof(*cells));
737-
cells[PQntuples(res) * cols] = NULL; /* end of list */
752+
/* note: initialize all cells[] to NULL in case of error exit */
753+
cells = xmalloczero((numrows * cols + 1) * sizeof(*cells));
738754

739-
for (i = 0; i < PQntuples(res); i++)
755+
for (i = 0; i < numrows; i++)
740756
{
741757
/* Name */
742758
cells[i * cols + 0] = PQgetvalue(res, i, 0); /* don't free this
@@ -747,12 +763,11 @@ describeOneTableDetails(const char *schemaname,
747763

748764
/* Extra: not null and default */
749765
/* (I'm cutting off the 'default' string at 128) */
750-
if (tableinfo.relkind == 'r' || tableinfo.relkind == 'v')
766+
if (show_modifiers)
751767
{
752-
cells[i * cols + 2] = xmalloc(128 + 128);
753-
cells[i * cols + 2][0] = '\0';
768+
resetPQExpBuffer(&tmpbuf);
754769
if (strcmp(PQgetvalue(res, i, 2), "t") == 0)
755-
strcat(cells[i * cols + 2], "not null");
770+
appendPQExpBufferStr(&tmpbuf, "not null");
756771

757772
/* handle "default" here */
758773
if (strcmp(PQgetvalue(res, i, 3), "t") == 0)
@@ -761,18 +776,21 @@ describeOneTableDetails(const char *schemaname,
761776

762777
printfPQExpBuffer(&buf,
763778
"SELECT substring(d.adsrc for 128) FROM pg_catalog.pg_attrdef d\n"
764-
"WHERE d.adrelid = '%s' AND d.adnum = %s",
779+
"WHERE d.adrelid = '%s' AND d.adnum = %s",
765780
oid, PQgetvalue(res, i, 4));
766781

767782
result = PSQLexec(buf.data, false);
768783

769-
if (cells[i * cols + 2][0])
770-
strcat(cells[i * cols + 2], " ");
771-
strcat(cells[i * cols + 2], "default ");
772-
strcat(cells[i * cols + 2], result ? PQgetvalue(result, 0, 0) : "?");
784+
if (tmpbuf.len > 0)
785+
appendPQExpBufferStr(&tmpbuf, " ");
786+
787+
appendPQExpBuffer(&tmpbuf, "default %s",
788+
result ? PQgetvalue(result, 0, 0) : "?");
773789

774790
PQclear(result);
775791
}
792+
793+
cells[i * cols + 2] = xstrdup(tmpbuf.data);
776794
}
777795

778796
/* Description */
@@ -841,15 +859,12 @@ describeOneTableDetails(const char *schemaname,
841859
}
842860
else
843861
{
844-
PQExpBufferData tmpbuf;
845862
char *indisunique = PQgetvalue(result, 0, 0);
846863
char *indisprimary = PQgetvalue(result, 0, 1);
847864
char *indamname = PQgetvalue(result, 0, 2);
848865
char *indtable = PQgetvalue(result, 0, 3);
849866
char *indpred = PQgetvalue(result, 0, 4);
850867

851-
initPQExpBuffer(&tmpbuf);
852-
853868
if (strcmp(indisprimary, "t") == 0)
854869
printfPQExpBuffer(&tmpbuf, _("primary key, "));
855870
else if (strcmp(indisunique, "t") == 0)
@@ -865,10 +880,9 @@ describeOneTableDetails(const char *schemaname,
865880
if (strlen(indpred))
866881
appendPQExpBuffer(&tmpbuf, ", predicate %s", indpred);
867882

868-
footers = xmalloc(2 * sizeof(*footers));
883+
footers = xmalloczero(2 * sizeof(*footers));
869884
footers[0] = xstrdup(tmpbuf.data);
870885
footers[1] = NULL;
871-
termPQExpBuffer(&tmpbuf);
872886
}
873887

874888
PQclear(result);
@@ -895,7 +909,7 @@ describeOneTableDetails(const char *schemaname,
895909
}
896910

897911
/* Footer information about a view */
898-
footers = xmalloc((rule_count + 2) * sizeof(*footers));
912+
footers = xmalloczero((rule_count + 2) * sizeof(*footers));
899913
footers[count_footers] = xmalloc(64 + strlen(view_def));
900914
snprintf(footers[count_footers], 64 + strlen(view_def),
901915
_("View definition: %s"), view_def);
@@ -1018,8 +1032,8 @@ describeOneTableDetails(const char *schemaname,
10181032
foreignkey_count = PQntuples(result5);
10191033
}
10201034

1021-
footers = xmalloc((index_count + check_count + rule_count + trigger_count + foreignkey_count + 1)
1022-
* sizeof(*footers));
1035+
footers = xmalloczero((index_count + check_count + rule_count + trigger_count + foreignkey_count + 1)
1036+
* sizeof(*footers));
10231037

10241038
/* print indexes */
10251039
for (i = 0; i < index_count; i++)
@@ -1148,12 +1162,15 @@ describeOneTableDetails(const char *schemaname,
11481162
/* clean up */
11491163
termPQExpBuffer(&buf);
11501164
termPQExpBuffer(&title);
1165+
termPQExpBuffer(&tmpbuf);
11511166

11521167
if (cells)
11531168
{
1154-
for (i = 0; i < PQntuples(res); i++)
1155-
if (tableinfo.relkind == 'r' || tableinfo.relkind == 'v')
1169+
for (i = 0; i < numrows; i++)
1170+
{
1171+
if (show_modifiers)
11561172
free(cells[i * cols + 2]);
1173+
}
11571174
free(cells);
11581175
}
11591176

0 commit comments

Comments
 (0)