-
Notifications
You must be signed in to change notification settings - Fork 2.4k
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
validate fds --preserve-fds #7125
Conversation
libpod/oci_conmon_linux.go
Outdated
@@ -956,6 +956,11 @@ func (r *ConmonOCIRuntime) createOCIContainer(ctr *Container, restoreOptions *Co | |||
|
|||
if ctr.config.PreserveFDs > 0 { | |||
for fd := 3; fd < int(3+ctr.config.PreserveFDs); fd++ { | |||
f := os.NewFile(uintptr(fd), fmt.Sprintf("fd-%d", fd)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we need to do this in cmd/podman
- we probably have at least this many open FDs of our own by this point (c/storage locks, etc)
4bb0211
to
40a9bfa
Compare
Add validation code. But this does not fix panic #6653
|
Go may well be happy to create a new file from an invalid FD - we probably need a test that the FD is actually valid. |
Yes look like it succeeds.
|
Just a heads-up: please see #7144, it looks germane. |
This works.
|
The call seems to return err = 0 on success. Not nil, but I think as long as we check for EBADF, then we should be safe. |
I didn't see the output from this success case, I guess the err is nil, can't we just return err as long as the err != nil, without checking EBADF?
|
The preserve-fds should fail on remote client and should also not be executed on Windows. |
How about?
|
cmd/podman/containers/run.go
Outdated
var fd uint | ||
for fd = 3; fd < 3+runOpts.PreserveFDs; fd++ { | ||
_, err := unix.FcntlInt(uintptr(fd), unix.F_GETFL, 0); err != nil && err != syscall.Errno(0) { | ||
return err |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this should be a wrapped error to tell the user which FD is invalid.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The FcntlInt code needs to be in a util_linux.go branch.
Does podman-remote throw an error when you do --preserver-fds?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added utils_linux.go --preserver-fds
is disabled in remote.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you want to have similar code in exec.go and perhaps attach.go as well?
ae93f3c
to
a10c42e
Compare
Your going to need verifyfd in the utils_unsupported.go as well. |
Almost there, now I need a test to make sure it errors out with the correct error podman run --preserve-fd 2 alpine true Should return an error containing bad fd. |
cmd/podman/containers/utils_linux.go
Outdated
func verifyFD(fd int) error { | ||
if _, err := unix.FcntlInt(uintptr(fd), unix.F_GETFL, 0); err != nil && err != syscall.Errno(0) { | ||
return errors.Wrapf(err, "failed to verify %d file descriptor", fd) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this won't detect fds that are opened by Podman.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If run podman run --preserve-fds
, it's possible that the file descriptor I want to pass has already opened by podman, so this won't detect that?
I don't think it can be solved at this level. Files can be opened by the Go runtime so we don't know what FDs are valid and what are not. rootless already stores at startup what ds were open before the Go runtime kicks in. I think we could take advantage of that and be sure that these fds were already opened when the program started ( |
Do we have access to these within golang? |
we will need to provide a wrapper, something like: diff --git a/pkg/rootless/rootless_linux.c b/pkg/rootless/rootless_linux.c
index d3e43e44d..6d353d2e2 100644
--- a/pkg/rootless/rootless_linux.c
+++ b/pkg/rootless/rootless_linux.c
@@ -225,6 +225,14 @@ can_use_shortcut ()
return ret;
}
+int
+is_fd_inherited(int fd)
+{
+ if (open_files_set == NULL || fd >= open_files_max_fd || fd < 0)
+ return false;
+ return FD_ISSET (fd % FD_SETSIZE, &(open_files_set[fd / FD_SETSIZE])) ? 1 : 0;
+}
+
static void __attribute__((constructor)) init()
{
const char *xdg_runtime_dir;
diff --git a/pkg/rootless/rootless_linux.go b/pkg/rootless/rootless_linux.go
index b1f200cc2..2fe915cab 100644
--- a/pkg/rootless/rootless_linux.go
+++ b/pkg/rootless/rootless_linux.go
@@ -32,6 +32,7 @@ extern uid_t rootless_gid();
extern int reexec_in_user_namespace(int ready, char *pause_pid_file_path, char *file_to_read, int fd);
extern int reexec_in_user_namespace_wait(int pid, int options);
extern int reexec_userns_join(int pid, char *pause_pid_file_path);
+extern int is_fd_inherited(int fd);
*/
import "C"
@@ -495,3 +496,10 @@ func ConfigurationMatches() (bool, error) {
return matches(GetRootlessGID(), gids, currentGIDs), nil
}
+
+func IsFdInherited(fd int) bool {
+ if int(C.is_fd_inherited(C.int(fd))) > 0 {
+ return true
+ }
+ return false
+}
diff --git a/pkg/rootless/rootless_unsupported.go b/pkg/rootless/rootless_unsupported.go
index 1499b737f..203d56acb 100644
--- a/pkg/rootless/rootless_unsupported.go
+++ b/pkg/rootless/rootless_unsupported.go
@@ -64,3 +64,7 @@ func GetConfiguredMappings() ([]idtools.IDMap, []idtools.IDMap, error) {
func ReadMappingsProc(path string) ([]idtools.IDMap, error) {
return nil, nil
}
+
+func IsFdInherited(fd int) bool {
+ return false
+}
|
@giuseppe Are you going to open PR to fix this? Do you mind I grab the code above PR? |
please go forward and use it in this PR |
@giuseppe Any ideas why the test fail? |
looks like there is an issue in the code I've provided you, can you try with this version for
|
@edsantiago @rhatdan @giuseppe PTAL |
/approve |
534d1e9
to
7f41015
Compare
cmd/podman/containers/exec.go
Outdated
@@ -110,6 +111,12 @@ func exec(_ *cobra.Command, args []string) error { | |||
|
|||
execOpts.Envs = envLib.Join(execOpts.Envs, cliEnv) | |||
|
|||
for fd := 3; fd < int(3+execOpts.PreserveFDs); fd++ { | |||
if !rootless.IsFdInherited(fd) { | |||
return errors.Errorf("failed to verify %d file descriptor", fd) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is confusing. Shouldn't it read file descriptor %d
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually" failed to verify" itself doesn't really make sense to me as an end user. How about "file descriptor %d is not open" or "...is not available for I/O" or something along those lines? @giuseppe since you have the best understanding of what this code is actually validating, could you suggest a phrasing that is both technically accurate and helpful to the end user?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The code is verifying it a file descriptor actually exists. I think "file descriptor %d is not open" is correct.
Users are telling podman to leak file descriptor 3 and 4 in to a container, and if 3 and 4 are not open, then something went wrong.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe "file descriptor %d is not available - the preserve-fds option requires that file descriptors must be passed"
cmd/podman/containers/run.go
Outdated
@@ -125,6 +125,11 @@ func run(cmd *cobra.Command, args []string) error { | |||
if err := createInit(cmd); err != nil { | |||
return err | |||
} | |||
for fd := 3; fd < int(3+runOpts.PreserveFDs); fd++ { | |||
if !rootless.IsFdInherited(fd) { | |||
return errors.Errorf("failed to verify %d file descriptor", fd) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same here
d302eac
to
7bffb4f
Compare
validate file descriptors passed from podman run and podman exec --preserve-fds. Signed-off-by: Qi Wang <[email protected]>
@edsantiago @rhatdan @mheon PTAL |
LGTM |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/lgtm
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: giuseppe, QiWang19, rhatdan The full list of commands accepted by this bot can be found here. The pull request process is described here
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
validate file descriptors passed from
podman run
andpodman exec
--preserve-fds.Signed-off-by: Qi Wang [email protected]