Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 34d21e7

Browse files
committed
Add error-throwing wrappers for the printf family of functions.
All known standard library implementations of these functions can fail with ENOMEM. A caller neglecting to check for failure would experience missing output, information exposure, or a crash. Check return values within wrappers and code, currently just snprintf.c, that bypasses the wrappers. The wrappers do not return after an error, so their callers need not check. Back-patch to 9.0 (all supported versions). Popular free software standard library implementations do take pains to bypass malloc() in simple cases, but they risk ENOMEM for floating point numbers, positional arguments, large field widths, and large precisions. No specification demands such caution, so this commit regards every call to a printf family function as a potential threat. Injecting the wrappers implicitly is a compromise between patch scope and design goals. I would prefer to edit each call site to name a wrapper explicitly. libpq and the ECPG libraries would, ideally, convey errors to the caller rather than abort(). All that would be painfully invasive for a back-patched security fix, hence this compromise. Security: CVE-2015-3166
1 parent d5abbd1 commit 34d21e7

File tree

16 files changed

+300
-93
lines changed

16 files changed

+300
-93
lines changed

src/include/port.h

Lines changed: 53 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -156,12 +156,11 @@ extern unsigned char pg_tolower(unsigned char ch);
156156
extern unsigned char pg_ascii_toupper(unsigned char ch);
157157
extern unsigned char pg_ascii_tolower(unsigned char ch);
158158

159-
#ifdef USE_REPL_SNPRINTF
160-
161159
/*
162-
* Versions of libintl >= 0.13 try to replace printf() and friends with
163-
* macros to their own versions that understand the %$ format. We do the
164-
* same, so disable their macros, if they exist.
160+
* Capture macro-compatible calls to printf() and friends, and redirect them
161+
* to wrappers that throw errors in lieu of reporting failure in a return
162+
* value. Versions of libintl >= 0.13 similarly redirect to versions that
163+
* understand the %$ format, so disable libintl macros first.
165164
*/
166165
#ifdef vsnprintf
167166
#undef vsnprintf
@@ -185,6 +184,55 @@ extern unsigned char pg_ascii_tolower(unsigned char ch);
185184
#undef printf
186185
#endif
187186

187+
extern int
188+
vsnprintf_throw_on_fail(char *str, size_t count, const char *fmt, va_list args)
189+
__attribute__((format(PG_PRINTF_ATTRIBUTE, 3, 0)));
190+
extern int
191+
snprintf_throw_on_fail(char *str, size_t count, const char *fmt,...)
192+
__attribute__((format(PG_PRINTF_ATTRIBUTE, 3, 4)));
193+
extern int
194+
vsprintf_throw_on_fail(char *str, const char *fmt, va_list args)
195+
__attribute__((format(PG_PRINTF_ATTRIBUTE, 2, 0)));
196+
extern int
197+
sprintf_throw_on_fail(char *str, const char *fmt,...)
198+
__attribute__((format(PG_PRINTF_ATTRIBUTE, 2, 3)));
199+
extern int
200+
vfprintf_throw_on_fail(FILE *stream, const char *fmt, va_list args)
201+
__attribute__((format(PG_PRINTF_ATTRIBUTE, 2, 0)));
202+
extern int
203+
fprintf_throw_on_fail(FILE *stream, const char *fmt,...)
204+
__attribute__((format(PG_PRINTF_ATTRIBUTE, 2, 3)));
205+
extern int
206+
printf_throw_on_fail(const char *fmt,...)
207+
__attribute__((format(PG_PRINTF_ATTRIBUTE, 1, 2)));
208+
209+
/*
210+
* The GCC-specific code below prevents the __attribute__(... 'printf')
211+
* above from being replaced, and this is required because gcc doesn't
212+
* know anything about printf_throw_on_fail.
213+
*/
214+
#ifdef __GNUC__
215+
#define vsnprintf(...) vsnprintf_throw_on_fail(__VA_ARGS__)
216+
#define snprintf(...) snprintf_throw_on_fail(__VA_ARGS__)
217+
#define vsprintf(...) vsprintf_throw_on_fail(__VA_ARGS__)
218+
#define sprintf(...) sprintf_throw_on_fail(__VA_ARGS__)
219+
#define vfprintf(...) vfprintf_throw_on_fail(__VA_ARGS__)
220+
#define fprintf(...) fprintf_throw_on_fail(__VA_ARGS__)
221+
#define printf(...) printf_throw_on_fail(__VA_ARGS__)
222+
#else
223+
#define vsnprintf vsnprintf_throw_on_fail
224+
#define snprintf snprintf_throw_on_fail
225+
#define vsprintf vsprintf_throw_on_fail
226+
#define sprintf sprintf_throw_on_fail
227+
#define vfprintf vfprintf_throw_on_fail
228+
#define fprintf fprintf_throw_on_fail
229+
#define printf printf_throw_on_fail
230+
#endif
231+
232+
#ifdef USE_REPL_SNPRINTF
233+
234+
/* Code outside syswrap.c should not call these. */
235+
188236
extern int pg_vsnprintf(char *str, size_t count, const char *fmt, va_list args);
189237
extern int
190238
pg_snprintf(char *str, size_t count, const char *fmt,...)
@@ -205,28 +253,6 @@ pg_printf(const char *fmt,...)
205253
/* This extension allows gcc to check the format string */
206254
__attribute__((format(PG_PRINTF_ATTRIBUTE, 1, 2)));
207255

