Skip to content
This repository was archived by the owner on Mar 9, 2022. It is now read-only.

[release/1.4] windows: Use GetFinalPathNameByHandle for ResolveSymbolicLink#1636

Merged
fuweid merged 2 commits intocontainerd:release/1.4from
kevpar:1.4-symlink
May 27, 2021
Merged

[release/1.4] windows: Use GetFinalPathNameByHandle for ResolveSymbolicLink#1636
fuweid merged 2 commits intocontainerd:release/1.4from
kevpar:1.4-symlink

Conversation

@kevpar
Copy link
Copy Markdown
Member

@kevpar kevpar commented May 5, 2021

Backport of containerd/containerd#5411 for release/1.4. I also had to update some vendoring to bring in the right dependencies.

This change splits the definition of pkg/cri/os.ResolveSymbolicLink by
platform (windows/!windows), and switches to an alternate implementation
for Windows. This aims to fix the issue described in containerd/containerd#5405.

The previous implementation which just called filepath.EvalSymlinks has
historically had issues on Windows. One of these issues we were able to
fix in Go, but EvalSymlinks's behavior is not well specified on
Windows, and there could easily be more issues in the future, so it
seems prudent to move to a separate implementation for Windows.

The new implementation uses the Windows GetFinalPathNameByHandle API,
which takes a handle to an open file or directory and some flags, and
returns the "real" name for the object. See comments in the code for
details on the implementation.

I have tested this change with a variety of mounts and everything seems
to work as expected. Functions that make incorrect assumptions on what a
Windows path can look like may have some trouble with the \?\ path
syntax. For instance EvalSymlinks fails when given a \?\UNC\ path. For
this reason, the resolvePath implementation modifies the returned path
to translate to the more common form (\?\UNC\server\share ->
\server\share).

Signed-off-by: Kevin Parsons kevpar@microsoft.com

From containerd/containerd@b0d3b35

@kevpar
Copy link
Copy Markdown
Member Author

kevpar commented May 5, 2021

The CI failures look unrelated. Maybe just hitting rate limits on gcr.io? I think it's safe to ignore them.

@estesp
Copy link
Copy Markdown
Member

estesp commented May 5, 2021

@mikebrow looks like release/1.4 doesn't have the magic update to the CRI test image(s) stuff we did on the main branch. Getting the 403 authorization failure on the old image layer. Can you help us figure out which pieces need backported here?

@kevpar
Copy link
Copy Markdown
Member Author

kevpar commented May 13, 2021

@mikebrow any thoughts on what is needed here to help CI?

@mikebrow
Copy link
Copy Markdown
Member

@mikebrow any thoughts on what is needed here to help CI?

@mikebrow looks like release/1.4 doesn't have the magic update to the CRI test image(s) stuff we did on the main branch. Getting the 403 authorization failure on the old image layer. Can you help us figure out which pieces need backported here?

thx almost forgot about this repo :-)

Let's merge this: #1638 brings critest back on-line then you can rebase..

@mikebrow
Copy link
Copy Markdown
Member

kk you should be ok for critest.. after rebase on release/1.4

@mikebrow
Copy link
Copy Markdown
Member

FYI also updated vendor, and cleaned up the node e2e test over here ... #1639 green lights!

@fuweid
Copy link
Copy Markdown
Member

fuweid commented May 14, 2021

@kevpar need rebase here~

Updating with new versions needed to support using GetFinalPathNameByHandle.

Signed-off-by: Kevin Parsons <kevpar@microsoft.com>
@kevpar
Copy link
Copy Markdown
Member Author

kevpar commented May 14, 2021

@mikebrow thank you! I've rebased now.

Copy link
Copy Markdown
Member

@mikebrow mikebrow left a comment

Choose a reason for hiding this comment

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

just a couple nits

@kevpar
Copy link
Copy Markdown
Member Author

kevpar commented May 14, 2021

