From f6f75539d24772126a975256b8df9f8d57b07851 Mon Sep 17 00:00:00 2001
From: Tom Lane <tgl@sss.pgh.pa.us>
Date: Mon, 9 Jul 2018 17:23:32 -0400
Subject: [PATCH] Prevent accidental linking of system-supplied copies of
 libpq.so etc.

Back-patch commit dddfc4cb2, which broke LDFLAGS and related Makefile
variables into two parts, one for within-build-tree library references and
one for external libraries, to ensure that the order of -L flags has all
of the former before all of the latter.  This turns out to fix a problem
recently noted on buildfarm member peripatus, that we attempted to
incorporate code from libpgport.a into a shared library.  That will fail on
platforms that are sticky about putting non-PIC code into shared libraries.
(It's quite surprising we hadn't seen such failures before, since the code
in question has been like that for a long time.)

I think that peripatus' problem could have been fixed with just a subset
of this patch; but since the previous issue of accidentally linking to the
wrong copy of a Postgres shlib seems likely to bite people in the field,
let's just back-patch the whole change.  Now that commit dddfc4cb2 has
survived some beta testing, I'm less afraid to back-patch it than I was
at the time.

This also fixes undesired inclusion of "-DFRONTEND" in pg_config's CPPFLAGS
output (in 9.6 and up) and undesired inclusion of "-L../../src/common" in
its LDFLAGS output (in all supported branches).

Back-patch to v10 and older branches; this is already in v11.

Discussion: https://postgr.es/m/20180704234304.bq2dxispefl65odz@ler-imac.local
---
 contrib/dblink/Makefile                       |  2 +-
 contrib/oid2name/Makefile                     |  2 +-
 contrib/pgbench/Makefile                      |  3 ++-
 contrib/postgres_fdw/Makefile                 |  2 +-
 contrib/spi/Makefile                          |  2 --
 contrib/vacuumlo/Makefile                     |  2 +-
 src/Makefile.global.in                        | 25 +++++++++++++------
 src/Makefile.shlib                            | 10 ++++++--
 .../replication/libpqwalreceiver/Makefile     |  2 +-
 src/bin/pg_config/Makefile                    |  2 +-
 src/bin/pg_ctl/Makefile                       |  3 ++-
 src/interfaces/ecpg/compatlib/Makefile        |  4 +--
 src/interfaces/ecpg/ecpglib/Makefile          |  3 ++-
 src/interfaces/ecpg/pgtypeslib/Makefile       |  2 +-
 src/interfaces/ecpg/test/Makefile.regress     |  5 ++--
 .../ecpg/test/compat_informix/Makefile        |  3 +--
 src/interfaces/libpq/test/Makefile            |  4 +--
 src/makefiles/pgxs.mk                         |  4 ++-
 src/test/examples/Makefile                    |  4 +--
 19 files changed, 51 insertions(+), 33 deletions(-)

diff --git a/contrib/dblink/Makefile b/contrib/dblink/Makefile
index 97cc98d4f06..1ee376bf788 100644
--- a/contrib/dblink/Makefile
+++ b/contrib/dblink/Makefile
@@ -3,7 +3,7 @@
 MODULE_big = dblink
 OBJS	= dblink.o
 PG_CPPFLAGS = -I$(libpq_srcdir)
-SHLIB_LINK = $(libpq)
+SHLIB_LINK_INTERNAL = $(libpq)
 SHLIB_PREREQS = submake-libpq
 
 EXTENSION = dblink
diff --git a/contrib/oid2name/Makefile b/contrib/oid2name/Makefile
index f695b4a84e1..b41f8af6661 100644
--- a/contrib/oid2name/Makefile
+++ b/contrib/oid2name/Makefile
@@ -7,7 +7,7 @@ PROGRAM = oid2name
 OBJS	= oid2name.o
 
 PG_CPPFLAGS = -I$(libpq_srcdir)
-PG_LIBS = $(libpq_pgport)
+PG_LIBS_INTERNAL = $(libpq_pgport)
 
 ifdef USE_PGXS
 PG_CONFIG = pg_config
diff --git a/contrib/pgbench/Makefile b/contrib/pgbench/Makefile
index b8f5fb467f6..d6fbdcc0d69 100644
--- a/contrib/pgbench/Makefile
+++ b/contrib/pgbench/Makefile
@@ -7,7 +7,8 @@ PROGRAM = pgbench
 OBJS	= pgbench.o
 
 PG_CPPFLAGS = -I$(libpq_srcdir)
