Skip to content

Multi stage builds cleanup for Windows#32084

Merged
vdemeester merged 1 commit intomoby:masterfrom
simonferquel:multi-stage-builds-windows
Apr 10, 2017
Merged

Multi stage builds cleanup for Windows#32084
vdemeester merged 1 commit intomoby:masterfrom
simonferquel:multi-stage-builds-windows

Conversation

@simonferquel
Copy link
Contributor

This PR improves Windows experience about multi-staged builds.
It fixes #32057

- What I did

  • Added tests for the forbidden paths rules (today, avoid copying from c:\ / c:\windows and from any relative path that might resolve to c:\ or c:\windows)
  • Fixed the forbidden paths detection
  • Added tests ensuring paths are case insensitive on Windows (both for forbidden path matches, and for actually copying a file)

- How I did it

Most of the work is in the form of cli integration tests, forbidden paths rules are in builder/dockerfile/internals.go.

- How to verify it

Already verified by integration tests

- Description for the changelog

Should be part of the multi-staged build change log. Might be usefull to indicate that sources paths on Windows are case insensitive and must be "drive-qualified" (and cannot be c:\ nor c:\windows

@simonferquel
Copy link
Contributor Author

cc @tonistiigi

@jhowardmsft, c:\ and c:\windows are obvious blacklisted paths, but I suspect there can be other files we should not try to copy from on Windows. I suppose that with Hyper-v isolation there must be a swap file somewhere and IIRC, I think it is a system file at the root of file system. Do you know what it is called ? Have you other suggestions for system file blacklisting ?

@AkihiroSuda AkihiroSuda added the status/failing-ci Indicates that the PR in its current state fails the test suite label Mar 24, 2017
@tonistiigi
Copy link
Member

@simonferquel I think should allow the same syntax that regular COPY without --from allows and only restrict specific values. Otherwise, it becomes complicated for the user and COPY doesn't look like a consistent command.

@simonferquel
Copy link
Contributor Author

I just changed that. the restriction list for now is:

  • .
  • ..
  • windows
  • /windows
  • c:/
  • c:
  • c:/windows

That makes it easier for the users, and for us to write common tests between windows and linux engines

@lowenna
Copy link
Member

lowenna commented Mar 24, 2017

I don't understand what this test is about ☹️ Can you explain?

There are some obvious things though - it should be using Execution.MinimalBaseImage rather than hard-coding an image name.

Also why is this hard coding c:? Are those container or host paths?

@simonferquel
Copy link
Contributor Author

@jhowardmsft this tests are in the context of multi-stage builds #31257 (where you can build stuff from a build image, extract them and put them in a runtime image).

The problem, is that if we allow these copy to get the whole image data from the build image, some files appear to be locked and that fails (and currently even seem to hang somewhere). So we want to establish a blacklist of stuff we don't allow to copy from a windows image (for now c:\ and c:\windows are forbidden, as well as relative paths that could resolve to those forbidden paths). The 2 first tests cover this blacklist, the 3rd one ensures that on Windows the COPY --from=context <source> <dest> construct is case insensitive.

I used nanoserver instead of MinimalBaseImage because for now MinimalBaseImage is based on Windows Server Core.

@simonferquel simonferquel force-pushed the multi-stage-builds-windows branch from 009c3e5 to f0a5c5f Compare March 24, 2017 18:03
@lowenna
Copy link
Member

lowenna commented Mar 24, 2017

@simonferquel OK, I'm going to have to look at multi-stage build when I get a chance. Haven't looked at it at all.

However, please switch to MinimalBaseImage and not hard-code a name. That's why it's there and is very deliberate.

@simonferquel
Copy link
Contributor Author

done

Copy link
Member

@vdemeester vdemeester left a comment

Choose a reason for hiding this comment

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

LGTM 🐯

@simonferquel simonferquel force-pushed the multi-stage-builds-windows branch from 755c548 to 7141824 Compare March 31, 2017 08:45
Copy link
Member

@dnephin dnephin left a comment

Choose a reason for hiding this comment

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

LGTM

@tonistiigi
Copy link
Member

@jhowardmsft @johnstep Could one of you review as well? I'm not sure how we handle the c: case or if it is supported at all. Didn't spot where we clean it up before path.join.

@thaJeztah thaJeztah removed the status/failing-ci Indicates that the PR in its current state fails the test suite label Apr 2, 2017
Copy link
Member

@thaJeztah thaJeztah left a comment

Choose a reason for hiding this comment

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

left some questions

Copy link
Member

Choose a reason for hiding this comment

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

Does WORKDIR affect the "base" path?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

For now it is not. We should document COPY --from in this way

Copy link
Member

Choose a reason for hiding this comment

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

For comparing; would it be better to use filepath.Abs(origPath)?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

What does "Abs" exactly, does it depend on WORKDIR ?

Copy link
Member

Choose a reason for hiding this comment

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

This looks messy. Perhaps better to define a "blacklist" slice blacklist := []string{".", "..", ....}, and iterate?

Copy link
Member

Choose a reason for hiding this comment

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

Maybe this instead of iterating:

switch p {
case ".", "..", "\\", "\\windows", "windows", "c:", "c:.", "c:\\", "c:\\windows", "c:\\windows\\":
    return nil, errors.Errorf("copy from %q is not allowed on windows", p)
}

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 like the blacklist idea, it would be much easier to modify

Copy link
Member

Choose a reason for hiding this comment

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

Do we want to blacklist exactly c:\windows\ or also, e.g. c:\windows\system32? If the latter, we should match on prefix (or another way to check if p is inside "forbiddenpath".

What about symlinks?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We might want to have a more precise blacklist. I know that I dont want c:\windows to be completely copied (it might fail on some system files anyway), I also know that some files at FS root should not be copied as well, I am not sure about system32 though. We might want to allow to copy some dlls from there. The idea of this PR is to help the user avoid to do obvious WRONG things (like copying the 4GB of Windows Server Core) on Windows.

@thaJeztah
Copy link
Member

Also, could you squash your commits?

@vdemeester vdemeester requested review from johnstep and lowenna April 2, 2017 10:32
@simonferquel simonferquel force-pushed the multi-stage-builds-windows branch from 7141824 to 9524a60 Compare April 7, 2017 12:32
@simonferquel
Copy link
Contributor Author

@thaJeztah I squashed and I changed the path analysis to use a blacklist with only absolute paths, and a logic that reconstructs the absolute path assuming WORKDIR is c:\ (which is the case on COPY --from)

@simonferquel simonferquel force-pushed the multi-stage-builds-windows branch from 9524a60 to f530ee8 Compare April 7, 2017 12:37
Copy link
Member

@thaJeztah thaJeztah left a comment

Choose a reason for hiding this comment

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

Left some thoughts, but possibly someone else could have a look if they make sense 😅

Copy link
Member

Choose a reason for hiding this comment

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

perhaps

windowsBlacklist := []string{ "c:\\", "c:\\windows" }

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'll go with the map solution to avoid looping (might become annoying if we put many system paths in the blacklist)

Copy link
Member

Choose a reason for hiding this comment

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

Not on a Windows machine, but instead of manually making this path absolute, would this work?

p := strings.ToLower(filepath.Abs(origPath))
for _, forbidden := range windowsBlacklist {
if p == forbidden {
	return nil, errors.New("copy from c:\\ or c:\\windows is not allowed on windows")
}

To prevent the loop, perhaps;

windowsBlacklist := map[string]interface{}{
  "c:\\" : true,
  "c:\\windows" : true,
}

if _, ok := windowsBlacklist[p]; ok {
	return nil, errors.New("copy from "+p+" is not allowed on windows")
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done
Problem of filepath.Abs is that it works relative to the current process workdir. This is not what we want (we know the path is relative to the context's "c:")

Copy link
Member

Choose a reason for hiding this comment

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

These checks are no longer needed?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It is not anymore (the blacklist replaces it)

Paths resolving to c:\ or c:\windows are forbidden

Replaced the obscure (and non-working) regex with a simple case
insensitive comparison to the black listed paths (we should forbid c:\,
c:\windows but not d:\)

Also, add a test ensuring paths are case insensitive on windows

Also, made sure existing multi-staged build tests pass on windows

Signed-off-by: Simon Ferquel <[email protected]>
Copy link
Member

@thaJeztah thaJeztah 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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

tests: multi stage builds needs more tests for windows

8 participants