From a7f5755ff8730808b5a79f5ed6c2c4446ba2942d Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Nov 10 2020 16:45:51 +0000 Subject: import docker-1.13.1-203.git0be3e21.el7_9 --- diff --git a/.docker.metadata b/.docker.metadata index 2a46834..7559a0b 100644 --- a/.docker.metadata +++ b/.docker.metadata @@ -1,10 +1,10 @@ -189beff513fdcd23fe50e0289fcd0b152c03f18c SOURCES/7f2769b9e0572f62730d91e79e674efd59b7e234.tar.gz +2cb8176bc19f75a8d9be33fa186070ed6ce8d7f6 SOURCES/0be3e217c42ecf554bf5117bec9c832bd3f3b6fd.tar.gz e21d6c1b9e04650915499946bb4e6a01727c7d54 SOURCES/container-storage-setup-413b408.tar.gz 0ab6f850918d4bca8b11a06d067e37e6a146d9a0 SOURCES/containerd-9c53e35.tar.gz c5e6169ea101c97d94257f48fa227f5ff0501454 SOURCES/docker-lvm-plugin-20a1f68.tar.gz 0beb6283e30f1e87e907576f4571ccb0a48b6be5 SOURCES/docker-novolume-plugin-385ec70.tar.gz 656b1d1605dc43d7f5c00cedadd686dbd418d285 SOURCES/libnetwork-c5d66a0.tar.gz 965d64f5a81c3a428ca3b29495ecf66748c67c1f SOURCES/rhel-push-plugin-af9107b.tar.gz -671e9be27aaef6c534eba2f7cca4c6fbc75613b6 SOURCES/runc-9c3c5f8.tar.gz +76c0a865f850368f23bbb8e862e8b7aff171fbcc SOURCES/runc-66aedde.tar.gz 7941233b1ed34afdc074e74ab26a86dea20ee7d4 SOURCES/tini-fec3683.tar.gz 496f9927f4254508ea1cd94f473b5b9321d41245 SOURCES/v1.10-migrator-c417a6a.tar.gz diff --git a/.gitignore b/.gitignore index 5f65b85..dee31b9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,10 +1,10 @@ -SOURCES/7f2769b9e0572f62730d91e79e674efd59b7e234.tar.gz +SOURCES/0be3e217c42ecf554bf5117bec9c832bd3f3b6fd.tar.gz SOURCES/container-storage-setup-413b408.tar.gz SOURCES/containerd-9c53e35.tar.gz SOURCES/docker-lvm-plugin-20a1f68.tar.gz SOURCES/docker-novolume-plugin-385ec70.tar.gz SOURCES/libnetwork-c5d66a0.tar.gz SOURCES/rhel-push-plugin-af9107b.tar.gz -SOURCES/runc-9c3c5f8.tar.gz +SOURCES/runc-66aedde.tar.gz SOURCES/tini-fec3683.tar.gz SOURCES/v1.10-migrator-c417a6a.tar.gz diff --git a/README.debrand b/README.debrand deleted file mode 100644 index 01c46d2..0000000 --- a/README.debrand +++ /dev/null @@ -1,2 +0,0 @@ -Warning: This package was configured for automatic debranding, but the changes -failed to apply. diff --git a/SOURCES/30.patch b/SOURCES/30.patch new file mode 100644 index 0000000..db8fee1 --- /dev/null +++ b/SOURCES/30.patch @@ -0,0 +1,25 @@ +From 44f6033c48968945353109af69114b5d0a1700de Mon Sep 17 00:00:00 2001 +From: Jhon Honce +Date: Fri, 11 Oct 2019 16:08:59 -0700 +Subject: [PATCH] Check for both nil and zero length + +Signed-off-by: Jhon Honce +--- + libcontainer/generic_error.go | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/libcontainer/generic_error.go b/libcontainer/generic_error.go +index de37715c..0f90369b 100644 +--- a/runc-66aedde759f33c190954815fb765eedc1d782dd9/libcontainer/generic_error.go ++++ b/runc-66aedde759f33c190954815fb765eedc1d782dd9/libcontainer/generic_error.go +@@ -93,6 +93,10 @@ func (e *genericError) Error() string { + if e.Cause == "" { + return e.Message + } ++ ++ if len(e.Stack.Frames) == 0 { ++ return fmt.Sprintf(":: %s caused %q", e.Cause, e.Message) ++ } + frame := e.Stack.Frames[0] + return fmt.Sprintf("%s:%d: %s caused %q", frame.File, frame.Line, e.Cause, e.Message) + } diff --git a/SOURCES/69518f0bbdb1f11113f46a4d794e09e2f21f5e91.patch b/SOURCES/69518f0bbdb1f11113f46a4d794e09e2f21f5e91.patch new file mode 100644 index 0000000..90ce818 --- /dev/null +++ b/SOURCES/69518f0bbdb1f11113f46a4d794e09e2f21f5e91.patch @@ -0,0 +1,46 @@ +From 69518f0bbdb1f11113f46a4d794e09e2f21f5e91 Mon Sep 17 00:00:00 2001 +From: Ulrich Obergfell +Date: Thu, 10 Oct 2019 11:59:44 +0200 +Subject: [PATCH] fix error handling in restore() function - version 2 + +If runtime.Load() returns an error, the restore() function removes the +/run/docker/libcontainerd/containerd/CONTAINERID directory recursively. +However, this is wrong if the error is not related to the init process +of the container. + +This patch introduces the following changes to the runtime.Load() function: + +- runtime.Load() handles errors from readProcessState() autonomously. The + /run/docker/libcontainerd/containerd/CONTAINERID/PROCESSID directory will + be removed recursively, and a warning message will be logged. + +- Errors returned by runtime.Load() are always related to the init process, + so restore() may remove /run/docker/libcontainerd/containerd/CONTAINERID. + +Signed-off-by: Ulrich Obergfell +--- + runtime/container.go | 9 ++++++--- + 1 file changed, 6 insertions(+), 3 deletions(-) + +diff --git a/runtime/container.go b/runtime/container.go +index 2e9e663..489e407 100644 +--- a/runtime/container.go ++++ b/runtime/container.go +@@ -182,11 +182,14 @@ func Load(root, id, shimName string, timeout time.Duration) (Container, error) { + continue + } + pid := d.Name() +- s, err := readProcessState(filepath.Join(root, id, pid)) ++ processStateDir := filepath.Join(root, id, pid) ++ s, err := readProcessState(processStateDir) + if err != nil { +- return nil, err ++ logrus.WithFields(logrus.Fields{"error": err, "pid": pid}).Warnf("containerd: failed to load exec process,removing state directory.") ++ os.RemoveAll(processStateDir) ++ continue + } +- p, err := loadProcess(filepath.Join(root, id, pid), pid, c, s) ++ p, err := loadProcess(processStateDir, pid, c, s) + if err != nil { + logrus.WithField("id", id).WithField("pid", pid).Debugf("containerd: error loading process %s", err) + continue diff --git a/SOURCES/97eff6cf6c9b58f8239b28be2f080e23c9da62c0.patch b/SOURCES/97eff6cf6c9b58f8239b28be2f080e23c9da62c0.patch new file mode 100644 index 0000000..2134937 --- /dev/null +++ b/SOURCES/97eff6cf6c9b58f8239b28be2f080e23c9da62c0.patch @@ -0,0 +1,103 @@ +From 97eff6cf6c9b58f8239b28be2f080e23c9da62c0 Mon Sep 17 00:00:00 2001 +From: Ulrich Obergfell +Date: Thu, 11 Jul 2019 14:33:55 +0200 +Subject: [PATCH] fix deadlock in restore() function + +When containerd starts up, the restore() function walks through the directory +hierarchy under /run/docker/libcontainerd/containerd and imports the state of +processes from files in /run/docker/libcontainerd/containerd/CONTAINERID and +in /run/docker/libcontainerd/containerd/CONTAINERID/PROCESSID. The restore() +function adds an ExitTask entry to the s.tasks queue for each process that is +no longer in state 'running'. The size of the s.tasks queue is hard-coded and +limited to 2048 (defaultBufferSize). If more than 2048 ExitTask entries need +to be added to the queue, the restore() function gets blocked (queue is full). +If this happens, containerd is in a kind of deadlock situation because the +handleTask() function (which would drain the ExitTask entries from the queue) +has not been started in a separate goroutine yet, and the main goroutine is +blocked in the restore() function (unable to start the handleTask() function). + +This patch introduces the dynamically allocated restoreExitTasks slice which +the restore() function uses to store the ExitTask entries separately instead +of adding them to the s.tasks queue. The task handler goroutine subsequently +drains all entries from restoreExitTasks frist before it enters the loop that +handles entries from the s.tasks queue. + +Signed-off-by: Ulrich Obergfell +--- + supervisor/supervisor.go | 35 +++++++++++++++++++++++++++++++++-- + 1 file changed, 33 insertions(+), 2 deletions(-) + +diff --git a/supervisor/supervisor.go b/supervisor/supervisor.go +index 8a26af0..d92de8a 100644 +--- a/supervisor/supervisor.go ++++ b/supervisor/supervisor.go +@@ -18,6 +18,16 @@ const ( + defaultBufferSize = 2048 // size of queue in eventloop + ) + ++// Pointers to all ExitTask that are created by the restore() function are stored in this slice. ++var restoreExitTasks []*ExitTask ++ ++func max(x, y int) int { ++ if x < y { ++ return y ++ } ++ return x ++} ++ + // New returns an initialized Process supervisor. + func New(stateDir string, runtimeName, shimName string, runtimeArgs []string, timeout time.Duration, retainCount int) (*Supervisor, error) { + startTasks := make(chan *startTask, 10) +@@ -207,7 +217,9 @@ type eventV1 struct { + // Events returns an event channel that external consumers can use to receive updates + // on container events + func (s *Supervisor) Events(from time.Time, storedOnly bool, id string) chan Event { +- c := make(chan Event, defaultBufferSize) ++ var c chan Event ++ ++ c = make(chan Event, defaultBufferSize) + if storedOnly { + defer s.Unsubscribe(c) + } +@@ -216,6 +228,9 @@ func (s *Supervisor) Events(from time.Time, storedOnly bool, id string) chan Eve + if !from.IsZero() { + // replay old event + s.eventLock.Lock() ++ close(c) ++ // Allocate a channel that has enough space for the entire event log. ++ c = make(chan Event, max(defaultBufferSize, len(s.eventLog))) + past := s.eventLog[:] + s.eventLock.Unlock() + for _, e := range past { +@@ -276,6 +291,21 @@ func (s *Supervisor) Start() error { + "cpus": s.machine.Cpus, + }).Debug("containerd: supervisor running") + go func() { ++ if (len(restoreExitTasks) > 0) { ++ logrus.Infof("containerd: found %d exited processes after restart", len(restoreExitTasks)) ++ // ++ // If the restore() function stored any ExitTask in the dedicated slice, ++ // then handle those tasks first. The purpose of the one second delay is ++ // to give dockerd a chance to establish its event stream connection to ++ // containerd. If the connection is established before the ExitTask are ++ // being handled, then dockerd can receive exit notifications directly ++ // (rather than having to replay the notifications from the event log). ++ // ++ time.Sleep(time.Second) ++ for _, e := range restoreExitTasks { ++ s.handleTask(e) ++ } ++ } + for i := range s.tasks { + s.handleTask(i) + } +@@ -385,7 +415,8 @@ func (s *Supervisor) restore() error { + Process: p, + } + e.WithContext(context.Background()) +- s.SendTask(e) ++ // Store pointer to ExitTask in dedicated slice. ++ restoreExitTasks = append(restoreExitTasks, e) + } + } + } diff --git a/SOURCES/bz1784228.patch b/SOURCES/bz1784228.patch new file mode 100644 index 0000000..90463e9 --- /dev/null +++ b/SOURCES/bz1784228.patch @@ -0,0 +1,22 @@ +diff -up docker-4ef4b30c57f05be26c9387ef0828e86c2ed543b8/profiles/seccomp/default.json.bz1784228 docker-4ef4b30c57f05be26c9387ef0828e86c2ed543b8/profiles/seccomp/default.json +--- docker-4ef4b30c57f05be26c9387ef0828e86c2ed543b8/profiles/seccomp/default.json.bz1784228 2019-12-20 11:36:58.836002843 +0100 ++++ docker-4ef4b30c57f05be26c9387ef0828e86c2ed543b8/profiles/seccomp/default.json 2019-12-20 11:10:34.359173999 +0100 +@@ -320,6 +320,7 @@ + "stat64", + "statfs", + "statfs64", ++ "statx", + "symlink", + "symlinkat", + "sync", +diff -up docker-4ef4b30c57f05be26c9387ef0828e86c2ed543b8/profiles/seccomp/seccomp_default.go.bz1784228 docker-4ef4b30c57f05be26c9387ef0828e86c2ed543b8/profiles/seccomp/seccomp_default.go +--- docker-4ef4b30c57f05be26c9387ef0828e86c2ed543b8/profiles/seccomp/seccomp_default.go.bz1784228 2019-12-20 11:37:11.606115942 +0100 ++++ docker-4ef4b30c57f05be26c9387ef0828e86c2ed543b8/profiles/seccomp/seccomp_default.go 2019-12-20 11:37:25.891242460 +0100 +@@ -314,6 +314,7 @@ func DefaultProfile() *types.Seccomp { + "stat64", + "statfs", + "statfs64", ++ "statx", + "symlink", + "symlinkat", + "sync", diff --git a/SOURCES/docker-1792243.patch b/SOURCES/docker-1792243.patch new file mode 100644 index 0000000..6eed8a1 --- /dev/null +++ b/SOURCES/docker-1792243.patch @@ -0,0 +1,12 @@ +diff -up ./docker-4ef4b30c57f05be26c9387ef0828e86c2ed543b8/vendor/github.com/mtrmac/gpgme/gpgme.go.1792243 ./docker-4ef4b30c57f05be26c9387ef0828e86c2ed543b8/vendor/github.com/mtrmac/gpgme/gpgme.go +--- docker-4ef4b30c57f05be26c9387ef0828e86c2ed543b8/vendor/github.com/mtrmac/gpgme/gpgme.go.1792243 2020-01-20 14:14:02.247121178 +0100 ++++ docker-4ef4b30c57f05be26c9387ef0828e86c2ed543b8/vendor/github.com/mtrmac/gpgme/gpgme.go 2020-01-20 14:14:02.249121198 +0100 +@@ -1,7 +1,7 @@ + // Package gpgme provides a Go wrapper for the GPGME library + package gpgme + +-// #cgo LDFLAGS: -lgpgme -lassuan -lgpg-error ++// #cgo LDFLAGS: -lgpgme-pthread -lassuan -lgpg-error + // #cgo CPPFLAGS: -D_FILE_OFFSET_BITS=64 + // #include + // #include diff --git a/SOURCES/docker-1879425.patch b/SOURCES/docker-1879425.patch new file mode 100644 index 0000000..149cc33 --- /dev/null +++ b/SOURCES/docker-1879425.patch @@ -0,0 +1,63 @@ +From 0f90cc1ecb2db92e5388e07b8662b6c4a3a64f6c Mon Sep 17 00:00:00 2001 +From: Kir Kolyshkin +Date: Tue, 15 Sep 2020 21:46:32 -0700 +Subject: [PATCH] runc run: fix panic on error + +In case (*initProcess).start did not set sentRun, and ierr is nil, +runc run panics: + +``` +panic: runtime error: invalid memory address or nil pointer dereference [recovered] + panic: runtime error: invalid memory address or nil pointer dereference +[signal SIGSEGV: segmentation violation code=0x1 addr=0x38 pc=0x68a117] + +goroutine 1 [running]: +github.com/urfave/cli.HandleAction.func1(0xc0002277d8) + /home/kir/go/src/github.com/projectatomic/runc/Godeps/_workspace/src/github.com/urfave/cli/app.go:478 +0x22d +panic(0x730b60, 0xa06fc0) + /usr/lib/golang/src/runtime/panic.go:969 +0x166 +github.com/opencontainers/runc/libcontainer.(*genericError).Error(0x0, 0xc0002ca0e0, 0xe) + /home/kir/go/src/github.com/projectatomic/runc/Godeps/_workspace/src/github.com/opencontainers/runc/libcontainer/generic_error.go:93 +0x37 +github.com/opencontainers/runc/libcontainer.createSystemError(0x7fcd20, 0x0, 0x78c23e, 0xe, 0xc000098050, 0x0) + /home/kir/go/src/github.com/projectatomic/runc/Godeps/_workspace/src/github.com/opencontainers/runc/libcontainer/generic_error.go:78 +0x14c +github.com/opencontainers/runc/libcontainer.newSystemErrorWithCause(...) + /home/kir/go/src/github.com/projectatomic/runc/Godeps/_workspace/src/github.com/opencontainers/runc/libcontainer/generic_error.go:63 +github.com/opencontainers/runc/libcontainer.(*initProcess).start(0xc000298000, 0x0, 0x0) + /home/kir/go/src/github.com/projectatomic/runc/Godeps/_workspace/src/github.com/opencontainers/runc/libcontainer/process_linux.go:361 +0x94b +.... +``` + +This is caused by the fact that `ierr` is a typed variable (rather than a +generic `error`), and when `newSystemErrorWithCause(ierr, ...)` is called +with a typed variable, the check `if err != nil` in `createSystemError` +does not work, since err has a type. This Golang peculiarity is described +in https://golang.org/doc/faq#nil_error. + +After this patch (tested by temporarily modifying the source to set +`sentRun` to `false`) it no longer panics, instead we get: + +``` +container_linux.go:247: starting container process caused "container init failed" +``` + +Signed-off-by: Kir Kolyshkin +--- + libcontainer/process_linux.go | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/libcontainer/process_linux.go b/libcontainer/process_linux.go +index 7c92c93a..53df9fa5 100644 +--- docker-0be3e217c42ecf554bf5117bec9c832bd3f3b6fd/runc-66aedde759f33c190954815fb765eedc1d782dd9/libcontainer/process_linux.go ++++ docker-0be3e217c42ecf554bf5117bec9c832bd3f3b6fd/runc-66aedde759f33c190954815fb765eedc1d782dd9/libcontainer/process_linux.go +@@ -364,7 +364,10 @@ loop: + return newSystemError(fmt.Errorf("container init exited prematurely")) + } + if !sentRun { +- return newSystemErrorWithCause(ierr, "container init") ++ if ierr != nil { ++ return newSystemErrorWithCause(ierr, "container init") ++ } ++ return newSystemError(errors.New("container init failed")) + } + if p.config.Config.Namespaces.Contains(configs.NEWNS) && !sentResume { + return newSystemError(fmt.Errorf("could not synchronise after executing prestart hooks with container process")) diff --git a/SOURCES/docker-CVE-2020-8945.patch b/SOURCES/docker-CVE-2020-8945.patch new file mode 100644 index 0000000..2a3481b --- /dev/null +++ b/SOURCES/docker-CVE-2020-8945.patch @@ -0,0 +1,2084 @@ +From 31b404f4a08322a5cf06b1d0637a4ada4323cbb1 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Miloslav=20Trma=C4=8D?= +Date: Thu, 20 Feb 2020 16:30:08 +0100 +Subject: [PATCH 1/2] Remove vendor/src/github.com/mtrmac/gpgme/ +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This seems to be a mistaken commit of an intermediate build state +in the old times when vendoring was used via a GOPATH at vendor/src/... + +Signed-off-by: Miloslav Trmač +--- + vendor/src/github.com/mtrmac/gpgme/LICENSE | 12 - + .../src/github.com/mtrmac/gpgme/callbacks.go | 42 - + vendor/src/github.com/mtrmac/gpgme/data.go | 191 ----- + vendor/src/github.com/mtrmac/gpgme/go_gpgme.c | 89 --- + vendor/src/github.com/mtrmac/gpgme/go_gpgme.h | 37 - + vendor/src/github.com/mtrmac/gpgme/gpgme.go | 740 ------------------ + 6 files changed, 1111 deletions(-) + delete mode 100644 vendor/src/github.com/mtrmac/gpgme/LICENSE + delete mode 100644 vendor/src/github.com/mtrmac/gpgme/callbacks.go + delete mode 100644 vendor/src/github.com/mtrmac/gpgme/data.go + delete mode 100644 vendor/src/github.com/mtrmac/gpgme/go_gpgme.c + delete mode 100644 vendor/src/github.com/mtrmac/gpgme/go_gpgme.h + delete mode 100644 vendor/src/github.com/mtrmac/gpgme/gpgme.go + +diff --git a/vendor/src/github.com/mtrmac/gpgme/LICENSE b/vendor/src/github.com/mtrmac/gpgme/LICENSE +deleted file mode 100644 +index 06d4ab77316f..000000000000 +--- a/vendor/src/github.com/mtrmac/gpgme/LICENSE ++++ /dev/null +@@ -1,12 +0,0 @@ +-Copyright (c) 2015, James Fargher +-All rights reserved. +- +-Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: +- +-1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. +- +-2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. +- +-3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. +- +-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +diff --git a/vendor/src/github.com/mtrmac/gpgme/callbacks.go b/vendor/src/github.com/mtrmac/gpgme/callbacks.go +deleted file mode 100644 +index d1dc610d42a8..000000000000 +--- a/vendor/src/github.com/mtrmac/gpgme/callbacks.go ++++ /dev/null +@@ -1,42 +0,0 @@ +-package gpgme +- +-import ( +- "sync" +-) +- +-var callbacks struct { +- sync.Mutex +- m map[uintptr]interface{} +- c uintptr +-} +- +-func callbackAdd(v interface{}) uintptr { +- callbacks.Lock() +- defer callbacks.Unlock() +- if callbacks.m == nil { +- callbacks.m = make(map[uintptr]interface{}) +- } +- callbacks.c++ +- ret := callbacks.c +- callbacks.m[ret] = v +- return ret +-} +- +-func callbackLookup(c uintptr) interface{} { +- callbacks.Lock() +- defer callbacks.Unlock() +- ret := callbacks.m[c] +- if ret == nil { +- panic("callback pointer not found") +- } +- return ret +-} +- +-func callbackDelete(c uintptr) { +- callbacks.Lock() +- defer callbacks.Unlock() +- if callbacks.m[c] == nil { +- panic("callback pointer not found") +- } +- delete(callbacks.m, c) +-} +diff --git a/vendor/src/github.com/mtrmac/gpgme/data.go b/vendor/src/github.com/mtrmac/gpgme/data.go +deleted file mode 100644 +index eebc9726347d..000000000000 +--- a/vendor/src/github.com/mtrmac/gpgme/data.go ++++ /dev/null +@@ -1,191 +0,0 @@ +-package gpgme +- +-// #include +-// #include +-// #include +-// #include "go_gpgme.h" +-import "C" +- +-import ( +- "io" +- "os" +- "runtime" +- "unsafe" +-) +- +-const ( +- SeekSet = C.SEEK_SET +- SeekCur = C.SEEK_CUR +- SeekEnd = C.SEEK_END +-) +- +-//export gogpgme_readfunc +-func gogpgme_readfunc(handle, buffer unsafe.Pointer, size C.size_t) C.ssize_t { +- d := callbackLookup(uintptr(handle)).(*Data) +- if len(d.buf) < int(size) { +- d.buf = make([]byte, size) +- } +- n, err := d.r.Read(d.buf[:size]) +- if err != nil && err != io.EOF { +- C.gpgme_err_set_errno(C.EIO) +- return -1 +- } +- C.memcpy(buffer, unsafe.Pointer(&d.buf[0]), C.size_t(n)) +- return C.ssize_t(n) +-} +- +-//export gogpgme_writefunc +-func gogpgme_writefunc(handle, buffer unsafe.Pointer, size C.size_t) C.ssize_t { +- d := callbackLookup(uintptr(handle)).(*Data) +- if len(d.buf) < int(size) { +- d.buf = make([]byte, size) +- } +- C.memcpy(unsafe.Pointer(&d.buf[0]), buffer, C.size_t(size)) +- n, err := d.w.Write(d.buf[:size]) +- if err != nil && err != io.EOF { +- C.gpgme_err_set_errno(C.EIO) +- return -1 +- } +- return C.ssize_t(n) +-} +- +-//export gogpgme_seekfunc +-func gogpgme_seekfunc(handle unsafe.Pointer, offset C.off_t, whence C.int) C.off_t { +- d := callbackLookup(uintptr(handle)).(*Data) +- n, err := d.s.Seek(int64(offset), int(whence)) +- if err != nil { +- C.gpgme_err_set_errno(C.EIO) +- return -1 +- } +- return C.off_t(n) +-} +- +-// The Data buffer used to communicate with GPGME +-type Data struct { +- dh C.gpgme_data_t +- buf []byte +- cbs C.struct_gpgme_data_cbs +- r io.Reader +- w io.Writer +- s io.Seeker +- cbc uintptr +-} +- +-func newData() *Data { +- d := &Data{} +- runtime.SetFinalizer(d, (*Data).Close) +- return d +-} +- +-// NewData returns a new memory based data buffer +-func NewData() (*Data, error) { +- d := newData() +- return d, handleError(C.gpgme_data_new(&d.dh)) +-} +- +-// NewDataFile returns a new file based data buffer +-func NewDataFile(f *os.File) (*Data, error) { +- d := newData() +- return d, handleError(C.gpgme_data_new_from_fd(&d.dh, C.int(f.Fd()))) +-} +- +-// NewDataBytes returns a new memory based data buffer that contains `b` bytes +-func NewDataBytes(b []byte) (*Data, error) { +- d := newData() +- var cb *C.char +- if len(b) != 0 { +- cb = (*C.char)(unsafe.Pointer(&b[0])) +- } +- return d, handleError(C.gpgme_data_new_from_mem(&d.dh, cb, C.size_t(len(b)), 1)) +-} +- +-// NewDataReader returns a new callback based data buffer +-func NewDataReader(r io.Reader) (*Data, error) { +- d := newData() +- d.r = r +- d.cbs.read = C.gpgme_data_read_cb_t(C.gogpgme_readfunc) +- cbc := callbackAdd(d) +- d.cbc = cbc +- return d, handleError(C.gogpgme_data_new_from_cbs(&d.dh, &d.cbs, C.uintptr_t(cbc))) +-} +- +-// NewDataWriter returns a new callback based data buffer +-func NewDataWriter(w io.Writer) (*Data, error) { +- d := newData() +- d.w = w +- d.cbs.write = C.gpgme_data_write_cb_t(C.gogpgme_writefunc) +- cbc := callbackAdd(d) +- d.cbc = cbc +- return d, handleError(C.gogpgme_data_new_from_cbs(&d.dh, &d.cbs, C.uintptr_t(cbc))) +-} +- +-// NewDataReadWriter returns a new callback based data buffer +-func NewDataReadWriter(rw io.ReadWriter) (*Data, error) { +- d := newData() +- d.r = rw +- d.w = rw +- d.cbs.read = C.gpgme_data_read_cb_t(C.gogpgme_readfunc) +- d.cbs.write = C.gpgme_data_write_cb_t(C.gogpgme_writefunc) +- cbc := callbackAdd(d) +- d.cbc = cbc +- return d, handleError(C.gogpgme_data_new_from_cbs(&d.dh, &d.cbs, C.uintptr_t(cbc))) +-} +- +-// NewDataReadWriteSeeker returns a new callback based data buffer +-func NewDataReadWriteSeeker(rw io.ReadWriteSeeker) (*Data, error) { +- d := newData() +- d.r = rw +- d.w = rw +- d.s = rw +- d.cbs.read = C.gpgme_data_read_cb_t(C.gogpgme_readfunc) +- d.cbs.write = C.gpgme_data_write_cb_t(C.gogpgme_writefunc) +- d.cbs.seek = C.gpgme_data_seek_cb_t(C.gogpgme_seekfunc) +- cbc := callbackAdd(d) +- d.cbc = cbc +- return d, handleError(C.gogpgme_data_new_from_cbs(&d.dh, &d.cbs, C.uintptr_t(cbc))) +-} +- +-// Close releases any resources associated with the data buffer +-func (d *Data) Close() error { +- if d.dh == nil { +- return nil +- } +- if d.cbc > 0 { +- callbackDelete(d.cbc) +- } +- _, err := C.gpgme_data_release(d.dh) +- d.dh = nil +- return err +-} +- +-func (d *Data) Write(p []byte) (int, error) { +- n, err := C.gpgme_data_write(d.dh, unsafe.Pointer(&p[0]), C.size_t(len(p))) +- if err != nil { +- return 0, err +- } +- if n == 0 { +- return 0, io.EOF +- } +- return int(n), nil +-} +- +-func (d *Data) Read(p []byte) (int, error) { +- n, err := C.gpgme_data_read(d.dh, unsafe.Pointer(&p[0]), C.size_t(len(p))) +- if err != nil { +- return 0, err +- } +- if n == 0 { +- return 0, io.EOF +- } +- return int(n), nil +-} +- +-func (d *Data) Seek(offset int64, whence int) (int64, error) { +- n, err := C.gpgme_data_seek(d.dh, C.off_t(offset), C.int(whence)) +- return int64(n), err +-} +- +-// Name returns the associated filename if any +-func (d *Data) Name() string { +- return C.GoString(C.gpgme_data_get_file_name(d.dh)) +-} +diff --git a/vendor/src/github.com/mtrmac/gpgme/go_gpgme.c b/vendor/src/github.com/mtrmac/gpgme/go_gpgme.c +deleted file mode 100644 +index b887574e0cb9..000000000000 +--- a/vendor/src/github.com/mtrmac/gpgme/go_gpgme.c ++++ /dev/null +@@ -1,89 +0,0 @@ +-#include "go_gpgme.h" +- +-gpgme_error_t gogpgme_data_new_from_cbs(gpgme_data_t *dh, gpgme_data_cbs_t cbs, uintptr_t handle) { +- return gpgme_data_new_from_cbs(dh, cbs, (void *)handle); +-} +- +-void gogpgme_set_passphrase_cb(gpgme_ctx_t ctx, gpgme_passphrase_cb_t cb, uintptr_t handle) { +- gpgme_set_passphrase_cb(ctx, cb, (void *)handle); +-} +- +-unsigned int key_revoked(gpgme_key_t k) { +- return k->revoked; +-} +- +-unsigned int key_expired(gpgme_key_t k) { +- return k->expired; +-} +- +-unsigned int key_disabled(gpgme_key_t k) { +- return k->disabled; +-} +- +-unsigned int key_invalid(gpgme_key_t k) { +- return k->invalid; +-} +- +-unsigned int key_can_encrypt(gpgme_key_t k) { +- return k->can_encrypt; +-} +- +-unsigned int key_can_sign(gpgme_key_t k) { +- return k->can_sign; +-} +- +-unsigned int key_can_certify(gpgme_key_t k) { +- return k->can_certify; +-} +- +-unsigned int key_secret(gpgme_key_t k) { +- return k->secret; +-} +- +-unsigned int key_can_authenticate(gpgme_key_t k) { +- return k->can_authenticate; +-} +- +-unsigned int key_is_qualified(gpgme_key_t k) { +- return k->is_qualified; +-} +- +-unsigned int signature_wrong_key_usage(gpgme_signature_t s) { +- return s->wrong_key_usage; +-} +- +-unsigned int signature_pka_trust(gpgme_signature_t s) { +- return s->pka_trust; +-} +- +-unsigned int signature_chain_model(gpgme_signature_t s) { +- return s->chain_model; +-} +- +-unsigned int subkey_revoked(gpgme_subkey_t k) { +- return k->revoked; +-} +- +-unsigned int subkey_expired(gpgme_subkey_t k) { +- return k->expired; +-} +- +-unsigned int subkey_disabled(gpgme_subkey_t k) { +- return k->disabled; +-} +- +-unsigned int subkey_invalid(gpgme_subkey_t k) { +- return k->invalid; +-} +- +-unsigned int subkey_secret(gpgme_subkey_t k) { +- return k->secret; +-} +- +-unsigned int uid_revoked(gpgme_user_id_t u) { +- return u->revoked; +-} +- +-unsigned int uid_invalid(gpgme_user_id_t u) { +- return u->invalid; +-} +diff --git a/vendor/src/github.com/mtrmac/gpgme/go_gpgme.h b/vendor/src/github.com/mtrmac/gpgme/go_gpgme.h +deleted file mode 100644 +index a3678b127ac7..000000000000 +--- a/vendor/src/github.com/mtrmac/gpgme/go_gpgme.h ++++ /dev/null +@@ -1,37 +0,0 @@ +-#ifndef GO_GPGME_H +-#define GO_GPGME_H +- +-#define _FILE_OFFSET_BITS 64 +-#include +- +-#include +- +-extern ssize_t gogpgme_readfunc(void *handle, void *buffer, size_t size); +-extern ssize_t gogpgme_writefunc(void *handle, void *buffer, size_t size); +-extern off_t gogpgme_seekfunc(void *handle, off_t offset, int whence); +-extern gpgme_error_t gogpgme_passfunc(void *hook, char *uid_hint, char *passphrase_info, int prev_was_bad, int fd); +-extern gpgme_error_t gogpgme_data_new_from_cbs(gpgme_data_t *dh, gpgme_data_cbs_t cbs, uintptr_t handle); +-extern void gogpgme_set_passphrase_cb(gpgme_ctx_t ctx, gpgme_passphrase_cb_t cb, uintptr_t handle); +- +-extern unsigned int key_revoked(gpgme_key_t k); +-extern unsigned int key_expired(gpgme_key_t k); +-extern unsigned int key_disabled(gpgme_key_t k); +-extern unsigned int key_invalid(gpgme_key_t k); +-extern unsigned int key_can_encrypt(gpgme_key_t k); +-extern unsigned int key_can_sign(gpgme_key_t k); +-extern unsigned int key_can_certify(gpgme_key_t k); +-extern unsigned int key_secret(gpgme_key_t k); +-extern unsigned int key_can_authenticate(gpgme_key_t k); +-extern unsigned int key_is_qualified(gpgme_key_t k); +-extern unsigned int signature_wrong_key_usage(gpgme_signature_t s); +-extern unsigned int signature_pka_trust(gpgme_signature_t s); +-extern unsigned int signature_chain_model(gpgme_signature_t s); +-extern unsigned int subkey_revoked(gpgme_subkey_t k); +-extern unsigned int subkey_expired(gpgme_subkey_t k); +-extern unsigned int subkey_disabled(gpgme_subkey_t k); +-extern unsigned int subkey_invalid(gpgme_subkey_t k); +-extern unsigned int subkey_secret(gpgme_subkey_t k); +-extern unsigned int uid_revoked(gpgme_user_id_t u); +-extern unsigned int uid_invalid(gpgme_user_id_t u); +- +-#endif +diff --git a/vendor/src/github.com/mtrmac/gpgme/gpgme.go b/vendor/src/github.com/mtrmac/gpgme/gpgme.go +deleted file mode 100644 +index 5f1793eab32d..000000000000 +--- a/vendor/src/github.com/mtrmac/gpgme/gpgme.go ++++ /dev/null +@@ -1,740 +0,0 @@ +-// Package gpgme provides a Go wrapper for the GPGME library +-package gpgme +- +-// #cgo LDFLAGS: -lgpgme -lassuan -lgpg-error +-// #cgo CPPFLAGS: -D_FILE_OFFSET_BITS=64 +-// #include +-// #include +-// #include "go_gpgme.h" +-import "C" +- +-import ( +- "io" +- "os" +- "runtime" +- "time" +- "unsafe" +-) +- +-var Version string +- +-func init() { +- Version = C.GoString(C.gpgme_check_version(nil)) +-} +- +-// Callback is the function that is called when a passphrase is required +-type Callback func(uidHint string, prevWasBad bool, f *os.File) error +- +-//export gogpgme_passfunc +-func gogpgme_passfunc(hook unsafe.Pointer, uid_hint, passphrase_info *C.char, prev_was_bad, fd C.int) C.gpgme_error_t { +- c := callbackLookup(uintptr(hook)).(*Context) +- go_uid_hint := C.GoString(uid_hint) +- f := os.NewFile(uintptr(fd), go_uid_hint) +- defer f.Close() +- err := c.callback(go_uid_hint, prev_was_bad != 0, f) +- if err != nil { +- return C.GPG_ERR_CANCELED +- } +- return 0 +-} +- +-type Protocol int +- +-const ( +- ProtocolOpenPGP Protocol = C.GPGME_PROTOCOL_OpenPGP +- ProtocolCMS Protocol = C.GPGME_PROTOCOL_CMS +- ProtocolGPGConf Protocol = C.GPGME_PROTOCOL_GPGCONF +- ProtocolAssuan Protocol = C.GPGME_PROTOCOL_ASSUAN +- ProtocolG13 Protocol = C.GPGME_PROTOCOL_G13 +- ProtocolUIServer Protocol = C.GPGME_PROTOCOL_UISERVER +- // ProtocolSpawn Protocol = C.GPGME_PROTOCOL_SPAWN // Unavailable in 1.4.3 +- ProtocolDefault Protocol = C.GPGME_PROTOCOL_DEFAULT +- ProtocolUnknown Protocol = C.GPGME_PROTOCOL_UNKNOWN +-) +- +-type PinEntryMode int +- +-// const ( // Unavailable in 1.3.2 +-// PinEntryDefault PinEntryMode = C.GPGME_PINENTRY_MODE_DEFAULT +-// PinEntryAsk PinEntryMode = C.GPGME_PINENTRY_MODE_ASK +-// PinEntryCancel PinEntryMode = C.GPGME_PINENTRY_MODE_CANCEL +-// PinEntryError PinEntryMode = C.GPGME_PINENTRY_MODE_ERROR +-// PinEntryLoopback PinEntryMode = C.GPGME_PINENTRY_MODE_LOOPBACK +-// ) +- +-type EncryptFlag uint +- +-const ( +- EncryptAlwaysTrust EncryptFlag = C.GPGME_ENCRYPT_ALWAYS_TRUST +- EncryptNoEncryptTo EncryptFlag = C.GPGME_ENCRYPT_NO_ENCRYPT_TO +- EncryptPrepare EncryptFlag = C.GPGME_ENCRYPT_PREPARE +- EncryptExceptSign EncryptFlag = C.GPGME_ENCRYPT_EXPECT_SIGN +- // EncryptNoCompress EncryptFlag = C.GPGME_ENCRYPT_NO_COMPRESS // Unavailable in 1.4.3 +-) +- +-type HashAlgo int +- +-// const values for HashAlgo values should be added when necessary. +- +-type KeyListMode uint +- +-const ( +- KeyListModeLocal KeyListMode = C.GPGME_KEYLIST_MODE_LOCAL +- KeyListModeExtern KeyListMode = C.GPGME_KEYLIST_MODE_EXTERN +- KeyListModeSigs KeyListMode = C.GPGME_KEYLIST_MODE_SIGS +- KeyListModeSigNotations KeyListMode = C.GPGME_KEYLIST_MODE_SIG_NOTATIONS +- // KeyListModeWithSecret KeyListMode = C.GPGME_KEYLIST_MODE_WITH_SECRET // Unavailable in 1.4.3 +- KeyListModeEphemeral KeyListMode = C.GPGME_KEYLIST_MODE_EPHEMERAL +- KeyListModeModeValidate KeyListMode = C.GPGME_KEYLIST_MODE_VALIDATE +-) +- +-type PubkeyAlgo int +- +-// const values for PubkeyAlgo values should be added when necessary. +- +-type SigMode int +- +-const ( +- SigModeNormal SigMode = C.GPGME_SIG_MODE_NORMAL +- SigModeDetach SigMode = C.GPGME_SIG_MODE_DETACH +- SigModeClear SigMode = C.GPGME_SIG_MODE_CLEAR +-) +- +-type SigSum int +- +-const ( +- SigSumValid SigSum = C.GPGME_SIGSUM_VALID +- SigSumGreen SigSum = C.GPGME_SIGSUM_GREEN +- SigSumRed SigSum = C.GPGME_SIGSUM_RED +- SigSumKeyRevoked SigSum = C.GPGME_SIGSUM_KEY_REVOKED +- SigSumKeyExpired SigSum = C.GPGME_SIGSUM_KEY_EXPIRED +- SigSumSigExpired SigSum = C.GPGME_SIGSUM_SIG_EXPIRED +- SigSumKeyMissing SigSum = C.GPGME_SIGSUM_KEY_MISSING +- SigSumCRLMissing SigSum = C.GPGME_SIGSUM_CRL_MISSING +- SigSumCRLTooOld SigSum = C.GPGME_SIGSUM_CRL_TOO_OLD +- SigSumBadPolicy SigSum = C.GPGME_SIGSUM_BAD_POLICY +- SigSumSysError SigSum = C.GPGME_SIGSUM_SYS_ERROR +-) +- +-type Validity int +- +-const ( +- ValidityUnknown Validity = C.GPGME_VALIDITY_UNKNOWN +- ValidityUndefined Validity = C.GPGME_VALIDITY_UNDEFINED +- ValidityNever Validity = C.GPGME_VALIDITY_NEVER +- ValidityMarginal Validity = C.GPGME_VALIDITY_MARGINAL +- ValidityFull Validity = C.GPGME_VALIDITY_FULL +- ValidityUltimate Validity = C.GPGME_VALIDITY_ULTIMATE +-) +- +-type ErrorCode int +- +-const ( +- ErrorNoError ErrorCode = C.GPG_ERR_NO_ERROR +- ErrorEOF ErrorCode = C.GPG_ERR_EOF +-) +- +-// Error is a wrapper for GPGME errors +-type Error struct { +- err C.gpgme_error_t +-} +- +-func (e Error) Code() ErrorCode { +- return ErrorCode(C.gpgme_err_code(e.err)) +-} +- +-func (e Error) Error() string { +- return C.GoString(C.gpgme_strerror(e.err)) +-} +- +-func handleError(err C.gpgme_error_t) error { +- e := Error{err: err} +- if e.Code() == ErrorNoError { +- return nil +- } +- return e +-} +- +-func cbool(b bool) C.int { +- if b { +- return 1 +- } +- return 0 +-} +- +-func EngineCheckVersion(p Protocol) error { +- return handleError(C.gpgme_engine_check_version(C.gpgme_protocol_t(p))) +-} +- +-type EngineInfo struct { +- info C.gpgme_engine_info_t +-} +- +-func (e *EngineInfo) Next() *EngineInfo { +- if e.info.next == nil { +- return nil +- } +- return &EngineInfo{info: e.info.next} +-} +- +-func (e *EngineInfo) Protocol() Protocol { +- return Protocol(e.info.protocol) +-} +- +-func (e *EngineInfo) FileName() string { +- return C.GoString(e.info.file_name) +-} +- +-func (e *EngineInfo) Version() string { +- return C.GoString(e.info.version) +-} +- +-func (e *EngineInfo) RequiredVersion() string { +- return C.GoString(e.info.req_version) +-} +- +-func (e *EngineInfo) HomeDir() string { +- return C.GoString(e.info.home_dir) +-} +- +-func GetEngineInfo() (*EngineInfo, error) { +- info := &EngineInfo{} +- return info, handleError(C.gpgme_get_engine_info(&info.info)) +-} +- +-func SetEngineInfo(proto Protocol, fileName, homeDir string) error { +- var cfn, chome *C.char +- if fileName != "" { +- cfn = C.CString(fileName) +- defer C.free(unsafe.Pointer(cfn)) +- } +- if homeDir != "" { +- chome = C.CString(homeDir) +- defer C.free(unsafe.Pointer(chome)) +- } +- return handleError(C.gpgme_set_engine_info(C.gpgme_protocol_t(proto), cfn, chome)) +-} +- +-func FindKeys(pattern string, secretOnly bool) ([]*Key, error) { +- var keys []*Key +- ctx, err := New() +- if err != nil { +- return keys, err +- } +- defer ctx.Release() +- if err := ctx.KeyListStart(pattern, secretOnly); err != nil { +- return keys, err +- } +- defer ctx.KeyListEnd() +- for ctx.KeyListNext() { +- keys = append(keys, ctx.Key) +- } +- if ctx.KeyError != nil { +- return keys, ctx.KeyError +- } +- return keys, nil +-} +- +-func Decrypt(r io.Reader) (*Data, error) { +- ctx, err := New() +- if err != nil { +- return nil, err +- } +- defer ctx.Release() +- cipher, err := NewDataReader(r) +- if err != nil { +- return nil, err +- } +- defer cipher.Close() +- plain, err := NewData() +- if err != nil { +- return nil, err +- } +- err = ctx.Decrypt(cipher, plain) +- plain.Seek(0, SeekSet) +- return plain, err +-} +- +-type Context struct { +- Key *Key +- KeyError error +- +- callback Callback +- cbc uintptr +- +- ctx C.gpgme_ctx_t +-} +- +-func New() (*Context, error) { +- c := &Context{} +- err := C.gpgme_new(&c.ctx) +- runtime.SetFinalizer(c, (*Context).Release) +- return c, handleError(err) +-} +- +-func (c *Context) Release() { +- if c.ctx == nil { +- return +- } +- if c.cbc > 0 { +- callbackDelete(c.cbc) +- } +- C.gpgme_release(c.ctx) +- c.ctx = nil +-} +- +-func (c *Context) SetArmor(yes bool) { +- C.gpgme_set_armor(c.ctx, cbool(yes)) +-} +- +-func (c *Context) Armor() bool { +- return C.gpgme_get_armor(c.ctx) != 0 +-} +- +-func (c *Context) SetTextMode(yes bool) { +- C.gpgme_set_textmode(c.ctx, cbool(yes)) +-} +- +-func (c *Context) TextMode() bool { +- return C.gpgme_get_textmode(c.ctx) != 0 +-} +- +-func (c *Context) SetProtocol(p Protocol) error { +- return handleError(C.gpgme_set_protocol(c.ctx, C.gpgme_protocol_t(p))) +-} +- +-func (c *Context) Protocol() Protocol { +- return Protocol(C.gpgme_get_protocol(c.ctx)) +-} +- +-func (c *Context) SetKeyListMode(m KeyListMode) error { +- return handleError(C.gpgme_set_keylist_mode(c.ctx, C.gpgme_keylist_mode_t(m))) +-} +- +-func (c *Context) KeyListMode() KeyListMode { +- return KeyListMode(C.gpgme_get_keylist_mode(c.ctx)) +-} +- +-// Unavailable in 1.3.2: +-// func (c *Context) SetPinEntryMode(m PinEntryMode) error { +-// return handleError(C.gpgme_set_pinentry_mode(c.ctx, C.gpgme_pinentry_mode_t(m))) +-// } +- +-// Unavailable in 1.3.2: +-// func (c *Context) PinEntryMode() PinEntryMode { +-// return PinEntryMode(C.gpgme_get_pinentry_mode(c.ctx)) +-// } +- +-func (c *Context) SetCallback(callback Callback) error { +- var err error +- c.callback = callback +- if c.cbc > 0 { +- callbackDelete(c.cbc) +- } +- if callback != nil { +- cbc := callbackAdd(c) +- c.cbc = cbc +- _, err = C.gogpgme_set_passphrase_cb(c.ctx, C.gpgme_passphrase_cb_t(C.gogpgme_passfunc), C.uintptr_t(cbc)) +- } else { +- c.cbc = 0 +- _, err = C.gogpgme_set_passphrase_cb(c.ctx, nil, 0) +- } +- return err +-} +- +-func (c *Context) EngineInfo() *EngineInfo { +- return &EngineInfo{info: C.gpgme_ctx_get_engine_info(c.ctx)} +-} +- +-func (c *Context) SetEngineInfo(proto Protocol, fileName, homeDir string) error { +- var cfn, chome *C.char +- if fileName != "" { +- cfn = C.CString(fileName) +- defer C.free(unsafe.Pointer(cfn)) +- } +- if homeDir != "" { +- chome = C.CString(homeDir) +- defer C.free(unsafe.Pointer(chome)) +- } +- return handleError(C.gpgme_ctx_set_engine_info(c.ctx, C.gpgme_protocol_t(proto), cfn, chome)) +-} +- +-func (c *Context) KeyListStart(pattern string, secretOnly bool) error { +- cpattern := C.CString(pattern) +- defer C.free(unsafe.Pointer(cpattern)) +- err := C.gpgme_op_keylist_start(c.ctx, cpattern, cbool(secretOnly)) +- return handleError(err) +-} +- +-func (c *Context) KeyListNext() bool { +- c.Key = newKey() +- err := handleError(C.gpgme_op_keylist_next(c.ctx, &c.Key.k)) +- if err != nil { +- if e, ok := err.(Error); ok && e.Code() == ErrorEOF { +- c.KeyError = nil +- } else { +- c.KeyError = err +- } +- return false +- } +- c.KeyError = nil +- return true +-} +- +-func (c *Context) KeyListEnd() error { +- return handleError(C.gpgme_op_keylist_end(c.ctx)) +-} +- +-func (c *Context) GetKey(fingerprint string, secret bool) (*Key, error) { +- key := newKey() +- cfpr := C.CString(fingerprint) +- defer C.free(unsafe.Pointer(cfpr)) +- return key, handleError(C.gpgme_get_key(c.ctx, cfpr, &key.k, cbool(secret))) +-} +- +-func (c *Context) Decrypt(ciphertext, plaintext *Data) error { +- return handleError(C.gpgme_op_decrypt(c.ctx, ciphertext.dh, plaintext.dh)) +-} +- +-func (c *Context) DecryptVerify(ciphertext, plaintext *Data) error { +- return handleError(C.gpgme_op_decrypt_verify(c.ctx, ciphertext.dh, plaintext.dh)) +-} +- +-type Signature struct { +- Summary SigSum +- Fingerprint string +- Status error +- Timestamp time.Time +- ExpTimestamp time.Time +- WrongKeyUsage bool +- PKATrust uint +- ChainModel bool +- Validity Validity +- ValidityReason error +- PubkeyAlgo PubkeyAlgo +- HashAlgo HashAlgo +-} +- +-func (c *Context) Verify(sig, signedText, plain *Data) (string, []Signature, error) { +- var signedTextPtr, plainPtr C.gpgme_data_t = nil, nil +- if signedText != nil { +- signedTextPtr = signedText.dh +- } +- if plain != nil { +- plainPtr = plain.dh +- } +- err := handleError(C.gpgme_op_verify(c.ctx, sig.dh, signedTextPtr, plainPtr)) +- if err != nil { +- return "", nil, err +- } +- res := C.gpgme_op_verify_result(c.ctx) +- sigs := []Signature{} +- for s := res.signatures; s != nil; s = s.next { +- sig := Signature{ +- Summary: SigSum(s.summary), +- Fingerprint: C.GoString(s.fpr), +- Status: handleError(s.status), +- // s.notations not implemented +- Timestamp: time.Unix(int64(s.timestamp), 0), +- ExpTimestamp: time.Unix(int64(s.exp_timestamp), 0), +- WrongKeyUsage: C.signature_wrong_key_usage(s) != 0, +- PKATrust: uint(C.signature_pka_trust(s)), +- ChainModel: C.signature_chain_model(s) != 0, +- Validity: Validity(s.validity), +- ValidityReason: handleError(s.validity_reason), +- PubkeyAlgo: PubkeyAlgo(s.pubkey_algo), +- HashAlgo: HashAlgo(s.hash_algo), +- } +- sigs = append(sigs, sig) +- } +- return C.GoString(res.file_name), sigs, nil +-} +- +-func (c *Context) Encrypt(recipients []*Key, flags EncryptFlag, plaintext, ciphertext *Data) error { +- size := unsafe.Sizeof(new(C.gpgme_key_t)) +- recp := C.calloc(C.size_t(len(recipients)+1), C.size_t(size)) +- defer C.free(recp) +- for i := range recipients { +- ptr := (*C.gpgme_key_t)(unsafe.Pointer(uintptr(recp) + size*uintptr(i))) +- *ptr = recipients[i].k +- } +- err := C.gpgme_op_encrypt(c.ctx, (*C.gpgme_key_t)(recp), C.gpgme_encrypt_flags_t(flags), plaintext.dh, ciphertext.dh) +- return handleError(err) +-} +- +-func (c *Context) Sign(signers []*Key, plain, sig *Data, mode SigMode) error { +- C.gpgme_signers_clear(c.ctx) +- for _, k := range signers { +- if err := handleError(C.gpgme_signers_add(c.ctx, k.k)); err != nil { +- C.gpgme_signers_clear(c.ctx) +- return err +- } +- } +- return handleError(C.gpgme_op_sign(c.ctx, plain.dh, sig.dh, C.gpgme_sig_mode_t(mode))) +-} +- +-// ImportStatusFlags describes the type of ImportStatus.Status. The C API in gpgme.h simply uses "unsigned". +-type ImportStatusFlags uint +- +-const ( +- ImportNew ImportStatusFlags = C.GPGME_IMPORT_NEW +- ImportUID ImportStatusFlags = C.GPGME_IMPORT_UID +- ImportSIG ImportStatusFlags = C.GPGME_IMPORT_SIG +- ImportSubKey ImportStatusFlags = C.GPGME_IMPORT_SUBKEY +- ImportSecret ImportStatusFlags = C.GPGME_IMPORT_SECRET +-) +- +-type ImportStatus struct { +- Fingerprint string +- Result error +- Status ImportStatusFlags +-} +- +-type ImportResult struct { +- Considered int +- NoUserID int +- Imported int +- ImportedRSA int +- Unchanged int +- NewUserIDs int +- NewSubKeys int +- NewSignatures int +- NewRevocations int +- SecretRead int +- SecretImported int +- SecretUnchanged int +- NotImported int +- Imports []ImportStatus +-} +- +-func (c *Context) Import(keyData *Data) (*ImportResult, error) { +- err := handleError(C.gpgme_op_import(c.ctx, keyData.dh)) +- if err != nil { +- return nil, err +- } +- res := C.gpgme_op_import_result(c.ctx) +- imports := []ImportStatus{} +- for s := res.imports; s != nil; s = s.next { +- imports = append(imports, ImportStatus{ +- Fingerprint: C.GoString(s.fpr), +- Result: handleError(s.result), +- Status: ImportStatusFlags(s.status), +- }) +- } +- return &ImportResult{ +- Considered: int(res.considered), +- NoUserID: int(res.no_user_id), +- Imported: int(res.imported), +- ImportedRSA: int(res.imported_rsa), +- Unchanged: int(res.unchanged), +- NewUserIDs: int(res.new_user_ids), +- NewSubKeys: int(res.new_sub_keys), +- NewSignatures: int(res.new_signatures), +- NewRevocations: int(res.new_revocations), +- SecretRead: int(res.secret_read), +- SecretImported: int(res.secret_imported), +- SecretUnchanged: int(res.secret_unchanged), +- NotImported: int(res.not_imported), +- Imports: imports, +- }, nil +-} +- +-type Key struct { +- k C.gpgme_key_t +-} +- +-func newKey() *Key { +- k := &Key{} +- runtime.SetFinalizer(k, (*Key).Release) +- return k +-} +- +-func (k *Key) Release() { +- C.gpgme_key_release(k.k) +- k.k = nil +-} +- +-func (k *Key) Revoked() bool { +- return C.key_revoked(k.k) != 0 +-} +- +-func (k *Key) Expired() bool { +- return C.key_expired(k.k) != 0 +-} +- +-func (k *Key) Disabled() bool { +- return C.key_disabled(k.k) != 0 +-} +- +-func (k *Key) Invalid() bool { +- return C.key_invalid(k.k) != 0 +-} +- +-func (k *Key) CanEncrypt() bool { +- return C.key_can_encrypt(k.k) != 0 +-} +- +-func (k *Key) CanSign() bool { +- return C.key_can_sign(k.k) != 0 +-} +- +-func (k *Key) CanCertify() bool { +- return C.key_can_certify(k.k) != 0 +-} +- +-func (k *Key) Secret() bool { +- return C.key_secret(k.k) != 0 +-} +- +-func (k *Key) CanAuthenticate() bool { +- return C.key_can_authenticate(k.k) != 0 +-} +- +-func (k *Key) IsQualified() bool { +- return C.key_is_qualified(k.k) != 0 +-} +- +-func (k *Key) Protocol() Protocol { +- return Protocol(k.k.protocol) +-} +- +-func (k *Key) IssuerSerial() string { +- return C.GoString(k.k.issuer_serial) +-} +- +-func (k *Key) IssuerName() string { +- return C.GoString(k.k.issuer_name) +-} +- +-func (k *Key) ChainID() string { +- return C.GoString(k.k.chain_id) +-} +- +-func (k *Key) OwnerTrust() Validity { +- return Validity(k.k.owner_trust) +-} +- +-func (k *Key) SubKeys() *SubKey { +- if k.k.subkeys == nil { +- return nil +- } +- return &SubKey{k: k.k.subkeys, parent: k} +-} +- +-func (k *Key) UserIDs() *UserID { +- if k.k.uids == nil { +- return nil +- } +- return &UserID{u: k.k.uids, parent: k} +-} +- +-func (k *Key) KeyListMode() KeyListMode { +- return KeyListMode(k.k.keylist_mode) +-} +- +-type SubKey struct { +- k C.gpgme_subkey_t +- parent *Key // make sure the key is not released when we have a reference to a subkey +-} +- +-func (k *SubKey) Next() *SubKey { +- if k.k.next == nil { +- return nil +- } +- return &SubKey{k: k.k.next, parent: k.parent} +-} +- +-func (k *SubKey) Revoked() bool { +- return C.subkey_revoked(k.k) != 0 +-} +- +-func (k *SubKey) Expired() bool { +- return C.subkey_expired(k.k) != 0 +-} +- +-func (k *SubKey) Disabled() bool { +- return C.subkey_disabled(k.k) != 0 +-} +- +-func (k *SubKey) Invalid() bool { +- return C.subkey_invalid(k.k) != 0 +-} +- +-func (k *SubKey) Secret() bool { +- return C.subkey_secret(k.k) != 0 +-} +- +-func (k *SubKey) KeyID() string { +- return C.GoString(k.k.keyid) +-} +- +-func (k *SubKey) Fingerprint() string { +- return C.GoString(k.k.fpr) +-} +- +-func (k *SubKey) Created() time.Time { +- if k.k.timestamp <= 0 { +- return time.Time{} +- } +- return time.Unix(int64(k.k.timestamp), 0) +-} +- +-func (k *SubKey) Expires() time.Time { +- if k.k.expires <= 0 { +- return time.Time{} +- } +- return time.Unix(int64(k.k.expires), 0) +-} +- +-func (k *SubKey) CardNumber() string { +- return C.GoString(k.k.card_number) +-} +- +-type UserID struct { +- u C.gpgme_user_id_t +- parent *Key // make sure the key is not released when we have a reference to a user ID +-} +- +-func (u *UserID) Next() *UserID { +- if u.u.next == nil { +- return nil +- } +- return &UserID{u: u.u.next, parent: u.parent} +-} +- +-func (u *UserID) Revoked() bool { +- return C.uid_revoked(u.u) != 0 +-} +- +-func (u *UserID) Invalid() bool { +- return C.uid_invalid(u.u) != 0 +-} +- +-func (u *UserID) Validity() Validity { +- return Validity(u.u.validity) +-} +- +-func (u *UserID) UID() string { +- return C.GoString(u.u.uid) +-} +- +-func (u *UserID) Name() string { +- return C.GoString(u.u.name) +-} +- +-func (u *UserID) Comment() string { +- return C.GoString(u.u.comment) +-} +- +-func (u *UserID) Email() string { +- return C.GoString(u.u.email) +-} +- +-// This is somewhat of a horrible hack. We need to unset GPG_AGENT_INFO so that gpgme does not pass --use-agent to GPG. +-// os.Unsetenv should be enough, but that only calls the underlying C library (which gpgme uses) if cgo is involved +-// - and cgo can't be used in tests. So, provide this helper for test initialization. +-func unsetenvGPGAgentInfo() { +- v := C.CString("GPG_AGENT_INFO") +- defer C.free(unsafe.Pointer(v)) +- C.unsetenv(v) +-} + +From 2c7552e51215d4bf6982b0999df2d67d0bc0de9f Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Miloslav=20Trma=C4=8D?= +Date: Thu, 20 Feb 2020 16:41:57 +0100 +Subject: [PATCH 2/2] Update to github.com/mtrmac/gpgme v0.1.2 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +This fixes CVE-2020-8945 by incorporating +https://github.com/proglottis/gpgme/pull/23 . + +Other changes included by the rebase: +- Support for gpgme_off_t (~no-op with the RHEL 7 GPGME 1.3.2) +- Wrapping a few more GPGME functions (irrelevant if we don't call them) +- Better error reporting in Context.GetKey + +Given how invasive the CVE fix is (affecting basically all binding +code), it seems safer to just update the package (and be verifiably +equivalent with upstream) than to backport and try to back out the few +other changes. + +Performed by updating vendor.conf, and +$ mkdir -p _build/src/github.com/docker +$ ln -s $(pwd) _build/src/github.com/docker/docker +$ GOPATH=$(pwd)/_build:$GOPATH vndr github.com/mtrmac/gpgme + +Signed-off-by: Miloslav Trmač +--- + vendor.conf | 2 +- + vendor/github.com/mtrmac/gpgme/README.md | 13 + + vendor/github.com/mtrmac/gpgme/data.go | 18 +- + vendor/github.com/mtrmac/gpgme/go.mod | 3 + + vendor/github.com/mtrmac/gpgme/go_gpgme.c | 22 ++ + vendor/github.com/mtrmac/gpgme/go_gpgme.h | 12 + + vendor/github.com/mtrmac/gpgme/gpgme.go | 354 ++++++++++++++---- + .../mtrmac/gpgme/unset_agent_info.go | 18 + + .../mtrmac/gpgme/unset_agent_info_windows.go | 14 + + 9 files changed, 378 insertions(+), 78 deletions(-) + create mode 100644 vendor/github.com/mtrmac/gpgme/README.md + create mode 100644 vendor/github.com/mtrmac/gpgme/go.mod + create mode 100644 vendor/github.com/mtrmac/gpgme/unset_agent_info.go + create mode 100644 vendor/github.com/mtrmac/gpgme/unset_agent_info_windows.go + +diff --git a/vendor.conf b/vendor.conf +index d71bcac3ccec..4d4927b0d6f2 100644 +--- a/vendor.conf ++++ b/vendor.conf +@@ -147,7 +147,7 @@ github.com/opencontainers/image-spec v1.0.0-rc4 + k8s.io/kubernetes 4a3f9c5b19c7ff804cbc1bf37a15c044ca5d2353 https://github.com/openshift/kubernetes + github.com/golang/glog 44145f04b68cf362d9c4df2182967c2275eaefed + github.com/ghodss/yaml 73d445a93680fa1a78ae23a5839bad48f32ba1ee +-github.com/mtrmac/gpgme master ++github.com/mtrmac/gpgme v0.1.2 + github.com/containers/storage master + github.com/opencontainers/go-digest master + +diff --git a/vendor/github.com/mtrmac/gpgme/README.md b/vendor/github.com/mtrmac/gpgme/README.md +new file mode 100644 +index 000000000000..4770b82a8e61 +--- /dev/null ++++ b/vendor/github.com/mtrmac/gpgme/README.md +@@ -0,0 +1,13 @@ ++# GPGME (golang) ++ ++Go wrapper for the GPGME library. ++ ++This library is intended for use with desktop applications. If you are looking to add OpenPGP support to a server application I suggest you first look at [golang.org/x/crypto/openpgp](https://godoc.org/golang.org/x/crypto/openpgp). ++ ++## Installation ++ ++ go get -u github.com/proglottis/gpgme ++ ++## Documentation ++ ++* [godoc](https://godoc.org/github.com/proglottis/gpgme) +diff --git a/vendor/github.com/mtrmac/gpgme/data.go b/vendor/github.com/mtrmac/gpgme/data.go +index eebc9726347d..eee32c0323fc 100644 +--- a/vendor/github.com/mtrmac/gpgme/data.go ++++ b/vendor/github.com/mtrmac/gpgme/data.go +@@ -50,25 +50,25 @@ func gogpgme_writefunc(handle, buffer unsafe.Pointer, size C.size_t) C.ssize_t { + } + + //export gogpgme_seekfunc +-func gogpgme_seekfunc(handle unsafe.Pointer, offset C.off_t, whence C.int) C.off_t { ++func gogpgme_seekfunc(handle unsafe.Pointer, offset C.gpgme_off_t, whence C.int) C.gpgme_off_t { + d := callbackLookup(uintptr(handle)).(*Data) + n, err := d.s.Seek(int64(offset), int(whence)) + if err != nil { + C.gpgme_err_set_errno(C.EIO) + return -1 + } +- return C.off_t(n) ++ return C.gpgme_off_t(n) + } + + // The Data buffer used to communicate with GPGME + type Data struct { +- dh C.gpgme_data_t ++ dh C.gpgme_data_t // WARNING: Call runtime.KeepAlive(d) after ANY passing of d.dh to C + buf []byte + cbs C.struct_gpgme_data_cbs + r io.Reader + w io.Writer + s io.Seeker +- cbc uintptr ++ cbc uintptr // WARNING: Call runtime.KeepAlive(d) after ANY use of d.cbc in C (typically via d.dh) + } + + func newData() *Data { +@@ -154,12 +154,14 @@ func (d *Data) Close() error { + callbackDelete(d.cbc) + } + _, err := C.gpgme_data_release(d.dh) ++ runtime.KeepAlive(d) + d.dh = nil + return err + } + + func (d *Data) Write(p []byte) (int, error) { + n, err := C.gpgme_data_write(d.dh, unsafe.Pointer(&p[0]), C.size_t(len(p))) ++ runtime.KeepAlive(d) + if err != nil { + return 0, err + } +@@ -171,6 +173,7 @@ func (d *Data) Write(p []byte) (int, error) { + + func (d *Data) Read(p []byte) (int, error) { + n, err := C.gpgme_data_read(d.dh, unsafe.Pointer(&p[0]), C.size_t(len(p))) ++ runtime.KeepAlive(d) + if err != nil { + return 0, err + } +@@ -181,11 +184,14 @@ func (d *Data) Read(p []byte) (int, error) { + } + + func (d *Data) Seek(offset int64, whence int) (int64, error) { +- n, err := C.gpgme_data_seek(d.dh, C.off_t(offset), C.int(whence)) ++ n, err := C.gogpgme_data_seek(d.dh, C.gpgme_off_t(offset), C.int(whence)) ++ runtime.KeepAlive(d) + return int64(n), err + } + + // Name returns the associated filename if any + func (d *Data) Name() string { +- return C.GoString(C.gpgme_data_get_file_name(d.dh)) ++ res := C.GoString(C.gpgme_data_get_file_name(d.dh)) ++ runtime.KeepAlive(d) ++ return res + } +diff --git a/vendor/github.com/mtrmac/gpgme/go.mod b/vendor/github.com/mtrmac/gpgme/go.mod +new file mode 100644 +index 000000000000..3dd09c9fbae5 +--- /dev/null ++++ b/vendor/github.com/mtrmac/gpgme/go.mod +@@ -0,0 +1,3 @@ ++module github.com/mtrmac/gpgme ++ ++go 1.11 +diff --git a/vendor/github.com/mtrmac/gpgme/go_gpgme.c b/vendor/github.com/mtrmac/gpgme/go_gpgme.c +index b887574e0cb9..00da3ab304f1 100644 +--- a/vendor/github.com/mtrmac/gpgme/go_gpgme.c ++++ b/vendor/github.com/mtrmac/gpgme/go_gpgme.c +@@ -8,6 +8,28 @@ void gogpgme_set_passphrase_cb(gpgme_ctx_t ctx, gpgme_passphrase_cb_t cb, uintpt + gpgme_set_passphrase_cb(ctx, cb, (void *)handle); + } + ++gpgme_off_t gogpgme_data_seek(gpgme_data_t dh, gpgme_off_t offset, int whence) { ++ return gpgme_data_seek(dh, offset, whence); ++} ++ ++gpgme_error_t gogpgme_op_assuan_transact_ext( ++ gpgme_ctx_t ctx, ++ char* cmd, ++ uintptr_t data_h, ++ uintptr_t inquiry_h, ++ uintptr_t status_h, ++ gpgme_error_t *operr ++ ){ ++ return gpgme_op_assuan_transact_ext( ++ ctx, ++ cmd, ++ (gpgme_assuan_data_cb_t) gogpgme_assuan_data_callback, (void *)data_h, ++ (gpgme_assuan_inquire_cb_t) gogpgme_assuan_inquiry_callback, (void *)inquiry_h, ++ (gpgme_assuan_status_cb_t) gogpgme_assuan_status_callback, (void *)status_h, ++ operr ++ ); ++} ++ + unsigned int key_revoked(gpgme_key_t k) { + return k->revoked; + } +diff --git a/vendor/github.com/mtrmac/gpgme/go_gpgme.h b/vendor/github.com/mtrmac/gpgme/go_gpgme.h +index a3678b127ac7..d4826ab368eb 100644 +--- a/vendor/github.com/mtrmac/gpgme/go_gpgme.h ++++ b/vendor/github.com/mtrmac/gpgme/go_gpgme.h +@@ -6,12 +6,24 @@ + + #include + ++/* GPGME_VERSION_NUMBER was introduced in 1.4.0 */ ++#if !defined(GPGME_VERSION_NUMBER) || GPGME_VERSION_NUMBER < 0x010402 ++typedef off_t gpgme_off_t; /* Introduced in 1.4.2 */ ++#endif ++ + extern ssize_t gogpgme_readfunc(void *handle, void *buffer, size_t size); + extern ssize_t gogpgme_writefunc(void *handle, void *buffer, size_t size); + extern off_t gogpgme_seekfunc(void *handle, off_t offset, int whence); + extern gpgme_error_t gogpgme_passfunc(void *hook, char *uid_hint, char *passphrase_info, int prev_was_bad, int fd); + extern gpgme_error_t gogpgme_data_new_from_cbs(gpgme_data_t *dh, gpgme_data_cbs_t cbs, uintptr_t handle); + extern void gogpgme_set_passphrase_cb(gpgme_ctx_t ctx, gpgme_passphrase_cb_t cb, uintptr_t handle); ++extern gpgme_off_t gogpgme_data_seek(gpgme_data_t dh, gpgme_off_t offset, int whence); ++ ++extern gpgme_error_t gogpgme_op_assuan_transact_ext(gpgme_ctx_t ctx, char *cmd, uintptr_t data_h, uintptr_t inquiry_h , uintptr_t status_h, gpgme_error_t *operr); ++ ++extern gpgme_error_t gogpgme_assuan_data_callback(void *opaque, void* data, size_t datalen ); ++extern gpgme_error_t gogpgme_assuan_inquiry_callback(void *opaque, char* name, char* args); ++extern gpgme_error_t gogpgme_assuan_status_callback(void *opaque, char* status, char* args); + + extern unsigned int key_revoked(gpgme_key_t k); + extern unsigned int key_expired(gpgme_key_t k); +diff --git a/vendor/github.com/mtrmac/gpgme/gpgme.go b/vendor/github.com/mtrmac/gpgme/gpgme.go +index 5f1793eab32d..c19b9aebc5cd 100644 +--- a/vendor/github.com/mtrmac/gpgme/gpgme.go ++++ b/vendor/github.com/mtrmac/gpgme/gpgme.go +@@ -7,8 +7,8 @@ package gpgme + // #include + // #include "go_gpgme.h" + import "C" +- + import ( ++ "fmt" + "io" + "os" + "runtime" +@@ -47,9 +47,8 @@ const ( + ProtocolAssuan Protocol = C.GPGME_PROTOCOL_ASSUAN + ProtocolG13 Protocol = C.GPGME_PROTOCOL_G13 + ProtocolUIServer Protocol = C.GPGME_PROTOCOL_UISERVER +- // ProtocolSpawn Protocol = C.GPGME_PROTOCOL_SPAWN // Unavailable in 1.4.3 +- ProtocolDefault Protocol = C.GPGME_PROTOCOL_DEFAULT +- ProtocolUnknown Protocol = C.GPGME_PROTOCOL_UNKNOWN ++ ProtocolDefault Protocol = C.GPGME_PROTOCOL_DEFAULT ++ ProtocolUnknown Protocol = C.GPGME_PROTOCOL_UNKNOWN + ) + + type PinEntryMode int +@@ -69,7 +68,6 @@ const ( + EncryptNoEncryptTo EncryptFlag = C.GPGME_ENCRYPT_NO_ENCRYPT_TO + EncryptPrepare EncryptFlag = C.GPGME_ENCRYPT_PREPARE + EncryptExceptSign EncryptFlag = C.GPGME_ENCRYPT_EXPECT_SIGN +- // EncryptNoCompress EncryptFlag = C.GPGME_ENCRYPT_NO_COMPRESS // Unavailable in 1.4.3 + ) + + type HashAlgo int +@@ -83,7 +81,6 @@ const ( + KeyListModeExtern KeyListMode = C.GPGME_KEYLIST_MODE_EXTERN + KeyListModeSigs KeyListMode = C.GPGME_KEYLIST_MODE_SIGS + KeyListModeSigNotations KeyListMode = C.GPGME_KEYLIST_MODE_SIG_NOTATIONS +- // KeyListModeWithSecret KeyListMode = C.GPGME_KEYLIST_MODE_WITH_SECRET // Unavailable in 1.4.3 + KeyListModeEphemeral KeyListMode = C.GPGME_KEYLIST_MODE_EPHEMERAL + KeyListModeModeValidate KeyListMode = C.GPGME_KEYLIST_MODE_VALIDATE + ) +@@ -167,39 +164,60 @@ func EngineCheckVersion(p Protocol) error { + } + + type EngineInfo struct { +- info C.gpgme_engine_info_t ++ next *EngineInfo ++ protocol Protocol ++ fileName string ++ homeDir string ++ version string ++ requiredVersion string + } + +-func (e *EngineInfo) Next() *EngineInfo { +- if e.info.next == nil { +- return nil ++func copyEngineInfo(info C.gpgme_engine_info_t) *EngineInfo { ++ res := &EngineInfo{ ++ next: nil, ++ protocol: Protocol(info.protocol), ++ fileName: C.GoString(info.file_name), ++ homeDir: C.GoString(info.home_dir), ++ version: C.GoString(info.version), ++ requiredVersion: C.GoString(info.req_version), ++ } ++ if info.next != nil { ++ res.next = copyEngineInfo(info.next) + } +- return &EngineInfo{info: e.info.next} ++ return res ++} ++ ++func (e *EngineInfo) Next() *EngineInfo { ++ return e.next + } + + func (e *EngineInfo) Protocol() Protocol { +- return Protocol(e.info.protocol) ++ return e.protocol + } + + func (e *EngineInfo) FileName() string { +- return C.GoString(e.info.file_name) ++ return e.fileName + } + + func (e *EngineInfo) Version() string { +- return C.GoString(e.info.version) ++ return e.version + } + + func (e *EngineInfo) RequiredVersion() string { +- return C.GoString(e.info.req_version) ++ return e.requiredVersion + } + + func (e *EngineInfo) HomeDir() string { +- return C.GoString(e.info.home_dir) ++ return e.homeDir + } + + func GetEngineInfo() (*EngineInfo, error) { +- info := &EngineInfo{} +- return info, handleError(C.gpgme_get_engine_info(&info.info)) ++ var cInfo C.gpgme_engine_info_t ++ err := handleError(C.gpgme_get_engine_info(&cInfo)) ++ if err != nil { ++ return nil, err ++ } ++ return copyEngineInfo(cInfo), nil // It is up to the caller not to invalidate cInfo concurrently until this is done. + } + + func SetEngineInfo(proto Protocol, fileName, homeDir string) error { +@@ -260,9 +278,9 @@ type Context struct { + KeyError error + + callback Callback +- cbc uintptr ++ cbc uintptr // WARNING: Call runtime.KeepAlive(c) after ANY use of c.cbc in C (typically via c.ctx) + +- ctx C.gpgme_ctx_t ++ ctx C.gpgme_ctx_t // WARNING: Call runtime.KeepAlive(c) after ANY passing of c.ctx to C + } + + func New() (*Context, error) { +@@ -280,49 +298,68 @@ func (c *Context) Release() { + callbackDelete(c.cbc) + } + C.gpgme_release(c.ctx) ++ runtime.KeepAlive(c) + c.ctx = nil + } + + func (c *Context) SetArmor(yes bool) { + C.gpgme_set_armor(c.ctx, cbool(yes)) ++ runtime.KeepAlive(c) + } + + func (c *Context) Armor() bool { +- return C.gpgme_get_armor(c.ctx) != 0 ++ res := C.gpgme_get_armor(c.ctx) != 0 ++ runtime.KeepAlive(c) ++ return res + } + + func (c *Context) SetTextMode(yes bool) { + C.gpgme_set_textmode(c.ctx, cbool(yes)) ++ runtime.KeepAlive(c) + } + + func (c *Context) TextMode() bool { +- return C.gpgme_get_textmode(c.ctx) != 0 ++ res := C.gpgme_get_textmode(c.ctx) != 0 ++ runtime.KeepAlive(c) ++ return res + } + + func (c *Context) SetProtocol(p Protocol) error { +- return handleError(C.gpgme_set_protocol(c.ctx, C.gpgme_protocol_t(p))) ++ err := handleError(C.gpgme_set_protocol(c.ctx, C.gpgme_protocol_t(p))) ++ runtime.KeepAlive(c) ++ return err + } + + func (c *Context) Protocol() Protocol { +- return Protocol(C.gpgme_get_protocol(c.ctx)) ++ res := Protocol(C.gpgme_get_protocol(c.ctx)) ++ runtime.KeepAlive(c) ++ return res + } + + func (c *Context) SetKeyListMode(m KeyListMode) error { +- return handleError(C.gpgme_set_keylist_mode(c.ctx, C.gpgme_keylist_mode_t(m))) ++ err := handleError(C.gpgme_set_keylist_mode(c.ctx, C.gpgme_keylist_mode_t(m))) ++ runtime.KeepAlive(c) ++ return err + } + + func (c *Context) KeyListMode() KeyListMode { +- return KeyListMode(C.gpgme_get_keylist_mode(c.ctx)) ++ res := KeyListMode(C.gpgme_get_keylist_mode(c.ctx)) ++ runtime.KeepAlive(c) ++ return res + } + + // Unavailable in 1.3.2: + // func (c *Context) SetPinEntryMode(m PinEntryMode) error { +-// return handleError(C.gpgme_set_pinentry_mode(c.ctx, C.gpgme_pinentry_mode_t(m))) ++// err := handleError(C.gpgme_set_pinentry_mode(c.ctx, C.gpgme_pinentry_mode_t(m))) ++// runtime.KeepAlive(c) ++// return err + // } + + // Unavailable in 1.3.2: + // func (c *Context) PinEntryMode() PinEntryMode { +-// return PinEntryMode(C.gpgme_get_pinentry_mode(c.ctx)) ++// res := PinEntryMode(C.gpgme_get_pinentry_mode(c.ctx)) ++// runtime.KeepAlive(c) ++// return res + // } + + func (c *Context) SetCallback(callback Callback) error { +@@ -339,11 +376,17 @@ func (c *Context) SetCallback(callback Callback) error { + c.cbc = 0 + _, err = C.gogpgme_set_passphrase_cb(c.ctx, nil, 0) + } ++ runtime.KeepAlive(c) + return err + } + + func (c *Context) EngineInfo() *EngineInfo { +- return &EngineInfo{info: C.gpgme_ctx_get_engine_info(c.ctx)} ++ cInfo := C.gpgme_ctx_get_engine_info(c.ctx) ++ runtime.KeepAlive(c) ++ // NOTE: c must be live as long as we are accessing cInfo. ++ res := copyEngineInfo(cInfo) ++ runtime.KeepAlive(c) // for accesses to cInfo ++ return res + } + + func (c *Context) SetEngineInfo(proto Protocol, fileName, homeDir string) error { +@@ -356,19 +399,23 @@ func (c *Context) SetEngineInfo(proto Protocol, fileName, homeDir string) error + chome = C.CString(homeDir) + defer C.free(unsafe.Pointer(chome)) + } +- return handleError(C.gpgme_ctx_set_engine_info(c.ctx, C.gpgme_protocol_t(proto), cfn, chome)) ++ err := handleError(C.gpgme_ctx_set_engine_info(c.ctx, C.gpgme_protocol_t(proto), cfn, chome)) ++ runtime.KeepAlive(c) ++ return err + } + + func (c *Context) KeyListStart(pattern string, secretOnly bool) error { + cpattern := C.CString(pattern) + defer C.free(unsafe.Pointer(cpattern)) +- err := C.gpgme_op_keylist_start(c.ctx, cpattern, cbool(secretOnly)) +- return handleError(err) ++ err := handleError(C.gpgme_op_keylist_start(c.ctx, cpattern, cbool(secretOnly))) ++ runtime.KeepAlive(c) ++ return err + } + + func (c *Context) KeyListNext() bool { + c.Key = newKey() + err := handleError(C.gpgme_op_keylist_next(c.ctx, &c.Key.k)) ++ runtime.KeepAlive(c) // implies runtime.KeepAlive(c.Key) + if err != nil { + if e, ok := err.(Error); ok && e.Code() == ErrorEOF { + c.KeyError = nil +@@ -382,22 +429,43 @@ func (c *Context) KeyListNext() bool { + } + + func (c *Context) KeyListEnd() error { +- return handleError(C.gpgme_op_keylist_end(c.ctx)) ++ err := handleError(C.gpgme_op_keylist_end(c.ctx)) ++ runtime.KeepAlive(c) ++ return err + } + + func (c *Context) GetKey(fingerprint string, secret bool) (*Key, error) { + key := newKey() + cfpr := C.CString(fingerprint) + defer C.free(unsafe.Pointer(cfpr)) +- return key, handleError(C.gpgme_get_key(c.ctx, cfpr, &key.k, cbool(secret))) ++ err := handleError(C.gpgme_get_key(c.ctx, cfpr, &key.k, cbool(secret))) ++ runtime.KeepAlive(c) ++ runtime.KeepAlive(key) ++ keyKIsNil := key.k == nil ++ runtime.KeepAlive(key) ++ if e, ok := err.(Error); keyKIsNil && ok && e.Code() == ErrorEOF { ++ return nil, fmt.Errorf("key %q not found", fingerprint) ++ } ++ if err != nil { ++ return nil, err ++ } ++ return key, nil + } + + func (c *Context) Decrypt(ciphertext, plaintext *Data) error { +- return handleError(C.gpgme_op_decrypt(c.ctx, ciphertext.dh, plaintext.dh)) ++ err := handleError(C.gpgme_op_decrypt(c.ctx, ciphertext.dh, plaintext.dh)) ++ runtime.KeepAlive(c) ++ runtime.KeepAlive(ciphertext) ++ runtime.KeepAlive(plaintext) ++ return err + } + + func (c *Context) DecryptVerify(ciphertext, plaintext *Data) error { +- return handleError(C.gpgme_op_decrypt_verify(c.ctx, ciphertext.dh, plaintext.dh)) ++ err := handleError(C.gpgme_op_decrypt_verify(c.ctx, ciphertext.dh, plaintext.dh)) ++ runtime.KeepAlive(c) ++ runtime.KeepAlive(ciphertext) ++ runtime.KeepAlive(plaintext) ++ return err + } + + type Signature struct { +@@ -424,10 +492,20 @@ func (c *Context) Verify(sig, signedText, plain *Data) (string, []Signature, err + plainPtr = plain.dh + } + err := handleError(C.gpgme_op_verify(c.ctx, sig.dh, signedTextPtr, plainPtr)) ++ runtime.KeepAlive(c) ++ runtime.KeepAlive(sig) ++ if signedText != nil { ++ runtime.KeepAlive(signedText) ++ } ++ if plain != nil { ++ runtime.KeepAlive(plain) ++ } + if err != nil { + return "", nil, err + } + res := C.gpgme_op_verify_result(c.ctx) ++ runtime.KeepAlive(c) ++ // NOTE: c must be live as long as we are accessing res. + sigs := []Signature{} + for s := res.signatures; s != nil; s = s.next { + sig := Signature{ +@@ -447,7 +525,9 @@ func (c *Context) Verify(sig, signedText, plain *Data) (string, []Signature, err + } + sigs = append(sigs, sig) + } +- return C.GoString(res.file_name), sigs, nil ++ fileName := C.GoString(res.file_name) ++ runtime.KeepAlive(c) // for all accesses to res above ++ return fileName, sigs, nil + } + + func (c *Context) Encrypt(recipients []*Key, flags EncryptFlag, plaintext, ciphertext *Data) error { +@@ -459,18 +539,116 @@ func (c *Context) Encrypt(recipients []*Key, flags EncryptFlag, plaintext, ciphe + *ptr = recipients[i].k + } + err := C.gpgme_op_encrypt(c.ctx, (*C.gpgme_key_t)(recp), C.gpgme_encrypt_flags_t(flags), plaintext.dh, ciphertext.dh) ++ runtime.KeepAlive(c) ++ runtime.KeepAlive(recipients) ++ runtime.KeepAlive(plaintext) ++ runtime.KeepAlive(ciphertext) + return handleError(err) + } + + func (c *Context) Sign(signers []*Key, plain, sig *Data, mode SigMode) error { + C.gpgme_signers_clear(c.ctx) ++ runtime.KeepAlive(c) + for _, k := range signers { +- if err := handleError(C.gpgme_signers_add(c.ctx, k.k)); err != nil { ++ err := handleError(C.gpgme_signers_add(c.ctx, k.k)) ++ runtime.KeepAlive(c) ++ runtime.KeepAlive(k) ++ if err != nil { + C.gpgme_signers_clear(c.ctx) ++ runtime.KeepAlive(c) + return err + } + } +- return handleError(C.gpgme_op_sign(c.ctx, plain.dh, sig.dh, C.gpgme_sig_mode_t(mode))) ++ err := handleError(C.gpgme_op_sign(c.ctx, plain.dh, sig.dh, C.gpgme_sig_mode_t(mode))) ++ runtime.KeepAlive(c) ++ runtime.KeepAlive(plain) ++ runtime.KeepAlive(sig) ++ return err ++} ++ ++type AssuanDataCallback func(data []byte) error ++type AssuanInquireCallback func(name, args string) error ++type AssuanStatusCallback func(status, args string) error ++ ++// AssuanSend sends a raw Assuan command to gpg-agent ++func (c *Context) AssuanSend( ++ cmd string, ++ data AssuanDataCallback, ++ inquiry AssuanInquireCallback, ++ status AssuanStatusCallback, ++) error { ++ var operr C.gpgme_error_t ++ ++ dataPtr := callbackAdd(&data) ++ inquiryPtr := callbackAdd(&inquiry) ++ statusPtr := callbackAdd(&status) ++ cmdCStr := C.CString(cmd) ++ defer C.free(unsafe.Pointer(cmdCStr)) ++ err := C.gogpgme_op_assuan_transact_ext( ++ c.ctx, ++ cmdCStr, ++ C.uintptr_t(dataPtr), ++ C.uintptr_t(inquiryPtr), ++ C.uintptr_t(statusPtr), ++ &operr, ++ ) ++ runtime.KeepAlive(c) ++ ++ if handleError(operr) != nil { ++ return handleError(operr) ++ } ++ return handleError(err) ++} ++ ++//export gogpgme_assuan_data_callback ++func gogpgme_assuan_data_callback(handle unsafe.Pointer, data unsafe.Pointer, datalen C.size_t) C.gpgme_error_t { ++ c := callbackLookup(uintptr(handle)).(*AssuanDataCallback) ++ if *c == nil { ++ return 0 ++ } ++ (*c)(C.GoBytes(data, C.int(datalen))) ++ return 0 ++} ++ ++//export gogpgme_assuan_inquiry_callback ++func gogpgme_assuan_inquiry_callback(handle unsafe.Pointer, cName *C.char, cArgs *C.char) C.gpgme_error_t { ++ name := C.GoString(cName) ++ args := C.GoString(cArgs) ++ c := callbackLookup(uintptr(handle)).(*AssuanInquireCallback) ++ if *c == nil { ++ return 0 ++ } ++ (*c)(name, args) ++ return 0 ++} ++ ++//export gogpgme_assuan_status_callback ++func gogpgme_assuan_status_callback(handle unsafe.Pointer, cStatus *C.char, cArgs *C.char) C.gpgme_error_t { ++ status := C.GoString(cStatus) ++ args := C.GoString(cArgs) ++ c := callbackLookup(uintptr(handle)).(*AssuanStatusCallback) ++ if *c == nil { ++ return 0 ++ } ++ (*c)(status, args) ++ return 0 ++} ++ ++// ExportModeFlags defines how keys are exported from Export ++type ExportModeFlags uint ++ ++const ( ++ ExportModeExtern ExportModeFlags = C.GPGME_EXPORT_MODE_EXTERN ++ ExportModeMinimal ExportModeFlags = C.GPGME_EXPORT_MODE_MINIMAL ++) ++ ++func (c *Context) Export(pattern string, mode ExportModeFlags, data *Data) error { ++ pat := C.CString(pattern) ++ defer C.free(unsafe.Pointer(pat)) ++ err := handleError(C.gpgme_op_export(c.ctx, pat, C.gpgme_export_mode_t(mode), data.dh)) ++ runtime.KeepAlive(c) ++ runtime.KeepAlive(data) ++ return err + } + + // ImportStatusFlags describes the type of ImportStatus.Status. The C API in gpgme.h simply uses "unsigned". +@@ -509,10 +687,14 @@ type ImportResult struct { + + func (c *Context) Import(keyData *Data) (*ImportResult, error) { + err := handleError(C.gpgme_op_import(c.ctx, keyData.dh)) ++ runtime.KeepAlive(c) ++ runtime.KeepAlive(keyData) + if err != nil { + return nil, err + } + res := C.gpgme_op_import_result(c.ctx) ++ runtime.KeepAlive(c) ++ // NOTE: c must be live as long as we are accessing res. + imports := []ImportStatus{} + for s := res.imports; s != nil; s = s.next { + imports = append(imports, ImportStatus{ +@@ -521,7 +703,7 @@ func (c *Context) Import(keyData *Data) (*ImportResult, error) { + Status: ImportStatusFlags(s.status), + }) + } +- return &ImportResult{ ++ importResult := &ImportResult{ + Considered: int(res.considered), + NoUserID: int(res.no_user_id), + Imported: int(res.imported), +@@ -536,11 +718,13 @@ func (c *Context) Import(keyData *Data) (*ImportResult, error) { + SecretUnchanged: int(res.secret_unchanged), + NotImported: int(res.not_imported), + Imports: imports, +- }, nil ++ } ++ runtime.KeepAlive(c) // for all accesses to res above ++ return importResult, nil + } + + type Key struct { +- k C.gpgme_key_t ++ k C.gpgme_key_t // WARNING: Call Runtime.KeepAlive(k) after ANY passing of k.k to C + } + + func newKey() *Key { +@@ -551,85 +735,122 @@ func newKey() *Key { + + func (k *Key) Release() { + C.gpgme_key_release(k.k) ++ runtime.KeepAlive(k) + k.k = nil + } + + func (k *Key) Revoked() bool { +- return C.key_revoked(k.k) != 0 ++ res := C.key_revoked(k.k) != 0 ++ runtime.KeepAlive(k) ++ return res + } + + func (k *Key) Expired() bool { +- return C.key_expired(k.k) != 0 ++ res := C.key_expired(k.k) != 0 ++ runtime.KeepAlive(k) ++ return res + } + + func (k *Key) Disabled() bool { +- return C.key_disabled(k.k) != 0 ++ res := C.key_disabled(k.k) != 0 ++ runtime.KeepAlive(k) ++ return res + } + + func (k *Key) Invalid() bool { +- return C.key_invalid(k.k) != 0 ++ res := C.key_invalid(k.k) != 0 ++ runtime.KeepAlive(k) ++ return res + } + + func (k *Key) CanEncrypt() bool { +- return C.key_can_encrypt(k.k) != 0 ++ res := C.key_can_encrypt(k.k) != 0 ++ runtime.KeepAlive(k) ++ return res + } + + func (k *Key) CanSign() bool { +- return C.key_can_sign(k.k) != 0 ++ res := C.key_can_sign(k.k) != 0 ++ runtime.KeepAlive(k) ++ return res + } + + func (k *Key) CanCertify() bool { +- return C.key_can_certify(k.k) != 0 ++ res := C.key_can_certify(k.k) != 0 ++ runtime.KeepAlive(k) ++ return res + } + + func (k *Key) Secret() bool { +- return C.key_secret(k.k) != 0 ++ res := C.key_secret(k.k) != 0 ++ runtime.KeepAlive(k) ++ return res + } + + func (k *Key) CanAuthenticate() bool { +- return C.key_can_authenticate(k.k) != 0 ++ res := C.key_can_authenticate(k.k) != 0 ++ runtime.KeepAlive(k) ++ return res + } + + func (k *Key) IsQualified() bool { +- return C.key_is_qualified(k.k) != 0 ++ res := C.key_is_qualified(k.k) != 0 ++ runtime.KeepAlive(k) ++ return res + } + + func (k *Key) Protocol() Protocol { +- return Protocol(k.k.protocol) ++ res := Protocol(k.k.protocol) ++ runtime.KeepAlive(k) ++ return res + } + + func (k *Key) IssuerSerial() string { +- return C.GoString(k.k.issuer_serial) ++ res := C.GoString(k.k.issuer_serial) ++ runtime.KeepAlive(k) ++ return res + } + + func (k *Key) IssuerName() string { +- return C.GoString(k.k.issuer_name) ++ res := C.GoString(k.k.issuer_name) ++ runtime.KeepAlive(k) ++ return res + } + + func (k *Key) ChainID() string { +- return C.GoString(k.k.chain_id) ++ res := C.GoString(k.k.chain_id) ++ runtime.KeepAlive(k) ++ return res + } + + func (k *Key) OwnerTrust() Validity { +- return Validity(k.k.owner_trust) ++ res := Validity(k.k.owner_trust) ++ runtime.KeepAlive(k) ++ return res + } + + func (k *Key) SubKeys() *SubKey { +- if k.k.subkeys == nil { ++ subKeys := k.k.subkeys ++ runtime.KeepAlive(k) ++ if subKeys == nil { + return nil + } +- return &SubKey{k: k.k.subkeys, parent: k} ++ return &SubKey{k: subKeys, parent: k} // The parent: k reference ensures subKeys remains valid + } + + func (k *Key) UserIDs() *UserID { +- if k.k.uids == nil { ++ uids := k.k.uids ++ runtime.KeepAlive(k) ++ if uids == nil { + return nil + } +- return &UserID{u: k.k.uids, parent: k} ++ return &UserID{u: uids, parent: k} // The parent: k reference ensures uids remains valid + } + + func (k *Key) KeyListMode() KeyListMode { +- return KeyListMode(k.k.keylist_mode) ++ res := KeyListMode(k.k.keylist_mode) ++ runtime.KeepAlive(k) ++ return res + } + + type SubKey struct { +@@ -729,12 +950,3 @@ func (u *UserID) Comment() string { + func (u *UserID) Email() string { + return C.GoString(u.u.email) + } +- +-// This is somewhat of a horrible hack. We need to unset GPG_AGENT_INFO so that gpgme does not pass --use-agent to GPG. +-// os.Unsetenv should be enough, but that only calls the underlying C library (which gpgme uses) if cgo is involved +-// - and cgo can't be used in tests. So, provide this helper for test initialization. +-func unsetenvGPGAgentInfo() { +- v := C.CString("GPG_AGENT_INFO") +- defer C.free(unsafe.Pointer(v)) +- C.unsetenv(v) +-} +diff --git a/vendor/github.com/mtrmac/gpgme/unset_agent_info.go b/vendor/github.com/mtrmac/gpgme/unset_agent_info.go +new file mode 100644 +index 000000000000..986aca59f67b +--- /dev/null ++++ b/vendor/github.com/mtrmac/gpgme/unset_agent_info.go +@@ -0,0 +1,18 @@ ++// +build !windows ++ ++package gpgme ++ ++// #include ++import "C" ++import ( ++ "unsafe" ++) ++ ++// This is somewhat of a horrible hack. We need to unset GPG_AGENT_INFO so that gpgme does not pass --use-agent to GPG. ++// os.Unsetenv should be enough, but that only calls the underlying C library (which gpgme uses) if cgo is involved ++// - and cgo can't be used in tests. So, provide this helper for test initialization. ++func unsetenvGPGAgentInfo() { ++ v := C.CString("GPG_AGENT_INFO") ++ defer C.free(unsafe.Pointer(v)) ++ C.unsetenv(v) ++} +diff --git a/vendor/github.com/mtrmac/gpgme/unset_agent_info_windows.go b/vendor/github.com/mtrmac/gpgme/unset_agent_info_windows.go +new file mode 100644 +index 000000000000..431ec86d3c24 +--- /dev/null ++++ b/vendor/github.com/mtrmac/gpgme/unset_agent_info_windows.go +@@ -0,0 +1,14 @@ ++package gpgme ++ ++// #include ++import "C" ++import ( ++ "unsafe" ++) ++ ++// unsetenv is not available in mingw ++func unsetenvGPGAgentInfo() { ++ v := C.CString("GPG_AGENT_INFO=") ++ defer C.free(unsafe.Pointer(v)) ++ C.putenv(v) ++} diff --git a/SOURCES/docker-collectmode.patch b/SOURCES/docker-collectmode.patch new file mode 100644 index 0000000..b938b08 --- /dev/null +++ b/SOURCES/docker-collectmode.patch @@ -0,0 +1,12 @@ +diff -up docker-cccb291d3613ade11e2c0b82541452e9db87b835/runc-66aedde759f33c190954815fb765eedc1d782dd9/libcontainer/cgroups/systemd/apply_systemd.go.collectmode docker-cccb291d3613ade11e2c0b82541452e9db87b835/runc-66aedde759f33c190954815fb765eedc1d782dd9/libcontainer/cgroups/systemd/apply_systemd.go +--- docker-cccb291d3613ade11e2c0b82541452e9db87b835/runc-66aedde759f33c190954815fb765eedc1d782dd9/libcontainer/cgroups/systemd/apply_systemd.go.collectmode 2020-01-23 17:04:43.761004295 +0100 ++++ docker-cccb291d3613ade11e2c0b82541452e9db87b835/runc-66aedde759f33c190954815fb765eedc1d782dd9/libcontainer/cgroups/systemd/apply_systemd.go 2020-01-23 17:04:55.584168909 +0100 +@@ -130,8 +130,6 @@ func (m *Manager) Apply(pid int) error { + properties = append(properties, newProp("PIDs", []uint32{uint32(pid)})) + } + +- properties = append(properties, newProp("CollectMode", "inactive-or-failed")) +- + // This is only supported on systemd versions 218 and above. + properties = append(properties, newProp("Delegate", true)) + diff --git a/SOURCES/f9a2eeb64054e740fb1ae3048dde153c257113c8.patch b/SOURCES/f9a2eeb64054e740fb1ae3048dde153c257113c8.patch new file mode 100644 index 0000000..1bd4019 --- /dev/null +++ b/SOURCES/f9a2eeb64054e740fb1ae3048dde153c257113c8.patch @@ -0,0 +1,86 @@ +From f9a2eeb64054e740fb1ae3048dde153c257113c8 Mon Sep 17 00:00:00 2001 +From: Ulrich Obergfell +Date: Thu, 10 Oct 2019 11:16:50 +0200 +Subject: [PATCH] revert changes introduced by "fix error handling in restore() + function", commit e96a10aef66e + (https://github.com/projectatomic/containerd/pull/10) + +Signed-off-by: Ulrich Obergfell +--- + runtime/container.go | 12 ++++++------ + supervisor/supervisor.go | 11 +++-------- + 2 files changed, 9 insertions(+), 14 deletions(-) + +diff --git a/runtime/container.go b/runtime/container.go +index 14002fc..2e9e663 100644 +--- a/runtime/container.go ++++ b/runtime/container.go +@@ -146,15 +146,15 @@ func New(opts ContainerOpts) (Container, error) { + } + + // Load return a new container from the matchin state file on disk. +-func Load(root, id, shimName string, timeout time.Duration) (Container, error, string) { ++func Load(root, id, shimName string, timeout time.Duration) (Container, error) { + var s state + f, err := os.Open(filepath.Join(root, id, StateFile)) + if err != nil { +- return nil, err, "init" ++ return nil, err + } + defer f.Close() + if err := json.NewDecoder(f).Decode(&s); err != nil { +- return nil, err, "init" ++ return nil, err + } + c := &container{ + root: root, +@@ -175,7 +175,7 @@ func Load(root, id, shimName string, timeout time.Duration) (Container, error, s + + dirs, err := ioutil.ReadDir(filepath.Join(root, id)) + if err != nil { +- return nil, err, "init" ++ return nil, err + } + for _, d := range dirs { + if !d.IsDir() { +@@ -184,7 +184,7 @@ func Load(root, id, shimName string, timeout time.Duration) (Container, error, s + pid := d.Name() + s, err := readProcessState(filepath.Join(root, id, pid)) + if err != nil { +- return nil, err, pid ++ return nil, err + } + p, err := loadProcess(filepath.Join(root, id, pid), pid, c, s) + if err != nil { +@@ -193,7 +193,7 @@ func Load(root, id, shimName string, timeout time.Duration) (Container, error, s + } + c.processes[pid] = p + } +- return c, nil, "" ++ return c, nil + } + + func readProcessState(dir string) (*ProcessState, error) { +diff --git a/supervisor/supervisor.go b/supervisor/supervisor.go +index d92de8a..e21ae7b 100644 +--- a/supervisor/supervisor.go ++++ b/supervisor/supervisor.go +@@ -364,15 +364,10 @@ func (s *Supervisor) restore() error { + continue + } + id := d.Name() +- container, err, pid := runtime.Load(s.stateDir, id, s.shim, s.timeout) ++ container, err := runtime.Load(s.stateDir, id, s.shim, s.timeout) + if err != nil { +- if (pid == "init") { +- logrus.WithFields(logrus.Fields{"error": err, "id": id}).Warnf("containerd: failed to load container,removing state directory.") +- os.RemoveAll(filepath.Join(s.stateDir, id)) +- } else { +- logrus.WithFields(logrus.Fields{"error": err, "pid": pid}).Warnf("containerd: failed to load exec process,removing state directory.") +- os.RemoveAll(filepath.Join(s.stateDir, id, pid)) +- } ++ logrus.WithFields(logrus.Fields{"error": err, "id": id}).Warnf("containerd: failed to load container,removing state directory.") ++ os.RemoveAll(filepath.Join(s.stateDir, id)) + continue + } + processes, err := container.Processes() diff --git a/SOURCES/seccomp.json b/SOURCES/seccomp.json index b9a4564..965a504 100644 --- a/SOURCES/seccomp.json +++ b/SOURCES/seccomp.json @@ -320,6 +320,7 @@ "stat64", "statfs", "statfs64", + "statx", "symlink", "symlinkat", "sync", diff --git a/SPECS/docker.spec b/SPECS/docker.spec index 56cc824..4eb29f3 100644 --- a/SPECS/docker.spec +++ b/SPECS/docker.spec @@ -23,7 +23,7 @@ # docker %global git_docker https://github.com/projectatomic/docker -%global commit_docker 7f2769b9e0572f62730d91e79e674efd59b7e234 +%global commit_docker 0be3e217c42ecf554bf5117bec9c832bd3f3b6fd %global shortcommit_docker %(c=%{commit_docker}; echo ${c:0:7}) # docker_branch used in %%check %global docker_branch %{name}-%{version} @@ -56,7 +56,7 @@ # docker-runc %global git_runc https://github.com/projectatomic/runc -%global commit_runc 9c3c5f853ebf0ffac0d087e94daef462133b69c7 +%global commit_runc 66aedde759f33c190954815fb765eedc1d782dd9 %global shortcommit_runc %(c=%{commit_runc}; echo ${c:0:7}) # docker-containerd @@ -77,7 +77,7 @@ Name: %{repo} Epoch: 2 Version: 1.13.1 -Release: 102.git%{shortcommit_docker}%{?dist} +Release: 203.git%{shortcommit_docker}%{?dist} Summary: Automates deployment of containerized applications License: ASL 2.0 URL: https://%{import_path} @@ -109,6 +109,23 @@ Source29: 99-docker.conf Source30: %{git_tini}/archive/%{commit_tini}/tini-%{shortcommit_tini}.tar.gz Source31: %{git_libnetwork}/archive/%{commit_libnetwork}/libnetwork-%{shortcommit_libnetwork}.tar.gz Source32: seccomp.json +# https://bugzilla.redhat.com/show_bug.cgi?id=1636244 +Patch0: https://github.com/projectatomic/containerd/pull/11/commits/97eff6cf6c9b58f8239b28be2f080e23c9da62c0.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1653292 +Patch1: https://github.com/projectatomic/containerd/pull/12/commits/f9a2eeb64054e740fb1ae3048dde153c257113c8.patch +Patch2: https://github.com/projectatomic/containerd/pull/12/commits/69518f0bbdb1f11113f46a4d794e09e2f21f5e91.patch +# related: https://bugzilla.redhat.com/show_bug.cgi?id=1766665 there is no CollectMode property in RHEL7 systemd +Patch3: docker-collectmode.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1784228 +Patch4: bz1784228.patch +Patch5: docker-1792243.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=1718441 +Patch6: https://patch-diff.githubusercontent.com/raw/projectatomic/runc/pull/30.patch +# https://patch-diff.githubusercontent.com/raw/projectatomic/docker/pull/369.patch +Patch7: docker-CVE-2020-8945.patch +# related bug: https://bugzilla.redhat.com/show_bug.cgi?id=1879425 +# patch: https://github.com/projectatomic/runc/pull/33.patch +Patch8: docker-1879425.patch BuildRequires: cmake BuildRequires: sed BuildRequires: git @@ -118,7 +135,7 @@ BuildRequires: %{?go_compiler:compiler(go-compiler)}%{!?go_compiler:golang} %else BuildRequires: go-toolset-1.10 BuildRequires: openssl-devel -%endif #fedora +%endif BuildRequires: gpgme-devel BuildRequires: device-mapper-devel BuildRequires: pkgconfig(audit) @@ -130,7 +147,7 @@ BuildRequires: libseccomp-devel BuildRequires: libassuan-devel %if 0%{?centos} Requires: subscription-manager-rhsm-certificates -%endif # centos +%endif Requires: %{name}-common = %{epoch}:%{version}-%{release} Requires: %{name}-client = %{epoch}:%{version}-%{release} Requires(post): systemd @@ -312,6 +329,20 @@ tar zxf %{SOURCE30} # untar libnetwork tar zxf %{SOURCE31} +cd containerd* +%patch0 -p1 +%patch1 -p1 +%patch2 -p1 +cd - +%patch3 -p1 +%patch4 -p1 +%patch5 -p1 +%patch6 -p1 +%patch7 -p1 + +# https://bugzilla.redhat.com/show_bug.cgi?id=1879425 +%patch8 -p1 + %build # compile docker-proxy first - otherwise deps in gopath conflict with the others below and this fails. Remove libnetwork libs then. pushd libnetwork-%{commit_libnetwork} @@ -741,6 +772,91 @@ fi %{_bindir}/%{name}-v1.10-migrator-* %changelog +* Tue Oct 27 2020 Jindrich Novy - 2:1.13.1-203.git0be3e21 +- do not enable CollectMode support yet because it is not still present in + 7.6-ALT +- Related: #1766665 + +* Tue Sep 29 2020 Jindrich Novy - 2:1.13.1-202.git0be3e21 +- fix "runc run: fix panic on failed init start" +- Resolves: #1879425 + +* Tue Sep 22 2020 Jindrich Novy - 2:1.13.1-201.git0be3e21 +- fix "Race condition in kubelet cgroup destroy process" +- Resolves: #1766665 + +* Mon Jun 22 2020 Jindrich Novy - 2:1.13.1-200.git0be3e21 +- rebuilt + +* Wed Jun 10 2020 Jindrich Novy - 2:1.13.1-162.git0be3e21 +- update docker to 0be3e21: fixes "dockerd leaks SELinux MCS labels" +- Resolves: #1734482 + +* Tue Mar 03 2020 Jindrich Novy - 2:1.13.1-161.git64e9980 +- make failure message for CVE-2020-1702 more obvious (#1804024) +- drop patch for #1734482 as it breaks compilation + +* Mon Mar 02 2020 Jindrich Novy - 2:1.13.1-160.git64e9980 +- fix "dockerd leaks SELinux MCS labels" (#1734482) + +* Fri Feb 21 2020 Jindrich Novy - 2:1.13.1-159.git64e9980 +- fix CVE-2020-8945 (#1784838) + +* Fri Feb 14 2020 Jindrich Novy - 2:1.13.1-158.git64e9980 +- add missing patch for #1718441 + +* Tue Feb 11 2020 Jindrich Novy - 2:1.13.1-157.git64e9980 +- fix CVE-2020-1702 (#1792796) + +* Fri Jan 24 2020 Jindrich Novy - 2:1.13.1-156.gitcccb291 +- resurrect s390x arch as kernel there now has the renameat2 syscall (#1773504) + +* Thu Jan 23 2020 Jindrich Novy - 2:1.13.1-155.gitcccb291 +- use runc sources off 66aedde7 commit in docker-1.13.1-rhel branch (#1791870) +- use docker sources off cccb291 commit in docker-1.13.1-rhel branch +- do not use CollectMode systemd property in RHEL7 + +* Mon Jan 20 2020 Jindrich Novy - 2:1.13.1-154.git4ef4b30 +- Fix thread safety of gpgme (#1792243) + +* Thu Jan 16 2020 Jindrich Novy - 2:1.13.1-153.git4ef4b30 +- temporary disable s390x arch due to #1773504 causing fuse-overlayfs + failing to build - skopeo/contaners-common requires it + +* Mon Dec 23 2019 Jindrich Novy - 2:1.13.1-152.git4ef4b30 +- patch also local seccomp.json (#1784228) + +* Fri Dec 20 2019 Jindrich Novy - 2:1.13.1-151.git4ef4b30 +- whitelist statx syscall (#1784228) +- remove garbage at the end of if statements in spec +- remove unreferenced bz1784228.patch from dist-git + +* Fri Dec 13 2019 Jindrich Novy - 2:1.13.1-150.git4ef4b30 +- revert fix for #1766665 as RHEL 7 systemd does not have the CollectMode + property +- bump release to not to clash with RHEL7.7 builds + +* Fri Dec 06 2019 Jindrich Novy - 2:1.13.1-107.git4ef4b30 +- bump version to assure upgrade path + +* Thu Dec 05 2019 Jindrich Novy - 2:1.13.1-106.git4ef4b30 +- fix "libcontainerd: failed to receive event from containerd:" error (#1636244) +- fix "Pods stuck in terminating state with rpc error: code = 2" (#1653292) +- fix "Docker panics when performing `docker search` due to potential + Search bug when using multiple registries" (#1732626) +- fix race condition in kubelet cgroup destroy process (#1766665) + +* Thu Nov 21 2019 Jindrich Novy - 2:1.13.1-105.git4ef4b30 +- update runc +- Resolves: #1718441 + +* Tue Sep 24 2019 Lokesh Mandvekar - 2:1.13.1-104.git4ef4b30 +- Resolves: #1653292, #1741718, #1739315, #1733941 +- built docker @projectatomic/docker-1.13.1-rhel commit 4ef4b30 + +* Fri Aug 02 2019 Jindrich Novy - 2:1.13.1-103.git7f2769b +- update RHEL7u7 branch with new version + * Thu Jul 11 2019 Lokesh Mandvekar - 2:1.13.1-102.git7f2769b - Resolves: #1727488, #1723491