-PG_LIBS = $(libpq_pgport) $(PTHREAD_LIBS)
+PG_LIBS_INTERNAL = $(libpq_pgport)
+PG_LIBS = $(PTHREAD_LIBS)
 
 ifdef USE_PGXS
 PG_CONFIG = pg_config
diff --git a/contrib/postgres_fdw/Makefile b/contrib/postgres_fdw/Makefile
index 8c497201d0e..7af3c6733b5 100644
--- a/contrib/postgres_fdw/Makefile
+++ b/contrib/postgres_fdw/Makefile
@@ -4,7 +4,7 @@ MODULE_big = postgres_fdw
 OBJS = postgres_fdw.o option.o deparse.o connection.o
 
 PG_CPPFLAGS = -I$(libpq_srcdir)
-SHLIB_LINK = $(libpq)
+SHLIB_LINK_INTERNAL = $(libpq)
 SHLIB_PREREQS = submake-libpq
 
 EXTENSION = postgres_fdw
diff --git a/contrib/spi/Makefile b/contrib/spi/Makefile
index 0c11bfcbbd4..f6ffe71c020 100644
--- a/contrib/spi/Makefile
+++ b/contrib/spi/Makefile
@@ -16,8 +16,6 @@ DOCS = $(addsuffix .example, $(MODULES))
 # comment out if you want a quieter refint package for other uses
 PG_CPPFLAGS = -DREFINT_VERBOSE
 
-LDFLAGS_SL += -L$(top_builddir)/src/port -lpgport
-
 ifdef USE_PGXS
 PG_CONFIG = pg_config
 PGXS := $(shell $(PG_CONFIG) --pgxs)
diff --git a/contrib/vacuumlo/Makefile b/contrib/vacuumlo/Makefile
index b658f9bf6f8..ccb7d074085 100644
--- a/contrib/vacuumlo/Makefile
+++ b/contrib/vacuumlo/Makefile
@@ -7,7 +7,7 @@ PROGRAM = vacuumlo
 OBJS	= vacuumlo.o
 
 PG_CPPFLAGS = -I$(libpq_srcdir)
-PG_LIBS = $(libpq_pgport)
+PG_LIBS_INTERNAL = $(libpq_pgport)
 
 ifdef USE_PGXS
 PG_CONFIG = pg_config
diff --git a/src/Makefile.global.in b/src/Makefile.global.in
index 41f18ada290..db40212f058 100644
--- a/src/Makefile.global.in
+++ b/src/Makefile.global.in
@@ -245,17 +245,26 @@ LD = @LD@
 with_gnu_ld = @with_gnu_ld@
 ld_R_works = @ld_R_works@
 
-# We want -L for libpgport.a and libpgcommon.a to be first in LDFLAGS.  We
-# also need LDFLAGS to be a "recursively expanded" variable, else adjustments
-# to rpathdir don't work right.  So we must NOT do LDFLAGS := something,
-# meaning this has to be done first and elsewhere we must only do LDFLAGS +=
-# something.
+# It's critical that within LDFLAGS, all -L switches pointing to build-tree
+# directories come before any -L switches pointing to external directories.
+# Otherwise it's possible for, e.g., a platform-provided copy of libpq.so
+# to get linked in place of the one we've built.  Therefore we adopt the
+# convention that the first component of LDFLAGS is an extra variable
+# LDFLAGS_INTERNAL, and -L and -l switches for PG's own libraries must be
+# put into LDFLAGS_INTERNAL, so they will appear ahead of those for external
+# libraries.
+#
+# We need LDFLAGS and LDFLAGS_INTERNAL to be "recursively expanded" variables,
+# else adjustments to, e.g., rpathdir don't work right.  So we must NOT do
+# "LDFLAGS := something" anywhere, ditto for LDFLAGS_INTERNAL.
+# These initial assignments must be "=" type, and elsewhere we must only do
+# "LDFLAGS += something" or "LDFLAGS_INTERNAL += something".
 ifdef PGXS
-  LDFLAGS = -L$(libdir)
+  LDFLAGS_INTERNAL = -L$(libdir)
 else
