fix rootless port forwarding with network dis-/connect

The rootlessport forwarder requires a child IP to be set. This must be a
valid ip in the container network namespace. The problem is that after a
network disconnect and connect the eth0 ip changed. Therefore the
packages are dropped since the source ip does no longer exists in the
netns.
One solution is to set the child IP to 127.0.0.1, however this is a
security problem. [1]

To fix this we have to recreate the ports after network connect and
disconnect. To make this work the rootlessport process exposes a socket
where podman network connect/disconnect connect to and send to new child
IP to rootlessport. The rootlessport process will remove all ports and
recreate them with the new correct child IP.

Also bump rootlesskit to v0.14.3 to fix a race with RemovePort().

Fixes #10052

[1] https://nvd.nist.gov/vuln/detail/CVE-2021-20199

Signed-off-by: Paul Holzinger <pholzing@redhat.com>
This commit is contained in:
Paul Holzinger
2021-07-30 14:33:08 +02:00
parent d25f8d07b3
commit e88d8dbeae
13 changed files with 284 additions and 47 deletions

View File

@ -12,6 +12,7 @@ import (
"strings"
"sync"
"syscall"
"time"
"github.com/pkg/errors"
@ -140,8 +141,13 @@ func (d *driver) AddPort(ctx context.Context, spec port.Spec) (*port.Status, err
}
routineStopCh := make(chan struct{})
routineStop := func() error {
close(routineStopCh)
return nil // FIXME
routineStopCh <- struct{}{}
select {
case <-routineStopCh:
case <-time.After(5 * time.Second):
return errors.New("stop timeout after 5 seconds")
}
return nil
}
switch spec.Proto {
case "tcp", "tcp4", "tcp6":

View File

@ -12,7 +12,7 @@ import (
"github.com/rootless-containers/rootlesskit/pkg/port/builtin/msg"
)
func Run(socketPath string, spec port.Spec, stopCh <-chan struct{}, logWriter io.Writer) error {
func Run(socketPath string, spec port.Spec, stopCh chan struct{}, logWriter io.Writer) error {
ln, err := net.Listen(spec.Proto, net.JoinHostPort(spec.ParentIP, strconv.Itoa(spec.ParentPort)))
if err != nil {
fmt.Fprintf(logWriter, "listen: %v\n", err)
@ -31,7 +31,10 @@ func Run(socketPath string, spec port.Spec, stopCh <-chan struct{}, logWriter io
}
}()
go func() {
defer ln.Close()
defer func() {
ln.Close()
close(stopCh)
}()
for {
select {
case c, ok := <-newConns:

View File

@ -13,7 +13,7 @@ import (
"github.com/rootless-containers/rootlesskit/pkg/port/builtin/parent/udp/udpproxy"
)
func Run(socketPath string, spec port.Spec, stopCh <-chan struct{}, logWriter io.Writer) error {
func Run(socketPath string, spec port.Spec, stopCh chan struct{}, logWriter io.Writer) error {
addr, err := net.ResolveUDPAddr(spec.Proto, net.JoinHostPort(spec.ParentIP, strconv.Itoa(spec.ParentPort)))
if err != nil {
return err
@ -51,6 +51,7 @@ func Run(socketPath string, spec port.Spec, stopCh <-chan struct{}, logWriter io
case <-stopCh:
// udpp.Close closes ln as well
udpp.Close()
close(stopCh)
return
}
}