Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

libcontainer/configs/config: Clear hook environ variables on empty Env #1738

Closed
wants to merge 1 commit into from

Conversation

wking
Copy link
Contributor

@wking wking commented Feb 24, 2018

The runtime spec has:

  • env (array of strings, OPTIONAL) with the same semantics as IEEE Std 1003.1-2008's environ.

And running execle or similar with NULL env results in an empty environent:

$ cat test.c
#include <unistd.h>

int main()
{
  return execle("/usr/bin/env", "env", NULL, NULL);
}
$ cc -o test test.c
$ ./test
…no output…

Go's Cmd.Env, on the other hand, has:

If Env is nil, the new process uses the current process's environment.

This commit works around that by setting a single dummy environment variable []string{} in those cases to avoid leaking the runtime environment into the hooks.

@@ -320,6 +320,9 @@ func (c Command) Run(s HookState) error {
Stdout: &stdout,
Stderr: &stderr,
}
if cmd.Env == nil {
cmd.Env = []string{"_GO_DOES_NOT_PROVIDE_A_WAY_TO_CLEAR_ENV="}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does cmd.Env = []string{} also not work?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does cmd.Env = []string{} also not work?

Looks like it does :). Fixed with 5f6ed8496e8770.

@justincormack
Copy link
Contributor

justincormack commented Feb 27, 2018

Why can't you just set it to []string{} which will give the desired outcome if the passed array is nil?

Ah sorry, was mislead by the comments above it has been changed to do this.

@wking
Copy link
Contributor Author

wking commented Feb 27, 2018

Ah sorry, was mislead by the comments above...

I've updated the initial comment to avoid misleading others.

wking added a commit to wking/libpod that referenced this pull request May 11, 2018
This shifts the matching logic out of libpod/container_internal and
into the hook package, where we can reuse it after vendoring into
CRI-O.  It also adds unit tests with almost-complete coverage.  Now
libpod is even more isolated from the hook internals, which makes it
fairly straightforward to bump the hook config file to 1.0.0.  I've
dubbed the old format 0.1.0, although it doesn't specify an explicit
version.  Motivation for some of my changes with 1.0.0:

* Add an explicit version field.  This will make any future JSON
  structure migrations more straightforward by avoiding the need for
  version-guessing heuristics.

* Collect the matching properties in a new When sub-structure.  This
  makes the root Hook structure easier to understand, because you
  don't have to read over all the matching properties when wrapping
  your head around Hook.

* Replace the old 'hook' and 'arguments' with a direct embedding of
  the runtime-spec's hook structure.  This provides access to
  additional upstream properties (args[0], env, and timeout) and
  avoids the complication of a CRI-O-specific analog structure.

* Add a 'when.always' property.  You can usually accomplish this
  effect in another way (e.g. when.commands = [".*"]), but having a
  boolean explicitly for this use-case makes for easier reading and
  writing.

* Replace the previous annotations array with an annotations map.  The
  0.1.0 approach matched only the values regardless of key, and that
  seems unreliable.

* Replace 'cmds' with 'when.commands', because while there are a few
  ways to abbreviate "commands", there's only one way to write it out
  in full ;).  This gives folks one less thing to remember when
  writing hook JSON.

* Replace the old "inject if any specified condition matches" with
  "inject if all specified conditions match".  This allows for more
  precise targeting.  Users that need more generous targeting can
  recover the previous behavior by creating a separate 1.0.0 hook file
  for each specified 0.1.0 condition.

I've added doc-compat support for the various pluralizations of the
0.1.0 properties.  Previously, the docs and code were not in
agreement.  More on this particular facet in [1].

I've updated the docs to point out that the annotations being matched
are the OCI config annotations.  This differs from CRI-O, where the
annotations used are the Kubernetes-supplied annotations [2,3].  For
example, io.kubernetes.cri-o.Volumes [4] is part of CRI-O's runtime
config annotations [5], but not part of the Kubernetes-supplied
annotations CRI-O uses for matching hooks.

The Monitor method supports the CRI-O use-case [6].  podman doesn't
need it directly, but CRI-O will need it when we vendor this package
there.

I've used nvidia-container-runtime-hook for the annotation examples
because Dan mentioned the Nvidia folks as the motivation behind
annotation matching.  The environment variables are documented in [7].
The 0.1.0 hook config, which does not allow for environment variables,
only works because runc currently leaks the host environment into the
hooks [8].  I haven't been able to find documentation for their usual
annotation trigger or hook-install path, so I'm just guessing there.

[1]: cri-o/cri-o#1235
[2]: https://github.com/kubernetes-incubator/cri-o/blob/v1.10.0/server/container_create.go#L760
[3]: https://github.com/kubernetes-incubator/cri-o/blob/v1.10.0/server/container_create.go#L772
[4]: https://github.com/kubernetes-incubator/cri-o/blob/v1.10.0/pkg/annotations/annotations.go#L97-L98
[5]: https://github.com/kubernetes-incubator/cri-o/blob/v1.10.0/server/container_create.go#L830-L834
[6]: cri-o/cri-o#1345
[7]: https://github.com/NVIDIA/nvidia-container-runtime/tree/v1.3.0-1#environment-variables-oci-spec
[8]: opencontainers/runc#1738