-  LDFLAGS = -L$(top_builddir)/src/port -L$(top_builddir)/src/common
+  LDFLAGS_INTERNAL = -L$(top_builddir)/src/port -L$(top_builddir)/src/common
 endif
-LDFLAGS += @LDFLAGS@
+LDFLAGS = $(LDFLAGS_INTERNAL) @LDFLAGS@
 
 LDFLAGS_EX = @LDFLAGS_EX@
 # LDFLAGS_SL might have already been assigned by calling makefile
diff --git a/src/Makefile.shlib b/src/Makefile.shlib
index 935e9070a74..7e18b46e2bc 100644
--- a/src/Makefile.shlib
+++ b/src/Makefile.shlib
@@ -20,12 +20,16 @@
 #
 # NAME                  Name of library to build (no suffix nor "lib" prefix)
 # OBJS                  List of object files to include in library
-# SHLIB_LINK            If shared library relies on other libraries,
-#                       additional stuff to put in its link command
+# SHLIB_LINK            Stuff to append to library's link command
+#                       (typically, -L and -l switches for external libraries)
+# SHLIB_LINK_INTERNAL   -L and -l switches for Postgres-supplied libraries
 # SHLIB_PREREQS         Order-only prerequisites for library build target
 # SHLIB_EXPORTS         (optional) Name of file containing list of symbols to
 #                       export, in the format "function_name  number"
 #
+# Don't use SHLIB_LINK for references to files in the build tree, or the
+# wrong things will happen --- use SHLIB_LINK_INTERNAL for those!
+#
 # When building a shared library, the following version information
 # must also be set.  It should be omitted when building a dynamically
 # loadable module.
@@ -77,6 +81,8 @@
 COMPILER = $(CC) $(CFLAGS)
 LINK.static = $(AR) $(AROPT)
 
+LDFLAGS_INTERNAL += $(SHLIB_LINK_INTERNAL)
+
 
 
 ifdef SO_MAJOR_VERSION
diff --git a/src/backend/replication/libpqwalreceiver/Makefile b/src/backend/replication/libpqwalreceiver/Makefile
index 774adaa24d4..552e80d8bd8 100644
--- a/src/backend/replication/libpqwalreceiver/Makefile
+++ b/src/backend/replication/libpqwalreceiver/Makefile
@@ -15,7 +15,7 @@ include $(top_builddir)/src/Makefile.global
 override CPPFLAGS := -I$(srcdir) -I$(libpq_srcdir) $(CPPFLAGS)
 
 OBJS = libpqwalreceiver.o
-SHLIB_LINK = $(libpq)
+SHLIB_LINK_INTERNAL = $(libpq)
 SHLIB_PREREQS = submake-libpq
 NAME = libpqwalreceiver
 
diff --git a/src/bin/pg_config/Makefile b/src/bin/pg_config/Makefile
index 8df4a9416a2..2be632ca985 100644
--- a/src/bin/pg_config/Makefile
+++ b/src/bin/pg_config/Makefile
@@ -19,7 +19,7 @@ OBJS=   pg_config.o $(WIN32RES)
 
 # don't include subdirectory-path-dependent -I and -L switches
 STD_CPPFLAGS := $(filter-out -I$(top_srcdir)/src/include -I$(top_builddir)/src/include,$(CPPFLAGS))
-STD_LDFLAGS := $(filter-out -L$(top_builddir)/src/port,$(LDFLAGS))
+STD_LDFLAGS := $(filter-out -L$(top_builddir)/src/common -L$(top_builddir)/src/port,$(LDFLAGS))
 
 override CPPFLAGS += -DVAL_CONFIGURE="\"$(configure_args)\""
 override CPPFLAGS += -DVAL_CC="\"$(CC)\""
diff --git a/src/bin/pg_ctl/Makefile b/src/bin/pg_ctl/Makefile
index 3e4dcf1ba9c..09ad5d1338c 100644
--- a/src/bin/pg_ctl/Makefile
+++ b/src/bin/pg_ctl/Makefile
@@ -17,13 +17,14 @@ top_builddir = ../../..
 include $(top_builddir)/src/Makefile.global
 
 override CPPFLAGS := -I$(libpq_srcdir) $(CPPFLAGS)