208-
/*
209-
* The GCC-specific code below prevents the __attribute__(... 'printf')
210-
* above from being replaced, and this is required because gcc doesn't
211-
* know anything about pg_printf.
212-
*/
213-
#ifdef __GNUC__
214-
#define vsnprintf(...) pg_vsnprintf(__VA_ARGS__)
215-
#define snprintf(...) pg_snprintf(__VA_ARGS__)
216-
#define vsprintf(...) pg_vsprintf(__VA_ARGS__)
217-
#define sprintf(...) pg_sprintf(__VA_ARGS__)
218-
#define vfprintf(...) pg_vfprintf(__VA_ARGS__)
219-
#define fprintf(...) pg_fprintf(__VA_ARGS__)
220-
#define printf(...) pg_printf(__VA_ARGS__)
221-
#else
222-
#define vsnprintf pg_vsnprintf
223-
#define snprintf pg_snprintf
224-
#define vsprintf pg_vsprintf
225-
#define sprintf pg_sprintf
226-
#define vfprintf pg_vfprintf
227-
#define fprintf pg_fprintf
228-
#define printf pg_printf
229-
#endif
230256
#endif /* USE_REPL_SNPRINTF */
231257

232258
#if defined(WIN32)

src/interfaces/ecpg/compatlib/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ submake-pgtypeslib:
4747
# Shared library stuff
4848
include $(top_srcdir)/src/Makefile.shlib
4949

50+
# XXX This library uses no symbols from snprintf.c.
5051
snprintf.c: % : $(top_srcdir)/src/port/%
5152
rm -f $@ && $(LN_S) $< .
5253

src/interfaces/ecpg/ecpglib/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,5 @@
55
/path.c
66
/pgstrcasecmp.c
77
/strlcpy.c
8+
/syswrap.c
89
/thread.c

src/interfaces/ecpg/ecpglib/Makefile

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ override CFLAGS += $(PTHREAD_CFLAGS)
2525
LIBS := $(filter-out -lpgport, $(LIBS))
2626

2727
OBJS= execute.o typename.o descriptor.o sqlda.o data.o error.o prepare.o memory.o \
28-
connect.o misc.o path.o pgstrcasecmp.o \
28+
connect.o misc.o path.o pgstrcasecmp.o syswrap.o \
2929
$(filter snprintf.o strlcpy.o win32setlocale.o isinf.o, $(LIBOBJS))
3030

3131
# thread.c is needed only for non-WIN32 implementation of path.c
@@ -59,7 +59,7 @@ include $(top_srcdir)/src/Makefile.shlib
5959
# necessarily use the same object files as the backend uses. Instead,
6060
# symlink the source files in here and build our own object file.
6161