Signed-off-by: W. Trevor King <wking@tremily.us>
rh-atomic-bot pushed a commit to containers/podman that referenced this pull request May 11, 2018
This shifts the matching logic out of libpod/container_internal and
into the hook package, where we can reuse it after vendoring into
CRI-O.  It also adds unit tests with almost-complete coverage.  Now
libpod is even more isolated from the hook internals, which makes it
fairly straightforward to bump the hook config file to 1.0.0.  I've
dubbed the old format 0.1.0, although it doesn't specify an explicit
version.  Motivation for some of my changes with 1.0.0:

* Add an explicit version field.  This will make any future JSON
  structure migrations more straightforward by avoiding the need for
  version-guessing heuristics.

* Collect the matching properties in a new When sub-structure.  This
  makes the root Hook structure easier to understand, because you
  don't have to read over all the matching properties when wrapping
  your head around Hook.

* Replace the old 'hook' and 'arguments' with a direct embedding of
  the runtime-spec's hook structure.  This provides access to
  additional upstream properties (args[0], env, and timeout) and
  avoids the complication of a CRI-O-specific analog structure.

* Add a 'when.always' property.  You can usually accomplish this
  effect in another way (e.g. when.commands = [".*"]), but having a
  boolean explicitly for this use-case makes for easier reading and
  writing.

* Replace the previous annotations array with an annotations map.  The
  0.1.0 approach matched only the values regardless of key, and that
  seems unreliable.

* Replace 'cmds' with 'when.commands', because while there are a few
  ways to abbreviate "commands", there's only one way to write it out
  in full ;).  This gives folks one less thing to remember when
  writing hook JSON.

* Replace the old "inject if any specified condition matches" with
  "inject if all specified conditions match".  This allows for more
  precise targeting.  Users that need more generous targeting can
  recover the previous behavior by creating a separate 1.0.0 hook file
  for each specified 0.1.0 condition.

I've added doc-compat support for the various pluralizations of the
0.1.0 properties.  Previously, the docs and code were not in
agreement.  More on this particular facet in [1].

I've updated the docs to point out that the annotations being matched
are the OCI config annotations.  This differs from CRI-O, where the
annotations used are the Kubernetes-supplied annotations [2,3].  For
example, io.kubernetes.cri-o.Volumes [4] is part of CRI-O's runtime
config annotations [5], but not part of the Kubernetes-supplied
annotations CRI-O uses for matching hooks.

The Monitor method supports the CRI-O use-case [6].  podman doesn't
need it directly, but CRI-O will need it when we vendor this package
there.

I've used nvidia-container-runtime-hook for the annotation examples
because Dan mentioned the Nvidia folks as the motivation behind
annotation matching.  The environment variables are documented in [7].
The 0.1.0 hook config, which does not allow for environment variables,
only works because runc currently leaks the host environment into the
hooks [8].  I haven't been able to find documentation for their usual
annotation trigger or hook-install path, so I'm just guessing there.

[1]: cri-o/cri-o#1235
[2]: https://github.com/kubernetes-incubator/cri-o/blob/v1.10.0/server/container_create.go#L760
[3]: https://github.com/kubernetes-incubator/cri-o/blob/v1.10.0/server/container_create.go#L772
[4]: https://github.com/kubernetes-incubator/cri-o/blob/v1.10.0/pkg/annotations/annotations.go#L97-L98
[5]: https://github.com/kubernetes-incubator/cri-o/blob/v1.10.0/server/container_create.go#L830-L834
[6]: cri-o/cri-o#1345
[7]: https://github.com/NVIDIA/nvidia-container-runtime/tree/v1.3.0-1#environment-variables-oci-spec
[8]: opencontainers/runc#1738

Signed-off-by: W. Trevor King <wking@tremily.us>

Closes: #686
Approved by: mheon
@kolyshkin
Copy link
Contributor

This makes sense but needs a test case (in e.g. tests/integration/hooks.bats)

The runtime spec has [1]:

  * env (array of strings, OPTIONAL) with the same semantics as IEEE
    Std 1003.1-2008's environ.

And running execle or similar with NULL env results in an empty
environent:

  $ cat test.c
  #include <unistd.h>

  int main()
  {
    return execle("/usr/bin/env", "env", NULL, NULL);
  }
  $ cc -o test test.c
  $ ./test
  ...no output...

Go's Cmd.Env, on the other hand, has [2]:

  If Env is nil, the new process uses the current process's
  environment.

This commit works around that by setting Env to an empty slice in
those cases to avoid leaking the runtime environment into the hooks.

[1]: https://github.com/opencontainers/runtime-spec/blob/v1.0.1/config.md#posix-platform-hooks
[2]: https://golang.org/pkg/os/exec/#Cmd

Signed-off-by: W. Trevor King <wking@tremily.us>
@lifubang
Copy link
Member

Carried in #4323

@kolyshkin
Copy link
Contributor

Closing in favor of #4323

@kolyshkin kolyshkin closed this Jun 23, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants