Skip to content

Commit 2394aa1

Browse files
authored
support both cimfs and cimwriter dlls (microsoft#2587)
* support both cimfs and cimwriter dlls The PR introducing `cimwriter.dll` was a breaking change, which is fixed in this PR. Split CIM syscalls into separate packages for `cimfs.dll` and `cimwriter.dll`, with shared types in `internal/winapi/types/`. Add `pickSupported()` to prefer `cimwriter.dll` for write operations and fall back to `cimfs.dll` when `cimwriter.dll` is not present. Mount, dismount, and verification operations always use `cimfs.dll`. Relax `CimFsSupported()` to only require cimfs.dll instead of both DLLs (the breaking change). Signed-off-by: Maksim An <maksiman@microsoft.com> * pr feedback regenerate code Regenerate zsyscall_windows.go files for the new cimfs and cimwriter packages after PR feedback. Signed-off-by: Maksim An <maksiman@microsoft.com> * allow cimwriter.dll outside of system directory and add logging Allow `cimwriter.dll` to be loaded from outside the system directory. Log the resolved DLL path on load using `GetModuleFileName`. Add `LogCimDLLSupport()` to report which DLL is active for write operations, called from `CreateBlockCIMWithOptions` on every block CIM creation. Add `TestMain` in `pkg/cimfs` to print DLL availability in test output. Signed-off-by: Maksim An <maksiman@microsoft.com> * preload cimwriter.dll limiting the dll search paths Limit cimwriter.dll search paths to system32 and app directory and add preload step. Signed-off-by: Maksim An <maksiman@microsoft.com> --------- Signed-off-by: Maksim An <maksiman@microsoft.com>
1 parent 763f059 commit 2394aa1

14 files changed

Lines changed: 1253 additions & 546 deletions

File tree

internal/winapi/cimfs.go

Lines changed: 152 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -3,60 +3,158 @@
33
package winapi
44

55
import (
6-
"unsafe"
7-
86
"github.com/Microsoft/go-winio/pkg/guid"
9-
"golang.org/x/sys/windows"
7+
"github.com/sirupsen/logrus"
8+
9+
"github.com/Microsoft/hcsshim/internal/winapi/cimfs"
10+
"github.com/Microsoft/hcsshim/internal/winapi/cimwriter"
11+
"github.com/Microsoft/hcsshim/internal/winapi/types"
1012
)
1113

12-
type g = guid.GUID
13-
type FsHandle uintptr
14-
type StreamHandle uintptr
15-
16-
type CimFsFileMetadata struct {
17-
Attributes uint32
18-
FileSize int64
19-
20-
CreationTime windows.Filetime
21-
LastWriteTime windows.Filetime
22-
ChangeTime windows.Filetime
23-
LastAccessTime windows.Filetime
24-
25-
SecurityDescriptorBuffer unsafe.Pointer
26-
SecurityDescriptorSize uint32
27-
28-
ReparseDataBuffer unsafe.Pointer
29-
ReparseDataSize uint32
30-
31-
ExtendedAttributes unsafe.Pointer
32-
EACount uint32
33-
}
34-
35-
type CimFsImagePath struct {
36-
ImageDir *uint16
37-
ImageName *uint16
38-
}
39-
40-
//sys CimMountImage(imagePath string, fsName string, flags uint32, volumeID *g) (hr error) = cimfs.CimMountImage?
41-
//sys CimDismountImage(volumeID *g) (hr error) = cimfs.CimDismountImage?
42-
43-
//sys CimCreateImage(imagePath string, oldFSName *uint16, newFSName *uint16, cimFSHandle *FsHandle) (hr error) = cimwriter.CimCreateImage?
44-
//sys CimCreateImage2(imagePath string, flags uint32, oldFSName *uint16, newFSName *uint16, cimFSHandle *FsHandle) (hr error) = cimwriter.CimCreateImage2?
45-
//sys CimCloseImage(cimFSHandle FsHandle) = cimwriter.CimCloseImage?
46-
//sys CimCommitImage(cimFSHandle FsHandle) (hr error) = cimwriter.CimCommitImage?
47-
48-
//sys CimCreateFile(cimFSHandle FsHandle, path string, file *CimFsFileMetadata, cimStreamHandle *StreamHandle) (hr error) = cimwriter.CimCreateFile?
49-
//sys CimCloseStream(cimStreamHandle StreamHandle) (hr error) = cimwriter.CimCloseStream?
50-
//sys CimWriteStream(cimStreamHandle StreamHandle, buffer uintptr, bufferSize uint32) (hr error) = cimwriter.CimWriteStream?
51-
//sys CimDeletePath(cimFSHandle FsHandle, path string) (hr error) = cimwriter.CimDeletePath?
52-
//sys CimCreateHardLink(cimFSHandle FsHandle, newPath string, oldPath string) (hr error) = cimwriter.CimCreateHardLink?
53-
//sys CimCreateAlternateStream(cimFSHandle FsHandle, path string, size uint64, cimStreamHandle *StreamHandle) (hr error) = cimwriter.CimCreateAlternateStream?
54-
//sys CimAddFsToMergedImage(cimFSHandle FsHandle, path string) (hr error) = cimwriter.CimAddFsToMergedImage?
55-
//sys CimAddFsToMergedImage2(cimFSHandle FsHandle, path string, flags uint32) (hr error) = cimwriter.CimAddFsToMergedImage2?
56-
//sys CimMergeMountImage(numCimPaths uint32, backingImagePaths *CimFsImagePath, flags uint32, volumeID *g) (hr error) = cimfs.CimMergeMountImage?
57-
//sys CimTombstoneFile(cimFSHandle FsHandle, path string) (hr error) = cimwriter.CimTombstoneFile?
58-
//sys CimCreateMergeLink(cimFSHandle FsHandle, newPath string, oldPath string) (hr error) = cimwriter.CimCreateMergeLink?
59-
//sys CimSealImage(blockCimPath string, hashSize *uint64, fixedHeaderSize *uint64, hash *byte) (hr error) = cimwriter.CimSealImage?
60-
//sys CimGetVerificationInformation(blockCimPath string, isSealed *uint32, hashSize *uint64, signatureSize *uint64, fixedHeaderSize *uint64, hash *byte, signature *byte) (hr error) = cimfs.CimGetVerificationInformation?
61-
//sys CimMountVerifiedImage(imagePath string, fsName string, flags uint32, volumeID *g, hashSize uint16, hash *byte) (hr error) = cimfs.CimMountVerifiedImage?
62-
//sys CimMergeMountVerifiedImage(numCimPaths uint32, backingImagePaths *CimFsImagePath, flags uint32, volumeID *g, hashSize uint16, hash *byte) (hr error) = cimfs.CimMergeMountVerifiedImage
14+
// LogCimDLLSupport logs which DLL is being used for CIM write operations.
15+
func LogCimDLLSupport() {
16+
if cimwriter.Supported() {
17+
logrus.Info("using cimwriter.dll for CIM write operations")
18+
} else if cimfs.Supported() {
19+
logrus.Info("using cimfs.dll for CIM write operations")
20+
} else {
21+
logrus.Warn("no CIM DLL available for write operations")
22+
}
23+
}
24+
25+
// pickSupported makes sure we use appropriate syscalls depending on which DLLs are present.
26+
func pickSupported[F any](cimWriterFunc, cimfsFunc F) F {
27+
if cimwriter.Supported() {
28+
return cimWriterFunc
29+
}
30+
return cimfsFunc
31+
}
32+
33+
func CimMountImage(imagePath string, fsName string, flags uint32, volumeID *guid.GUID) error {
34+
return cimfs.CimMountImage(imagePath, fsName, flags, volumeID)
35+
}
36+
37+
func CimDismountImage(volumeID *guid.GUID) error {
38+
return cimfs.CimDismountImage(volumeID)
39+
}
40+
41+
func CimCreateImage(imagePath string, oldFSName *uint16, newFSName *uint16, cimFSHandle *types.FsHandle) error {
42+
return pickSupported(
43+
cimwriter.CimCreateImage,
44+
cimfs.CimCreateImage,
45+
)(imagePath, oldFSName, newFSName, cimFSHandle)
46+
}
47+
48+
func CimCreateImage2(imagePath string, flags uint32, oldFSName *uint16, newFSName *uint16, cimFSHandle *types.FsHandle) error {
49+
return pickSupported(
50+
cimwriter.CimCreateImage2,
51+
cimfs.CimCreateImage2,
52+
)(imagePath, flags, oldFSName, newFSName, cimFSHandle)
53+
}
54+
55+
func CimCloseImage(cimFSHandle types.FsHandle) error {
56+
return pickSupported(
57+
cimwriter.CimCloseImage,
58+
cimfs.CimCloseImage,
59+
)(cimFSHandle)
60+
}
61+
62+
func CimCommitImage(cimFSHandle types.FsHandle) error {
63+
return pickSupported(
64+
cimwriter.CimCommitImage,
65+
cimfs.CimCommitImage,
66+
)(cimFSHandle)
67+
}
68+
69+
func CimCreateFile(cimFSHandle types.FsHandle, path string, file *types.CimFsFileMetadata, cimStreamHandle *types.StreamHandle) error {
70+
return pickSupported(
71+
cimwriter.CimCreateFile,
72+
cimfs.CimCreateFile,
73+
)(cimFSHandle, path, file, cimStreamHandle)
74+
}
75+
76+
func CimCloseStream(cimStreamHandle types.StreamHandle) error {
77+
return pickSupported(
78+
cimwriter.CimCloseStream,
79+
cimfs.CimCloseStream,
80+
)(cimStreamHandle)
81+
}
82+
83+
func CimWriteStream(cimStreamHandle types.StreamHandle, buffer uintptr, bufferSize uint32) error {
84+
return pickSupported(
85+
cimwriter.CimWriteStream,
86+
cimfs.CimWriteStream,
87+
)(cimStreamHandle, buffer, bufferSize)
88+
}
89+
90+
func CimDeletePath(cimFSHandle types.FsHandle, path string) error {
91+
return pickSupported(
92+
cimwriter.CimDeletePath,
93+
cimfs.CimDeletePath,
94+
)(cimFSHandle, path)
95+
}
96+
97+
func CimCreateHardLink(cimFSHandle types.FsHandle, newPath string, oldPath string) error {
98+
return pickSupported(
99+
cimwriter.CimCreateHardLink,
100+
cimfs.CimCreateHardLink,
101+
)(cimFSHandle, newPath, oldPath)
102+
}
103+
104+
func CimCreateAlternateStream(cimFSHandle types.FsHandle, path string, size uint64, cimStreamHandle *types.StreamHandle) error {
105+
return pickSupported(
106+
cimwriter.CimCreateAlternateStream,
107+
cimfs.CimCreateAlternateStream,
108+
)(cimFSHandle, path, size, cimStreamHandle)
109+
}
110+
111+
func CimAddFsToMergedImage(cimFSHandle types.FsHandle, path string) error {
112+
return pickSupported(
113+
cimwriter.CimAddFsToMergedImage,
114+
cimfs.CimAddFsToMergedImage,
115+
)(cimFSHandle, path)
116+
}
117+
118+
func CimAddFsToMergedImage2(cimFSHandle types.FsHandle, path string, flags uint32) error {
119+
return pickSupported(
120+
cimwriter.CimAddFsToMergedImage2,
121+
cimfs.CimAddFsToMergedImage2,
122+
)(cimFSHandle, path, flags)
123+
}
124+
125+
func CimMergeMountImage(numCimPaths uint32, backingImagePaths *types.CimFsImagePath, flags uint32, volumeID *guid.GUID) error {
126+
return cimfs.CimMergeMountImage(numCimPaths, backingImagePaths, flags, volumeID)
127+
}
128+
129+
func CimTombstoneFile(cimFSHandle types.FsHandle, path string) error {
130+
return pickSupported(
131+
cimwriter.CimTombstoneFile,
132+
cimfs.CimTombstoneFile,
133+
)(cimFSHandle, path)
134+
}
135+
136+
func CimCreateMergeLink(cimFSHandle types.FsHandle, newPath string, oldPath string) (hr error) {
137+
return pickSupported(
138+
cimwriter.CimCreateMergeLink,
139+
cimfs.CimCreateMergeLink,
140+
)(cimFSHandle, newPath, oldPath)
141+
}
142+
143+
func CimSealImage(blockCimPath string, hashSize *uint64, fixedHeaderSize *uint64, hash *byte) (hr error) {
144+
return pickSupported(
145+
cimwriter.CimSealImage,
146+
cimfs.CimSealImage,
147+
)(blockCimPath, hashSize, fixedHeaderSize, hash)
148+
}
149+
150+
func CimGetVerificationInformation(blockCimPath string, isSealed *uint32, hashSize *uint64, signatureSize *uint64, fixedHeaderSize *uint64, hash *byte, signature *byte) (hr error) {
151+
return cimfs.CimGetVerificationInformation(blockCimPath, isSealed, hashSize, signatureSize, fixedHeaderSize, hash, signature)
152+
}
153+
154+
func CimMountVerifiedImage(imagePath string, fsName string, flags uint32, volumeID *guid.GUID, hashSize uint16, hash *byte) error {
155+
return cimfs.CimMountVerifiedImage(imagePath, fsName, flags, volumeID, hashSize, hash)
156+
}
157+
158+
func CimMergeMountVerifiedImage(numCimPaths uint32, backingImagePaths *types.CimFsImagePath, flags uint32, volumeID *guid.GUID, hashSize uint16, hash *byte) error {
159+
return cimfs.CimMergeMountVerifiedImage(numCimPaths, backingImagePaths, flags, volumeID, hashSize, hash)
160+
}

internal/winapi/cimfs/cimfs.go

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
//go:build windows
2+
3+
package cimfs
4+
5+
import (
6+
"sync"
7+
8+
"github.com/Microsoft/go-winio/pkg/guid"
9+
"github.com/sirupsen/logrus"
10+
"golang.org/x/sys/windows"
11+
12+
"github.com/Microsoft/hcsshim/internal/winapi/types"
13+
)
14+
15+
// Type aliases
16+
17+
type GUID = guid.GUID
18+
type FsHandle = types.FsHandle
19+
type StreamHandle = types.StreamHandle
20+
type FileMetadata = types.CimFsFileMetadata
21+
type ImagePath = types.CimFsImagePath
22+
23+
//sys CimMountImage(imagePath string, fsName string, flags uint32, volumeID *GUID) (hr error) = cimfs.CimMountImage?
24+
//sys CimDismountImage(volumeID *GUID) (hr error) = cimfs.CimDismountImage?
25+
26+
//sys CimCreateImage(imagePath string, oldFSName *uint16, newFSName *uint16, cimFSHandle *FsHandle) (hr error) = cimfs.CimCreateImage?
27+
//sys CimCreateImage2(imagePath string, flags uint32, oldFSName *uint16, newFSName *uint16, cimFSHandle *FsHandle) (hr error) = cimfs.CimCreateImage2?
28+
//sys CimCloseImage(cimFSHandle FsHandle) = cimfs.CimCloseImage?
29+
//sys CimCommitImage(cimFSHandle FsHandle) (hr error) = cimfs.CimCommitImage?
30+
31+
//sys CimCreateFile(cimFSHandle FsHandle, path string, file *FileMetadata, cimStreamHandle *StreamHandle) (hr error) = cimfs.CimCreateFile?
32+
//sys CimCloseStream(cimStreamHandle StreamHandle) (hr error) = cimfs.CimCloseStream?
33+
//sys CimWriteStream(cimStreamHandle StreamHandle, buffer uintptr, bufferSize uint32) (hr error) = cimfs.CimWriteStream?
34+
//sys CimDeletePath(cimFSHandle FsHandle, path string) (hr error) = cimfs.CimDeletePath?
35+
//sys CimCreateHardLink(cimFSHandle FsHandle, newPath string, oldPath string) (hr error) = cimfs.CimCreateHardLink?
36+
//sys CimCreateAlternateStream(cimFSHandle FsHandle, path string, size uint64, cimStreamHandle *StreamHandle) (hr error) = cimfs.CimCreateAlternateStream?
37+
//sys CimAddFsToMergedImage(cimFSHandle FsHandle, path string) (hr error) = cimfs.CimAddFsToMergedImage?
38+
//sys CimAddFsToMergedImage2(cimFSHandle FsHandle, path string, flags uint32) (hr error) = cimfs.CimAddFsToMergedImage2?
39+
//sys CimMergeMountImage(numCimPaths uint32, backingImagePaths *ImagePath, flags uint32, volumeID *GUID) (hr error) = cimfs.CimMergeMountImage?
40+
//sys CimTombstoneFile(cimFSHandle FsHandle, path string) (hr error) = cimfs.CimTombstoneFile?
41+
//sys CimCreateMergeLink(cimFSHandle FsHandle, newPath string, oldPath string) (hr error) = cimfs.CimCreateMergeLink?
42+
//sys CimSealImage(blockCimPath string, hashSize *uint64, fixedHeaderSize *uint64, hash *byte) (hr error) = cimfs.CimSealImage?
43+
//sys CimGetVerificationInformation(blockCimPath string, isSealed *uint32, hashSize *uint64, signatureSize *uint64, fixedHeaderSize *uint64, hash *byte, signature *byte) (hr error) = cimfs.CimGetVerificationInformation?
44+
//sys CimMountVerifiedImage(imagePath string, fsName string, flags uint32, volumeID *GUID, hashSize uint16, hash *byte) (hr error) = cimfs.CimMountVerifiedImage?
45+
//sys CimMergeMountVerifiedImage(numCimPaths uint32, backingImagePaths *ImagePath, flags uint32, volumeID *GUID, hashSize uint16, hash *byte) (hr error) = cimfs.CimMergeMountVerifiedImage?
46+
47+
var load = sync.OnceValue(func() error {
48+
if err := modcimfs.Load(); err != nil {
49+
return err
50+
}
51+
var buf [windows.MAX_PATH]uint16
52+
n, _ := windows.GetModuleFileName(windows.Handle(modcimfs.Handle()), &buf[0], uint32(len(buf)))
53+
if n > 0 {
54+
logrus.WithField("path", windows.UTF16ToString(buf[:n])).Info("loaded cimfs.dll")
55+
}
56+
return nil
57+
})
58+
59+
// Supported checks if cimfs.dll is present on the system.
60+
func Supported() bool {
61+
return load() == nil
62+
}

internal/winapi/cimfs/syscall.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
package cimfs
2+
3+
//go:generate go tool github.com/Microsoft/go-winio/tools/mkwinsyscall -output zsyscall_windows.go ./*.go

0 commit comments

Comments
 (0)