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

Fix copy API (docker cp, etc) uid/gid handling #28923

Merged
merged 1 commit into from
Apr 12, 2017
Merged

Fix copy API (docker cp, etc) uid/gid handling #28923

merged 1 commit into from
Apr 12, 2017

Conversation

erikh
Copy link
Contributor

@erikh erikh commented Nov 29, 2016

Closes #21651

- What I did

Adjusted the archiving UID/GID maps to not only consider root. Adjusted tests to appropriately measure permissions as well as the metadata it already carried to better enable testing with permissions crossing the border into/out of a container.

- How I did it

It's a pretty small patch. :D

- How to verify it

This aughta work:

  • docker create --name foo debian
  • touch bar && chown nobody:nogroup bar
  • docker cp bar foo:/bar

Before, these files would be root. After, they should reflect the UID of the files on the host.

- Description for the changelog

Fixed copy protocol and docker cp to appropriately transfer UID/GID to files copied into the container.

@AkihiroSuda
Copy link
Member

For compatibility, probably it should be an option, e.g. docker cp --preserve-permission?
#21651 (comment)

cc @thaJeztah @estesp

@AkihiroSuda
Copy link
Member

windowsRS1 failing with many "not supported by windows" errors

08:12:47 ----------------------------------------------------------------------
08:12:47 FAIL: docker_cli_cp_to_container_test.go:228: DockerSuite.TestCpToCaseA
08:12:47 
08:12:47 docker_cli_cp_to_container_test.go:236:
08:12:47     makeTestContentInDir(c, tmpDir)
08:12:47 docker_cli_cp_utils.go:107:
08:12:47     c.Assert(os.Chown(path, fd.uid, fd.gid), checker.IsNil)
08:12:47 ... value *os.PathError = &os.PathError{Op:"chown", Path:"d:\\CI\\CI-f2356d4\\test-cp-to-case-a949295019\\file1", Err:0x20000082} ("chown d:\\CI\\CI-f2356d4\\test-cp-to-case-a949295019\\file1: not supported by windows")
08:12:47 
08:12:51 
08:12:51 ----------------------------------------------------------------------

@AkihiroSuda AkihiroSuda added the status/failing-ci Indicates that the PR in its current state fails the test suite label Nov 29, 2016
@erikh
Copy link
Contributor Author

erikh commented Nov 29, 2016 via email

@thaJeztah
Copy link
Member

@erikh if it requires a Linux daemon;

https://github.com/docker/docker/blob/master/integration-cli/docker_api_stats_test.go#L262

If it requires the daemon and client to be linux, probably https://github.com/docker/docker/blob/master/integration-cli/docker_api_stats_test.go#L166

However, there are also some test files that are only built/run on Linux/Unix (keep in mind that work is in progress on Solaris support); https://github.com/docker/docker/blob/master/integration-cli/docker_api_stats_unix_test.go#L1

@erikh
Copy link
Contributor Author

erikh commented Nov 29, 2016 via email

@erikh
Copy link
Contributor Author

erikh commented Dec 5, 2016

I'm working on this now, sorry for the delay.

@erikh
Copy link
Contributor Author

erikh commented Dec 5, 2016

The cp tests are passing again on windows. PTAL?

@thaJeztah
Copy link
Member

/cc @jlhawn @estesp

@estesp estesp removed the status/failing-ci Indicates that the PR in its current state fails the test suite label Dec 5, 2016
@estesp
Copy link
Contributor

estesp commented Dec 5, 2016

@thaJeztah do we have a way to force a userns CI run? I know on a recent PR it was mentioned that it wasn't working properly?

@thaJeztah
Copy link
Member

hm, no doesn't seem to work indeed 😢 not sure

@estesp
Copy link
Contributor

estesp commented Dec 8, 2016

FWIW, I ran the full suite myself against a user namespace-enabled daemon and all tests passed, but most importantly:

PASS: docker_cli_cp_to_container_test.go:602: DockerSuite.TestCpToHostWithPermissions   24.939s

