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: acquire privileges to access special files on windows #4994

Merged
merged 1 commit into from
Jun 27, 2024

Conversation

profnandaa
Copy link
Collaborator

@profnandaa profnandaa commented Jun 4, 2024

fixes #4985

Windows has some special / metadata files that need special privileges to access, even if the process is running as Admin.
Some of those files (across nanoserver and servercore) currently are:

\\Program Files\\Windows Defender Advanced Threat Protection\\Classification\\Configuration
\\ProgramData\\Microsoft\\Windows Defender Advanced Threat Protection\\Cache
\\ProgramData\\Microsoft\\Windows Defender Advanced Threat Protection\\Cyber
\\ProgramData\\Microsoft\\Windows Defender Advanced Threat Protection\\DLP
\\ProgramData\\Microsoft\\Windows Defender Advanced Threat Protection\\DataCollection
\\ProgramData\\Microsoft\\Windows Defender Advanced Threat Protection\\Downloads
\\ProgramData\\Microsoft\\Windows Defender Advanced Threat Protection\\Platform
\\ProgramData\\Microsoft\\Windows Defender Advanced Threat Protection\\SenseCM
\\ProgramData\\Microsoft\\Windows Defender Advanced Threat Protection\\SenseNDR
\\ProgramData\\Microsoft\\Windows Defender Advanced Threat Protection\\Temp\\PSScriptOutputs
\\ProgramData\\Microsoft\\Windows Defender Advanced Threat Protection\\Trace
\\System Volume Information
\\WcSandboxState
\\Windows\\System32\\LogFiles\\WMI\\RtBackup
\\Windows\Globalization\\ICU\\icudtl.dat

Additionally, we have directories that don't need to be exported, I have separated that work in a separate issue here #5011

Also, I'm currently working on enabling the skipped integration tests on Windows, and most of them are using local exporter, therefore will be depending on this change e.g.:

_, err = f.Solve(sb.Context(), c, client.SolveOpt{
Exports: []client.ExportEntry{
{
Type: client.ExporterLocal,
OutputDir: destDir,
},
},
LocalMounts: map[string]fsutil.FS{
dockerui.DefaultLocalNameDockerfile: dir,
dockerui.DefaultLocalNameContext: dir,
},
}, nil)

--

Sample Test