@mikebrow de-nit'd :)

Copy link
Copy Markdown
Member

@mikebrow mikebrow left a comment

Choose a reason for hiding this comment

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

LGTM
just a new line missing

Copy link
Copy Markdown
Member

@fuweid fuweid 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 comments~

// We could use os.Open if the path is a file, but it's easier to just use the same code for both.
// Therefore, we call windows.CreateFile directly.
func openPath(path string) (windows.Handle, error) {
u16, err := windows.UTF16PtrFromString(path)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Is it possible to use syscall.UTF16PtrFromString? I see stdlib provides the function. https://golang.org/pkg/syscall/?GOOS=windows#UTF16PtrFromString.

GetFinalPathNameByHandle is unavailable in stdlib syscall.

New: func() interface{} {
// Size of buffer chosen somewhat arbitrarily to accommodate a large number of path strings.
// MAX_PATH (260) + size of volume GUID prefix (49) + null terminator = 310.
b := make([]uint16, 310)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggest to add docs here https://docs.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation?tabs=cmd.

Starting in Windows 10, version 1607, MAX_PATH limitations have been removed from common Win32 file and directory functions.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Maybe we can use 4096 :)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Given this is a backport (of containerd/containerd@b0d3b35), my assumption is we shouldn't diverge from what was put into containerd master. For this and the other comments you have left, do you feel these should be addressed here?

Copy link
Copy Markdown
Member

@fuweid fuweid May 27, 2021

Choose a reason for hiding this comment

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

I am fine with current change ~ just think 4096 looks better than 310

// correct size for the call.
func getFinalPathNameByHandle(h windows.Handle, flags uint32) (string, error) {
b := *(pool.Get().(*[]uint16))
defer func() { pool.Put(&b) }()
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The b has been re-allocated. defer should be handled in some condition.

--> in for loop
// If the buffer wasn't large enough, n will be the total size needed (including null terminator).		
// Resize and try again.		
if n > uint32(len(b) {
     b = make([]uint16, n)
     continue		
}

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I'm not sure I understand your comment. Can you clarify what you're asking for?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Sorry for the late reply. A b is from pool.Get so that we should put the b back into the pool.
But the b has been changed when the size of original b is not large enough. In this case, it is not good to put the changed b into the pool.

This change splits the definition of pkg/cri/os.ResolveSymbolicLink by
platform (windows/!windows), and switches to an alternate implementation
for Windows. This aims to fix the issue described in containerd/containerd#5405.

The previous implementation which just called filepath.EvalSymlinks has
historically had issues on Windows. One of these issues we were able to
fix in Go, but EvalSymlinks's behavior is not well specified on
Windows, and there could easily be more issues in the future, so it
seems prudent to move to a separate implementation for Windows.

The new implementation uses the Windows GetFinalPathNameByHandle API,
which takes a handle to an open file or directory and some flags, and
returns the "real" name for the object. See comments in the code for
details on the implementation.

I have tested this change with a variety of mounts and everything seems
to work as expected. Functions that make incorrect assumptions on what a
Windows path can look like may have some trouble with the \\?\ path
syntax. For instance EvalSymlinks fails when given a \\?\UNC\ path. For
this reason, the resolvePath implementation modifies the returned path
to translate to the more common form (\\?\UNC\server\share ->
\\server\share).

Signed-off-by: Kevin Parsons <kevpar@microsoft.com>

From containerd/containerd@b0d3b35
@thaJeztah
Copy link
Copy Markdown
Member

/test pull-cri-containerd-node-e2e

Copy link
Copy Markdown
Member

@fuweid fuweid left a comment

Choose a reason for hiding this comment

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

LGTM

@fuweid fuweid merged commit 4cc8ca2 into containerd:release/1.4 May 27, 2021
@kevpar
Copy link
Copy Markdown
Member Author

kevpar commented May 27, 2021

Thanks @fuweid!

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants