1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package time
17
18 import (
19 "bytes"
20 "runtime"
21
22 "github.com/pkg/errors"
23
24 "github.com/chaos-mesh/chaos-mesh/pkg/mapreader"
25 "github.com/chaos-mesh/chaos-mesh/pkg/ptrace"
26 )
27
28
29 const timeSkewFakeImage = "fake_clock_gettime.o"
30
31
32 const vdsoEntryName = "[vdso]"
33
34
35 const clockGettime = "clock_gettime"
36
37
38 const (
39 externVarClockIdsMask = "CLOCK_IDS_MASK"
40 externVarTvSecDelta = "TV_SEC_DELTA"
41 externVarTvNsecDelta = "TV_NSEC_DELTA"
42 )
43
44 type TimeSkew struct {
45 deltaSeconds int64
46 deltaNanoSeconds int64
47 clockIDsMask uint64
48 fakeImage *FakeImage
49 }
50
51 func NewTimeSkew(deltaSeconds int64, deltaNanoSeconds int64, clockIDsMask uint64) (*TimeSkew, error) {
52 var image *FakeImage
53 var err error
54
55 if image, err = LoadFakeImageFromEmbedFs(timeSkewFakeImage); err != nil {
56 return nil, errors.Wrap(err, "load fake image")
57 }
58
59 return NewTimeSkewWithCustomFakeImage(deltaSeconds, deltaNanoSeconds, clockIDsMask, image), nil
60 }
61
62 func NewTimeSkewWithCustomFakeImage(deltaSeconds int64, deltaNanoSeconds int64, clockIDsMask uint64, fakeImage *FakeImage) *TimeSkew {
63 return &TimeSkew{deltaSeconds: deltaSeconds, deltaNanoSeconds: deltaNanoSeconds, clockIDsMask: clockIDsMask, fakeImage: fakeImage}
64 }
65
66 func (it *TimeSkew) Inject(pid int) error {
67
68 runtime.LockOSThread()
69 defer func() {
70 runtime.UnlockOSThread()
71 }()
72
73 program, err := ptrace.Trace(pid)
74 if err != nil {
75 return errors.Wrapf(err, "ptrace on target process, pid: %d", pid)
76 }
77 defer func() {
78 err = program.Detach()
79 if err != nil {
80 log.Error(err, "fail to detach program", "pid", program.Pid())
81 }
82 }()
83
84 var vdsoEntry *mapreader.Entry
85 for index := range program.Entries {
86
87 e := program.Entries[len(program.Entries)-index-1]
88 if e.Path == vdsoEntryName {
89 vdsoEntry = &e
90 break
91 }
92 }
93 if vdsoEntry == nil {
94 return errors.Errorf("cannot find [vdso] entry, pid: %d", pid)
95 }
96
97
98
99 constImageLen := len(it.fakeImage.content) - 8*len(it.fakeImage.offset)
100 var fakeEntry *mapreader.Entry
101
102
103 for _, e := range program.Entries {
104 e := e
105
106 image, err := program.ReadSlice(e.StartAddress, uint64(constImageLen))
107 if err != nil {
108 continue
109 }
110
111 if bytes.Equal(*image, it.fakeImage.content[0:constImageLen]) {
112 fakeEntry = &e
113 log.Info("found injected image", "addr", fakeEntry.StartAddress, "pid", pid)
114 break
115 }
116 }
117
118
119 if fakeEntry == nil {
120 fakeEntry, err = program.MmapSlice(it.fakeImage.content)
121 if err != nil {
122 return errors.Wrapf(err, "mmap fake image, pid: %d", pid)
123 }
124
125 originAddr, err := program.FindSymbolInEntry(clockGettime, vdsoEntry)
126 if err != nil {
127 return errors.Wrapf(err, "find origin clock_gettime in vdso, pid: %d", pid)
128 }
129
130 err = program.JumpToFakeFunc(originAddr, fakeEntry.StartAddress)
131 if err != nil {
132 return errors.Wrapf(err, "override origin clock_gettime, pid: %d", pid)
133 }
134 }
135
136 err = program.WriteUint64ToAddr(fakeEntry.StartAddress+uint64(it.fakeImage.offset[externVarClockIdsMask]), it.clockIDsMask)
137 if err != nil {
138 return errors.Wrapf(err, "set %s for time skew, pid: %d", externVarClockIdsMask, pid)
139 }
140
141 err = program.WriteUint64ToAddr(fakeEntry.StartAddress+uint64(it.fakeImage.offset[externVarTvSecDelta]), uint64(it.deltaSeconds))
142 if err != nil {
143 return errors.Wrapf(err, "set %s for time skew, pid: %d", externVarTvSecDelta, pid)
144 }
145
146 err = program.WriteUint64ToAddr(fakeEntry.StartAddress+uint64(it.fakeImage.offset[externVarTvNsecDelta]), uint64(it.deltaNanoSeconds))
147 if err != nil {
148 return errors.Wrapf(err, "set %s for time skew, pid: %d", externVarTvNsecDelta, pid)
149 }
150 return nil
151 }
152
153 func (it *TimeSkew) Recover(pid int) error {
154 zeroSkew := NewTimeSkewWithCustomFakeImage(0, 0, it.clockIDsMask, it.fakeImage)
155 return zeroSkew.Inject(pid)
156 }
157