]> granicus.if.org Git - postgresql/commitdiff
Fix misuse of StrNCpy to copy and add null to non-null-terminated data.
authorTom Lane <tgl@sss.pgh.pa.us>
Fri, 7 Jul 2000 21:12:53 +0000 (21:12 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Fri, 7 Jul 2000 21:12:53 +0000 (21:12 +0000)
Does not work since it fetches one byte beyond the source data, and when
the phase of the moon is wrong, the source data is smack up against the
end of backend memory and you get SIGSEGV.  Don't laugh, this is a fix
for an actual user bug report.

contrib/miscutil/misc_utils.c
src/backend/libpq/be-fsstubs.c
src/backend/libpq/be-pqexec.c
src/backend/port/dynloader/aix.c
src/backend/utils/adt/like.c
src/backend/utils/adt/not_in.c
src/backend/utils/adt/regexp.c
src/backend/utils/adt/varchar.c
src/include/c.h

index f5a98683280e3cfd9b1251662315ef8eb1150d2e..e7949d32aa6da3d591fc80a074752cbe726b95c6 100644 (file)
@@ -99,9 +99,9 @@ active_listeners(text *relname)
 
        if (relname && (VARSIZE(relname) > VARHDRSZ))
        {
+               MemSet(listen_name, 0, NAMEDATALEN);
                len = MIN(VARSIZE(relname) - VARHDRSZ, NAMEDATALEN - 1);
-               strncpy(listen_name, VARDATA(relname), len);
-               listen_name[len] = '\0';
+               memcpy(listen_name, VARDATA(relname), len);
                ScanKeyEntryInitialize(&key, 0,
                                                           Anum_pg_listener_relname,
                                                           F_NAMEEQ,
index 91769120f959edfa2a3972e0d0c75e8b119c2d85..929ddad5aa85cff56afc401fab53bf4682caa377 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/libpq/be-fsstubs.c,v 1.48 2000/07/03 23:09:37 wieck Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/libpq/be-fsstubs.c,v 1.49 2000/07/07 21:12:53 tgl Exp $
  *
  * NOTES
  *       This should be moved to a more appropriate place.  It is here
@@ -379,26 +379,23 @@ lo_import(PG_FUNCTION_ARGS)
        /*
         * open the file to be read in
         */
-       nbytes = VARSIZE(filename) - VARHDRSZ + 1;
-       if (nbytes > FNAME_BUFSIZE)
-               nbytes = FNAME_BUFSIZE;
-       StrNCpy(fnamebuf, VARDATA(filename), nbytes);
+       nbytes = VARSIZE(filename) - VARHDRSZ;
+       if (nbytes >= FNAME_BUFSIZE)
+               nbytes = FNAME_BUFSIZE-1;
+       memcpy(fnamebuf, VARDATA(filename), nbytes);
+       fnamebuf[nbytes] = '\0';
        fd = PathNameOpenFile(fnamebuf, O_RDONLY | PG_BINARY, 0666);
        if (fd < 0)
-       {                                                       /* error */
                elog(ERROR, "lo_import: can't open unix file \"%s\": %m",
                         fnamebuf);
-       }
 
        /*
         * create an inversion "object"
         */
        lobj = inv_create(INV_READ | INV_WRITE);
        if (lobj == NULL)
-       {
                elog(ERROR, "lo_import: can't create inv object for \"%s\"",
                         fnamebuf);
-       }
 
        /*
         * the oid for the large object is just the oid of the relation
@@ -461,18 +458,17 @@ lo_export(PG_FUNCTION_ARGS)
         * 022.  This code used to drop it all the way to 0, but creating
         * world-writable export files doesn't seem wise.
         */
-       nbytes = VARSIZE(filename) - VARHDRSZ + 1;
-       if (nbytes > FNAME_BUFSIZE)
-               nbytes = FNAME_BUFSIZE;
-       StrNCpy(fnamebuf, VARDATA(filename), nbytes);
+       nbytes = VARSIZE(filename) - VARHDRSZ;
+       if (nbytes >= FNAME_BUFSIZE)
+               nbytes = FNAME_BUFSIZE-1;
+       memcpy(fnamebuf, VARDATA(filename), nbytes);
+       fnamebuf[nbytes] = '\0';
        oumask = umask((mode_t) 0022);
        fd = PathNameOpenFile(fnamebuf, O_CREAT | O_WRONLY | O_TRUNC | PG_BINARY, 0666);
        umask(oumask);
        if (fd < 0)
-       {                                                       /* error */
                elog(ERROR, "lo_export: can't open unix file \"%s\": %m",
                         fnamebuf);
-       }
 
        /*
         * read in from the Unix file and write to the inversion file
index 78745d50a7f30e362188051402e794d5361ed0b8..474da587792ad32343b1d49fd5d889b979bc451f 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/libpq/Attic/be-pqexec.c,v 1.35 2000/07/05 23:11:19 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/libpq/Attic/be-pqexec.c,v 1.36 2000/07/07 21:12:53 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -236,8 +236,8 @@ strmake(char *str, int len)
        if (len <= 0)
                len = strlen(str);
 
-       newstr = (char *) palloc((unsigned) len + 1);
-       StrNCpy(newstr, str, len + 1);
+       newstr = (char *) palloc(len + 1);
+       memcpy(newstr, str, len);
        newstr[len] = (char) 0;
        return newstr;
 }
index 61705551430cb1d93047cd2186af1bc11ad7cbd8..c6295406e2273ea3ff1cef5af7b6193a024c5c69 100644 (file)
@@ -536,7 +536,8 @@ readExports(ModulePtr mp)
                         * first SYMNMLEN chars and make sure we have a zero byte at
                         * the end.
                         */
-                       StrNCpy(tmpsym, ls->l_name, SYMNMLEN + 1);
+                       strncpy(tmpsym, ls->l_name, SYMNMLEN);
+                       tmpsym[SYMNMLEN] = '\0';
                        symname = tmpsym;
                }
                ep->name = strdup(symname);
index 6fbd95ffe25ac53ce55016e641a0f038e45d7930..5a7b84733924a1ea403c9a255917fa5cf7dd2157 100644 (file)
@@ -11,7 +11,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *     $Header: /cvsroot/pgsql/src/backend/utils/adt/like.c,v 1.36 2000/07/06 05:48:11 tgl Exp $
+ *     $Header: /cvsroot/pgsql/src/backend/utils/adt/like.c,v 1.37 2000/07/07 21:12:50 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -48,7 +48,8 @@ fixedlen_like(char *s, text *p, int charlen)
        (void) pg_mb2wchar_with_len((unsigned char *) s, sterm, charlen);
 #else
        sterm = (char *) palloc(charlen + 1);
-       StrNCpy(sterm, s, charlen + 1);
+       memcpy(sterm, s, charlen);
+       sterm[charlen] = '\0';
 #endif
 
        /*
index ec3b82c502a0efa6369b7ddf19bb54c990bd0ed5..55182f1bf94436886020d02fabb112a61bc18bc9 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/not_in.c,v 1.23 2000/06/09 01:11:09 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/not_in.c,v 1.24 2000/07/07 21:12:50 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -52,10 +52,12 @@ int4notin(PG_FUNCTION_ARGS)
        char            my_copy[NAMEDATALEN * 2 + 2];
        Datum           value;
 
-       strlength = VARSIZE(relation_and_attr) - VARHDRSZ + 1;
-       if (strlength > sizeof(my_copy))
-               strlength = sizeof(my_copy);
-       StrNCpy(my_copy, VARDATA(relation_and_attr), strlength);
+       /* make a null-terminated copy of text */
+       strlength = VARSIZE(relation_and_attr) - VARHDRSZ;
+       if (strlength >= sizeof(my_copy))
+               strlength = sizeof(my_copy)-1;
+       memcpy(my_copy, VARDATA(relation_and_attr), strlength);
+       my_copy[strlength] = '\0';
 
        relation = (char *) strtok(my_copy, ".");
        attribute = (char *) strtok(NULL, ".");
index dcf158c7a28ee8f8b01fe5fde4bc760410883c9e..5e9a91dbf48a4abd20ff1ef3988cfbf34d756afa 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/utils/adt/regexp.c,v 1.32 2000/07/06 05:48:11 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/utils/adt/regexp.c,v 1.33 2000/07/07 21:12:50 tgl Exp $
  *
  *             Alistair Crooks added the code for the regex caching
  *             agc - cached the regular expressions used - there's a good chance
@@ -164,7 +164,8 @@ fixedlen_regexeq(char *s, text *p, int charlen, int cflags)
 
        /* be sure sterm is null-terminated */
        sterm = (char *) palloc(charlen + 1);
-       StrNCpy(sterm, s, charlen + 1);
+       memcpy(sterm, s, charlen);
+       sterm[charlen] = '\0';
 
        result = RE_compile_and_execute(p, sterm, cflags);
 
index 6f17cb589ae60f59a8b19c50a59299ae0ebca655..58b24f339e185209d632ed174db6f3d106780d34 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/utils/adt/varchar.c,v 1.67 2000/07/03 23:09:53 wieck Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/utils/adt/varchar.c,v 1.68 2000/07/07 21:12:50 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -115,9 +115,11 @@ bpcharout(PG_FUNCTION_ARGS)
        char       *result;
        int                     len;
 
+       /* copy and add null term */
        len = VARSIZE(s) - VARHDRSZ;
        result = (char *) palloc(len + 1);
-       StrNCpy(result, VARDATA(s), len + 1); /* copy and add null term */
+       memcpy(result, VARDATA(s), len);
+       result[len] = '\0';
 
 #ifdef CYR_RECODE
        convertstr(result, len, 1);
@@ -268,8 +270,8 @@ bpchar_name(char *s)
                return NULL;
 
        len = VARSIZE(s) - VARHDRSZ;
-       if (len > NAMEDATALEN)
-               len = NAMEDATALEN;
+       if (len >= NAMEDATALEN)
+               len = NAMEDATALEN-1;
 
        while (len > 0)
        {
@@ -284,7 +286,7 @@ bpchar_name(char *s)
 #endif
 
        result = (NameData *) palloc(NAMEDATALEN);
-       StrNCpy(NameStr(*result), VARDATA(s), NAMEDATALEN);
+       memcpy(NameStr(*result), VARDATA(s), len);
 
        /* now null pad to full length... */
        while (len < NAMEDATALEN)
@@ -316,7 +318,7 @@ name_bpchar(NameData *s)
 #endif
 
        result = (char *) palloc(VARHDRSZ + len);
-       strncpy(VARDATA(result), NameStr(*s), len);
+       memcpy(VARDATA(result), NameStr(*s), len);
        VARATT_SIZEP(result) = len + VARHDRSZ;
 
        return result;
@@ -365,9 +367,11 @@ varcharout(PG_FUNCTION_ARGS)
        char       *result;
        int                     len;
 
+       /* copy and add null term */
        len = VARSIZE(s) - VARHDRSZ;
        result = (char *) palloc(len + 1);
-       StrNCpy(result, VARDATA(s), len + 1); /* copy and add null term */
+       memcpy(result, VARDATA(s), len);
+       result[len] = '\0';
 
 #ifdef CYR_RECODE
        convertstr(result, len, 1);
index 65ff45aa9234fd7e6d3184f5bbc83462afaa0b79..250a8c6db164f98928b1928431201bcce6ca79df 100644 (file)
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: c.h,v 1.75 2000/07/06 21:33:44 petere Exp $
+ * $Id: c.h,v 1.76 2000/07/07 21:12:47 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -781,11 +781,19 @@ extern int        assertTest(int val);
 
 /*
  * StrNCpy
- *             Like standard library function strncpy(), except that result string
- *             is guaranteed to be null-terminated --- that is, at most N-1 bytes
- *             of the source string will be kept.
- *             Also, the macro returns no result (too hard to do that without
- *             evaluating the arguments multiple times, which seems worse).
+ *     Like standard library function strncpy(), except that result string
+ *     is guaranteed to be null-terminated --- that is, at most N-1 bytes
+ *     of the source string will be kept.
+ *     Also, the macro returns no result (too hard to do that without
+ *     evaluating the arguments multiple times, which seems worse).
+ *
+ *     BTW: when you need to copy a non-null-terminated string (like a text
+ *     datum) and add a null, do not do it with StrNCpy(..., len+1).  That
+ *     might seem to work, but it fetches one byte more than there is in the
+ *     text object.  One fine day you'll have a SIGSEGV because there isn't
+ *     another byte before the end of memory.  Don't laugh, we've had real
+ *     live bug reports from real live users over exactly this mistake.
+ *     Do it honestly with "memcpy(dst,src,len); dst[len] = '\0';", instead.
  */
 #define StrNCpy(dst,src,len) \
        do \