Skip to content

Commit b08c7af

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 19f7adc commit b08c7af

File tree

14 files changed

+292
-77
lines changed

14 files changed

+292
-77
lines changed

src/include/port.h

Lines changed: 53 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -148,12 +148,11 @@ extern int pg_strncasecmp(const char *s1, const char *s2, size_t n);
148148
extern unsigned char pg_toupper(unsigned char ch);
149149
extern unsigned char pg_tolower(unsigned char ch);
150150

151-
#ifdef USE_REPL_SNPRINTF
152-
153151
/*
154-
* Versions of libintl >= 0.13 try to replace printf() and friends with
155-
* macros to their own versions that understand the %$ format. We do the
156-
* same, so disable their macros, if they exist.
152+
* Capture macro-compatible calls to printf() and friends, and redirect them
153+
* to wrappers that throw errors in lieu of reporting failure in a return
154+
* value. Versions of libintl >= 0.13 similarly redirect to versions that
155+
* understand the %$ format, so disable libintl macros first.
157156
*/
158157
#ifdef vsnprintf
159158
#undef vsnprintf
@@ -177,6 +176,55 @@ extern unsigned char pg_tolower(unsigned char ch);
177176
#undef printf
178177
#endif
179178

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

200-
/*
201-
* The GCC-specific code below prevents the __attribute__(... 'printf')
202-
* above from being replaced, and this is required because gcc doesn't
203-
* know anything about pg_printf.
204-
*/
205-
#ifdef __GNUC__
206-
#define vsnprintf(...) pg_vsnprintf(__VA_ARGS__)
207-
#define snprintf(...) pg_snprintf(__VA_ARGS__)
208-
#define vsprintf(...) pg_vsprintf(__VA_ARGS__)
209-
#define sprintf(...) pg_sprintf(__VA_ARGS__)
210-
#define vfprintf(...) pg_vfprintf(__VA_ARGS__)
211-
#define fprintf(...) pg_fprintf(__VA_ARGS__)
212-
#define printf(...) pg_printf(__VA_ARGS__)
213-
#else
214-
#define vsnprintf pg_vsnprintf
215-
#define snprintf pg_snprintf
216-
#define vsprintf pg_vsprintf
217-
#define sprintf pg_sprintf
218-
#define vfprintf pg_vfprintf
219-
#define fprintf pg_fprintf
220-
#define printf pg_printf
221-
#endif
222248
#endif /* USE_REPL_SNPRINTF */
223249