buildctl build `
--frontend=dockerfile.v0 `
--local context=C:\dev\play\dockerfiles\export_local `
--local dockerfile=C:\dev\play\dockerfiles\export_local `
--output type=tar,dest=C:\dev\tmp\exp-2.tar `
--progress plain --no-cache

Before:

#7 exporting to client tarball
#7 sending tarball
#7 sending tarball 0.1s done
#7 ERROR: open C:\Users\nandaa\AppData\Local\Temp\buildkit-mount91402518\System Volume Information: Access is denied.

After fix:

#7 exporting to client tarball
#7 sending tarball
#7 sending tarball 30.6s done
#7 DONE 32.1s

@profnandaa
Copy link
Collaborator Author

Ref: #4837 (comment)

@gabriel-samfira
Copy link
Collaborator

There might be files you forgot to commit, as I don't see where the list of files you mentioned are excluded.

As for the windows specific privilege escalation, I would only apply it in the local exporter:

eg.Go(export(ctx, p.ID, r, inp.Attestations[p.ID]))
}
} else {
eg.Go(export(ctx, "", inp.Ref, nil))

There is no need to do that in fsutil. The functions in fsutil may be used in multiple situations and I don't think all those situations will require escalated privileges.

@profnandaa profnandaa force-pushed the fix-windows-local-export-2 branch 4 times, most recently from dadc834 to a465895 Compare June 7, 2024 07:46
// TODO: [discussion] wrapping this from the caller's side in buildkit
// at the last point at session/filesync/diffcopy.go:25
// had no effect. Suspect is to do with the goroutines.
return winio.RunWithPrivileges([]string{winio.SeBackupPrivilege}, func() error {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

@gabriel-samfira -- so, I did manage to do for type=tar but for local, wrapping session/filesync/diffcopy.go:25 block didn't have any effect. Even tried separating out fsutil.Send(stream.Context(), stream, fs, progress) alone, same.

Might you have any pointers? My hunch is that it's because the call breaks into goroutines and escapes the privilege binding?

return errors.WithStack(fsutil.Send(stream.Context(), stream, fs, progress))

I agree, would have been nice not to touch fsutil.

Copy link
Collaborator

Choose a reason for hiding this comment

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

My hunch is that it's because the call breaks into goroutines and escapes the privilege binding?

I think that's indeed what's happening. The RunWithPrivileges function locks the current thread for just the function that is about to run, then escalates privileges. At the end it releases the thread and restores previous privileges.

If the execution happens in another thread, that thread won't have the same privileges.

One more heavy handed way to do this is to try to escalate privileges process-wide using:

https://github.com/microsoft/go-winio/blob/bdc6c112805ce13d7b235dc6257f258d958f5471/privilege.go#L108

something like

winio.EnableProcessPrivileges([]string{winio.SeBackupPrivilege})
defer winio.DisableProcessPrivileges([]string{winio.SeBackupPrivilege})

// do the thing

Enabling process wide privileges is not ideal if it's being done in multiple places of the code base. There is a chance (I am not vastly familiar with internals) that if you revoke the privilege once you are done in a defer, you may remove the privilege, while it's needed by some other go routine somewhere else in the code.

There is one other place that EnableProcessPrivilege is used in fsutil, here:

https://github.com/tonistiigi/fsutil/blob/91a3fc46842c58b62dd4630b688662842364da49/copy/copy_windows.go#L62-L74

That can actually be converted to RunWithPrivileges as it only sets the security descriptor on a file and can run in the same thread. But my point is that enabling/disabling privileges process wide needs to be done carefully. And we need to be aware of the potential hard to debug scenarios when something fails intermittently without obvious reason.

Adding this to fsutil might make sense, but it feels equally heavy handed to require elevated privileges for every Walk(), even when it's called for paths that we should have access to normally. The fsutil package is generic. The case we're trying to address here is specific to the particular need we have here.

@tonistiigi what are your thoughts here?

Copy link
Collaborator Author

@profnandaa profnandaa Jun 7, 2024

Choose a reason for hiding this comment

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

Thanks for that. Sure, I agree we need caution for process-wide escalation.

// at the last point at session/filesync/diffcopy.go:25
// had no effect. Suspect is to do with the goroutines.
return winio.RunWithPrivileges([]string{winio.SeBackupPrivilege}, func() error {
return s.walk(ctx)
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Then as for the file skipping, also this needed to be at the place walking is happening, which is in fsutil; I though of leaving that out so not to pollute the fsutil too much?

Right now those metadata files are being exported which I think it's okay, to have the end user deal with the files as they so wish?

    Directory: C:\dev\tmp\sample-1

Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
d----            5/8/2021  9:43 AM                ProgramData
d----           5/31/2024  4:36 PM                System Volume Information <----
d----           5/10/2024 11:17 PM                Users
d----            6/7/2024 10:44 AM                WcSandboxState <----
d----           5/10/2024 11:17 PM                Windows
-a---            6/6/2024 12:44 PM             97 hello.txt
-a---           5/10/2024 11:14 PM           5647 License.txt

Copy link
Collaborator

@gabriel-samfira gabriel-samfira Jun 7, 2024

Choose a reason for hiding this comment

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

The WcSandboxState should be skipped. It gets created by the host OS when mounting layers. It is of no use to users.

It may be worth asking the server team about this.

Copy link
Collaborator Author

@profnandaa profnandaa Jun 7, 2024

Choose a reason for hiding this comment

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

Sure, I can add that the exclusion, the team was okay with skipping that, was listed among what's skipped in their layer exports:

"\\System Volume Information",
"\\ProgramData\\Microsoft\\Diagnosis",
"\\WcSandboxState",

Do you suggest adding that in the fsutil side or sending it from the caller?

Copy link
Collaborator

Choose a reason for hiding this comment

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

sending it from the caller makes more sense. If fsutil allows setting an exclusion list, that would be great.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

opened a separate issue for that here #5011

Copy link

@billywr billywr left a comment

Choose a reason for hiding this comment

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

recalling my approval, I didn't notice PR is still in draft mode....

@profnandaa profnandaa force-pushed the fix-windows-local-export-2 branch 4 times, most recently from 2a25c5b to 8ab986d Compare June 10, 2024 12:27
@profnandaa profnandaa force-pushed the fix-windows-local-export-2 branch from 8ab986d to 7ae3211 Compare June 10, 2024 14:07
TODO: need to cross-check that there is no way the
SeBackupPrivilege can be abused/exploited.

WIP: how best to handle the files to be exclused
without touching `fsutil`

Signed-off-by: Anthony Nandaa <profnandaa@gmail.com>
@profnandaa profnandaa force-pushed the fix-windows-local-export-2 branch from 7ae3211 to e7ceb63 Compare June 10, 2024 14:24
@profnandaa profnandaa changed the title RFC: acquire privileges to access special files on windows fix: acquire privileges to access special files on windows Jun 11, 2024
@profnandaa profnandaa marked this pull request as ready for review June 11, 2024 10:15
@profnandaa
Copy link
Collaborator Author

@gabriel-samfira @tonistiigi PTAL, also updated the PR description.

profnandaa added a commit to profnandaa/buildkit that referenced this pull request Jun 12, 2024
Depends on moby#4994
Partial fix for moby#4485

Tests covered so far:

- [x] `/frontend/dockerfile: testEnvEmptyFormatting`
- [x] `/frontend/dockerfile: testDockerignoreOverride`
- [x] `/frontend/dockerfile: caseEmptyDestDir`

Signed-off-by: Anthony Nandaa (from Dev Box) <profnandaa@gmail.com>
@thompson-shaun thompson-shaun added this to the v0.future milestone Jun 13, 2024
profnandaa added a commit to profnandaa/buildkit that referenced this pull request Jun 13, 2024
Depends on moby#4994
Partial fix for moby#4485

Starting off with this one as a POC on the approach, before we
proceed to complete the rest under `/frontend/dockerfile`.

Tests covered so far:

- [x] `/frontend/dockerfile: testEnvEmptyFormatting`
- [x] `/frontend/dockerfile: testDockerignoreOverride`
- [x] `/frontend/dockerfile: caseEmptyDestDir`

Signed-off-by: Anthony Nandaa (from Dev Box) <profnandaa@gmail.com>
profnandaa added a commit to profnandaa/buildkit that referenced this pull request Jun 13, 2024
profnandaa added a commit to profnandaa/buildkit that referenced this pull request Jun 13, 2024
Depends on moby#4994
Partial fix for moby#4485

Starting off with this one as a POC on the approach, before we
proceed to complete the rest under `/frontend/dockerfile`.

Tests covered so far:

- [x] `/frontend/dockerfile: testEnvEmptyFormatting`
- [x] `/frontend/dockerfile: testDockerignoreOverride`
- [x] `/frontend/dockerfile: caseEmptyDestDir`

Signed-off-by: Anthony Nandaa <profnandaa@gmail.com>
Copy link
Collaborator

@gabriel-samfira gabriel-samfira left a comment

Choose a reason for hiding this comment

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

With the caveat that I already mentioned, this looks ok.

@tonistiigi tonistiigi merged commit 1ebbf43 into moby:master Jun 27, 2024
75 checks passed
@profnandaa profnandaa deleted the fix-windows-local-export-2 branch June 28, 2024 07:46
@profnandaa profnandaa modified the milestones: v0.future, v0.14.2 Jun 28, 2024
@profnandaa
Copy link
Collaborator Author

@tonistiigi @thompson-shaun -- moved it to milestone v0.14.2, hope that's ok?

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.

WCOW: local and tar exporters on Windows failing with error: "Access is denied."
5 participants