Skip to content

Commit

Permalink
Pass Systemd LISTEN_* environment to the container
Browse files Browse the repository at this point in the history
If a container is running within a systemd service and it is socket
activated, we need to leak the LISTEN_* environment variables into the
container.

Fixes: containers#10443

Signed-off-by: Daniel J Walsh <dwalsh@redhat.com>
  • Loading branch information
rhatdan committed May 27, 2021
1 parent 3223cb5 commit b479da3
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 7 deletions.
6 changes: 6 additions & 0 deletions cmd/podman/system/service_abi.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,12 @@ func restService(opts entities.ServiceOptions, flags *pflag.FlagSet, cfg *entiti
}
}()

// If the podman service is setup as socket activated, we don't want any containers
// to inherit these settings from the service.
for _, lEnv := range []string{"LISTEN_PID", "LISTEN_FDS", "LISTEN_FDNAMES"} {
os.Unsetenv(lEnv)
}

err = server.Serve()
if listener != nil {
_ = (*listener).Close()
Expand Down
12 changes: 12 additions & 0 deletions libpod/container_internal_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -648,6 +648,18 @@ func (c *Container) generateSpec(ctx context.Context) (*spec.Spec, error) {
g.AddProcessEnv("HOSTNAME", hostname)
}

for _, lEnv := range []string{"LISTEN_PID", "LISTEN_FDS", "LISTEN_FDNAMES"} {
if val, ok := os.LookupEnv(lEnv); ok {
// The primary process within the container will be PID=1, so this
// value needs to be reset
if lEnv == "LISTEN_PID" {
g.AddProcessEnv(lEnv, "1")
continue
}
g.AddProcessEnv(lEnv, val)
}
}

if c.config.UTSNsCtr != "" {
if err := c.addNamespaceContainer(&g, UTSNS, c.config.UTSNsCtr, spec.UTSNamespace); err != nil {
return nil, err
Expand Down
10 changes: 10 additions & 0 deletions libpod/oci_conmon_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -1051,6 +1051,16 @@ func (r *ConmonOCIRuntime) createOCIContainer(ctr *Container, restoreOptions *Co
}
}

if l, ok := os.LookupEnv("LISTEN_FDS"); ok {
listenFds, err := strconv.ParseUint(l, 10, 64)
if err != nil {
logrus.Warnf("Error LISTEN_FDS environment variable not an int %v", err)
}

if uint(listenFds) > ctr.config.PreserveFDs {
ctr.config.PreserveFDs = uint(listenFds)
}
}
if ctr.config.PreserveFDs > 0 {
args = append(args, formatRuntimeOpts("--preserve-fds", fmt.Sprintf("%d", ctr.config.PreserveFDs))...)
}
Expand Down
53 changes: 46 additions & 7 deletions test/system/250-systemd.bats
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ function teardown() {
function xdg_rootless() {
# podman initializes this if unset, but systemctl doesn't
if is_rootless; then
if [ -z "$XDG_RUNTIME_DIR" ]; then
export XDG_RUNTIME_DIR=/run/user/$(id -u)
fi
if [ -z "$XDG_RUNTIME_DIR" ]; then
export XDG_RUNTIME_DIR=/run/user/$(id -u)
fi
fi
}

Expand All @@ -52,20 +52,20 @@ function service_setup() {

run $SYSTEMCTL start "$SERVICE_NAME"
if [ $status -ne 0 ]; then
die "Error starting systemd unit $SERVICE_NAME, output: $output"
die "Error starting systemd unit $SERVICE_NAME, output: $output"
fi

run $SYSTEMCTL status "$SERVICE_NAME"
if [ $status -ne 0 ]; then
die "Non-zero status of systemd unit $SERVICE_NAME, output: $output"
die "Non-zero status of systemd unit $SERVICE_NAME, output: $output"
fi
}

# Helper to stop a systemd service running a container
function service_cleanup() {
run $SYSTEMCTL stop "$SERVICE_NAME"
if [ $status -ne 0 ]; then
die "Error stopping systemd unit $SERVICE_NAME, output: $output"
die "Error stopping systemd unit $SERVICE_NAME, output: $output"
fi

rm -f "$UNIT_FILE"
Expand Down Expand Up @@ -132,7 +132,7 @@ function service_cleanup() {

cname=$(random_string)
FOO=value BAR=%s run_podman create --name $cname --env FOO -e BAR --env MYVAR=myval \
$IMAGE sh -c 'printenv && sleep 100'
$IMAGE sh -c 'printenv && sleep 100'

# Start systemd service to run this container
service_setup
Expand All @@ -148,4 +148,43 @@ function service_cleanup() {
service_cleanup
}

@test "podman pass run LISTEN environment " {
tmpdir=$PODMAN_TMPDIR/build-test
subdir=$tmpdir/subdir
run_podman run --hostname=host1 --rm $IMAGE printenv
std_output=$output

export LISTEN_PID="listen_pid" LISTEN_FDS="listen_fds" LISTEN_FDNAMES="listen_fdnames"
run_podman run --hostname=host1 --rm $IMAGE printenv
if is_remote; then
is "$output" "$std_output" "LISTEN Environment did not pass"
else
is "$output" "$std_output
LISTEN_PID=1
LISTEN_FDS=listen_fds
LISTEN_FDNAMES=listen_fdnames" "LISTEN Environment passed"
fi
unset LISTEN_PID LISTEN_FDS LISTEN_FDNAMES
}

@test "podman pass start LISTEN environment " {
tmpdir=$PODMAN_TMPDIR/build-test
subdir=$tmpdir/subdir
run_podman run --hostname=host1 --rm $IMAGE printenv
std_output=$output

run_podman create --name=test --hostname=host1 --rm $IMAGE printenv
export LISTEN_PID="listen_pid" LISTEN_FDS="listen_fds" LISTEN_FDNAMES="listen_fdnames"
run_podman start --attach test
if is_remote; then
is "$output" "$std_output" "LISTEN Environment did not pass"
else
is "$output" "$std_output
LISTEN_PID=1
LISTEN_FDS=listen_fds
LISTEN_FDNAMES=listen_fdnames" "LISTEN Environment passed"
fi
unset LISTEN_PID LISTEN_FDS LISTEN_FDNAMES
}

# vim: filetype=sh

0 comments on commit b479da3

Please sign in to comment.