224250
/*

src/interfaces/ecpg/compatlib/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ all: all-lib
3636
# Shared library stuff
3737
include $(top_srcdir)/src/Makefile.shlib
3838

39+
# XXX This library uses no symbols from snprintf.c.
3940
snprintf.c: % : $(top_srcdir)/src/port/%
4041
rm -f $@ && $(LN_S) $< .
4142

src/interfaces/ecpg/ecpglib/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,5 @@
66
/path.c
77
/pgstrcasecmp.c
88
/strlcpy.c
9+
/syswrap.c
910
/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 isinf.o, $(LIBOBJS))
3030

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

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

6464
misc.o: misc.c $(top_builddir)/src/port/pg_config_paths.h
@@ -75,6 +75,6 @@ uninstall: uninstall-lib
7575

7676
clean distclean: clean-lib
7777
rm -f $(OBJS)
78-
rm -f path.c pgstrcasecmp.c snprintf.c strlcpy.c thread.c
78+
rm -f path.c pgstrcasecmp.c snprintf.c strlcpy.c syswrap.c thread.c
7979

8080
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
@@ -4,3 +4,4 @@
44
/exports.list
55

66
/pgstrcasecmp.c
7+
/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
@@ -8,6 +8,7 @@
88
/snprintf.c
99
/strerror.c
1010
/strlcpy.c
11+
/syswrap.c
1112
/thread.c
1213
/win32error.c
1314
/pgsleep.c

src/interfaces/libpq/Makefile

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ LIBS := $(LIBS:-lpgport=)
3333
OBJS= fe-auth.o fe-connect.o fe-exec.o fe-misc.o fe-print.o fe-lobj.o \
3434
fe-protocol2.o fe-protocol3.o pqexpbuffer.o pqsignal.o fe-secure.o \
3535
libpq-events.o \
36-
md5.o ip.o wchar.o encnames.o noblock.o pgstrcasecmp.o thread.o \
36+
md5.o ip.o wchar.o encnames.o noblock.o pgstrcasecmp.o syswrap.o thread.o \
3737
$(filter crypt.o getaddrinfo.o inet_aton.o open.o snprintf.o strerror.o strlcpy.o win32error.o, $(LIBOBJS))
3838

3939
ifeq ($(PORTNAME), cygwin)
@@ -80,7 +80,7 @@ backend_src = $(top_srcdir)/src/backend
8080
# For port modules, this only happens if configure decides the module
8181
# is needed (see filter hack in OBJS, above).
8282

83-
crypt.c getaddrinfo.c inet_aton.c noblock.c open.c pgstrcasecmp.c snprintf.c strerror.c strlcpy.c thread.c win32error.c pgsleep.c: % : $(top_srcdir)/src/port/%
83+
crypt.c getaddrinfo.c inet_aton.c noblock.c open.c pgstrcasecmp.c snprintf.c strerror.c strlcpy.c syswrap.c thread.c win32error.c pgsleep.c: % : $(top_srcdir)/src/port/%
8484
rm -f $@ && $(LN_S) $< .
8585

8686
md5.c ip.c: % : $(backend_src)/libpq/%
@@ -133,7 +133,7 @@ ifneq (,$(findstring $(PORTNAME), win32 cygwin))
133133
endif
134134

135135
clean distclean: clean-lib
136-
rm -f $(OBJS) pg_config_paths.h crypt.c getaddrinfo.c inet_aton.c noblock.c open.c pgstrcasecmp.c snprintf.c strerror.c strlcpy.c thread.c md5.c ip.c encnames.c wchar.c win32error.c pgsleep.c pthread.h libpq.rc
136+
rm -f $(OBJS) pg_config_paths.h crypt.c getaddrinfo.c inet_aton.c noblock.c open.c pgstrcasecmp.c snprintf.c strerror.c strlcpy.c syswrap.c thread.c md5.c ip.c encnames.c wchar.c win32error.c pgsleep.c pthread.h libpq.rc
137137
# Might be left over from a Win32 client-only build
138138
rm -f pg_config_paths.h
139139

src/interfaces/libpq/bcc32.mak

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ CLEAN :
104104
-@erase "$(INTDIR)\dirmod.obj"
105105
-@erase "$(INTDIR)\pgsleep.obj"
106106
-@erase "$(INTDIR)\open.obj"
107+
-@erase "$(INTDIR)\syswrap.obj"
107108
-@erase "$(INTDIR)\win32error.obj"
108109
-@erase "$(OUTDIR)\$(OUTFILENAME).lib"
109110
-@erase "$(OUTDIR)\$(OUTFILENAME)dll.lib"
@@ -145,6 +146,7 @@ LIB32_OBJS= \
145146
"$(INTDIR)\dirmod.obj" \
146147
"$(INTDIR)\pgsleep.obj" \
147148
"$(INTDIR)\open.obj" \
149+
"$(INTDIR)\syswrap.obj" \
148150
"$(INTDIR)\win32error.obj" \
149151
"$(INTDIR)\pthread-win32.obj"
150152

@@ -273,6 +275,11 @@ LINK32_FLAGS = -Gn -L$(BCB)\lib;$(INTDIR); -x -Tpd -v
273275
$(CPP_PROJ) /I"." ..\..\port\open.c
274276
<<
275277

278+
"$(INTDIR)\syswrap.obj" : ..\..\port\syswrap.c
279+
$(CPP) @<<
280+
$(CPP_PROJ) ..\..\port\syswrap.c
281+
<<
282+
276283
"$(INTDIR)\win32error.obj" : ..\..\port\win32error.c
277284
$(CPP) @<<
278285
$(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
@@ -111,6 +111,7 @@ CLEAN :
111111
-@erase "$(INTDIR)\dirmod.obj"
112112
-@erase "$(INTDIR)\pgsleep.obj"
113113
-@erase "$(INTDIR)\open.obj"
114+
-@erase "$(INTDIR)\syswrap.obj"
114115
-@erase "$(INTDIR)\win32error.obj"
115116
-@erase "$(OUTDIR)\$(OUTFILENAME).lib"
116117
-@erase "$(OUTDIR)\$(OUTFILENAME)dll.lib"
@@ -154,6 +155,7 @@ LIB32_OBJS= \
154155
"$(INTDIR)\dirmod.obj" \
155156
"$(INTDIR)\pgsleep.obj" \
156157
"$(INTDIR)\open.obj" \
158+
"$(INTDIR)\syswrap.obj" \
157159
"$(INTDIR)\win32error.obj" \
158160
"$(INTDIR)\pthread-win32.obj"
159161

@@ -311,6 +313,11 @@ LINK32_OBJS= \
311313
$(CPP_PROJ) /I"." ..\..\port\open.c
312314
<<
313315

316+
"$(INTDIR)\syswrap.obj" : ..\..\port\syswrap.c
317+
$(CPP) @<<
318+
$(CPP_PROJ) ..\..\port\syswrap.c
319+
<<
320+
314321
"$(INTDIR)\win32error.obj" : ..\..\port\win32error.c
315322
$(CPP) @<<
316323
$(CPP_PROJ) /I"." ..\..\port\win32error.c

src/port/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ override CPPFLAGS := -I$(top_builddir)/src/port -DFRONTEND $(CPPFLAGS)
3131
LIBS += $(PTHREAD_LIBS)
3232

3333
OBJS = $(LIBOBJS) chklocale.o dirmod.o exec.o noblock.o path.o \
34-
pgsleep.o pgstrcasecmp.o qsort.o qsort_arg.o sprompt.o thread.o
34+
pgsleep.o pgstrcasecmp.o qsort.o qsort_arg.o sprompt.o syswrap.o thread.o
3535
ifneq (,$(filter $(PORTNAME),cygwin win32))
3636
OBJS += pipe.o
3737
endif

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy