Expose security attribute errors with their own messages

This creates error objects for runtime errors that might come from the
runtime. Thus, indicating to users that the place to debug should be in
the security attributes of the container.

When creating a container with a SELinux label that doesn't exist, we
get a fairly cryptic error message:

```
$ podman run --security-opt label=type:my_container.process -it fedora bash
Error: OCI runtime error: write file `/proc/thread-self/attr/exec`: Invalid argument
```

This instead handles any errors coming from LSM's `/proc` API and
enhances the error message with a relevant indicator that it's related
to the container's security attributes.

A sample run looks as follows:

```
$ bin/podman run --security-opt label=type:my_container.process -it fedora bash
Error: `/proc/thread-self/attr/exec`: OCI runtime error: unable to assign security attribute
```

With `debug` log level enabled it would be:

```
Error: write file `/proc/thread-self/attr/exec`: Invalid argument: OCI runtime error: unable to assign security attribute
```

Note that these errors wrap ErrOCIRuntime, so it's still possible to to
compare these errors with `errors.Is/errors.As`.

One advantage of this approach is that we could start handling these
errors in a more efficient manner in the future.

e.g. If a SELinux label doesn't exist (yet), we could retry until it
becomes available.

Signed-off-by: Juan Antonio Osorio Robles <jaosorior@redhat.com>
This commit is contained in:
Juan Antonio Osorio Robles 2021-01-12 15:54:32 +02:00
parent 64b86d004e
commit 020abbfeab
2 changed files with 25 additions and 0 deletions

View File

@ -2,6 +2,7 @@ package define
import ( import (
"errors" "errors"
"fmt"
) )
var ( var (
@ -181,4 +182,16 @@ var (
// ErrNoNetwork indicates that a container has no net namespace, like network=none // ErrNoNetwork indicates that a container has no net namespace, like network=none
ErrNoNetwork = errors.New("container has no network namespace") ErrNoNetwork = errors.New("container has no network namespace")
// ErrSetSecurityAttribute indicates that a request to set a container's security attribute
// was not possible.
ErrSetSecurityAttribute = fmt.Errorf("%w: unable to assign security attribute", ErrOCIRuntime)
// ErrGetSecurityAttribute indicates that a request to get a container's security attribute
// was not possible.
ErrGetSecurityAttribute = fmt.Errorf("%w: unable to get security attribute", ErrOCIRuntime)
// ErrSecurityAttribute indicates that an error processing security attributes
// for the container
ErrSecurityAttribute = fmt.Errorf("%w: unable to process security attribute", ErrOCIRuntime)
) )

View File

@ -126,5 +126,17 @@ func getOCIRuntimeError(runtimeMsg string) error {
} }
return errors.Wrapf(define.ErrOCIRuntimeNotFound, "%s", strings.Trim(errStr, "\n")) return errors.Wrapf(define.ErrOCIRuntimeNotFound, "%s", strings.Trim(errStr, "\n"))
} }
if match := regexp.MustCompile("`/proc/[a-z0-9-].+/attr.*`").FindString(runtimeMsg); match != "" {
errStr := match
if includeFullOutput {
errStr = runtimeMsg
}
if strings.HasSuffix(match, "/exec`") {
return errors.Wrapf(define.ErrSetSecurityAttribute, "%s", strings.Trim(errStr, "\n"))
} else if strings.HasSuffix(match, "/current`") {
return errors.Wrapf(define.ErrGetSecurityAttribute, "%s", strings.Trim(errStr, "\n"))
}
return errors.Wrapf(define.ErrSecurityAttribute, "%s", strings.Trim(errStr, "\n"))
}
return errors.Wrapf(define.ErrOCIRuntime, "%s", strings.Trim(runtimeMsg, "\n")) return errors.Wrapf(define.ErrOCIRuntime, "%s", strings.Trim(runtimeMsg, "\n"))
} }