精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

硬核!如何在容器中做時間漫游者

存儲 存儲軟件
分布式數(shù)據(jù)庫要實現(xiàn)全局一致性快照,很多方案使用時間做邏輯時鐘,所以需要解決不同節(jié)點之間時鐘一致的問題。

[[402031]]

本文轉(zhuǎn)載自微信公眾號「董澤潤的技術筆記」,作者董澤潤。轉(zhuǎn)載本文請聯(lián)系董澤潤的技術筆記公眾號。

題目稍有些標題黨,最近公司想用 chaos-mesh 對 k8s 做混沌測試,開始做前期的調(diào)研,發(fā)現(xiàn) pingcap[1] 對時間的注入非常硬核,而且最終方案居然是實習生構思出來的 ^^ 感謝 pingcap 貢獻的項目

TL;DR: 通過劫持 vdso, 將時間函數(shù)跳轉(zhuǎn)到 hack 過的匯編指令來實現(xiàn) time skew. 原理不難懂,但細節(jié)超多,參考官方文檔[2]

為什么需要 time skew

可以參考 Chaos Mesh - 讓時間在容器中自由搖擺[3], 簡單來說就是:

分布式數(shù)據(jù)庫要實現(xiàn)全局一致性快照,很多方案使用時間做邏輯時鐘,所以需要解決不同節(jié)點之間時鐘一致的問題。但往往物理節(jié)點上的物理時間總是會出現(xiàn)偏差,不管是使用 NPT 服務同步也好,或者其他方法總是沒辦法完全避免出現(xiàn)誤差,這時候如果我們的應用不能夠很好的處理這樣的情況的話,就可能造成無法預知的錯誤。

其實這很符合工程設計哲學:design for failure, 任何一個硬件或是軟件都會有錯誤(fault),系統(tǒng)如何在不影響對外提供服務的前提下,如何處理這些故障,就是我們常說的 fault tolerance

但是對于非金融業(yè)務來說,時間偏移一點影響并不大,相比其它 chaos, time的場景還是受限一些

如何注入

從實體機的經(jīng)驗來看,所謂的混沌測試都比較直觀的,比如用 tc 做網(wǎng)絡的丟包,限速來模擬網(wǎng)絡故障,使用 stress 模擬 cpu 壓力。但是在容器中做如何模擬 time skew 呢?

如果直接使用 linux date 命令修改,會影響到宿主機上其它所有容器。有沒有方法能只影響某個容器?

之前發(fā)過一篇文章 時鐘源為什么會影響性能[4], 從中可以看到,go 調(diào)用系統(tǒng)時間函數(shù)時,會先調(diào)用 vdso 的代碼,如果時鐘源符合條件,直接在用戶空間完成,并不會進入內(nèi)核空間,所以針對這一現(xiàn)象,syscall 劫持的方法就不能使用了

那么是否可以直接修改 vdso 段代碼呢?

查看 vdso

  1. # cat /proc/1970/maps 
  2. ...... 
  3. 7ffe8478a000-7ffe847ab000 rw-p 00000000 00:00 0                          [stack] 
  4. 7ffe847bb000-7ffe847be000 r--p 00000000 00:00 0                          [vvar] 
  5. 7ffe847be000-7ffe847bf000 r-xp 00000000 00:00 0                          [vdso] 
  6. ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0                  [vsyscall] 

可以看到 vdso 代碼段的起始邏輯地址,同時注意權限位是 r-xp, 這就意味著用戶態(tài)的進程是無法直接修改該內(nèi)容。

真的就沒辦法了嘛?有的,ptrace[5] 法力無邊

The ptrace() system call provides a means by which one process (the "tracer") may observe and control the execution of another process (the "tracee"), and examine and change the tracee's memory and registers. It is primarily used to implement breakpoint debugging and system call tracing.

ptrace 提供了一種修改和觀察其它進程的手段,包括修改內(nèi)存值和寄存器,巧了這些 chaos-mesh 都用到了。如何實現(xiàn) go 調(diào)試器[6] 這篇文章也講了 ptrace 的用途,很棒的文章。

整體實現(xiàn)

