...

Source file src/github.com/chaos-mesh/chaos-mesh/pkg/time/time_linux_amd64.go

Documentation: github.com/chaos-mesh/chaos-mesh/pkg/time

     1  // Copyright 2020 Chaos Mesh 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  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package time
    15  
    16  import (
    17  	"bytes"
    18  	"errors"
    19  	"runtime"
    20  
    21  	"github.com/chaos-mesh/chaos-mesh/pkg/mapreader"
    22  	"github.com/chaos-mesh/chaos-mesh/pkg/mock"
    23  	"github.com/chaos-mesh/chaos-mesh/pkg/ptrace"
    24  )
    25  
    26  // TODO: support more cpu architecture
    27  // TODO: auto generate these codes
    28  var fakeImage = []byte{
    29  	0xb8, 0xe4, 0x00, 0x00, 0x00, //mov    $0xe4,%eax
    30  	0x0f, 0x05, //syscall
    31  	0xba, 0x01, 0x00, 0x00, 0x00, //mov    $0x1,%edx
    32  	0x89, 0xf9, //mov    %edi,%ecx
    33  	0xd3, 0xe2, //shl    %cl,%edx
    34  	0x48, 0x8d, 0x0d, 0x74, 0x00, 0x00, 0x00, //lea    0x74(%rip),%rcx        # <CLOCK_IDS_MASK>
    35  	0x48, 0x63, 0xd2, //movslq %edx,%rdx
    36  	0x48, 0x85, 0x11, //test   %rdx,(%rcx)
    37  	0x74, 0x6b, //je     108a <clock_gettime+0x8a>
    38  	0x48, 0x8d, 0x15, 0x6d, 0x00, 0x00, 0x00, //lea    0x6d(%rip),%rdx        # <TV_SEC_DELTA>
    39  	0x4c, 0x8b, 0x46, 0x08, //mov    0x8(%rsi),%r8
    40  	0x48, 0x8b, 0x0a, //mov    (%rdx),%rcx
    41  	0x48, 0x8d, 0x15, 0x67, 0x00, 0x00, 0x00, //lea    0x67(%rip),%rdx        # <TV_NSEC_DELTA>
    42  	0x48, 0x8b, 0x3a, //mov    (%rdx),%rdi
    43  	0x4a, 0x8d, 0x14, 0x07, //lea    (%rdi,%r8,1),%rdx
    44  	0x48, 0x81, 0xfa, 0x00, 0xca, 0x9a, 0x3b, //cmp    $0x3b9aca00,%rdx
    45  	0x7e, 0x1c, //jle    <clock_gettime+0x60>
    46  	0x0f, 0x1f, 0x40, 0x00, //nopl   0x0(%rax)
    47  	0x48, 0x81, 0xef, 0x00, 0xca, 0x9a, 0x3b, //sub    $0x3b9aca00,%rdi
    48  	0x48, 0x83, 0xc1, 0x01, //add    $0x1,%rcx
    49  	0x49, 0x8d, 0x14, 0x38, //lea    (%r8,%rdi,1),%rdx
    50  	0x48, 0x81, 0xfa, 0x00, 0xca, 0x9a, 0x3b, //cmp    $0x3b9aca00,%rdx
    51  	0x7f, 0xe8, //jg     <clock_gettime+0x48>
    52  	0x48, 0x85, 0xd2, //test   %rdx,%rdx
    53  	0x79, 0x1e, //jns    <clock_gettime+0x83>
    54  	0x4a, 0x8d, 0xbc, 0x07, 0x00, 0xca, 0x9a, //lea    0x3b9aca00(%rdi,%r8,1),%rdi
    55  	0x3b,             //
    56  	0x0f, 0x1f, 0x00, //nopl   (%rax)
    57  	0x48, 0x89, 0xfa, //mov    %rdi,%rdx
    58  	0x48, 0x83, 0xe9, 0x01, //sub    $0x1,%rcx
    59  	0x48, 0x81, 0xc7, 0x00, 0xca, 0x9a, 0x3b, //add    $0x3b9aca00,%rdi
    60  	0x48, 0x85, 0xd2, //test   %rdx,%rdx
    61  	0x78, 0xed, //js     <clock_gettime+0x70>
    62  	0x48, 0x01, 0x0e, //add    %rcx,(%rsi)
    63  	0x48, 0x89, 0x56, 0x08, //mov    %rdx,0x8(%rsi)
    64  	0xc3, //retq
    65  	// constant
    66  	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //CLOCK_IDS_MASK
    67  	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //TV_SEC_DELTA
    68  	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //TV_NSEC_DELTA
    69  }
    70  
    71  // ModifyTime modifies time of target process
    72  func ModifyTime(pid int, deltaSec int64, deltaNsec int64, clockIdsMask uint64) error {
    73  	// Mock point to return error in unit test
    74  	if err := mock.On("ModifyTimeError"); err != nil {
    75  		if e, ok := err.(error); ok {
    76  			return e
    77  		}
    78  		if ignore, ok := err.(bool); ok && ignore {
    79  			return nil
    80  		}
    81  	}
    82  
    83  	runtime.LockOSThread()
    84  	defer func() {
    85  		runtime.UnlockOSThread()
    86  	}()
    87  
    88  	program, err := ptrace.Trace(pid)
    89  	if err != nil {
    90  		return err
    91  	}
    92  	defer func() {
    93  		err = program.Detach()
    94  		if err != nil {
    95  			log.Error(err, "fail to detach program", "pid", program.Pid())
    96  		}
    97  	}()
    98  
    99  	var vdsoEntry *mapreader.Entry
   100  	for index := range program.Entries {
   101  		// reverse loop is faster
   102  		e := program.Entries[len(program.Entries)-index-1]
   103  		if e.Path == "[vdso]" {
   104  			vdsoEntry = &e
   105  			break
   106  		}
   107  	}
   108  	if vdsoEntry == nil {
   109  		return errors.New("cannot find [vdso] entry")
   110  	}
   111  
   112  	// minus tailing variable part
   113  	// 24 = 3 * 8 because we have three variables
   114  	constImageLen := len(fakeImage) - 24
   115  	var fakeEntry *mapreader.Entry
   116  
   117  	// find injected image to avoid redundant inject (which will lead to memory leak)
   118  	for _, e := range program.Entries {
   119  		e := e
   120  
   121  		image, err := program.ReadSlice(e.StartAddress, uint64(constImageLen))
   122  		if err != nil {
   123  			continue
   124  		}
   125  
   126  		if bytes.Equal(*image, fakeImage[0:constImageLen]) {
   127  			fakeEntry = &e
   128  			log.Info("found injected image", "addr", fakeEntry.StartAddress)
   129  			break
   130  		}
   131  	}
   132  	if fakeEntry == nil {
   133  		fakeEntry, err = program.MmapSlice(fakeImage)
   134  		if err != nil {
   135  			return err
   136  		}
   137  	}
   138  	fakeAddr := fakeEntry.StartAddress
   139  
   140  	// 139 is the index of CLOCK_IDS_MASK in fakeImage
   141  	err = program.WriteUint64ToAddr(fakeAddr+139, clockIdsMask)
   142  	if err != nil {
   143  		return err
   144  	}
   145  
   146  	// 147 is the index of TV_SEC_DELTA in fakeImage
   147  	err = program.WriteUint64ToAddr(fakeAddr+147, uint64(deltaSec))
   148  	if err != nil {
   149  		return err
   150  	}
   151  
   152  	// 155 is the index of TV_NSEC_DELTA in fakeImage
   153  	err = program.WriteUint64ToAddr(fakeAddr+155, uint64(deltaNsec))
   154  	if err != nil {
   155  		return err
   156  	}
   157  
   158  	originAddr, err := program.FindSymbolInEntry("clock_gettime", vdsoEntry)
   159  	if err != nil {
   160  		return err
   161  	}
   162  
   163  	err = program.JumpToFakeFunc(originAddr, fakeAddr)
   164  	return err
   165  }
   166