62-
path.c pgstrcasecmp.c snprintf.c strlcpy.c thread.c win32setlocale.c isinf.c: % : $(top_srcdir)/src/port/%
62+
path.c pgstrcasecmp.c snprintf.c strlcpy.c syswrap.c thread.c win32setlocale.c isinf.c: % : $(top_srcdir)/src/port/%
6363
rm -f $@ && $(LN_S) $< .
6464

6565
misc.o: misc.c $(top_builddir)/src/port/pg_config_paths.h
@@ -76,6 +76,6 @@ uninstall: uninstall-lib
7676

7777
clean distclean: clean-lib
7878
rm -f $(OBJS)
79-
rm -f path.c pgstrcasecmp.c snprintf.c strlcpy.c thread.c win32setlocale.c
79+
rm -f path.c pgstrcasecmp.c snprintf.c strlcpy.c syswrap.c thread.c win32setlocale.c
8080

8181
maintainer-clean: distclean maintainer-clean-lib

src/interfaces/ecpg/pgtypeslib/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@
33
/exports.list
44

55
/pgstrcasecmp.c
6+
/syswrap.c

src/interfaces/ecpg/pgtypeslib/Makefile

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ SHLIB_LINK += -lm
2929
SHLIB_EXPORTS = exports.txt
3030

3131
OBJS= numeric.o datetime.o common.o dt_common.o timestamp.o interval.o \
32-
pgstrcasecmp.o \
32+
pgstrcasecmp.o syswrap.o \
3333
$(filter rint.o snprintf.o, $(LIBOBJS))
3434

3535
all: all-lib
@@ -42,7 +42,7 @@ include $(top_srcdir)/src/Makefile.shlib
4242
# necessarily use the same object files as the backend uses. Instead,
4343
# symlink the source files in here and build our own object file.
4444

45-
pgstrcasecmp.c rint.c snprintf.c: % : $(top_srcdir)/src/port/%
45+
pgstrcasecmp.c rint.c snprintf.c syswrap.c: % : $(top_srcdir)/src/port/%
4646
rm -f $@ && $(LN_S) $< .
4747

4848
install: all installdirs install-lib
@@ -52,6 +52,6 @@ installdirs: installdirs-lib
5252
uninstall: uninstall-lib
5353

5454
clean distclean: clean-lib
55-
rm -f $(OBJS) pgstrcasecmp.c rint.c snprintf.c
55+
rm -f $(OBJS) pgstrcasecmp.c rint.c snprintf.c syswrap.c
5656

5757
maintainer-clean: distclean maintainer-clean-lib

src/interfaces/libpq/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
/snprintf.c
1313
/strerror.c
1414
/strlcpy.c
15+
/syswrap.c
1516
/thread.c
1617
/win32error.c
1718
/win32setlocale.c

src/interfaces/libpq/Makefile

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ OBJS= fe-auth.o fe-connect.o fe-exec.o fe-misc.o fe-print.o fe-lobj.o \
3636
libpq-events.o
3737
# libpgport C files we always use
3838
OBJS += chklocale.o inet_net_ntop.o noblock.o pgstrcasecmp.o pqsignal.o \
39-
thread.o
39+
syswrap.o thread.o
4040
# libpgport C files that are needed if identified by configure
4141
OBJS += $(filter crypt.o getaddrinfo.o getpeereid.o inet_aton.o open.o snprintf.o strerror.o strlcpy.o win32error.o win32setlocale.o, $(LIBOBJS))
4242
# backend/libpq
@@ -89,7 +89,7 @@ backend_src = $(top_srcdir)/src/backend
8989
# For some libpgport modules, this only happens if configure decides
9090
# the module is needed (see filter hack in OBJS, above).
9191

92-
chklocale.c crypt.c getaddrinfo.c getpeereid.c inet_aton.c inet_net_ntop.c noblock.c open.c pgsleep.c pgstrcasecmp.c pqsignal.c snprintf.c strerror.c strlcpy.c thread.c win32error.c win32setlocale.c: % : $(top_srcdir)/src/port/%
92+
chklocale.c crypt.c getaddrinfo.c getpeereid.c inet_aton.c inet_net_ntop.c noblock.c open.c pgsleep.c pgstrcasecmp.c pqsignal.c snprintf.c strerror.c strlcpy.c syswrap.c thread.c win32error.c win32setlocale.c: % : $(top_srcdir)/src/port/%
9393
rm -f $@ && $(LN_S) $< .
9494