這就是簡單的流程圖,主要代碼都是 time_linux_amd64.go[7], 當前僅支持 linux amd64 平臺,不支持 Windows/MacOS

  1. // ModifyTime modifies time of target process 
  2. func ModifyTime(pid int, deltaSec int64, deltaNsec int64, clockIdsMask uint64) error { 
  3.   ...... 
  4.  runtime.LockOSThread() // 將當前 goroutine 綁定底層線程 
  5.  defer func() { 
  6.   runtime.UnlockOSThread() 
  7.  }() 
  8.  
  9.  program, err := ptrace.Trace(pid) // ptrace 獲得 program 
  10.  if err != nil { 
  11.   return err 
  12.  } 
  13.  defer func() { 
  14.   err = program.Detach() 
  15.   if err != nil { 
  16.    log.Error(err, "fail to detach program""pid", program.Pid()) 
  17.   } 
  18.  }() 
  19.  
  20.  var vdsoEntry *mapreader.Entry // 遍歷 entry 找到 vdso 
  21.  for index := range program.Entries { 
  22.   // reverse loop is faster 
  23.   e := program.Entries[len(program.Entries)-index-1] 
  24.   if e.Path == "[vdso]" { 
  25.    vdsoEntry = &e 
  26.    break 
  27.   } 
  28.  } 
  29.  if vdsoEntry == nil { 
  30.   return errors.New("cannot find [vdso] entry"
  31.  } 
  32.  
  33.  // minus tailing variable part 
  34.  // 24 = 3 * 8 because we have three variables 
  35.  constImageLen := len(fakeImage) - 24 
  36.  var fakeEntry *mapreader.Entry 
  37.  
  38.  // find injected image to avoid redundant inject (which will lead to memory leak) 
  39.  for _, e := range program.Entries { 
  40.   e := e 
  41.  
  42.   image, err := program.ReadSlice(e.StartAddress, uint64(constImageLen)) 
  43.   if err != nil { 
  44.    continue 
  45.   } 
  46.  
  47.   if bytes.Equal(*image, fakeImage[0:constImageLen]) { 
  48.    fakeEntry = &e // 遍歷找到 fake Image Entry,不能重復生成 
  49.    log.Info("found injected image""addr", fakeEntry.StartAddress) 
  50.    break 
  51.   } 
  52.  } 
  53.  if fakeEntry == nil { // 如果 fakeEntry 不存在,用 Mmap 分配內(nèi)存,內(nèi)容是 fakeImage 匯編指令 
  54.   fakeEntry, err = program.MmapSlice(fakeImage) 
  55.   if err != nil { 
  56.    return err 
  57.   } 
  58.  } 
  59.  fakeAddr := fakeEntry.StartAddress 
  60.  
  61.  // 139 is the index of CLOCK_IDS_MASK in fakeImage 寫 clockidsmask 
  62.  err = program.WriteUint64ToAddr(fakeAddr+139, clockIdsMask) 
  63.  if err != nil { 
  64.   return err 
  65.  } 
  66.  
  67.  // 147 is the index of TV_SEC_DELTA in fakeImage 寫偏移量秒 
  68.  err = program.WriteUint64ToAddr(fakeAddr+147, uint64(deltaSec)) 
  69.  if err != nil { 
  70.   return err 
  71.  } 
  72.  
  73.  // 155 is the index of TV_NSEC_DELTA in fakeImage 寫偏移量納秒 
  74.  err = program.WriteUint64ToAddr(fakeAddr+155, uint64(deltaNsec)) 
  75.  if err != nil { 
  76.   return err 
  77.  } 
  78.   // 找到 clock_gettime 在 vdso 中的位置 
  79.  originAddr, err := program.FindSymbolInEntry("clock_gettime", vdsoEntry) 
  80.  if err != nil { 
  81.   return err 
  82.  } 
  83.   // originAddr 位置 hijack, 寫上 jump 指令,跳轉(zhuǎn)到 fakeImage 
  84.  err = program.JumpToFakeFunc(originAddr, fakeAddr) 
  85.  return err 

代碼寫上了注釋,分別對應上面的流程圖。下面分解來看。

1. Ptrace

  1. type TracedProgram struct { 
  2.  pid     int 
  3.  tids    []int 
  4.  Entries []mapreader.Entry 
  5.  
  6.  backupRegs *syscall.PtraceRegs 
  7.  backupCode []byte 

TracedProgram 結(jié)構體比較簡單,pid 是待注入 chaos 的進程 id, 同時 tids 保存所有的線程 id, Entries 是進程邏輯地址空間,

Trace 函數(shù)在代碼 ptrace_linux_amd64.go[8] 中

通過讀取 /proc/{pid}/task 獲取進程的所有線程,然后分別對所有線程執(zhí)行 linux ptrace 調(diào)用。然后生成 Entries, 什么是 Entry 呢?就是上文提到的 /proc/{pid}/maps 內(nèi)容

  1. ...... 
  2. 7ffe8478a000-7ffe847ab000 rw-p 00000000 00:00 0                          [stack] 
  3. 7ffe847bb000-7ffe847be000 r--p 00000000 00:00 0                          [vvar] 
  4. 7ffe847be000-7ffe847bf000 r-xp 00000000 00:00 0                          [vdso] 
  5. ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0                  [vsyscall] 

2. Mmap FakeImage

查找 vdso[9], 如何失敗,直接退出。一般 vdso 都在最后,所以從尾開始遍歷

同時還要查找 fakeEntry, 如果存在,直接復用。否則會造成內(nèi)存泄漏,當然了,一直創(chuàng)建新的 fakeEntry .....

  1. // MmapSlice mmaps a slice and return it's addr 
  2. func (p *TracedProgram) MmapSlice(slice []byte) (*mapreader.Entry, error) { 
  3.  size := uint64(len(slice)) 
  4.  
  5.  addr, err := p.Mmap(size, 0) 
  6.  if err != nil { 
  7.   return nil, errors.WithStack(err) 
  8.  } 
  9.  
  10.  err = p.WriteSlice(addr, slice) 
  11.  if err != nil { 
  12.   return nil, errors.WithStack(err) 
  13.  } 
  14.  
  15.  return &mapreader.Entry{ 
  16.   StartAddress: addr, 
  17.   EndAddress:   addr + size
  18.   Privilege:    "rwxp"
  19.   PaddingSize:  0, 
  20.   Path:         ""
  21.  }, nil 

注意,這不是簡單的調(diào)用 Mmap Syscall !!! ptrace.Syscall[12] 是利用 ptrace 控制進程,讓目標進程單步執(zhí)行 syscall

  1. // Syscall runs a syscall at main thread of process 
  2. func (p *TracedProgram) Syscall(number uint64, args ...uint64) (uint64, error) { 
  3.  err := p.Protect() // 保存目標進程的寄存器 
  4.  if err != nil { 
  5.   return 0, err 
  6.  } 
  7.  
  8.  var regs syscall.PtraceRegs 
  9.  
  10.  err = syscall.PtraceGetRegs(p.pid, &regs) 
  11.  if err != nil { 
  12.   return 0, err 
  13.  } 
  14.  regs.Rax = number // 設置操作 syscall number, 填充其它參數(shù) 
  15.  for index, arg := range args { 
  16.   // All these registers are hard coded for x86 platform 
  17.   if index == 0 { 
  18.    regs.Rdi = arg 
  19.   } else if index == 1 { 
  20.    regs.Rsi = arg 
  21.   } else if index == 2 { 
  22.    regs.Rdx = arg 
  23.   } else if index == 3 { 
  24.    regs.R10 = arg 
  25.   } else if index == 4 { 
  26.    regs.R8 = arg 
  27.   } else if index == 5 { 
  28.    regs.R9 = arg 
  29.   } else { 
  30.    return 0, fmt.Errorf("too many arguments for a syscall"
  31.   } 
  32.  } 
  33.  err = syscall.PtraceSetRegs(p.pid, &regs) 
  34.  if err != nil { 
  35.   return 0, err 
  36.  } 
  37.  
  38.  ip := make([]byte, ptrSize) 
  39.  
  40.  // We only support x86-64 platform now, so using hard coded `LittleEndian` here is ok. 設置 rip 寄存器 
  41.  binary.LittleEndian.PutUint16(ip, 0x050f) 
  42.  _, err = syscall.PtracePokeData(p.pid, uintptr(p.backupRegs.Rip), ip) 
  43.  if err != nil { 
  44.   return 0, err 
  45.  } 
  46.  
  47.  err = p.Step() // 單步執(zhí)行 
  48.  if err != nil { 
  49.   return 0, err 
  50.  } 
  51.  
  52.  err = syscall.PtraceGetRegs(p.pid, &regs) 
  53.  if err != nil { 
  54.   return 0, err 
  55.  } 
  56.  
  57.  return regs.Rax, p.Restore() // 獲取返回值,并且恢復寄存器 

參考代碼的注釋,搞過嵌入式的肯定熟悉:保存寄存器現(xiàn)場,設置新的寄存器值為 syscall number 以及參數(shù),最后設置指令寄存器 rip 單步執(zhí)行,就完成了讓目標進程執(zhí)行 mmap 的操作,最后也要恢復寄存器,還原現(xiàn)場。

這里為什么 rip 寄存器要設置成 0x050f 呢???其實這是 syscall 的操作碼

另外 p.WriteSlice 是使用 syscall process_vm_writev 將數(shù)據(jù)寫入目標進程的內(nèi)存邏輯地址空間。

3. FindSymbolInEntry

  1. ~# file /tmp/vdso.so 
  2. /tmp/vdso.so: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, BuildID[sha1]=17d65245b85cd032de7ab130d053551fb0bd284a, stripped 
  3. ~# objdump -T /tmp/vdso.so 
  4.  
  5. /tmp/vdso.so:     file format elf64-x86-64 
  6.  
  7. DYNAMIC SYMBOL TABLE
  8. 0000000000000950  w   DF .text 00000000000000a1  LINUX_2.6   clock_gettime 
  9. 00000000000008a0 g    DF .text 0000000000000083  LINUX_2.6   __vdso_gettimeofday 
  10. 0000000000000a00  w   DF .text 000000000000000a  LINUX_2.6   clock_getres 
  11. 0000000000000a00 g    DF .text 000000000000000a  LINUX_2.6   __vdso_clock_getres 
  12. 00000000000008a0  w   DF .text 0000000000000083  LINUX_2.6   gettimeofday 
  13. 0000000000000930 g    DF .text 0000000000000015  LINUX_2.6   __vdso_time 
  14. 0000000000000930  w   DF .text 0000000000000015  LINUX_2.6   time 
  15. 0000000000000950 g    DF .text 00000000000000a1  LINUX_2.6   __vdso_clock_gettime 
  16. 0000000000000000 g    DO *ABS* 0000000000000000  LINUX_2.6   LINUX_2.6 
  17. 0000000000000a10 g    DF .text 000000000000002a  LINUX_2.6   __vdso_getcpu 
  18. 0000000000000a10  w   DF .text 000000000000002a  LINUX_2.6   getcpu 

FindSymbolInEntry 函數(shù)很簡單,就是要找到 clock_gettime 在 vdso 中的地址,參考我之前的文章,上面是 dump 出來的符號表

4. JumpToFakeFunc

  1. // JumpToFakeFunc writes jmp instruction to jump to fake function 
  2. func (p *TracedProgram) JumpToFakeFunc(originAddr uint64, targetAddr uint64) error { 
  3.  instructions := make([]byte, 16) 
  4.  
  5.  // mov rax, targetAddr; 
  6.  // jmp rax ; 
  7.  instructions[0] = 0x48 
  8.  instructions[1] = 0xb8 
  9.  binary.LittleEndian.PutUint64(instructions[2:10], targetAddr) 
  10.  instructions[10] = 0xff 
  11.  instructions[11] = 0xe0 
  12.  
  13.  return p.PtraceWriteSlice(originAddr, instructions) 

JumpToFakeFunc[13], 修改 vdso 符號表中的匯編代碼,使所有調(diào)用 clock_gettime 的都跳轉(zhuǎn)到我們 fakeEntry 的地址,劫持 vdso

FakeImage

  1. var fakeImage = []byte{ 
  2.  0xb8, 0xe4, 0x00, 0x00, 0x00, //mov    $0xe4,%eax 
  3.  0x0f, 0x05, //syscall 
  4.  0xba, 0x01, 0x00, 0x00, 0x00, //mov    $0x1,%edx 
  5.  0x89, 0xf9, //mov    %edi,%ecx 
  6.  0xd3, 0xe2, //shl    %cl,%edx 
  7.  0x48, 0x8d, 0x0d, 0x74, 0x00, 0x00, 0x00, //lea    0x74(%rip),%rcx        # <CLOCK_IDS_MASK> 
  8.  0x48, 0x63, 0xd2, //movslq %edx,%rdx 
  9.  0x48, 0x85, 0x11, //test   %rdx,(%rcx) 
  10.  0x74, 0x6b, //je     108a <clock_gettime+0x8a> 
  11.  0x48, 0x8d, 0x15, 0x6d, 0x00, 0x00, 0x00, //lea    0x6d(%rip),%rdx        # <TV_SEC_DELTA> 
  12.  0x4c, 0x8b, 0x46, 0x08, //mov    0x8(%rsi),%r8 
  13.  0x48, 0x8b, 0x0a, //mov    (%rdx),%rcx 
  14.  0x48, 0x8d, 0x15, 0x67, 0x00, 0x00, 0x00, //lea    0x67(%rip),%rdx        # <TV_NSEC_DELTA> 
  15.  0x48, 0x8b, 0x3a, //mov    (%rdx),%rdi 
  16.  0x4a, 0x8d, 0x14, 0x07, //lea    (%rdi,%r8,1),%rdx 
  17.  0x48, 0x81, 0xfa, 0x00, 0xca, 0x9a, 0x3b, //cmp    $0x3b9aca00,%rdx 
  18.  0x7e, 0x1c, //jle    <clock_gettime+0x60> 
  19.  0x0f, 0x1f, 0x40, 0x00, //nopl   0x0(%rax) 
  20.  0x48, 0x81, 0xef, 0x00, 0xca, 0x9a, 0x3b, //sub    $0x3b9aca00,%rdi 
  21.  0x48, 0x83, 0xc1, 0x01, //add    $0x1,%rcx 
  22.  0x49, 0x8d, 0x14, 0x38, //lea    (%r8,%rdi,1),%rdx 
  23.  0x48, 0x81, 0xfa, 0x00, 0xca, 0x9a, 0x3b, //cmp    $0x3b9aca00,%rdx 
  24.  0x7f, 0xe8, //jg     <clock_gettime+0x48> 
  25.  0x48, 0x85, 0xd2, //test   %rdx,%rdx 
  26.  0x79, 0x1e, //jns    <clock_gettime+0x83> 
  27.  0x4a, 0x8d, 0xbc, 0x07, 0x00, 0xca, 0x9a, //lea    0x3b9aca00(%rdi,%r8,1),%rdi 
  28.  0x3b,             // 
  29.  0x0f, 0x1f, 0x00, //nopl   (%rax) 
  30.  0x48, 0x89, 0xfa, //mov    %rdi,%rdx 
  31.  0x48, 0x83, 0xe9, 0x01, //sub    $0x1,%rcx 
  32.  0x48, 0x81, 0xc7, 0x00, 0xca, 0x9a, 0x3b, //add    $0x3b9aca00,%rdi 
  33.  0x48, 0x85, 0xd2, //test   %rdx,%rdx 
  34.  0x78, 0xed, //js     <clock_gettime+0x70> 
  35.  0x48, 0x01, 0x0e, //add    %rcx,(%rsi) 
  36.  0x48, 0x89, 0x56, 0x08, //mov    %rdx,0x8(%rsi) 
  37.  0xc3, //retq 
  38.  // constant 
  39.  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //CLOCK_IDS_MASK 
  40.  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //TV_SEC_DELTA 
  41.  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //TV_NSEC_DELTA 

fakeImage 最后三個參數(shù)是偏移量,以及傳遞的 CLOCK_IDS_MASK, 這些匯編是什么意思呢???

查看匯編操作碼[14],0xe4 是系統(tǒng)調(diào)用 clock_gettime 的操作碼,后續(xù)都是對結(jié)果進行注入,要么增要么減,制造偏移量 time skew

測試案例

  1. # git clone https://github.com/chaos-mesh/chaos-mesh 
  2. # cd chaos-mesh; make watchmaker 

首先下載 chaos-mesh, 然后編譯 watchmaker, 這是一個方便注入的小工具。

  1. package main 
  2.  
  3. import ( 
  4.         "fmt" 
  5.         "time" 
  6.  
  7. func main() { 
  8.         fmt.Println("start print time"
  9.         for { 
  10.                 fmt.Printf("now %v\n"time.Now()) 
  11.                 time.Sleep(time.Second * 20) 
  12.         } 

上面是測試的代碼,每隔 20 打印當前時間,編譯執(zhí)行,同時用 watchmaker 注入 time skew

  1. # ./watchmaker -pid 1970 -sec_delta -300 

隔一段時間間后,再次執(zhí)行停止執(zhí)行注入

  1. # ./watchmaker -pid 1970 -sec_delta 0 
  1. # ./test 
  2. start print time 
  3. now 2021-05-26 03:31:46.701902309 +0000 UTC m=+0.000131483 
  4. now 2021-05-26 03:32:06.702230391 +0000 UTC m=+20.000459585 
  5. now 2021-05-26 03:32:26.702406569 +0000 UTC m=+40.000635793 
  6. now 2021-05-26 03:27:46.702688433 +0000 UTC m=+60.000918297 
  7. ^@now 2021-05-26 03:28:06.702914898 +0000 UTC m=+80.001145022 
  8. now 2021-05-26 03:28:26.703120914 +0000 UTC m=+100.001350878 
  9. now 2021-05-26 03:28:46.703398463 +0000 UTC m=+120.001628357 
  10. ^@now 2021-05-26 03:29:06.703707514 +0000 UTC m=+140.001937468 
  11. now 2021-05-26 03:29:26.704025346 +0000 UTC m=+160.002255480 
  12. now 2021-05-26 03:29:46.704302832 +0000 UTC m=+180.002532766 
  13. ^@now 2021-05-26 03:35:06.704505387 +0000 UTC m=+200.002735491 
  14.  
  15. now 2021-05-26 03:35:26.704931111 +0000 UTC m=+220.003161235 

上面是代碼執(zhí)行的輸出,可以看到 03:32:26 之后時間變成了 03:27:46, 停止注入后恢復

Limits

當前的實現(xiàn),停止注入,并不會還原 vdso 代碼,也就是說 fakeEntry 會一直存在,每次 clock_gettime 都會跳轉(zhuǎn),只不過偏移量為 0 而己

由于以上原因的存在,注入及注入之后的 clock_gettime 都是走的 syscall 系統(tǒng)調(diào)用,性能很慢,敏感業(yè)務需要重啟,細節(jié)可以參考我之前的文章《時鐘源為什么會影響性能》

當前注入,只能針對容器里的主進程,那些 fork 出來,派生出來的無做做到注入

以上限制有沒有優(yōu)化空間呢?當然有,問題都是用來解決的嘛~

小結(jié)

這次分享就這些,以后面還會分享更多的內(nèi)容,如果感興趣,可以關注并點擊左下角的分享轉(zhuǎn)發(fā)哦(:

參考資料

[1]Chaos Mesh - 讓時間在容器中自由搖擺: https://www.jianshu.com/p/6425050591b7,

[2]官方文檔: https://chaos-mesh.org/docs/chaos_experiments/timechaos_experiment/#limitation,

[3]讓時間在容器中自由搖擺: https://www.jianshu.com/p/6425050591b7,

[4]時鐘源為什么會影響性能: https://mp.weixin.qq.com/s/06SDQLzDprJf2AEaDnX-QQ,

[5]ptrace: https://man7.org/linux/man-pages/man2/ptrace.2.html,

[6]如何實現(xiàn) go 調(diào)試器: https://studygolang.com/articles/12804,

[7]time_linux_amd64.go: https://github.com/chaos-mesh/chaos-mesh/blob/master/pkg/time/time_linux_amd64.go#L72,

[8]ptrace_linux_amd64.go: https://github.com/chaos-mesh/chaos-mesh/blob/master/pkg/ptrace/ptrace_linux_amd64.go#L87,

[9]time_linux_amd64.go#L102 vdso: https://github.com/chaos-mesh/chaos-mesh/blob/master/pkg/time/time_linux_amd64.go#L102,

[10]program.MmapSlice: https://github.com/chaos-mesh/chaos-mesh/blob/master/pkg/time/time_linux_amd64.go#L132,

[11]FakeImage: https://github.com/chaos-mesh/chaos-mesh/blob/master/pkg/time/time_linux_amd64.go#L28,

[12]ptrace.Syscall: https://github.com/chaos-mesh/chaos-mesh/blob/master/pkg/ptrace/ptrace_linux_amd64.go#L251,

[13]JumpToFakeFunc: https://github.com/chaos-mesh/chaos-mesh/blob/master/pkg/ptrace/ptrace_linux_amd64.go#L480,

[14]匯編操作碼: https://chromium.googlesource.com/chromiumos/docs/+/master/constants/syscalls.md,

 

責任編輯:武曉燕 來源: 董澤潤的技術筆記
相關推薦

2021-09-03 09:06:42

代碼時間開發(fā)

2022-06-27 05:48:24

Kubernetes容器

2011-04-11 14:45:15

Oracle表系統(tǒng)時間

2015-08-07 10:10:18

LinuxDocker容器

2020-09-19 18:03:42

Docker

2018-07-02 06:33:25

物聯(lián)網(wǎng)手機漫游網(wǎng)絡

2017-09-18 10:05:15

WindowsLinux容器

2018-11-05 14:53:14

Go函數(shù)代碼

2021-04-02 14:23:12

WiFi網(wǎng)絡技術

2021-03-31 21:20:15

WiFi網(wǎng)絡漫游

2013-09-27 10:51:00

Github

2018-07-02 09:00:27

Linux特定時間運行命令

2022-01-05 18:19:30

容器鏡像Golang

2015-05-12 10:03:55

OpenStack環(huán)境容器編排Docker

2024-11-20 16:09:04

API開源Bruno

2022-04-20 11:40:51

元宇宙區(qū)塊鏈代幣

2019-08-13 16:10:38

UbuntuLinux時間同步

2014-11-18 00:45:58

UbuntuLXC容器

2014-05-07 09:56:48

Docker管理Linux容器

2019-07-08 08:59:41

Docker容器主機
點贊
收藏

51CTO技術棧公眾號

欧美最猛性xxxxx直播| 91在线观看下载| 久久这里只有精品视频首页| 中文字幕视频观看| 自拍视频在线看| 最好看的中文字幕久久| 国产在线一区二区三区播放| 亚洲永久精品一区| 欧美三级小说| 国产一区二区欧美日韩| 精品久久久久久无码人妻| av有声小说一区二区三区| 亚洲男人天堂av| 日本午夜精品一区二区三区| 性一交一乱一精一晶| 爽好多水快深点欧美视频| 欧美激情视频一区二区| 亚洲精品视频网址| 日韩av资源网| 日韩欧美中文字幕一区| 91香蕉视频污版| 黑森林国产精品av| 亚洲精品老司机| 亚洲免费精品视频| 免费黄色片在线观看| 大白屁股一区二区视频| 成人看片人aa| 一起草av在线| 奇米777欧美一区二区| 91av国产在线| 久久9999久久免费精品国产| 91精品国产乱码久久久久久| 综合网日日天干夜夜久久| 中文字幕一区二区三区人妻电影| 动漫3d精品一区二区三区乱码| 欧美另类videos死尸| 欧美激情国产精品日韩| 中文在线аv在线| 午夜国产不卡在线观看视频| 国产va亚洲va在线va| 国产福利视频在线观看| 国产精品成人免费精品自在线观看| 免费一区二区三区在在线视频| 欧美熟女一区二区| 成+人+亚洲+综合天堂| 99在线看视频| 国产综合视频在线| 成人免费看黄yyy456| 波多野结衣一区二区三区在线观看| 91精品国产综合久| 精品一区二区三区免费播放| 国产日韩欧美黄色| 一炮成瘾1v1高h| 激情欧美一区二区三区在线观看| 国产欧美日韩中文字幕| 中文字幕有码视频| 久久成人免费网| 国产色视频一区| 国产又粗又猛又爽又黄的| 久久99国产精品久久99果冻传媒| 国产日韩欧美中文在线播放| 一级特黄aaa大片在线观看| 国产在线国偷精品产拍免费yy| 91精品综合视频| 精品国产无码AV| 成人永久免费视频| 久久久久九九九| 成人午夜影视| 亚洲欧美aⅴ...| 精品成在人线av无码免费看| 日本在线播放一二三区| 在线这里只有精品| 国产精品自在自线| 狠狠一区二区三区| 亚洲色图狂野欧美| 四虎永久免费在线| 亚洲激情视频| 国产精品网红福利| 成人1区2区3区| 久久综合色婷婷| 亚洲制服欧美久久| 岛国毛片av在线| 91黄色小视频| 色哟哟在线观看视频| 色天天色综合| 久久九九精品99国产精品| 激情五月少妇a| 美女国产精品| 97超级碰碰| 日本福利片在线| 综合久久给合久久狠狠狠97色| 无码人妻精品一区二区蜜桃网站| 周于希免费高清在线观看| 欧美高清视频一二三区| 黄色国产在线观看| 夜间精品视频| 国产精品99免视看9| 国产婷婷在线视频| 国产亚洲一区字幕| www.亚洲成人网| 婷婷激情一区| 精品久久人人做人人爽| 久久精品三级视频| 亚洲深夜影院| 91麻豆精品秘密入口| 美女做暖暖视频免费在线观看全部网址91 | 一级日本不卡的影视| 99色精品视频| www.豆豆成人网.com| 中文字幕亚洲综合久久| 日本少妇性高潮| 精品中文字幕一区二区小辣椒| 国产伦精品一区二区三区视频黑人 | 一级久久久久久久| 久久蜜桃一区二区| 国产不卡一区二区视频| 青草伊人久久| 色悠悠久久久久| aaaaaa毛片| 99久久夜色精品国产网站| 国产精品igao激情视频| 日韩亚洲国产免费| 伊人伊人伊人久久| 日韩 国产 欧美| 94色蜜桃网一区二区三区| 国产在线观看欧美| 试看120秒一区二区三区| 日韩中文字幕网| 中文在线免费观看| 久久久久久久精| 女人和拘做爰正片视频| 精品国产一区二区三区不卡蜜臂 | 图片区小说区区亚洲五月| 天堂av在线| 亚洲精品乱码久久久久久金桔影视 | 中国1级黄色片| 七七婷婷婷婷精品国产| 色大师av一区二区三区| 午夜精品成人av| 亚洲欧美国产精品久久久久久久| 国产成人精品一区二三区| 白白色 亚洲乱淫| 精品国产一区三区| 日韩伦理一区二区三区| 日本不卡高字幕在线2019| 日韩福利一区二区| 日本高清免费不卡视频| 无码一区二区三区在线| 日韩电影在线观看一区| 婷婷久久五月天| 久久麻豆视频| 久久视频中文字幕| 国产成人三级在线播放| 亚洲一区二区综合| 亚洲色图14p| 视频在线观看一区| 亚洲第一综合| 精品视频在线观看免费观看| 欧美夫妻性生活视频| 空姐吹箫视频大全| 色婷婷久久久亚洲一区二区三区| 国产精品20p| 国产综合久久久久久久久久久久| 黄色a级在线观看| 国产精品22p| 欧美中文在线字幕| 在线观看的av| 欧美一级一级性生活免费录像| 久久97人妻无码一区二区三区| a在线欧美一区| 日韩中文在线视频| 亚洲综合自拍网| 日精品一区二区三区| 亚洲欧洲日韩综合二区| 天堂久久av| 8090成年在线看片午夜| 午夜在线观看视频| 精品国产一区二区三区久久久蜜月| 欧美激情亚洲综合| 国产精品久久久久久久岛一牛影视| 激情图片中文字幕| 99热这里只有精品8| 天堂va久久久噜噜噜久久va| 精品亚洲a∨一区二区三区18| 亚洲2020天天堂在线观看| 国产h视频在线观看| 欧美成人精精品一区二区频| 7799精品视频天天看| 综合激情成人伊人| 欧美bbbbb性bbbbb视频| 激情综合色综合久久综合| 日本xxxxxxxxxx75| 91一区二区| 精品国产电影| 99er精品视频| 国产成人在线播放| 波多野结衣中文字幕久久| 最新的欧美黄色| 香蕉久久国产av一区二区| 欧美精品久久99| 精品国产一区二区三区四| 亚洲美女屁股眼交| 国产免费无遮挡吸奶头视频| 国产高清不卡一区二区| 日本在线观看免费视频| 亚洲深夜福利| 国产aaa免费视频| 国产精品91一区二区三区| 欧美激情论坛| 成人av动漫| 91青青草免费观看| 日韩免费大片| 国产精品成人av性教育| 欧美调教sm| 国内精久久久久久久久久人| 黄a在线观看| 中文字幕自拍vr一区二区三区| 天天爽夜夜爽夜夜爽| 日韩免费视频一区| 国产裸体永久免费无遮挡| 欧日韩精品视频| 欧美日韩综合一区二区三区| 亚洲午夜免费福利视频| 印度午夜性春猛xxx交| 国产精品久久久久桃色tv| 国产肥白大熟妇bbbb视频| 91老司机福利 在线| 欧美一区二区免费在线观看| 国产不卡在线一区| 亚洲一区二区三区三州| 国产在线精品国自产拍免费| 伊人影院综合在线| 蜜臀av性久久久久蜜臀aⅴ| 不卡av免费在线| 日韩精品视频网| 99久久国产宗和精品1上映| 性娇小13――14欧美| av高清在线免费观看| 99精品视频免费全部在线| 免费超爽大片黄| 亚洲裸体俱乐部裸体舞表演av| 国产日本在线播放| 999亚洲国产精| 97成人在线免费视频| 99精品视频网| 天天摸天天碰天天添| 久久精品一区| 青青青在线视频免费观看| 免费国产亚洲视频| 91小视频在线播放| 国产一区二区美女| aaaaa黄色片| a亚洲天堂av| 性欧美13一14内谢| 国产蜜臀97一区二区三区 | 亚洲第一页视频| 欧美精品一区二区三区视频| 日本人妻丰满熟妇久久久久久| 精品成a人在线观看| 日本不卡免费播放| 中日韩美女免费视频网址在线观看 | 国产亚洲精品中文字幕| 一本色道久久88| 一区二区久久久久| 波多野结衣国产| 在线观看亚洲精品| 99产精品成人啪免费网站| 精品国产青草久久久久福利| 日本一区二区三区在线观看视频| 永久555www成人免费| 国产不卡在线| 91国内产香蕉| 国产国产一区| 国产精品视频入口| 国产一区二区三区不卡视频网站| 亚洲欧洲另类精品久久综合| 欧美福利一区| 亚洲爆乳无码专区| 国产精一区二区三区| 国产乱了高清露脸对白| 欧美国产精品专区| 国产精品成人久久| 欧美性极品少妇| 丰满少妇一级片| 一夜七次郎国产精品亚洲| 最新超碰在线| 国产福利精品在线| 在这里有精品| 日韩不卡av| 国产精品大片免费观看| 日本激情视频在线| eeuss国产一区二区三区| 久久人妻无码aⅴ毛片a片app | 国产91对白刺激露脸在线观看| 美女脱光内衣内裤视频久久网站| 蜜臀视频在线观看| 中文字幕一区二区三| 特级做a爱片免费69| 日韩一区二区三区四区| 国产在线色视频| 久久久久久亚洲精品中文字幕| 欧美高清你懂的| 欧美13一14另类| 亚洲三级免费| 日本一本在线视频| 国产精品国产自产拍高清av王其| 久久久久久久久久久久久av| 日韩欧美自拍偷拍| 色的视频在线免费看| 日本亚洲欧美成人| 成人三级av在线| 日本一区二区免费高清视频| 久久久久免费| 亚洲专区区免费| 亚洲电影一级黄| 午夜精品久久久久久久99热黄桃| 在线一区二区日韩| 日韩中文影院| 欧美日韩一区二| 国产婷婷精品| 国产人妻黑人一区二区三区| 一区二区三区四区乱视频| 91av久久久| 中文字幕亚洲在线| 精品自拍视频| 五月天婷亚洲天综合网鲁鲁鲁| 欧美一级久久| 美女洗澡无遮挡| 色狠狠色噜噜噜综合网| 青青草av免费在线观看| 51午夜精品视频| 色哟哟精品丝袜一区二区| 少妇人妻无码专区视频| 波多野结衣中文字幕一区 | 欧美专区日韩专区| 六十路在线观看| 国产精品成人一区| 日韩精品一卡| 亚洲午夜激情影院| 中文字幕一区二区三区乱码在线| 亚洲字幕av一区二区三区四区| 最新亚洲国产精品| av在线成人| 一本大道东京热无码aⅴ| 国产69精品久久久久毛片| 精品无码一区二区三区电影桃花| 日韩精品一区二区三区在线| 日本高清在线观看| 国产精品免费观看高清| 亚洲毛片在线| 亚洲午夜久久久久久久久红桃| 精品福利一区二区| 高清毛片在线看| 成人精品视频99在线观看免费| 久久精品久久久| 香蕉视频免费网站| 黄色一区二区三区| 电影在线一区| 亚洲专区在线视频| 亚洲精品乱码| 日韩一区二区a片免费观看| 欧美色精品在线视频| a毛片在线观看| 精品国产综合区久久久久久| 天堂成人国产精品一区| 亚洲国产精品一区二区久久hs| 91精品国产福利| 日韩脚交footjobhdboots| 日韩欧美亚洲在线| 黄页视频在线91| 日韩手机在线观看| 伊人久久免费视频| 亚洲一区二区三区免费| 欧美日韩在线不卡视频| 亚洲天堂精品视频| 亚洲人视频在线观看| 国产精品视频专区| 韩国精品一区二区三区| 干b视频在线观看| 日韩视频在线观看一区二区| 亚洲精品永久免费视频| 国产高清免费在线| 91丨porny丨户外露出| 91精品国产乱码久久| 91精品国产91久久久久久| 99精品网站| 中文在线一区二区三区| 欧美日韩日本视频| 久草在线资源福利站| 一级一片免费播放| 久久综合色综合88| www久久久久久| 国产精品第三页| 亚洲视频1区| 欧美极品视频在线观看| 国产亚洲欧美aaaa| 欧美自拍一区| 成年人看片网站| 欧美视频一区二区| 亚洲精品日产|