Taking 25sec to run the test seems a bit long given the steps don't seem intensive, but it is passing.

Personally I'm fine with design; not sure if this needs more design review or just code review and confirmation on functionality of preserving ownership (which probably was the way it was working before user namespaces were merged in 1.9 experimental)

@tonistiigi
Copy link
Member

That is a documented behavior in https://github.com/docker/docker/blob/master/docs/reference/commandline/cp.md so I'm not sure we can just flip it.

Even if it makes more sense we should probably keep the cli behavior and change the API only.

cc @jlhawn

@jlhawn
Copy link
Contributor

jlhawn commented Dec 8, 2016

That is a documented behavior so I'm not sure we can just flip it.

Ownership is set to the user and primary group at the destination. For example, files copied to a container are created with UID:GID of the root user. Files copied to the local machine are created with the UID:GID of the user which invoked the docker cp command.

Even if it makes more sense we should probably keep the cli behavior and change the API only.

👍

I'm not sure what the project's official process and policy is if we were to change the default behavior, but I think it would be a good idea to do this (preserve permissions) since the stated goal of docker container cp ... is to behave like the utility cp -a which does preserve ownership. Here's the relevant section from the manual for the BSD cp utility:

     -p    Cause cp to preserve the following attributes of each source file
           in the copy: modification time, access time, file flags, file mode,
           user ID, and group ID, as allowed by permissions.  Access Control
           Lists (ACLs) and Extended Attributes (EAs), including resource
           forks, will also be preserved.

           If the user ID and group ID cannot be preserved, no error message
           is displayed and the exit value is not altered.

           If the source file has its set-user-ID bit on and the user ID can-
           not be preserved, the set-user-ID bit is not preserved in the
           copy's permissions.  If the source file has its set-group-ID bit on
           and the group ID cannot be preserved, the set-group-ID bit is not
           preserved in the copy's permissions.  If the source file has both
           its set-user-ID and set-group-ID bits on, and either the user ID or
           group ID cannot be preserved, neither the set-user-ID nor set-
           group-ID bits are preserved in the copy's permissions.

If we do not want to change the current behavior, we could provide a --preserve-ownership, -p flag to the CLI subcommand which defaults to false.

Also, last year, when we added support for extracting an archive into a container, I considered adding a --chown uid[:gid] option but it was too much extra work at the time. This option would be used to specify that you want to recursively set user and group ownership of the copied content to the given uid and gid. You might also argue that chown could be its own separate command ... then you get into debating whether we should have an entire remote filesystem API and we probably don't want to go there.

@thaJeztah
Copy link
Member

Adding -p / --preserve-ownership doesn't sound too bad; at least it guarantees a non-breaking change

@erikh
Copy link
Contributor Author

erikh commented Dec 10, 2016 via email

@thaJeztah
Copy link
Member

This is the less surprising behavior to me (documented or not, broken is broken).

Not saying I disagree, but changing behavior like this has bitten us on multiple occasions, because people start to rely on it (even if it's broken). If we do decide to change the default, we should consider adding a flag / option to restore the current behavior.

@erikh
Copy link
Contributor Author

erikh commented Dec 12, 2016 via email

@Kronos1776
Copy link

Kronos1776 commented Dec 14, 2016

Consider the linux command: chmod --reference={reference_file} {target_file}
This is an established behavior in linux.
The same works on chown and chcon.
The default behavior when a file is created is to use the current user/group/rwx/tag.
This matches the current 'docker cp' behavior very well and with the addition of parameter(s) the behavior can be modified... possibly setting values based on a reference already inside the volume using a flag like --reference={container_file_reference}... and, do we even dare, use a flag like --chown user:group or --chmod 755 on the docker cp? These are very familiar to most of us and would require no additional learning curve.
The permissions issue may eventually grow to encompass all of the permission attributes. ;-)

@thaJeztah
Copy link
Member

We were comparing behavior with a regular cp;

  • cp source target uses permissions of target if target exists, and uses permissions of the current user if the target file doesn't exist
  • cp -a source target uses permissions of source if target exists, and also uses permissions of the current user if the target file doesn't exist