9595
ip.c md5.c: % : $(backend_src)/libpq/%
@@ -150,7 +150,7 @@ clean distclean: clean-lib
150150
# Might be left over from a Win32 client-only build
151151
rm -f pg_config_paths.h
152152
rm -f inet_net_ntop.c noblock.c pgstrcasecmp.c pqsignal.c thread.c
153-
rm -f chklocale.c crypt.c getaddrinfo.c getpeereid.c inet_aton.c open.c snprintf.c strerror.c strlcpy.c win32error.c win32setlocale.c
153+
rm -f chklocale.c crypt.c getaddrinfo.c getpeereid.c inet_aton.c open.c snprintf.c strerror.c strlcpy.c syswrap.c win32error.c win32setlocale.c
154154
rm -f pgsleep.c
155155
rm -f md5.c ip.c
156156
rm -f encnames.c wchar.c

src/interfaces/libpq/bcc32.mak

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ CLEAN :
106106
-@erase "$(INTDIR)\dirmod.obj"
107107
-@erase "$(INTDIR)\pgsleep.obj"
108108
-@erase "$(INTDIR)\open.obj"
109+
-@erase "$(INTDIR)\syswrap.obj"
109110
-@erase "$(INTDIR)\win32error.obj"
110111
-@erase "$(OUTDIR)\$(OUTFILENAME).lib"
111112
-@erase "$(OUTDIR)\$(OUTFILENAME)dll.lib"
@@ -149,6 +150,7 @@ LIB32_OBJS= \
149150
"$(INTDIR)\dirmod.obj" \
150151
"$(INTDIR)\pgsleep.obj" \
151152
"$(INTDIR)\open.obj" \
153+
"$(INTDIR)\syswrap.obj" \
152154
"$(INTDIR)\win32error.obj" \
153155
"$(INTDIR)\pthread-win32.obj"
154156

@@ -295,6 +297,11 @@ LINK32_FLAGS = -Gn -L$(BCB)\lib;$(INTDIR); -x -Tpd -v
295297
$(CPP_PROJ) /I"." ..\..\port\open.c
296298
<<
297299

300+
"$(INTDIR)\syswrap.obj" : ..\..\port\syswrap.c
301+
$(CPP) @<<
302+
$(CPP_PROJ) ..\..\port\syswrap.c
303+
<<
304+
298305
"$(INTDIR)\win32error.obj" : ..\..\port\win32error.c
299306
$(CPP) @<<
300307
$(CPP_PROJ) /I"." ..\..\port\win32error.c

src/interfaces/libpq/win32.mak

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ CLEAN :
113113
-@erase "$(INTDIR)\dirmod.obj"
114114
-@erase "$(INTDIR)\pgsleep.obj"
115115
-@erase "$(INTDIR)\open.obj"
116+
-@erase "$(INTDIR)\syswrap.obj"
116117
-@erase "$(INTDIR)\win32error.obj"
117118
-@erase "$(INTDIR)\win32setlocale.obj"
118119
-@erase "$(OUTDIR)\$(OUTFILENAME).lib"
@@ -159,6 +160,7 @@ LIB32_OBJS= \
159160
"$(INTDIR)\dirmod.obj" \
160161
"$(INTDIR)\pgsleep.obj" \
161162
"$(INTDIR)\open.obj" \
163+
"$(INTDIR)\syswrap.obj" \
162164
"$(INTDIR)\win32error.obj" \
163165
"$(INTDIR)\win32setlocale.obj" \
164166
"$(INTDIR)\pthread-win32.obj"
@@ -335,6 +337,11 @@ LINK32_OBJS= \
335337
$(CPP_PROJ) /I"." ..\..\port\open.c
336338
<<
337339

340+
"$(INTDIR)\syswrap.obj" : ..\..\port\syswrap.c
341+
$(CPP) @<<
342+
$(CPP_PROJ) ..\..\port\syswrap.c
343+
<<
344+
338345
"$(INTDIR)\win32error.obj" : ..\..\port\win32error.c
339346
$(CPP) @<<
340347
$(CPP_PROJ) /I"." ..\..\port\win32error.c

