diff --git a/bsc1021227-0001-pkg-devmapper-dynamically-load-dm_task_deferred_remo.patch b/bsc1021227-0001-pkg-devmapper-dynamically-load-dm_task_deferred_remo.patch new file mode 100644 index 0000000..ffc4153 --- /dev/null +++ b/bsc1021227-0001-pkg-devmapper-dynamically-load-dm_task_deferred_remo.patch @@ -0,0 +1,244 @@ +From 69d2f2339e43e44ea23bb9b9f699b093046568fe Mon Sep 17 00:00:00 2001 +From: Aleksa Sarai +Date: Thu, 16 Nov 2017 17:09:16 +1100 +Subject: [PATCH] pkg: devmapper: dynamically load dm_task_deferred_remove + +dm_task_deferred_remove is not supported by all distributions, due to +out-dated versions of devicemapper. However, in the case where the +devicemapper library was updated without rebuilding Docker (which can +happen in some distributions) then we should attempt to dynamically load +the relevant object rather than try to link to it. + +This can only be done if Docker was built dynamically, for obvious +reasons. + +In order to avoid having issues arise when dlsym(3) was unnecessary, +gate the whole dlsym(3) logic behind a buildflag that we disable by +default (libdm_dlsym_deferred_remove). + +SUSE-Bugs: bsc#1021227 bsc#1029320 bsc#1058173 +SUSE-Backport: https://github.com/moby/moby/pull/35518 +Signed-off-by: Aleksa Sarai +--- + hack/make.sh | 12 +- + ...> devmapper_wrapper_dynamic_deferred_remove.go} | 10 +- + ...mapper_wrapper_dynamic_dlsym_deferred_remove.go | 128 +++++++++++++++++++++ + .../devmapper_wrapper_no_deferred_remove.go | 6 +- + 4 files changed, 149 insertions(+), 7 deletions(-) + rename pkg/devicemapper/{devmapper_wrapper_deferred_remove.go => devmapper_wrapper_dynamic_deferred_remove.go} (78%) + create mode 100644 pkg/devicemapper/devmapper_wrapper_dynamic_dlsym_deferred_remove.go + +diff --git a/hack/make.sh b/hack/make.sh +index 58e0d8cd628a..3b78ddef30b0 100755 +--- a/hack/make.sh ++++ b/hack/make.sh +@@ -112,6 +112,12 @@ if [ ! "$GOPATH" ]; then + exit 1 + fi + ++# Adds $1_$2 to DOCKER_BUILDTAGS unless it already ++# contains a word starting from $1_ ++add_buildtag() { ++ [[ " $DOCKER_BUILDTAGS" == *" $1_"* ]] || DOCKER_BUILDTAGS+=" $1_$2" ++} ++ + if ${PKG_CONFIG} 'libsystemd >= 209' 2> /dev/null ; then + DOCKER_BUILDTAGS+=" journald" + elif ${PKG_CONFIG} 'libsystemd-journal' 2> /dev/null ; then +@@ -127,12 +133,14 @@ if \ + fi + + # test whether "libdevmapper.h" is new enough to support deferred remove +-# functionality. ++# functionality. We favour libdm_dlsym_deferred_remove over ++# libdm_no_deferred_remove in dynamic cases because the binary could be shipped ++# with a newer libdevmapper than the one it was built wih. + if \ + command -v gcc &> /dev/null \ + && ! ( echo -e '#include \nint main() { dm_task_deferred_remove(NULL); }'| gcc -xc - -o /dev/null -ldevmapper &> /dev/null ) \ + ; then +- DOCKER_BUILDTAGS+=' libdm_no_deferred_remove' ++ add_buildtag libdm dlsym_deferred_remove + fi + + # Use these flags when compiling the tests and final binary +diff --git a/pkg/devicemapper/devmapper_wrapper_deferred_remove.go b/pkg/devicemapper/devmapper_wrapper_dynamic_deferred_remove.go +similarity index 78% +rename from pkg/devicemapper/devmapper_wrapper_deferred_remove.go +rename to pkg/devicemapper/devmapper_wrapper_dynamic_deferred_remove.go +index 7f793c270868..bf57371ff4cf 100644 +--- a/pkg/devicemapper/devmapper_wrapper_deferred_remove.go ++++ b/pkg/devicemapper/devmapper_wrapper_dynamic_deferred_remove.go +@@ -1,14 +1,15 @@ +-// +build linux,cgo,!libdm_no_deferred_remove ++// +build linux,cgo,!static_build ++// +build !libdm_dlsym_deferred_remove,!libdm_no_deferred_remove + + package devicemapper + + /* +-#cgo LDFLAGS: -L. -ldevmapper + #include + */ + import "C" + +-// LibraryDeferredRemovalSupport is supported when statically linked. ++// LibraryDeferredRemovalSupport tells if the feature is supported by the ++// current Docker invocation. + const LibraryDeferredRemovalSupport = true + + func dmTaskDeferredRemoveFct(task *cdmTask) int { +diff --git a/pkg/devicemapper/devmapper_wrapper_dynamic_dlsym_deferred_remove.go b/pkg/devicemapper/devmapper_wrapper_dynamic_dlsym_deferred_remove.go +new file mode 100644 +index 000000000000..5dfb369f1ff8 +--- /dev/null ++++ b/pkg/devicemapper/devmapper_wrapper_dynamic_dlsym_deferred_remove.go +@@ -0,0 +1,128 @@ ++// +build linux,cgo,!static_build ++// +build libdm_dlsym_deferred_remove,!libdm_no_deferred_remove ++ ++package devicemapper ++ ++/* ++#cgo LDFLAGS: -ldl ++#include ++#include ++#include ++ ++// Yes, I know this looks scary. In order to be able to fill our own internal ++// dm_info with deferred_remove we need to have a struct definition that is ++// correct (regardless of the version of libdm that was used to compile it). To ++// this end, we define struct_backport_dm_info. This code comes from lvm2, and ++// I have verified that the structure has only ever had elements *appended* to ++// it (since 2001). ++// ++// It is also important that this structure be _larger_ than the dm_info that ++// libdevmapper expected. Otherwise libdm might try to write to memory it ++// shouldn't (they don't have a "known size" API). ++struct backport_dm_info { ++ int exists; ++ int suspended; ++ int live_table; ++ int inactive_table; ++ int32_t open_count; ++ uint32_t event_nr; ++ uint32_t major; ++ uint32_t minor; ++ int read_only; ++ ++ int32_t target_count; ++ ++ int deferred_remove; ++ int internal_suspend; ++ ++ // Padding, purely for our own safety. This is to avoid cases where libdm ++ // was updated underneath us and we call into dm_task_get_info() with too ++ // small of a buffer. ++ char _[512]; ++}; ++ ++// We have to wrap this in CGo, because Go really doesn't like function pointers. ++int call_dm_task_deferred_remove(void *fn, struct dm_task *task) ++{ ++ int (*_dm_task_deferred_remove)(struct dm_task *task) = fn; ++ return _dm_task_deferred_remove(task); ++} ++*/ ++import "C" ++ ++import ( ++ "unsafe" ++ ++ "github.com/Sirupsen/logrus" ++) ++ ++// dm_task_deferred_remove is not supported by all distributions, due to ++// out-dated versions of devicemapper. However, in the case where the ++// devicemapper library was updated without rebuilding Docker (which can happen ++// in some distributions) then we should attempt to dynamically load the ++// relevant object rather than try to link to it. ++ ++// dmTaskDeferredRemoveFct is a "bound" version of dm_task_deferred_remove. ++// It is nil if dm_task_deferred_remove was not found in the libdevmapper that ++// is currently loaded. ++var dmTaskDeferredRemovePtr unsafe.Pointer ++ ++// LibraryDeferredRemovalSupport tells if the feature is supported by the ++// current Docker invocation. This value is fixed during init. ++var LibraryDeferredRemovalSupport bool ++ ++func init() { ++ // Clear any errors. ++ var err *C.char ++ C.dlerror() ++ ++ // The symbol we want to fetch. ++ symName := C.CString("dm_task_deferred_remove") ++ defer C.free(unsafe.Pointer(symName)) ++ ++ // See if we can find dm_task_deferred_remove. Since we already are linked ++ // to libdevmapper, we can search our own address space (rather than trying ++ // to guess what libdevmapper is called). We use NULL here, as RTLD_DEFAULT ++ // is not available in CGO (even if you set _GNU_SOURCE for some reason). ++ // The semantics are identical on glibc. ++ sym := C.dlsym(nil, symName) ++ err = C.dlerror() ++ if err != nil { ++ logrus.Debugf("devmapper: could not load dm_task_deferred_remove: %s", C.GoString(err)) ++ return ++ } ++ ++ logrus.Debugf("devmapper: found dm_task_deferred_remove at %x", uintptr(sym)) ++ dmTaskDeferredRemovePtr = sym ++ LibraryDeferredRemovalSupport = true ++} ++ ++func dmTaskDeferredRemoveFct(task *cdmTask) int { ++ sym := dmTaskDeferredRemovePtr ++ if sym == nil || !LibraryDeferredRemovalSupport { ++ return -1 ++ } ++ return int(C.call_dm_task_deferred_remove(sym, (*C.struct_dm_task)(task))) ++} ++ ++func dmTaskGetInfoWithDeferredFct(task *cdmTask, info *Info) int { ++ if !LibraryDeferredRemovalSupport { ++ return -1 ++ } ++ ++ Cinfo := C.struct_backport_dm_info{} ++ defer func() { ++ info.Exists = int(Cinfo.exists) ++ info.Suspended = int(Cinfo.suspended) ++ info.LiveTable = int(Cinfo.live_table) ++ info.InactiveTable = int(Cinfo.inactive_table) ++ info.OpenCount = int32(Cinfo.open_count) ++ info.EventNr = uint32(Cinfo.event_nr) ++ info.Major = uint32(Cinfo.major) ++ info.Minor = uint32(Cinfo.minor) ++ info.ReadOnly = int(Cinfo.read_only) ++ info.TargetCount = int32(Cinfo.target_count) ++ info.DeferredRemove = int(Cinfo.deferred_remove) ++ }() ++ return int(C.dm_task_get_info((*C.struct_dm_task)(task), (*C.struct_dm_info)(unsafe.Pointer(&Cinfo)))) ++} +diff --git a/pkg/devicemapper/devmapper_wrapper_no_deferred_remove.go b/pkg/devicemapper/devmapper_wrapper_no_deferred_remove.go +index a880fec8c499..80b034b3ff17 100644 +--- a/pkg/devicemapper/devmapper_wrapper_no_deferred_remove.go ++++ b/pkg/devicemapper/devmapper_wrapper_no_deferred_remove.go +@@ -1,8 +1,10 @@ +-// +build linux,cgo,libdm_no_deferred_remove ++// +build linux,cgo ++// +build !libdm_dlsym_deferred_remove,libdm_no_deferred_remove + + package devicemapper + +-// LibraryDeferredRemovalSupport is not supported when statically linked. ++// LibraryDeferredRemovalSupport tells if the feature is supported by the ++// current Docker invocation. + const LibraryDeferredRemovalSupport = false + + func dmTaskDeferredRemoveFct(task *cdmTask) int { +-- +2.15.1 + diff --git a/docker.changes b/docker.changes index 09e98e2..379427e 100644 --- a/docker.changes +++ b/docker.changes @@ -1,3 +1,14 @@ +------------------------------------------------------------------- +Tue Dec 5 10:58:07 UTC 2017 - asarai@suse.com + +- Add a patch to dynamically probe whether libdevmapper supports + dm_task_deferred_remove. This is necessary because we build the containers + module on a SLE12 base, but later SLE versions have libdevmapper support. + This should not affect openSUSE, as all openSUSE versions have a new enough + libdevmapper. Backport of https://github.com/moby/moby/pull/35518. + bsc#1021227 bsc#1029320 bsc#1058173 + + bsc1021227-0001-pkg-devmapper-dynamically-load-dm_task_deferred_remo.patch + ------------------------------------------------------------------- Mon Dec 4 12:22:29 UTC 2017 - asarai@suse.com diff --git a/docker.spec b/docker.spec index 40e59f4..204c739 100644 --- a/docker.spec +++ b/docker.spec @@ -66,6 +66,8 @@ Patch403: bsc1064781-0001-Allow-to-override-build-date.patch Patch404: bsc1066801-0001-oci-add-proc-scsi-to-masked-paths.patch # SUSE-BACKPORT: Backport of https://github.com/moby/moby/pull/35424. boo#1066210 CVE-2017-14992 Patch405: bsc1066210-0001-vendor-update-to-github.com-vbatts-tar-split-v0.10.2.patch +# SUSE-BACKPORT: Backport of https://github.com/moby/moby/pull/35518. bsc#1021227 bsc#1029320 bsc#1058173 +Patch406: bsc1021227-0001-pkg-devmapper-dynamically-load-dm_task_deferred_remo.patch BuildRequires: audit BuildRequires: bash-completion BuildRequires: ca-certificates @@ -194,6 +196,8 @@ Test package for docker. It contains the source code and the tests. %patch404 -p1 -d components/engine # boo#1066210 CVE-2017-14992 %patch405 -p1 -d components/engine +# bsc#1021227 bsc#1029320 bsc#1058173 +%patch406 -p1 -d components/engine cp %{SOURCE7} . cp %{SOURCE9} . @@ -203,10 +207,11 @@ BUILDTAGS="exclude_graphdriver_aufs apparmor selinux pkcs11" %if 0%{?with_libseccomp} BUILDTAGS="seccomp $BUILDTAGS" %endif -# For SLE12 libdevmapper.h is not recent enough to define -# dm_task_deferred_remove(). %if 0%{?sle_version} == 120000 - BUILDTAGS="libdm_no_deferred_remove $BUILDTAGS" + # Provided by patch406, to allow us to build with older distros but still + # have deferred removal support at runtime. We only use this when building + # on SLE12. + BUILDTAGS="libdm_dlsym_deferred_remove $BUILDTAGS" %endif (cat <