Hello community,

here is the log from the commit of package runc for openSUSE:Factory checked in 
at 2017-01-23 11:36:50
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/runc (Old)
 and      /work/SRC/openSUSE:Factory/.runc.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "runc"

Changes:
--------
--- /work/SRC/openSUSE:Factory/runc/runc.changes        2017-01-10 
10:44:32.474394530 +0100
+++ /work/SRC/openSUSE:Factory/.runc.new/runc.changes   2017-01-23 
11:36:54.941912764 +0100
@@ -1,0 +2,7 @@
+Fri Jan 13 13:58:33 UTC 2017 - [email protected]
+
+- fix CVE-2016-9962 bsc#1012568 and applying the patch
+  CVE-2016-9962.patch, because 1.12.6 partially fixes it (it contains
+  the first patch attached in bsc#1012568) 
+
+-------------------------------------------------------------------

Old:
----
  runc-git.f59ba3cdd76f.tar.xz

New:
----
  CVE-2016-9962.patch
  runc-git.50a19c6.tar.xz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ runc.spec ++++++
--- /var/tmp/diff_new_pack.1y6yTQ/_old  2017-01-23 11:36:55.509832222 +0100
+++ /var/tmp/diff_new_pack.1y6yTQ/_new  2017-01-23 11:36:55.513831656 +0100
@@ -1,7 +1,7 @@
 #
 # spec file for package runc
 #
-# Copyright (c) 2016 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2017 SUSE LINUX GmbH, Nuernberg, Germany.
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -40,13 +40,13 @@
 # FIX-OPENSUSE: This will be removed as soon as we move Docker's runC fork into
 #               a separate package. This whole versioning mess is caused by
 #               Docker vendoring non-releases of runC.
-%define git_version f59ba3cdd76f
+%define git_version 50a19c6
 # How to get the git_revision
 # git clone ${url}.git runc-upstream
 # cd runc-upstream
 # git checkout $git_version
 # git_revision=r$(git rev-list HEAD | wc -l)
-%define git_revision r2818
+%define git_revision r2819
 %define version_unconverted %{git_version}
 
 Name:           runc
@@ -57,6 +57,7 @@
 Group:          System/Management
 Url:            https://github.com/opencontainers/runc
 Source:         %{name}-git.%{git_version}.tar.xz
+Patch0:         CVE-2016-9962.patch
 BuildRequires:  fdupes
 %ifarch %go_arches
 BuildRequires:  go >= 1.5
@@ -102,6 +103,7 @@
 
 %prep
 %setup -q -n %{name}-git.%{git_version}
+%patch0 -p1
 
 %build
 # Do not use symlinks. If you want to run the unit tests for this package at

++++++ CVE-2016-9962.patch ++++++
>From 9729fc3127c5e27d59a0126f52e91c61037173ae Mon Sep 17 00:00:00 2001
From: Aleksa Sarai <[email protected]>
Date: Tue, 29 Nov 2016 01:25:06 +1100
Subject: [PATCH] libcontainer: init: only pass stateDirFd when creating a
 container

If we pass a file descriptor to the host filesystem while joining a
container, there is a race condition where a process inside the
container can ptrace(2) the joining process and stop it from closing its
file descriptor to the stateDirFd. Then the process can access the *host*
filesystem from that file descriptor.

To fix this, don't open or pass the stateDirFd to the init process
unless we're creating a new container. A proper fix for this would be to
remove the need for even passing around directory file descriptors
(which are quite dangerous in the context of mount namespaces).

SUSE: This is an additional patch which was the original "fix" for the
      CVE. It was agreed that the patch was too complicated to be used
      as a fix for a security issue -- but it will be upstreamed once
      the embargo passes.

Fixes: CVE-2016-9962
Signed-off-by: Aleksa Sarai <[email protected]>
---
 libcontainer/container_linux.go  | 30 ++++++++++++++++++------------
 libcontainer/factory_linux.go    | 37 ++++++++++++++++++++++---------------
 libcontainer/init_linux.go       |  3 +--
 libcontainer/process_linux.go    |  2 --
 libcontainer/setns_init_linux.go |  7 +------
 5 files changed, 42 insertions(+), 37 deletions(-)

diff --git a/libcontainer/container_linux.go b/libcontainer/container_linux.go
index 29c8b3437be3..4110af6fd89d 100644
--- a/libcontainer/container_linux.go
+++ b/libcontainer/container_linux.go
@@ -294,21 +294,29 @@ func (c *linuxContainer) newParentProcess(p *Process, 
doInit bool) (parentProces
        if err != nil {
                return nil, newSystemErrorWithCause(err, "creating new init 
pipe")
        }
-       rootDir, err := os.Open(c.root)
-       if err != nil {
-               return nil, err
-       }
-       cmd, err := c.commandTemplate(p, childPipe, rootDir)
+       cmd, err := c.commandTemplate(p, childPipe)
        if err != nil {
                return nil, newSystemErrorWithCause(err, "creating new command 
template")
        }
        if !doInit {
-               return c.newSetnsProcess(p, cmd, parentPipe, childPipe, rootDir)
+               return c.newSetnsProcess(p, cmd, parentPipe, childPipe)
        }
+
+       // We only set up rootDir if we're not doing a `runc exec`. The reason 
for
+       // this is to avoid cases where a racing, unprivileged process inside 
the
+       // container can get access to the statedir file descriptor (which would
+       // allow for container rootfs escape).
+       rootDir, err := os.Open(c.root)
+       if err != nil {
+               return nil, err
+       }
+       cmd.ExtraFiles = append(cmd.ExtraFiles, rootDir)
+       cmd.Env = append(cmd.Env,
+               fmt.Sprintf("_LIBCONTAINER_STATEDIR=%d", 
stdioFdCount+len(cmd.ExtraFiles)-1))
        return c.newInitProcess(p, cmd, parentPipe, childPipe, rootDir)
 }
 
-func (c *linuxContainer) commandTemplate(p *Process, childPipe, rootDir 
*os.File) (*exec.Cmd, error) {
+func (c *linuxContainer) commandTemplate(p *Process, childPipe *os.File) 
(*exec.Cmd, error) {
        cmd := exec.Command(c.initArgs[0], c.initArgs[1:]...)
        cmd.Stdin = p.Stdin
        cmd.Stdout = p.Stdout
@@ -317,10 +325,9 @@ func (c *linuxContainer) commandTemplate(p *Process, 
childPipe, rootDir *os.File
        if cmd.SysProcAttr == nil {
                cmd.SysProcAttr = &syscall.SysProcAttr{}
        }
-       cmd.ExtraFiles = append(p.ExtraFiles, childPipe, rootDir)
+       cmd.ExtraFiles = append(p.ExtraFiles, childPipe)
        cmd.Env = append(cmd.Env,
-               fmt.Sprintf("_LIBCONTAINER_INITPIPE=%d", 
stdioFdCount+len(cmd.ExtraFiles)-2),
-               fmt.Sprintf("_LIBCONTAINER_STATEDIR=%d", 
stdioFdCount+len(cmd.ExtraFiles)-1))
+               fmt.Sprintf("_LIBCONTAINER_INITPIPE=%d", 
stdioFdCount+len(cmd.ExtraFiles)-1))
        // NOTE: when running a container with no PID namespace and the parent 
process spawning the container is
        // PID1 the pdeathsig is being delivered to the container's init 
process by the kernel for some reason
        // even with the parent still running.
@@ -357,7 +364,7 @@ func (c *linuxContainer) newInitProcess(p *Process, cmd 
*exec.Cmd, parentPipe, c
        }, nil
 }
 
-func (c *linuxContainer) newSetnsProcess(p *Process, cmd *exec.Cmd, 
parentPipe, childPipe, rootDir *os.File) (*setnsProcess, error) {
+func (c *linuxContainer) newSetnsProcess(p *Process, cmd *exec.Cmd, 
parentPipe, childPipe *os.File) (*setnsProcess, error) {
        cmd.Env = append(cmd.Env, "_LIBCONTAINER_INITTYPE="+string(initSetns))
        state, err := c.currentState()
        if err != nil {
@@ -378,7 +385,6 @@ func (c *linuxContainer) newSetnsProcess(p *Process, cmd 
*exec.Cmd, parentPipe,
                config:        c.newInitConfig(p),
                process:       p,
                bootstrapData: data,
-               rootDir:       rootDir,
        }, nil
 }
 
diff --git a/libcontainer/factory_linux.go b/libcontainer/factory_linux.go
index cc336c147fb9..e3478d5b50e3 100644
--- a/libcontainer/factory_linux.go
+++ b/libcontainer/factory_linux.go
@@ -222,27 +222,34 @@ func (l *LinuxFactory) Type() string {
 // StartInitialization loads a container by opening the pipe fd from the 
parent to read the configuration and state
 // This is a low level implementation detail of the reexec and should not be 
consumed externally
 func (l *LinuxFactory) StartInitialization() (err error) {
-       var pipefd, rootfd int
-       for _, pair := range []struct {
-               k string
-               v *int
-       }{
-               {"_LIBCONTAINER_INITPIPE", &pipefd},
-               {"_LIBCONTAINER_STATEDIR", &rootfd},
-       } {
-
-               s := os.Getenv(pair.k)
+       var (
+               pipefd, rootfd int
+               envInitPipe    = os.Getenv("_LIBCONTAINER_INITPIPE")
+               envStateDir    = os.Getenv("_LIBCONTAINER_STATEDIR")
+       )
 
-               i, err := strconv.Atoi(s)
-               if err != nil {
-                       return fmt.Errorf("unable to convert %s=%s to int", 
pair.k, s)
-               }
-               *pair.v = i
+       // Get the INITPIPE.
+       pipefd, err = strconv.Atoi(envInitPipe)
+       if err != nil {
+               return fmt.Errorf("unable to convert _LIBCONTAINER_INITPIPE=%s 
to int: %s", envInitPipe, err)
        }
+
        var (
                pipe = os.NewFile(uintptr(pipefd), "pipe")
                it   = initType(os.Getenv("_LIBCONTAINER_INITTYPE"))
        )
+
+       // Only get the STATEDIR if we're an init process. It's a bit late to do
+       // anything about this if we've already brought in an fd (a racing 
process
+       // could've opened the fd by now because we're in the PID namespace).
+       rootfd = -1
+       if it == initStandard {
+               rootfd, err = strconv.Atoi(envStateDir)
+               if err != nil {
+                       return fmt.Errorf("unable to convert 
_LIBCONTAINER_STATEDIR=%s to int: %s", envStateDir, err)
+               }
+       }
+
        // clear the current process's environment to clean any libcontainer
        // specific env vars.
        os.Clearenv()
diff --git a/libcontainer/init_linux.go b/libcontainer/init_linux.go
index 4043d51c0bd0..b1e6762ecdf3 100644
--- a/libcontainer/init_linux.go
+++ b/libcontainer/init_linux.go
@@ -77,8 +77,7 @@ func newContainerInit(t initType, pipe *os.File, stateDirFD 
int) (initer, error)
        switch t {
        case initSetns:
                return &linuxSetnsInit{
-                       config:     config,
-                       stateDirFD: stateDirFD,
+                       config: config,
                }, nil
        case initStandard:
                return &linuxStandardInit{
diff --git a/libcontainer/process_linux.go b/libcontainer/process_linux.go
index 5b81317fd711..7b90c6b8faae 100644
--- a/libcontainer/process_linux.go
+++ b/libcontainer/process_linux.go
@@ -51,7 +51,6 @@ type setnsProcess struct {
        fds           []string
        process       *Process
        bootstrapData io.Reader
-       rootDir       *os.File
 }
 
 func (p *setnsProcess) startTime() (string, error) {
@@ -70,7 +69,6 @@ func (p *setnsProcess) start() (err error) {
        defer p.parentPipe.Close()
        err = p.cmd.Start()
        p.childPipe.Close()
-       p.rootDir.Close()
        if err != nil {
                return newSystemErrorWithCause(err, "starting setns process")
        }
diff --git a/libcontainer/setns_init_linux.go b/libcontainer/setns_init_linux.go
index 7f5f182402cc..2a8f34528179 100644
--- a/libcontainer/setns_init_linux.go
+++ b/libcontainer/setns_init_linux.go
@@ -5,7 +5,6 @@ package libcontainer
 import (
        "fmt"
        "os"
-       "syscall"
 
        "github.com/opencontainers/runc/libcontainer/apparmor"
        "github.com/opencontainers/runc/libcontainer/keys"
@@ -17,8 +16,7 @@ import (
 // linuxSetnsInit performs the container's initialization for running a new 
process
 // inside an existing container.
 type linuxSetnsInit struct {
-       config     *initConfig
-       stateDirFD int
+       config *initConfig
 }
 
 func (l *linuxSetnsInit) getSessionRingName() string {
@@ -51,8 +49,5 @@ func (l *linuxSetnsInit) Init() error {
        if err := label.SetProcessLabel(l.config.ProcessLabel); err != nil {
                return err
        }
-       // close the statedir fd before exec because the kernel resets dumpable 
in the wrong order
-       // https://github.com/torvalds/linux/blob/v4.9/fs/exec.c#L1290-L1318
-       syscall.Close(l.stateDirFD)
        return system.Execv(l.config.Args[0], l.config.Args[0:], os.Environ())
 }
-- 
2.11.0

++++++ _service ++++++
--- /var/tmp/diff_new_pack.1y6yTQ/_old  2017-01-23 11:36:55.561824849 +0100
+++ /var/tmp/diff_new_pack.1y6yTQ/_new  2017-01-23 11:36:55.561824849 +0100
@@ -8,7 +8,7 @@
     <param name="scm">git</param>
     <param name="filename">runc</param>
     <param name="versionformat">git.%h</param>
-    <param name="revision">f59ba3cdd76fdc08c004f42aa915996f6f420899</param>
+    <param name="revision">50a19c6ff828</param>
     <param name="exclude">.git</param>
   </service>
   <service name="recompress" mode="disabled">

++++++ runc-git.f59ba3cdd76f.tar.xz -> runc-git.50a19c6.tar.xz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/runc-git.f59ba3cdd76f/libcontainer/init_linux.go 
new/runc-git.50a19c6/libcontainer/init_linux.go
--- old/runc-git.f59ba3cdd76f/libcontainer/init_linux.go        2016-10-21 
00:22:03.000000000 +0200
+++ new/runc-git.50a19c6/libcontainer/init_linux.go     2016-12-17 
18:01:09.000000000 +0100
@@ -77,7 +77,8 @@
        switch t {
        case initSetns:
                return &linuxSetnsInit{
-                       config: config,
+                       config:     config,
+                       stateDirFD: stateDirFD,
                }, nil
        case initStandard:
                return &linuxStandardInit{
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/runc-git.f59ba3cdd76f/libcontainer/nsenter/nsexec.c 
new/runc-git.50a19c6/libcontainer/nsenter/nsexec.c
--- old/runc-git.f59ba3cdd76f/libcontainer/nsenter/nsexec.c     2016-10-21 
00:22:03.000000000 +0200
+++ new/runc-git.50a19c6/libcontainer/nsenter/nsexec.c  2016-12-17 
18:01:09.000000000 +0100
@@ -408,6 +408,11 @@
        if (pipenum == -1)
                return;
 
+       /* make the process non-dumpable */
+       if (prctl(PR_SET_DUMPABLE, 0, 0, 0, 0) != 0) {
+               bail("failed to set process as non-dumpable");
+       }
+
        /* Parse all of the netlink configuration. */
        nl_parse(pipenum, &config);
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/runc-git.f59ba3cdd76f/libcontainer/setns_init_linux.go 
new/runc-git.50a19c6/libcontainer/setns_init_linux.go
--- old/runc-git.f59ba3cdd76f/libcontainer/setns_init_linux.go  2016-10-21 
00:22:03.000000000 +0200
+++ new/runc-git.50a19c6/libcontainer/setns_init_linux.go       2016-12-17 
18:01:09.000000000 +0100
@@ -5,6 +5,7 @@
 import (
        "fmt"
        "os"
+       "syscall"
 
        "github.com/opencontainers/runc/libcontainer/apparmor"
        "github.com/opencontainers/runc/libcontainer/keys"
@@ -16,7 +17,8 @@
 // linuxSetnsInit performs the container's initialization for running a new 
process
 // inside an existing container.
 type linuxSetnsInit struct {
-       config *initConfig
+       config     *initConfig
+       stateDirFD int
 }
 
 func (l *linuxSetnsInit) getSessionRingName() string {
@@ -49,5 +51,8 @@
        if err := label.SetProcessLabel(l.config.ProcessLabel); err != nil {
                return err
        }
+       // close the statedir fd before exec because the kernel resets dumpable 
in the wrong order
+       // https://github.com/torvalds/linux/blob/v4.9/fs/exec.c#L1290-L1318
+       syscall.Close(l.stateDirFD)
        return system.Execv(l.config.Args[0], l.config.Args[0:], os.Environ())
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/runc-git.f59ba3cdd76f/libcontainer/standard_init_linux.go 
new/runc-git.50a19c6/libcontainer/standard_init_linux.go
--- old/runc-git.f59ba3cdd76f/libcontainer/standard_init_linux.go       
2016-10-21 00:22:03.000000000 +0200
+++ new/runc-git.50a19c6/libcontainer/standard_init_linux.go    2016-12-17 
18:01:09.000000000 +0100
@@ -171,6 +171,9 @@
                        return newSystemErrorWithCause(err, "init seccomp")
                }
        }
+       // close the statedir fd before exec because the kernel resets dumpable 
in the wrong order
+       // https://github.com/torvalds/linux/blob/v4.9/fs/exec.c#L1290-L1318
+       syscall.Close(l.stateDirFD)
        if err := syscall.Exec(name, l.config.Args[0:], os.Environ()); err != 
nil {
                return newSystemErrorWithCause(err, "exec user process")
        }


Reply via email to