+LDFLAGS_INTERNAL += $(libpq_pgport)
 
 OBJS=	pg_ctl.o $(WIN32RES)
 
 all: pg_ctl
 
 pg_ctl: $(OBJS) | submake-libpq submake-libpgport
-	$(CC) $(CFLAGS) $(OBJS) $(libpq_pgport) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
+	$(CC) $(CFLAGS) $(OBJS) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
 
 install: all installdirs
 	$(INSTALL_PROGRAM) pg_ctl$(X) '$(DESTDIR)$(bindir)/pg_ctl$(X)'
diff --git a/src/interfaces/ecpg/compatlib/Makefile b/src/interfaces/ecpg/compatlib/Makefile
index ca489d32b94..941a3f833b2 100644
--- a/src/interfaces/ecpg/compatlib/Makefile
+++ b/src/interfaces/ecpg/compatlib/Makefile
@@ -21,8 +21,8 @@ override CPPFLAGS := -I../include -I$(top_srcdir)/src/interfaces/ecpg/include \
 	-I$(libpq_srcdir) -I$(top_srcdir)/src/include/utils -DFRONTEND $(CPPFLAGS)
 override CFLAGS += $(PTHREAD_CFLAGS)
 
-SHLIB_LINK = -L../ecpglib -lecpg -L../pgtypeslib -lpgtypes $(libpq) \
-	$(filter -lintl -lm, $(LIBS)) $(PTHREAD_LIBS)
+SHLIB_LINK_INTERNAL = -L../ecpglib -lecpg -L../pgtypeslib -lpgtypes $(libpq)
+SHLIB_LINK = $(filter -lintl -lm, $(LIBS)) $(PTHREAD_LIBS)
 SHLIB_PREREQS = submake-ecpglib submake-pgtypeslib
 
 SHLIB_EXPORTS = exports.txt
diff --git a/src/interfaces/ecpg/ecpglib/Makefile b/src/interfaces/ecpg/ecpglib/Makefile
index 86dbdc22145..15c9f9ada6e 100644
--- a/src/interfaces/ecpg/ecpglib/Makefile
+++ b/src/interfaces/ecpg/ecpglib/Makefile
@@ -33,7 +33,8 @@ ifneq ($(PORTNAME), win32)
 OBJS += thread.o
 endif
 
-SHLIB_LINK = -L../pgtypeslib -lpgtypes $(libpq) $(filter -lintl -lm, $(LIBS)) $(PTHREAD_LIBS)
+SHLIB_LINK_INTERNAL = -L../pgtypeslib -lpgtypes $(libpq)
+SHLIB_LINK = $(filter -lintl -lm, $(LIBS)) $(PTHREAD_LIBS)
 SHLIB_PREREQS = submake-libpq submake-pgtypeslib
 
 SHLIB_EXPORTS = exports.txt
diff --git a/src/interfaces/ecpg/pgtypeslib/Makefile b/src/interfaces/ecpg/pgtypeslib/Makefile
index 340bef398bd..71f25bb4f4d 100644
--- a/src/interfaces/ecpg/pgtypeslib/Makefile
+++ b/src/interfaces/ecpg/pgtypeslib/Makefile
@@ -24,7 +24,7 @@ override CFLAGS += $(PTHREAD_CFLAGS)
 # Need to recompile any libpgport object files
 LIBS := $(filter-out -lpgport, $(LIBS))
 
-SHLIB_LINK += -lm
+SHLIB_LINK += $(filter -lm, $(LIBS))
 
 SHLIB_EXPORTS = exports.txt
 
diff --git a/src/interfaces/ecpg/test/Makefile.regress b/src/interfaces/ecpg/test/Makefile.regress
index edfece07df6..e08247fcce1 100644
--- a/src/interfaces/ecpg/test/Makefile.regress
+++ b/src/interfaces/ecpg/test/Makefile.regress
@@ -2,8 +2,9 @@ override CPPFLAGS := -I../../include -I$(top_srcdir)/src/interfaces/ecpg/include
 	-I$(libpq_srcdir) $(CPPFLAGS)
 override CFLAGS += $(PTHREAD_CFLAGS)
 