Suggested;

  • use an --inherit-ownership flag (but open to suggestions)
  • if target does not exist, give the file ownership of the container user (instead of root)
  • if target file does exist, give the file ownership of the source file.
  • add another flag (suggestions as well) to force files maintaining ownership of the source files

/cc @cpuguy83

@erikh
Copy link
Contributor Author

erikh commented Dec 15, 2016 via email

@cpuguy83
Copy link
Member

if target file does exist, give the file ownership of the source file.

Wouldn't the new file inherit ownership from the target file?

Is there any justification out there I can read? Mostly just curious.

Open source fire hose.
Probably something like "we want to add this!", "ok, sounds awesome!", "woohoo docker cp is now a thing!"

@erikh
Copy link
Contributor Author

erikh commented Dec 15, 2016 via email

@erikh
Copy link
Contributor Author

erikh commented Dec 15, 2016 via email

@erikh
Copy link
Contributor Author

erikh commented Apr 9, 2017

no idea; if you have any suggestions or clues that'd be great.

@anusha-ragunathan
Copy link
Contributor

@erikh : Use debian:jessie instead of debian in https://github.com/erikh/docker/blob/a52ae4b6491afe07c7a09786ca11c224112ec040/integration-cli/docker_cli_cp_to_container_unix_test.go#L27, so that CI uses the frozen images and not pulling from Hub, which is what was causing the extra time.

@anusha-ragunathan
Copy link
Contributor

I get PASS: docker_cli_cp_to_container_unix_test.go:17: DockerSuite.TestCpToContainerWithPermissions 0.943s once this is done.

@anusha-ragunathan
Copy link
Contributor

anusha-ragunathan commented Apr 11, 2017

That's why the test fails on powerpc and s390 as well. Download frozen images on both arch shows debian:jessie is available.

ppc64le/debian:jessie@sha256:412845f51b6ab662afba71bc7a716e20fdb9b84f185d180d4c7504f8a75c4f91

s390x/debian:jessie@sha256:b74c863400909eff3c5e196cac9bfd1f6333ce47aae6a38398d87d5875da170a

@erikh
Copy link
Contributor Author

erikh commented Apr 11, 2017 via email

This changes the long-standing bug of copy operations not preserving the
UID/GID information after the files arrive to the container.

Signed-off-by: Erik Hollensbe <github@hollensbe.org>
@erikh
Copy link
Contributor Author

erikh commented Apr 12, 2017

Tests are running now, I'll validate later today.

@anusha-ragunathan
Copy link
Contributor

LGTM

Copy link
Contributor

@estesp estesp left a comment

Choose a reason for hiding this comment

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

LGTM

@estesp
Copy link
Contributor

estesp commented Apr 12, 2017

@thaJeztah are there any follow-on doc changes needed for the new -a flag? I know it will automatically get into the help output of docker cp, but wasn't sure if there are other docs that need an update.

@anusha-ragunathan
Copy link
Contributor

Changelog needs update and I've added the label so that it gets tracked.

dnephin pushed a commit to dnephin/docker that referenced this pull request Apr 17, 2017
Fix copy API (`docker cp`, etc) uid/gid handling
dnephin pushed a commit to dnephin/docker that referenced this pull request Apr 17, 2017
Fix copy API (`docker cp`, etc) uid/gid handling
@thaJeztah thaJeztah added this to the 17.06.0 milestone May 11, 2017
@javabrett
Copy link
Contributor

javabrett commented Dec 5, 2017

I'm been doing some work on #34096 and wondered if (other than what is in the updated docs for docker cp -a) whether there is any more detail on the intended behaviour. Something like:

  • docker cp without -a: behaviour should be unchanged - files are copied to the container as root:root ownership.
    • need to check what happens when running with --user
    • need to check impact of --userns
  • docker cp -a should copy verbatim the uid:gid of the local file into the container. The remote uid:gid might not exist.
    • any special handling for --user?
    • any special handling for --userns?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

API PUT archive file ownership root when container running as non-root.