@@ -21,6 +21,7 @@ package subpath
21
21
import (
22
22
"fmt"
23
23
"os"
24
+ "os/exec"
24
25
"path/filepath"
25
26
"strings"
26
27
"syscall"
@@ -43,18 +44,45 @@ func NewNSEnter(mounter mount.Interface, ne *nsenter.Nsenter, rootDir string) In
43
44
return nil
44
45
}
45
46
47
+ // evalPath returns the path name after the evaluation of any symbolic links.
48
+ // If the path after evaluation starts with Volume or \??\Volume, it means that it was a symlink from
49
+ // volume (represented by volumeID) to the given path. In this case, the given path is returned.
50
+ func evalPath (path string ) (linkedPath string , err error ) {
51
+ cmd := fmt .Sprintf ("Get-Item -Path %s | Select-Object -ExpandProperty Target" , path )
52
+ output , err := exec .Command ("powershell" , "/c" , cmd ).CombinedOutput ()
53
+ klog .V (4 ).Infof ("evaluate symlink from %s: %s %v" , path , string (output ), err )
54
+ if err != nil {
55
+ return "" , err
56
+ }
57
+ linkedPath = strings .TrimSpace (string (output ))
58
+ if isVolumePrefix (linkedPath ) {
59
+ return path , err
60
+ }
61
+ return linkedPath , err
62
+ }
63
+
64
+ // isVolumePrefix returns true if the given path name starts with "Volume" or volume prefix including
65
+ // "\\.\" or "\\?\". Otherwise, it returns false.
66
+ func isVolumePrefix (path string ) bool {
67
+ if strings .HasPrefix (path , "Volume" ) || strings .HasPrefix (path , "\\ \\ ?\\ " ) || strings .HasPrefix (path , "\\ \\ .\\ " ) {
68
+ return true
69
+ }
70
+ return false
71
+ }
72
+
46
73
// check whether hostPath is within volume path
47
74
// this func will lock all intermediate subpath directories, need to close handle outside of this func after container started
48
75
func lockAndCheckSubPath (volumePath , hostPath string ) ([]uintptr , error ) {
49
76
if len (volumePath ) == 0 || len (hostPath ) == 0 {
50
77
return []uintptr {}, nil
51
78
}
52
79
53
- finalSubPath , err := filepath . EvalSymlinks (hostPath )
80
+ finalSubPath , err := evalPath (hostPath )
54
81
if err != nil {
55
- return []uintptr {}, fmt .Errorf ("cannot read link %s: %s" , hostPath , err )
82
+ return []uintptr {}, fmt .Errorf ("cannot evaluate link %s: %s" , hostPath , err )
56
83
}
57
- finalVolumePath , err := filepath .EvalSymlinks (volumePath )
84
+
85
+ finalVolumePath , err := evalPath (volumePath )
58
86
if err != nil {
59
87
return []uintptr {}, fmt .Errorf ("cannot read link %s: %s" , volumePath , err )
60
88
}
@@ -162,7 +190,7 @@ func (sp *subpath) CleanSubPaths(podDir string, volumeName string) error {
162
190
163
191
// SafeMakeDir makes sure that the created directory does not escape given base directory mis-using symlinks.
164
192
func (sp * subpath ) SafeMakeDir (subdir string , base string , perm os.FileMode ) error {
165
- realBase , err := filepath . EvalSymlinks (base )
193
+ realBase , err := evalPath (base )
166
194
if err != nil {
167
195
return fmt .Errorf ("error resolving symlinks in %s: %s" , base , err )
168
196
}
@@ -201,11 +229,11 @@ func doSafeMakeDir(pathname string, base string, perm os.FileMode) error {
201
229
}
202
230
203
231
// Ensure the existing directory is inside allowed base
204
- fullExistingPath , err := filepath . EvalSymlinks (existingPath )
232
+ fullExistingPath , err := evalPath (existingPath )
205
233
if err != nil {
206
234
return fmt .Errorf ("error opening existing directory %s: %s" , existingPath , err )
207
235
}
208
- fullBasePath , err := filepath . EvalSymlinks (base )
236
+ fullBasePath , err := evalPath (base )
209
237
if err != nil {
210
238
return fmt .Errorf ("cannot read link %s: %s" , base , err )
211
239
}
0 commit comments