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/go-logr/logr"
23 "github.com/pkg/errors"
24
25 "github.com/chaos-mesh/chaos-mesh/pkg/cerr"
26 "github.com/chaos-mesh/chaos-mesh/pkg/mapreader"
27 "github.com/chaos-mesh/chaos-mesh/pkg/ptrace"
28 )
29
30
31 const vdsoEntryName = "[vdso]"
32
33
34
35 type FakeImage struct {
36
37 symbolName string
38
39 content []byte
40
41
42 offset map[string]int
43
44 OriginFuncCode []byte
45
46 OriginAddress uint64
47
48 fakeEntry *mapreader.Entry
49
50 logger logr.Logger
51 }
52
53 func NewFakeImage(symbolName string, content []byte, offset map[string]int, logger logr.Logger) *FakeImage {
54 return &FakeImage{symbolName: symbolName, content: content, offset: offset, logger: logger}
55 }
56
57
58
59 func (it *FakeImage) AttachToProcess(pid int, variables map[string]uint64) (err error) {
60 if len(variables) != len(it.offset) {
61 return errors.New("fake image: extern variable number not match")
62 }
63
64 runtime.LockOSThread()
65 defer func() {
66 runtime.UnlockOSThread()
67 }()
68
69 program, err := ptrace.Trace(pid, it.logger.WithName("ptrace").WithValues("pid", pid))
70 if err != nil {
71 return errors.Wrapf(err, "ptrace on target process, pid: %d", pid)
72 }
73 defer func() {
74 err = program.Detach()
75 if err != nil {
76 it.logger.Error(err, "fail to detach program", "pid", program.Pid())
77 }
78 }()
79
80 vdsoEntry, err := FindVDSOEntry(program)
81 if err != nil {
82 return errors.Wrapf(err, "PID : %d", pid)
83 }
84
85 fakeEntry, err := it.FindInjectedImage(program, len(variables))
86 if err != nil {
87 return errors.Wrapf(err, "PID : %d", pid)
88 }
89
90 if fakeEntry == nil {
91 fakeEntry, err = it.InjectFakeImage(program, vdsoEntry)
92 if err != nil {
93 return errors.Wrapf(err, "injecting fake image , PID : %d", pid)
94 }
95 defer func() {
96 if err != nil {
97 errIn := it.TryReWriteFakeImage(program)
98 if errIn != nil {
99 it.logger.Error(errIn, "rewrite fail, recover fail")
100 }
101 it.OriginFuncCode = nil
102 it.OriginAddress = 0
103 }
104 }()
105 }
106
107 for k, v := range variables {
108 err = it.SetVarUint64(program, fakeEntry, k, v)
109
110 if err != nil {
111 return errors.Wrapf(err, "set %s for time skew, pid: %d", k, pid)
112 }
113 }
114
115 return
116 }
117
118 func FindVDSOEntry(program *ptrace.TracedProgram) (*mapreader.Entry, error) {
119 var vdsoEntry *mapreader.Entry
120 for index := range program.Entries {
121
122 e := program.Entries[len(program.Entries)-index-1]
123 if e.Path == vdsoEntryName {
124 vdsoEntry = &e
125 break
126 }
127 }
128 if vdsoEntry == nil {
129 return nil, cerr.NotFound("VDSOEntry").Err()
130 }
131 return vdsoEntry, nil
132 }
133
134
135 func (it *FakeImage) FindInjectedImage(program *ptrace.TracedProgram, varNum int) (*mapreader.Entry, error) {
136 it.logger.Info("finding injected image")
137
138
139
140 if it.fakeEntry != nil {
141 content, err := program.ReadSlice(it.fakeEntry.StartAddress, it.fakeEntry.EndAddress-it.fakeEntry.StartAddress)
142 if err != nil {
143 it.logger.Info("ReadSlice fail")
144 return nil, nil
145 }
146 if varNum*8 > len(it.content) {
147 return nil, errors.New("variable num bigger than content num")
148 }
149 contentWithoutVariable := (*content)[:len(it.content)-varNum*varLength]
150 expectedContentWithoutVariable := it.content[:len(it.content)-varNum*varLength]
151 it.logger.Info("successfully read slice", "content", contentWithoutVariable, "expected content", expectedContentWithoutVariable)
152
153 if bytes.Equal(contentWithoutVariable, expectedContentWithoutVariable) {
154 it.logger.Info("slice found")
155 return it.fakeEntry, nil
156 }
157 it.logger.Info("slice not found")
158 }
159 return nil, nil
160 }
161
162
163
164 func (it *FakeImage) InjectFakeImage(program *ptrace.TracedProgram,
165 vdsoEntry *mapreader.Entry) (*mapreader.Entry, error) {
166 fakeEntry, err := program.MmapSlice(it.content)
167 if err != nil {
168 return nil, errors.Wrapf(err, "mmap fake image")
169 }
170 it.fakeEntry = fakeEntry
171 originAddr, size, err := program.FindSymbolInEntry(it.symbolName, vdsoEntry)
172 if err != nil {
173 return nil, errors.Wrapf(err, "find origin %s in vdso", it.symbolName)
174 }
175 funcBytes, err := program.ReadSlice(originAddr, size)
176 if err != nil {
177 return nil, errors.Wrapf(err, "ReadSlice failed")
178 }
179 err = program.JumpToFakeFunc(originAddr, fakeEntry.StartAddress)
180 if err != nil {
181 errIn := it.TryReWriteFakeImage(program)
182 if errIn != nil {
183 it.logger.Error(errIn, "rewrite fail, recover fail")
184 }
185 return nil, errors.Wrapf(err, "override origin %s", it.symbolName)
186 }
187
188 it.OriginFuncCode = *funcBytes
189 it.OriginAddress = originAddr
190 return fakeEntry, nil
191 }
192
193 func (it *FakeImage) TryReWriteFakeImage(program *ptrace.TracedProgram) error {
194 if it.OriginFuncCode != nil {
195 err := program.PtraceWriteSlice(it.OriginAddress, it.OriginFuncCode)
196 if err != nil {
197 return err
198 }
199 it.OriginFuncCode = nil
200 it.OriginAddress = 0
201 }
202 return nil
203 }
204
205
206
207 func (it *FakeImage) Recover(pid int, vars map[string]uint64) error {
208 runtime.LockOSThread()
209 defer func() {
210 runtime.UnlockOSThread()
211 }()
212 if it.OriginFuncCode == nil {
213 return nil
214 }
215 program, err := ptrace.Trace(pid, it.logger.WithName("ptrace").WithValues("pid", pid))
216 if err != nil {
217 return errors.Wrapf(err, "ptrace on target process, pid: %d", pid)
218 }
219 defer func() {
220 err = program.Detach()
221 if err != nil {
222 it.logger.Error(err, "fail to detach program", "pid", program.Pid())
223 }
224 }()
225
226 fakeEntry, err := it.FindInjectedImage(program, len(vars))
227 if err != nil {
228 return errors.Wrapf(err, "FindInjectedImage , pid: %d", pid)
229 }
230 if fakeEntry == nil {
231 return nil
232 }
233
234 err = it.TryReWriteFakeImage(program)
235 return err
236 }
237