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

archive: skip chmod IsNotExist error #4099

Merged
merged 1 commit into from
Mar 23, 2020
Merged

Conversation

mythi
Copy link
Contributor

@mythi mythi commented Mar 10, 2020

handleLChmod() does not properly check that files behind the handlinks exist
before calling os.Chmod(). We've seen base images where this results in
"no such file or directory" error from os.Chmod() when unpacking the image.

os.Stat() follows symlinks and tells us if the destination file exists.
Use that as the pre-check before os.Chmod() to avoid errors.

The failing case for me was:
sudo ctr i pull docker.io/library/clearlinux:base

@theopenlab-ci
Copy link

theopenlab-ci bot commented Mar 10, 2020

Build succeeded.

@@ -124,7 +124,7 @@ func handleTarTypeBlockCharFifo(hdr *tar.Header, path string) error {

func handleLChmod(hdr *tar.Header, path string, hdrInfo os.FileInfo) error {
if hdr.Typeflag == tar.TypeLink {
if fi, err := os.Lstat(hdr.Linkname); err == nil && (fi.Mode()&os.ModeSymlink == 0) {
if _, err := os.Stat(path); os.IsExist(err) {
Copy link
Member

Choose a reason for hiding this comment

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

Can you clarify os.IsExists(err) part? When file exists, os.Stat returns nil error, right?

Copy link
Member

Choose a reason for hiding this comment

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

If os.Chmod() changes the mode of the target, wouldn't this be the same as skipping the whole if hdr.Typeflag ..., and unconditionally doing;

if err := os.Chmod(path, hdrInfo.Mode()); err != nil && !os.IsNotExist(err) {
	return err
}

Was the intent here to set the mode of the link itself (and not the target?)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Was the intent here to set the mode of the link itself (and not the target?)

What the original code tried to do is not clear (the commit message that added it does not give any reasoning). The original code checks that if tar headers say the file is hardlink and the target is not a symlink then os.Chmod().

My patch follows that but adds a check that the file exists before os.Chmod() for it. AFAICS,

if err := os.Chmod(path, hdrInfo.Mode()); err != nil && !os.IsNotExist(err) {
	return err
}

would also work.

Copy link
Member

Choose a reason for hiding this comment

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

Did some quick digging to find out what this code was intended to do. Haven't looked deeply yet, but looking for the history of it:

The code looks to be copied from https://github.com/moby/moby, where this function was extracted to a function (accounting for windows) in moby/moby@8228ee4.

The original code for this was added in moby/moby@ab181ce, which was this PR: moby/moby#11099, and was created to fix moby/moby#10937

Copy link
Member

Choose a reason for hiding this comment

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

OK, so IIUC, the code was for situations where the hardlink is pointing to a symlink, which links to something that was not yet extracted from the tar archive. (which (again, IIUC) can cause issues in a situation where the hardlink/symlink is received before the final target is received from the tar stream?

I'm not too familiar with this stuff, but looks like we need to tread with care, and be sure this doesn't cause a regression.

At least looks like;

  • we need to add proper comments to this code to explain what it's doing
  • if fixes are needed, please also open a pull request in the https://github.com/moby/moby repository to have the same fix there 🤗

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@thaJeztah btw, can you confirm the failure on your side?

sudo ctr i pull docker.io/library/clearlinux:base

Copy link
Contributor

Choose a reason for hiding this comment

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

How come the change from os.Lstat() to os.Stat()? If you are concerned with chmod'ing things, if it is a symlink (how this could even be the case, i'm not sure) then you'll need the information of the link itself. Stat will just give the information on the underlying inode which would be the hardlink you're targeting. Either may need to be chmod'ed.
I think the behaviour you're seeking would not be to edit this case, but add another that checks for the presence of the underlying file.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think the behaviour you're seeking would not be to edit this case, but add another that checks for the presence of the underlying file.

Yes, so as @thaJeztah also suggested,

if err := os.Chmod(path, hdrInfo.Mode()); err != nil && !os.IsNotExist(err) {
	return err
}

Copy link
Contributor

Choose a reason for hiding this comment

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

ah right

Copy link
Contributor Author

Choose a reason for hiding this comment

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

but let me comment still on:

How come the change from os.Lstat() to os.Stat()

os.Lstat() does not follow symlinks which is what os.Chmod() does so currently there's a race that a missing file can get unnoticed... that is why I suggested to move to os.Stat().

anyway, I'll submit an update to have it as suggested above.

handleLChmod() does not properly check that files behind the handlinks exist
before calling os.Chmod(). We've seen base images where this results in
"no such file or directory" error from os.Chmod() when unpacking the image.

To keep the existing logic but fix the problem, this commit simply skips
IsNotExist error.

Signed-off-by: Mikko Ylinen <mikko.ylinen@intel.com>
@mythi mythi changed the title archive: make sure target file exists before chmod for hardlinks archive: skip chmod IsNotExist error Mar 23, 2020
@mythi
Copy link
Contributor Author

mythi commented Mar 23, 2020

v2: updated the commit to simply just skip chmod IsNotExist error.

@theopenlab-ci
Copy link

theopenlab-ci bot commented Mar 23, 2020

Build succeeded.

@codecov-io
Copy link

codecov-io commented Mar 23, 2020

Codecov Report

Merging #4099 into master will increase coverage by 3.33%.
The diff coverage is 0.00%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #4099      +/-   ##
==========================================
+ Coverage   42.43%   45.76%   +3.33%     
==========================================
  Files         129      116      -13     
  Lines       14875    11935    -2940     
==========================================
- Hits         6312     5462     -850     
+ Misses       7644     5555    -2089     
+ Partials      919      918       -1     
Flag Coverage Δ
#linux 45.76% <0.00%> (ø)
#windows ?
Impacted Files Coverage Δ
archive/tar_unix.go 43.56% <0.00%> (ø)
remotes/docker/fetcher.go 54.11% <0.00%> (-5.41%) ⬇️
remotes/docker/auth.go 63.82% <0.00%> (-3.97%) ⬇️
remotes/docker/status.go 21.42% <0.00%> (-3.58%) ⬇️
remotes/docker/errdesc.go 28.12% <0.00%> (-2.65%) ⬇️
remotes/docker/errcode.go 47.61% <0.00%> (-1.60%) ⬇️
filters/scanner.go 81.35% <0.00%> (-0.85%) ⬇️
platforms/platforms.go 79.41% <0.00%> (-0.81%) ⬇️
platforms/cpuinfo.go 3.57% <0.00%> (-0.72%) ⬇️
remotes/docker/handler.go 22.38% <0.00%> (-0.09%) ⬇️
... and 75 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 2899cb2...e2269f2. Read the comment docs.

@crosbymichael
Copy link
Member

LGTM

1 similar comment
@vbatts
Copy link
Contributor

vbatts commented Mar 23, 2020

LGTM

Copy link
Member

@mxpv mxpv left a comment

Choose a reason for hiding this comment

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

LGTM

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.

6 participants