github.com/epfl-dcsl/gotee@v0.0.0-20200909122901-014b35f5e5e9/src/gosec/sgxlib.go (about) 1 package gosec 2 3 import ( 4 "debug/elf" 5 "log" 6 "os" 7 "reflect" 8 "runtime" 9 "sort" 10 "syscall" 11 "unsafe" 12 ) 13 14 const ( 15 SGX_PATH = "/dev/isgx" 16 PSIZE = uintptr(0x1000) 17 //TODO @aghosn this must be exactly the same as in amd64/obj.go 18 ENCLMASK = 0x040000000000 19 ENCLSIZE = 0x001000000000 20 21 MMMASK = 0x050000000000 22 SIM_OFF = 0x08 23 24 SIM_FLAG = 0x050000000008 25 MSGX_ADDR = 0x050000000020 26 //TLS is m0+m_tls+8 27 TLS_MSGX_OFF = (0x98 + 8) // TODO this depends on m_tls which is bad. 28 NBTCS = runtime.EnclaveMaxTls // how many tcs do we provide. 29 ) 30 31 type SortedElfSections []*elf.Section 32 33 func (s SortedElfSections) Len() int { 34 return len(s) 35 } 36 37 func (s SortedElfSections) Swap(i, j int) { 38 s[i], s[j] = s[j], s[i] 39 } 40 41 func (s SortedElfSections) Less(i, j int) bool { 42 return s[i].Addr < s[j].Addr 43 } 44 45 var ( 46 sgxFd *os.File = nil 47 enclWrap *sgx_wrapper 48 srcWrap *sgx_wrapper 49 ) 50 51 // asm_eenter calls the enclu. 52 func asm_eenter(tcs, xcpt, rdi, rsi uint64) 53 54 // asm_eresume calls enclu to resume execution 55 func asm_eresume(tcs, xcpt uint64) 56 57 // asm_exception does an eresume 58 func asm_exception() 59 60 func sgxLoadProgram(path string) { 61 sgxInit() 62 file, err := elf.Open(path) 63 check(err) 64 var secs *secs_t 65 secs, enclWrap = sgxCreateSecs(file) 66 enclWrap.isSim = false 67 68 // ECREATE & mmap enclave 69 sgxEcreate(secs) 70 71 // Allocate the equivalent region for the eadd page. 72 srcWrap = transposeOutWrapper(enclWrap) 73 74 src := srcWrap.base 75 prot := int(_PROT_READ | _PROT_WRITE) 76 srcptr, ret := syscall.RMmap(src, int(srcWrap.siz), prot, 77 _MAP_NORESERVE|_MAP_ANON|_MAP_FIXED|_MAP_PRIVATE, -1, 0) 78 check(ret) 79 srcWrap.alloc = srcptr 80 81 // Check that the sections are sorted now. 82 sort.Sort(SortedElfSections(file.Sections)) 83 84 // EADD the different parts, mmap them at different offsets. 85 var aggreg []*elf.Section 86 for _, sec := range file.Sections { 87 if sec.Flags&elf.SHF_ALLOC != elf.SHF_ALLOC { 88 continue 89 } 90 if len(aggreg) == 0 || aggreg[len(aggreg)-1].Flags == sec.Flags { 91 aggreg = append(aggreg, sec) 92 continue 93 } 94 95 sgxMapSections(secs, aggreg, enclWrap, srcWrap) 96 aggreg = nil 97 aggreg = append(aggreg, sec) 98 } 99 sgxMapSections(secs, aggreg, enclWrap, srcWrap) 100 101 //Setup the stack arguments and Cooprt heap. 102 //This allows to make the argv part of the measurement. 103 stcs := srcWrap.defaultTcs() 104 _ = runtime.SetupEnclSysStack(stcs.Stack+stcs.Ssiz, enclWrap.mhstart) 105 106 // Mprotect and EADD stack and preallocated. 107 sgxEaddPrealloc(secs, enclWrap, srcWrap) 108 // initialize the TCSs and Eadd their elements. 109 sgxRegisterTCSs(enclWrap, srcWrap) 110 111 // EINIT: first get the token, then call the ioctl. 112 sgxHashFinalize() 113 tok := sgxTokenGetAesm(secs) 114 sgxEinit(secs, &tok) 115 116 //unmap the srcRegion 117 err = syscall.Munmap(srcptr) 118 check(err) 119 120 //transpstack := transposeIn(pstack) 121 fn := unsafe.Pointer(reflect.ValueOf(asm_eenter).Pointer()) 122 enclWrap.entry = uintptr(fn) 123 runtime.Cooprt.Tcss = enclWrap.tcss 124 runtime.Cooprt.ExceptionHandler = uint64(reflect.ValueOf(asm_exception).Pointer()) 125 stcs = srcWrap.defaultTcs() 126 dtcs := enclWrap.defaultTcs() 127 stcs.Used, dtcs.Used = true, true 128 sgxEEnter(uint64(0), dtcs, stcs, nil) 129 } 130 131 // palign does a page align. 132 // If lower is true, it takes the lower address to start (align up)errno 0 133 // Otherwise it takes the greater page alignment address (align down) 134 func palign(addr uint64, lower bool) uint64 { 135 const mask = uint64(0xFFFFFFFFFFFFF000) 136 res := addr & mask 137 if res < addr && !lower { 138 return res + uint64(PSIZE) 139 } 140 141 return res 142 } 143 144 // sgxCreateSecs generates the SGX SECS struct according to the file. 145 // It goes through the elf and computes the range of addresses needed for the 146 // enclave ELRANGE. That includes the heap and the system stack. 147 // It should not mmap anything. This will be done later on. 148 func sgxCreateSecs(file *elf.File) (*secs_t, *sgx_wrapper) { 149 var aggreg []*elf.Section 150 fnFilter := func(e *elf.Section) bool { 151 return e.Flags&elf.SHF_ALLOC == elf.SHF_ALLOC 152 } 153 for _, sec := range file.Sections { 154 if fnFilter(sec) { 155 aggreg = append(aggreg, sec) 156 } 157 } 158 var baseAddr = uint64(ENCLMASK * 2) 159 var endAddr = uint64(0x0) 160 for _, sec := range aggreg { 161 if sec.Addr < baseAddr { 162 baseAddr = sec.Addr 163 } 164 if sec.Addr+sec.Size > endAddr { 165 endAddr = sec.Addr + sec.Size 166 } 167 } 168 // We can create the bounds that we want for the enclave as long as it contains 169 // the values from the binary. 170 if baseAddr < ENCLMASK { 171 log.Fatalf("gosec: < binary outside of enclave region: %x\n", baseAddr) 172 } 173 174 if endAddr > ENCLMASK+ENCLSIZE { 175 log.Fatalf("gosec: > binary outside of enclave region: %x\n", endAddr) 176 } 177 secs := &secs_t{} 178 secs.baseAddr = uint64(ENCLMASK) 179 secs.size = uint64(ENCLSIZE) 180 secs.xfrm = 0x7 181 secs.ssaFrameSize = 1 182 secs.attributes = 0x06 183 // Here we should setup stack | guard page | TCS | SSA 184 wrapper := &sgx_wrapper{} 185 wrapper.base = uintptr(secs.baseAddr) 186 wrapper.siz = uintptr(secs.size) 187 wrapper.tcss = make([]sgx_tcs_info, NBTCS) 188 wrapper.mtlsarr = getMtlsArr(file) 189 for i := 0; i < NBTCS; i++ { 190 ptcs := &wrapper.tcss[i] 191 ptcs.Stack = uintptr(palign(endAddr, false)) + 2*PSIZE 192 ptcs.Ssiz = uintptr(STACK_SIZE) 193 ptcs.Tcs = ptcs.Stack + uintptr(STACK_SIZE) + STACK_TCS_OFF 194 ptcs.Ssa = ptcs.Tcs + uintptr(TCS_SIZE) + TCS_SSA_OFF 195 endAddr = uint64(ptcs.Ssa + SSA_SIZE + SSA_MSGX_OFF + MSGX_SIZE + MSGX_TLS_OFF + TLS_SIZE) 196 ptcs.Msgx = wrapper.mtlsarr + uintptr(i)*(MSGX_SIZE+MSGX_TLS_OFF+TLS_SIZE) 197 ptcs.Tls = ptcs.Msgx + uintptr(MSGX_SIZE) + MSGX_TLS_OFF 198 ptcs.Entry = uintptr(file.Entry) 199 ptcs.Used = false 200 } 201 wrapper.mhstart = uintptr(endAddr) + TLS_MHSTART_OFF 202 wrapper.mhsize = runtime.EnclHeapSizeToAllocate() 203 wrapper.membuf = ENCLMASK + ENCLSIZE - PSIZE - MEMBUF_SIZE 204 if wrapper.membuf < wrapper.mhstart+wrapper.mhsize { 205 panic("gosec: reduce the amount of pages in membuf.") 206 } 207 wrapper.alloc = nil 208 if wrapper.mhstart+wrapper.mhsize > ENCLMASK+ENCLSIZE { 209 log.Printf("enclave limit: %x - end: %x\n", ENCLMASK+ENCLSIZE, wrapper.mhstart+wrapper.mhsize) 210 panic("gosec: Required size is out of enclave limits.") 211 } 212 wrapper.secs = secs 213 return secs, wrapper 214 } 215 216 //sgxTCSPrealloc eadds all preallocated memory (stacks, heap and membuf) 217 func sgxEaddPrealloc(secs *secs_t, dest, src *sgx_wrapper) { 218 prot := uintptr(_PROT_READ | _PROT_WRITE) 219 for i, dtcs := range dest.tcss { 220 stcs := &src.tcss[i] 221 sgxAddRegion(secs, dtcs.Stack, stcs.Stack, dtcs.Ssiz, prot, SGX_SECINFO_REG) 222 } 223 //eadd heap and membuf 224 sgxAddRegion(secs, dest.mhstart, src.mhstart, dest.mhsize, prot, SGX_SECINFO_REG) 225 sgxAddRegion(secs, dest.membuf, src.membuf, MEMBUF_SIZE, prot, SGX_SECINFO_REG) 226 } 227 228 func sgxRegisterTCSs(dest, src *sgx_wrapper) { 229 if dest.secs == nil || dest.tcss == nil || len(dest.tcss) != len(src.tcss) { 230 panic("Uninitialized parameters.") 231 } 232 233 for i := range dest.tcss { 234 sgxInitEaddTCS(uint64(dest.tcss[i].Entry), dest.secs, &dest.tcss[i], &src.tcss[i]) 235 } 236 } 237 238 func sgxInitEaddTCS(entry uint64, secs *secs_t, dest, src *sgx_tcs_info) { 239 tcs := (*tcs_t)(unsafe.Pointer(src.Tcs)) 240 tcs.reserved1 = uint64(0) 241 tcs.flags = uint64(0) 242 tcs.ossa = uint64(dest.Ssa) - secs.baseAddr 243 tcs.cssa = uint32(0) 244 tcs.nssa = TCS_N_SSA 245 tcs.oentry = entry - secs.baseAddr 246 tcs.reserved2 = uint64(0) 247 248 tcs.ofsbasgx = uint64(dest.Tls) - secs.baseAddr 249 tcs.ogsbasgx = tcs.ofsbasgx 250 tcs.fslimit = SGX_FS_LIMIT 251 tcs.gslimit = SGX_GS_LIMIT 252 for i := range tcs.reserved3 { 253 tcs.reserved3[i] = uint64(0) 254 } 255 256 // Add the TCS 257 sgxAddRegion(secs, dest.Tcs, src.Tcs, PSIZE, _PROT_READ|_PROT_WRITE, 258 SGX_SECINFO_TCS) 259 260 // Add the SSA and FS. 261 sgxAddRegion(secs, dest.Ssa, src.Ssa, 262 SSA_SIZE, _PROT_READ|_PROT_WRITE, SGX_SECINFO_REG) 263 264 // TLS and MSGX are already mapped in BSS. 265 } 266 267 func sgxAddRegion(secs *secs_t, addr, src, siz, prot uintptr, tpe uint64) { 268 // First do the mprotect. 269 _, _, ret := syscall.Syscall(syscall.SYS_MPROTECT, addr, siz, prot) 270 if ret != 0 { 271 log.Println("gosec: sgxAddRegion mprotect failed ", ret) 272 panic("stopping execution.") 273 } 274 for x, y := addr, src; x < addr+siz; x, y = x+PSIZE, y+PSIZE { 275 sgxEadd(secs, x, y, prot, tpe) 276 } 277 } 278 279 func transposeOut(addr uintptr) uintptr { 280 if addr < ENCLMASK || addr > ENCLMASK+ENCLSIZE { 281 log.Fatalln("gosec: transpose out invalid address: ", addr) 282 } 283 return (addr - ENCLMASK + MMMASK) 284 } 285 286 func transposeIn(addr uintptr) uintptr { 287 if addr < MMMASK || addr > MMMASK+ENCLSIZE { 288 log.Fatalln("gosec: transpose in invalid address: ", addr) 289 } 290 return (addr - MMMASK + ENCLMASK) 291 } 292 293 func sgxMapSections(sgxsec *secs_t, secs []*elf.Section, wrap, srcRegion *sgx_wrapper) { 294 if len(secs) == 0 { 295 return 296 } 297 298 start := uintptr(palign(uint64(secs[0].Addr), true)) 299 end := uintptr(palign(uint64(secs[len(secs)-1].Addr+secs[len(secs)-1].Size), false)) 300 size := int(end - start) 301 if start >= end { 302 log.Fatalf("Error, sections are not ordered: %#x - %#x", start, end) 303 } 304 if start < wrap.base || end > wrap.base+wrap.siz { 305 panic("gosec: section is outside of the enclave region.") 306 } 307 308 for _, sec := range secs { 309 if sec.Type == elf.SHT_NOBITS { 310 continue 311 } 312 data, err := sec.Data() 313 check(err) 314 offset := int(sec.Addr - uint64(wrap.base)) 315 for i := range data { 316 srcRegion.alloc[offset+i] = data[i] 317 } 318 } 319 prot := _PROT_READ 320 if (secs[0].Flags & elf.SHF_WRITE) == elf.SHF_WRITE { 321 prot |= _PROT_WRITE 322 } 323 324 if (secs[0].Flags & elf.SHF_EXECINSTR) == elf.SHF_EXECINSTR { 325 prot |= _PROT_EXEC 326 } 327 328 sgxAddRegion(sgxsec, start, transposeOut(start), uintptr(size), uintptr(prot), SGX_SECINFO_REG) 329 } 330 331 func sgxInit() int { 332 if sgxFd != nil { 333 return 0 334 } 335 var err error 336 sgxFd, err = os.OpenFile(SGX_PATH, os.O_RDWR, 0) 337 check(err) 338 // Initialize the signature. 339 sgxHashInit() 340 return 0 341 } 342 343 // sgxEcreate calls the IOCTL to create the enclave. 344 // It first performs an mmap of the entire region that we use for the enclave. 345 func sgxEcreate(secs *secs_t) { 346 prot := int32(_PROT_NONE) 347 mprot := int32(_MAP_SHARED | _MAP_FIXED) 348 fd := int32(sgxFd.Fd()) 349 addr := uintptr(secs.baseAddr) 350 ptr, err := runtime.RMmap(unsafe.Pointer(addr), uintptr(secs.size), prot, mprot, fd, 0) 351 if err != 0 || addr != uintptr(ptr) { 352 log.Fatalln("gosec: unable to mmap the enclave: ", err) 353 } 354 355 parms := &sgx_enclave_create{} 356 parms.src = uint64(uintptr(unsafe.Pointer(secs))) 357 ptr2 := uintptr(unsafe.Pointer(parms)) 358 _, _, ret := syscall.Syscall(syscall.SYS_IOCTL, uintptr(sgxFd.Fd()), uintptr(SGX_IOC_ENCLAVE_CREATE), ptr2) 359 if ret != 0 { 360 log.Println("The secs: ", secs) 361 log.Fatalln("Failed in call to ecreate: ", ret) 362 } 363 364 sgxHashEcreate(secs) 365 } 366 367 func sgxEadd(secs *secs_t, daddr, oaddr, prot uintptr, tpe uint64) { 368 eadd := &sgx_enclave_add_page{} 369 eadd.addr = uint64(daddr) 370 eadd.src = uint64(uintptr(oaddr)) 371 eadd.mrmask = uint16(0xffff) 372 if prot&_PROT_WRITE != 0 && tpe != SGX_SECINFO_TCS { 373 eadd.mrmask = uint16(0x0) 374 } 375 376 secinfo := &isgx_secinfo{} 377 secinfo.flags = tpe 378 if prot&_PROT_EXEC != 0 { 379 secinfo.flags |= SGX_SECINFO_X 380 } 381 if prot&_PROT_READ != 0 { 382 secinfo.flags |= SGX_SECINFO_R 383 } 384 if prot&_PROT_WRITE != 0 { 385 secinfo.flags |= SGX_SECINFO_W 386 } 387 388 // Special case for the TCS, no protections. 389 if tpe == SGX_SECINFO_TCS { 390 secinfo.flags = SGX_SECINFO_TCS 391 } 392 eadd.secinfo = uint64(uintptr(unsafe.Pointer(secinfo))) 393 _, _, ret := syscall.Syscall(syscall.SYS_IOCTL, uintptr(sgxFd.Fd()), uintptr(SGX_IOC_ENCLAVE_ADD_PAGE), uintptr(unsafe.Pointer(eadd))) 394 if ret != 0 { 395 log.Println("Unable to add a page: ", daddr) 396 panic("Stopping execution before adding a page.") 397 } 398 399 // Add it to the hash. 400 sgxHashEadd(secs, secinfo, daddr) 401 } 402 403 func sgxEinit(secs *secs_t, tok *TokenGob) { 404 parm := &sgx_enclave_init{} 405 parm.addr = secs.baseAddr 406 407 //Create the proper size for enclave css. 408 signature := &tok.Meta.Enclave_css //&flat_enclave_css_t{} 409 if unsafe.Sizeof(*signature) != uintptr(1808) { 410 panic("gosec: the enclave_css is not the proper size.") 411 } 412 413 parm.sigstruct = uint64(uintptr(unsafe.Pointer(signature))) 414 parm.einittoken = uint64(uintptr(unsafe.Pointer(&tok.Token[0]))) 415 416 ptr := uintptr(unsafe.Pointer(parm)) 417 p1, _, ret := syscall.Syscall(syscall.SYS_IOCTL, uintptr(sgxFd.Fd()), uintptr(SGX_IOC_ENCLAVE_INIT), ptr) 418 419 if ret != 0 || p1 != 0 { 420 log.Println("gosec: sgxEinit failed with return code ", ret, "-- p1: ", p1) 421 panic("Stopping the execution before performing einit.") 422 } 423 } 424 425 //TODO @aghosn, this is bad, we should use the address from source, 426 // we should also change the way the assembly works (maybe later). 427 //go:nosplit 428 func sgxEEnter(id uint64, dest, src *sgx_tcs_info, req *runtime.OExitRequest) { 429 prot := int32(_PROT_READ | _PROT_WRITE) 430 manon := int32(_MAP_ANON | _MAP_FIXED | _MAP_PRIVATE) 431 432 //mmap the unprotected stack 433 //_, ret := syscall.RMmap(src.stack, int(src.ssiz), prot, manon, -1, 0) 434 //check(ret) 435 _, ret := runtime.RMmap(unsafe.Pointer(src.Stack), src.Ssiz, prot, manon, -1, 0) 436 if ret != 0 { 437 panic("Unable to map tcs stack.") 438 } 439 swsptr := src.Stack + src.Ssiz 440 ptrs := (*uint64)(unsafe.Pointer(swsptr)) 441 442 // Spawning a new thread for the enclave 443 if req != nil { 444 // the id for the procid - 72 RSP 445 swsptr -= unsafe.Sizeof(uint64(0)) 446 ptrs = (*uint64)(unsafe.Pointer(swsptr)) 447 *ptrs = id 448 449 // the target g - 64 RSP 450 swsptr -= unsafe.Sizeof(uint64(0)) 451 ptrs = (*uint64)(unsafe.Pointer(swsptr)) 452 *ptrs = uint64(req.Gp) 453 454 // the target m - 56 RSP 455 swsptr -= unsafe.Sizeof(uint64(0)) 456 ptrs = (*uint64)(unsafe.Pointer(swsptr)) 457 *ptrs = uint64(req.Mp) 458 } 459 460 // protected stack address - 48 RSP 461 swsptr -= unsafe.Sizeof(uint64(0)) 462 ptrs = (*uint64)(unsafe.Pointer(swsptr)) 463 // room for the argc argv, so sizeof(int32) + sizeof(ptr -- 64bits) 464 if req == nil { 465 argssiz := unsafe.Sizeof(int32(0)) + unsafe.Sizeof(uint64(0)) 466 *ptrs = uint64(dest.Stack + dest.Ssiz - argssiz) 467 } else { 468 *ptrs = uint64(dest.Stack + dest.Ssiz) 469 } 470 471 // isSim flag - 40 RSP 472 simFlag := uint64(0) 473 if enclWrap.isSim { 474 simFlag = uint64(1) 475 } 476 swsptr -= unsafe.Sizeof(uint64(0)) 477 ptrs = (*uint64)(unsafe.Pointer(swsptr)) 478 *ptrs = uint64(simFlag) 479 480 // msgx address - 32 RSP 481 swsptr -= unsafe.Sizeof(uint64(0)) 482 ptrs = (*uint64)(unsafe.Pointer(swsptr)) 483 *ptrs = uint64(dest.Tls - TLS_MSGX_OFF) 484 485 // RSI - 24 RSP 486 swsptr -= unsafe.Sizeof(uint64(0)) 487 ptrs = (*uint64)(unsafe.Pointer(swsptr)) 488 *ptrs = uint64(uintptr(unsafe.Pointer(&dest.Rsi))) 489 490 // RDI - 16 RSP 491 swsptr -= unsafe.Sizeof(uint64(0)) 492 ptrs = (*uint64)(unsafe.Pointer(swsptr)) 493 *ptrs = uint64(uintptr(unsafe.Pointer(&dest.Rdi))) 494 495 // Xception - 8 RSP 496 xcpt := runtime.Cooprt.ExceptionHandler 497 swsptr -= unsafe.Sizeof(uint64(0)) 498 ptrs = (*uint64)(unsafe.Pointer(swsptr)) 499 *ptrs = xcpt 500 501 // tcs - 0 RSP 502 swsptr -= unsafe.Sizeof(uint64(0)) 503 ptrs = (*uint64)(unsafe.Pointer(swsptr)) 504 *ptrs = uint64(dest.Tcs) 505 506 runtime.StartEnclaveOSThread(swsptr, unsafe.Pointer(enclWrap.entry)) 507 } 508 509 func testEntry() { 510 log.Println("Test and I am here") 511 } 512 513 func sgxException() { 514 log.Fatalln("SGX exception occured.") 515 }