-override LDFLAGS := -L../../ecpglib -L../../pgtypeslib $(filter-out -l%, $(libpq)) $(LDFLAGS)
-override LIBS := -lecpg -lpgtypes $(filter -l%, $(libpq)) $(LIBS) $(PTHREAD_LIBS)
+LDFLAGS_INTERNAL += -L../../ecpglib -lecpg -L../../pgtypeslib -lpgtypes $(libpq)
+
+override LIBS += $(PTHREAD_LIBS)
 
 ECPG = ../../preproc/ecpg --regression -I$(srcdir)/../../include
 
diff --git a/src/interfaces/ecpg/test/compat_informix/Makefile b/src/interfaces/ecpg/test/compat_informix/Makefile
index a8e2ca972ec..6274a841391 100644
--- a/src/interfaces/ecpg/test/compat_informix/Makefile
+++ b/src/interfaces/ecpg/test/compat_informix/Makefile
@@ -7,8 +7,7 @@ include $(top_srcdir)/$(subdir)/../Makefile.regress
 ECPG += -C INFORMIX
 ECPG_NOIND  = $(ECPG) -r no_indicator
 
-override LDFLAGS := -L../../compatlib $(LDFLAGS)
-override LIBS := -lecpg_compat $(LIBS)
+LDFLAGS_INTERNAL += -L../../compatlib -lecpg_compat
 
 TESTS = test_informix test_informix.c \
         test_informix2 test_informix2.c \
diff --git a/src/interfaces/libpq/test/Makefile b/src/interfaces/libpq/test/Makefile
index 01041fb15f0..4832fab9d23 100644
--- a/src/interfaces/libpq/test/Makefile
+++ b/src/interfaces/libpq/test/Makefile
@@ -3,11 +3,11 @@ top_builddir = ../../../..
 include $(top_builddir)/src/Makefile.global
 
 ifeq ($(PORTNAME), win32)
-LDLIBS += -lws2_32
+LDFLAGS += -lws2_32
 endif
 
 override CPPFLAGS := -I$(libpq_srcdir) $(CPPFLAGS)
-override LDLIBS := $(libpq_pgport) $(LDLIBS)
+LDFLAGS_INTERNAL += $(libpq_pgport)
 
 PROGS = uri-regress
 
diff --git a/src/makefiles/pgxs.mk b/src/makefiles/pgxs.mk
index bbcfe048644..e2aa2b30b2f 100644
--- a/src/makefiles/pgxs.mk
+++ b/src/makefiles/pgxs.mk
@@ -42,7 +42,9 @@
 #   EXTRA_CLEAN -- extra files to remove in 'make clean'
 #   PG_CPPFLAGS -- will be added to CPPFLAGS
 #   PG_LIBS -- will be added to PROGRAM link line
+#   PG_LIBS_INTERNAL -- same, for references to libraries within build tree
 #   SHLIB_LINK -- will be added to MODULE_big link line
+#   SHLIB_LINK_INTERNAL -- same, for references to libraries within build tree
 #   PG_CONFIG -- path to pg_config program for the PostgreSQL installation
 #     to build against (typically just "pg_config" to use the first one in
 #     your PATH)
@@ -296,5 +298,5 @@ endif
 
 ifdef PROGRAM
 $(PROGRAM): $(OBJS)
-	$(CC) $(CFLAGS) $(OBJS) $(PG_LIBS) $(LDFLAGS) $(LDFLAGS_EX) $(LIBS) -o $@$(X)
+	$(CC) $(CFLAGS) $(OBJS) $(PG_LIBS_INTERNAL) $(LDFLAGS) $(LDFLAGS_EX) $(PG_LIBS) $(LIBS) -o $@$(X)
 endif
diff --git a/src/test/examples/Makefile b/src/test/examples/Makefile
index aee5c044075..1064a10be99 100644
--- a/src/test/examples/Makefile
+++ b/src/test/examples/Makefile
@@ -7,11 +7,11 @@ top_builddir = ../../..
 include $(top_builddir)/src/Makefile.global
 
 ifeq ($(PORTNAME), win32)
-LDLIBS += -lws2_32
+LDFLAGS += -lws2_32
 endif
 
 override CPPFLAGS := -I$(libpq_srcdir) $(CPPFLAGS)
-override LDLIBS := $(libpq_pgport) $(LDLIBS)
+LDFLAGS_INTERNAL += $(libpq_pgport)
 
 
 PROGS = testlibpq testlibpq2 testlibpq3 testlibpq4 testlo testlo64
-- 
GitLab