src/pl/plperl/plperl.h

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,8 @@
3939
* So we undefine them here and redefine them after it's done its dirty deed.
4040
*/
4141

42-
#ifdef USE_REPL_SNPRINTF
4342
#undef snprintf
4443
#undef vsnprintf
45-
#endif
4644

4745

4846
/* required for perl API */
@@ -51,21 +49,19 @@
5149
#include "XSUB.h"
5250

5351
/* put back our snprintf and vsnprintf */
54-
#ifdef USE_REPL_SNPRINTF
5552
#ifdef snprintf
5653
#undef snprintf
5754
#endif
5855
#ifdef vsnprintf
5956
#undef vsnprintf
6057
#endif
6158
#ifdef __GNUC__
62-
#define vsnprintf(...) pg_vsnprintf(__VA_ARGS__)
63-
#define snprintf(...) pg_snprintf(__VA_ARGS__)
59+
#define vsnprintf(...) vsnprintf_throw_on_fail(__VA_ARGS__)
60+
#define snprintf(...) snprintf_throw_on_fail(__VA_ARGS__)
6461
#else
65-
#define vsnprintf pg_vsnprintf
66-
#define snprintf pg_snprintf
62+
#define vsnprintf vsnprintf_throw_on_fail
63+
#define snprintf snprintf_throw_on_fail
6764
#endif /* __GNUC__ */
68-
#endif /* USE_REPL_SNPRINTF */
6965

7066
/* perl version and platform portability */
7167
#define NEED_eval_pv

src/pl/plpython/plpython.h

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,8 @@
3535
* So we undefine them here and redefine them after it's done its dirty deed.
3636
*/
3737

38-
#ifdef USE_REPL_SNPRINTF
3938
#undef snprintf
4039
#undef vsnprintf
41-
#endif
4240

4341
#if defined(_MSC_VER) && defined(_DEBUG)
4442
/* Python uses #pragma to bring in a non-default libpython on VC++ if
@@ -124,21 +122,19 @@ typedef int Py_ssize_t;
124122
#include <eval.h>
125123

126124
/* put back our snprintf and vsnprintf */
127-
#ifdef USE_REPL_SNPRINTF
128125
#ifdef snprintf
129126
#undef snprintf
130127
#endif
131128
#ifdef vsnprintf
132129
#undef vsnprintf
133130
#endif
134131
#ifdef __GNUC__
135-
#define vsnprintf(...) pg_vsnprintf(__VA_ARGS__)
136-
#define snprintf(...) pg_snprintf(__VA_ARGS__)
132+
#define vsnprintf(...) vsnprintf_throw_on_fail(__VA_ARGS__)
133+
#define snprintf(...) snprintf_throw_on_fail(__VA_ARGS__)
137134
#else
138-
#define vsnprintf pg_vsnprintf
139-
#define snprintf pg_snprintf
135+
#define vsnprintf vsnprintf_throw_on_fail
136+
#define snprintf snprintf_throw_on_fail
140137
#endif /* __GNUC__ */
141-
#endif /* USE_REPL_SNPRINTF */
142138

143139
/*
144140
* Used throughout, and also by the Python 2/3 porting layer, so it's easier to

src/port/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ LIBS += $(PTHREAD_LIBS)
3333
OBJS = $(LIBOBJS) chklocale.o dirmod.o erand48.o exec.o fls.o inet_net_ntop.o \
3434
noblock.o path.o pgcheckdir.o pg_crc.o pgmkdirp.o pgsleep.o \
3535
pgstrcasecmp.o pqsignal.o \
36-
qsort.o qsort_arg.o quotes.o sprompt.o tar.o thread.o \
36+
qsort.o qsort_arg.o quotes.o sprompt.o syswrap.o tar.o thread.o \
3737
wait_error.o
3838

3939
# foo_srv.o and foo.o are both built from foo.c, but only foo.o has -DFRONTEND

0 commit comments

Comments
 (0)