github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/pkg/sentry/platform/kvm/virtual_map.go (about) 1 // Copyright 2018 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package kvm 16 17 import ( 18 "bufio" 19 "fmt" 20 "io" 21 "os" 22 "regexp" 23 "strconv" 24 25 "github.com/SagerNet/gvisor/pkg/hostarch" 26 ) 27 28 type virtualRegion struct { 29 region 30 accessType hostarch.AccessType 31 shared bool 32 offset uintptr 33 filename string 34 } 35 36 // mapsLine matches a single line from /proc/PID/maps. 37 var mapsLine = regexp.MustCompile("([0-9a-f]+)-([0-9a-f]+) ([r-][w-][x-][sp]) ([0-9a-f]+) [0-9a-f]{2,3}:[0-9a-f]{2,} [0-9]+\\s+(.*)") 38 39 // excludeRegion returns true if these regions should be excluded from the 40 // physical map. Virtual regions need to be excluded if get_user_pages will 41 // fail on those addresses, preventing KVM from satisfying EPT faults. 42 // 43 // This includes the VVAR page because the VVAR page may be mapped as I/O 44 // memory. And the VDSO page is knocked out because the VVAR page is not even 45 // recorded in /proc/self/maps on older kernels; knocking out the VDSO page 46 // prevents code in the VDSO from accessing the VVAR address. 47 // 48 // This is called by the physical map functions, not applyVirtualRegions. 49 func excludeVirtualRegion(r virtualRegion) bool { 50 return r.filename == "[vvar]" || r.filename == "[vdso]" 51 } 52 53 // applyVirtualRegions parses the process maps file. 54 // 55 // Unlike mappedRegions, these are not consistent over time. 56 func applyVirtualRegions(fn func(vr virtualRegion)) error { 57 // Open /proc/self/maps. 58 f, err := os.Open("/proc/self/maps") 59 if err != nil { 60 return err 61 } 62 defer f.Close() 63 64 // Parse all entries. 65 r := bufio.NewReader(f) 66 for { 67 b, err := r.ReadBytes('\n') 68 if b != nil && len(b) > 0 { 69 m := mapsLine.FindSubmatch(b) 70 if m == nil { 71 // This should not happen: kernel bug? 72 return fmt.Errorf("badly formed line: %v", string(b)) 73 } 74 start, err := strconv.ParseUint(string(m[1]), 16, 64) 75 if err != nil { 76 return fmt.Errorf("bad start address: %v", string(b)) 77 } 78 end, err := strconv.ParseUint(string(m[2]), 16, 64) 79 if err != nil { 80 return fmt.Errorf("bad end address: %v", string(b)) 81 } 82 read := m[3][0] == 'r' 83 write := m[3][1] == 'w' 84 execute := m[3][2] == 'x' 85 shared := m[3][3] == 's' 86 offset, err := strconv.ParseUint(string(m[4]), 16, 64) 87 if err != nil { 88 return fmt.Errorf("bad offset: %v", string(b)) 89 } 90 fn(virtualRegion{ 91 region: region{ 92 virtual: uintptr(start), 93 length: uintptr(end - start), 94 }, 95 accessType: hostarch.AccessType{ 96 Read: read, 97 Write: write, 98 Execute: execute, 99 }, 100 shared: shared, 101 offset: uintptr(offset), 102 filename: string(m[5]), 103 }) 104 } 105 if err != nil && err == io.EOF { 106 break 107 } else if err != nil { 108 return err 109 } 110 } 111 112 return nil 113 }