xref: /linux-tools/drivers/mremap/inject.cpp (revision 74ce4ce33d5b8318cee71b38976a25818e666ff3)
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <sys/types.h>
4 #include <sys/wait.h>
5 #include <sys/ptrace.h>
6 #include <sys/user.h>
7 #include <sys/syscall.h>
8 #include <netinet/in.h>
9 #include <netinet/ip.h>
10 #include <errno.h>
11 #include <linux/elf.h>
12 #include <string.h>
13 #include <sys/stat.h>
14 #include <fcntl.h>
15 #include <unistd.h>
16 #include <sys/ioctl.h>
17 
18 #include <set>
19 #include <vector>
20 #include <string>
21 using namespace std;
22 
23 #define exiterr(err, msg) do{ if(err<0) { perror(msg); exit(1); }} while(0)
24 
25 enum {
26     PTRACEXX_REMAP = 1,
27 };
28 
29 typedef struct {
30     int pid;
31     unsigned long old_start, old_end;
32     unsigned long new_start, new_end;
33 } RemapDataT;
34 
35 typedef union {
36     RemapDataT remap;
37 } IoctlDataT;
38 
39 char ibuf[1024*8];
40 typedef struct {
41     unsigned long long start, end, offset;
42     char mode;
43     string name;
44 } MNode;
45 char ns[1024*8];
46 char vmk[128];
load_maps(int pid)47 vector<MNode>* load_maps(int pid) {
48     sprintf(ibuf, "/proc/%d/maps", pid);
49     FILE *fp = fopen(ibuf, "r");
50     char addrs[64], mode[8], offs[16], dev[16];
51     long long inode;
52     unsigned long long start, end, offset;
53     MNode nn;
54     int i, j, k;
55     char m, *p;
56     if (fp==NULL) return NULL;
57     vector<MNode>* ms = new vector<MNode>();
58     while(1) {
59         p = fgets(ibuf, sizeof(ibuf), fp); if (p==NULL) break;
60         k = sscanf(p, "%s %s %s %s %lld %s", addrs, mode, offs, dev, &inode, ns);
61         if (k<5) continue;
62         start=end=offset=0;
63         i=0; while(addrs[i]&&addrs[i]!='-') {
64             if (vmk[addrs[i]]==-1) break;
65             start=start*16+vmk[addrs[i]];
66             i++;
67         } if (i==0||addrs[i]!='-') continue;
68         j=i+1; while(addrs[j]) {
69             if (vmk[addrs[j]]==-1) break;
70             end = end*16+vmk[addrs[j]];
71             j++;
72         } if (j==i+1||addrs[j]!=0) continue;
73         i=0; while(offs[i]) {
74             if (vmk[offs[i]]==-1) break;
75             offset = offset*16+vmk[offs[i]];
76             i++;
77         } if (i==0||offs[i]!=0) continue;
78         m=0; for (i=0; i<4; i++) if (mode[i]!='-') m|=(1<<i);
79         nn.start=start;
80         nn.end = end;
81         nn.offset = offset;
82         nn.mode=m;
83         if (k==5) {
84             nn.name = string();
85         } else if (k==6) {
86             i=0; while(ns[i]) i++;
87             while(i>0&&ns[i-1]!='/') i--;
88             nn.name = string(ns+i);
89         }
90         ms->push_back(nn);
91     }
92     fclose(fp);
93     return ms;
94 }
95 
96 char buf[1024*1024];
97 typedef struct {
98     int regset;
99     size_t size;
100     unsigned long offset;
101 } RegHNode;
102 
103 typedef struct {
104     unsigned long start, end, offset;
105     unsigned long noffset, doffset;
106     size_t nlen, dsize;
107     unsigned int mode;
108 } MapHNode;
109 
110 char mmk[128];
111 
main(int argc,char * argv[])112 int main(int argc, char *argv[]) {
113     int pid, err, status, x, i, z, n, fd=-1;
114     unsigned long offset, hlen, dlen;
115     unsigned long faddr = 0x200000000000;
116     struct iovec regset;
117     unsigned long cz, sz, zzz, nstart, nend, _start, _end;
118     int ddd, j, nj;
119     long rc;
120     unsigned long vw, *tp;
121     struct user userinfo;
122     FILE *fp_header=NULL, *fp_binary=NULL;
123     vector<MNode>* mp = NULL;
124     RegHNode regset_header;
125     MapHNode mheader;
126     vector<MapHNode> omp;
127     vector<string> oname;
128     vector<RegHNode> regsets;
129     IoctlDataT d;
130     if (argc<2) { printf("need pid\n"); return 1; }
131     pid = atoi(argv[1]);
132     if (pid<=0) { printf("invalid pid %s\n", argv[1]); return 1; }
133     err = ptrace(PTRACE_ATTACH, pid, 0, 0);
134     exiterr(err, "fail to attach");
135     printf("attached with %d\n", pid);
136     x = waitpid(-1, &status, __WALL);
137     if (x != pid) {
138         printf("expect pid %d, got %d\n", pid, x);
139         return 1;
140     }
141     fp_header = fopen("./spirity.header", "rb"); if (fp_header==NULL) goto out;
142     fp_binary = fopen("./spirity.binary", "rb"); if (fp_binary==NULL) goto out;
143     fd = open("/dev/ptracexx", O_NONBLOCK);
144     if (fd<0) { perror("fail to open ptracexx\n"); goto out; }
145     // read user info
146     if (fread(&userinfo, sizeof(userinfo), 1, fp_header)!=1) {
147         printf("fail to read userinfo\n"); goto out;
148     }
149     // read reg header
150     regset.iov_base = (void*)buf;
151     while(1) {
152         n = fread(&regset_header, sizeof(regset_header), 1, fp_header);
153         if (n!=1) goto out;
154         if (regset_header.regset == -1) break;
155         printf("regset %d: size %ld, data offset 0x%lx\n", regset_header.regset, regset_header.size, regset_header.offset);
156         regsets.push_back(regset_header);
157         // write back
158         // read to buf
159         /*
160         fseek(fp_binary, regset_header.offset, SEEK_SET);
161         n = fread(buf, 1, regset_header.size, fp_binary); if (n!=regset_header.size) {
162             printf("fail to load regset data");
163             goto out;
164         }
165         regset.iov_len = regset_header.size;
166         x = ptrace(PTRACE_SETREGSET, pid, regset_header.regset, &regset);
167         if (x<0) {
168             printf("fail to load regset\n");
169             goto out;
170         }
171         */
172     }
173     // get pid maps
174     memset(vmk, 0xff, sizeof(vmk));
175     for (i='0'; i<='9'; i++) vmk[i]=i-'0';
176     for (i='a'; i<='f'; i++) vmk[i]=i-'a'+10;
177     for (i='A'; i<='F'; i++) vmk[i]=i-'A'+10;
178     mp = load_maps(pid); if (mp==NULL) goto  out;
179     // read mmaps from save
180     while(1) {
181         n = fread(&mheader, sizeof(mheader), 1, fp_header); if (n!=1) goto out;
182         if (mheader.start == -1) break;
183         ibuf[0]=0;
184         if (mheader.nlen) {
185             fseek(fp_binary, mheader.noffset, SEEK_SET);
186             fread(ibuf, 1, mheader.nlen, fp_binary);
187             ibuf[mheader.nlen]=0;
188         }
189         printf("[0x%lx,0x%lx) 0x%lx 0x%x  namelen(%d):[%s], noffset(0x%lx), doffset(0x%lx)\n",
190                 mheader.start, mheader.end, mheader.offset, mheader.mode, mheader.nlen, ibuf,
191                 mheader.noffset, mheader.doffset);
192         omp.push_back(mheader);
193         if (ibuf[0]==0) oname.push_back(string());
194         else oname.push_back(string(ibuf));
195     }
196     // align maps
197     n = omp.size();
198     if (mp->size() != n) {
199         printf("size not match, current %d, expect %d\n", mp->size(), omp.size());
200         goto out;
201     }
202     for (i=0; i<n; i++) mmk[i]=0;
203     for (i=0; i<n; i++) printf("0x%lx[%s](0x%lx)---\n", (*mp)[i].start, (*mp)[i].name.c_str(), (*mp)[i].offset);
204     d.remap.pid = pid;
205     for (i=0; i<n; i++) {
206         printf("0x%lx[%s](0x%lx) --->\n", omp[i].start, oname[i].c_str(), omp[i].offset);
207         for (j=0; j<n; j++) if (mmk[j]==0) {
208             if (oname[i]==(*mp)[j].name && omp[i].offset==(*mp)[j].offset) break;
209         }
210         if (j>=n) { printf("no match found\n"); goto out; }
211         printf("found match --->0x%lx[%s](0x%lx)\n", (*mp)[j].start, (*mp)[j].name.c_str(), (*mp)[j].offset);
212         mmk[j]=1;
213         nstart = omp[i].start;
214         nend = omp[i].end;
215         if (omp[i].start!=(*mp)[j].start) {
216             for (nj=0; nj<n; nj++) if (mmk[nj]==0) {
217                 _start = (*mp)[nj].start;
218                 _end = (*mp)[nj].end;
219                 if (_start>=nend) continue;
220                 if (_end<=nstart) continue;
221                 // remap to faddr
222                 d.remap.old_start = _start;
223                 d.remap.old_end = _end;
224                 d.remap.new_start = faddr;
225                 d.remap.new_end = _end-_start+faddr;
226                 (*mp)[nj].start = faddr;
227                 faddr += (_end-_start);
228                 (*mp)[nj].end = faddr;
229                 rc = ioctl(fd, PTRACEXX_REMAP, &d);
230                 if (rc<0) {
231                     printf("fail to remap %ld\n", rc);
232                     goto out;
233                 }
234             }
235             d.remap.old_start = (*mp)[j].start;
236             d.remap.old_end = (*mp)[j].end;
237             d.remap.new_start = nstart;
238             d.remap.new_end = nend;
239             rc = ioctl(fd, PTRACEXX_REMAP, &d);
240             if (rc<0) {
241                 printf("fail to remap %ld\n", rc);
242                 goto out;
243             }
244         }
245         // write memory
246         //  if ((omp[i].mode&(1<<1))==0) continue;
247         printf("try to copy memory\n");
248         fseek(fp_binary, omp[i].doffset, SEEK_SET);
249         sz = omp[i].dsize; // nend-nstart;
250         while(sz) {
251             cz=sz; if (cz>sizeof(buf)) cz=sizeof(buf);
252             if(fread(buf, 1, cz, fp_binary)!=cz) { printf("fail to load map memory\n"); goto out; }
253             for (zzz=0; zzz<cz; zzz+=8) {
254                 // copy word by word
255                 vw = *(unsigned long*)(buf+zzz);
256                 // printf("write to 0x%lx %x\n", nstart+zzz, ddd);
257                 x = ptrace(PTRACE_POKEDATA, pid, nstart+zzz, vw);
258                 if (x<0) { perror("fail to poke user memory"); break; }
259             }
260             if (zzz<cz) {
261                 sz-=zzz;
262                 break;
263             }
264             sz-=cz;
265             nstart+=cz;
266         }
267         if (sz) printf("....%ld left\n", sz);
268     }
269     // load user
270     tp = (unsigned long*)&userinfo;
271     for (i=0; i<sizeof(userinfo); i+=sizeof(unsigned long)) {
272         vw = ptrace(PTRACE_POKEUSER, pid, i, *tp);
273         if (vw==-1) {
274             printf("poke offset %d failed\n", i);
275             perror("error:");
276             goto out;
277         }
278         tp++;
279     }
280     // load reg
281     n = regsets.size();
282     for (i=0; i<n; i++) {
283         regset_header = regsets[i];
284         printf("load regset %d\n", regset_header.regset);
285         // write back
286         // read to buf
287         fseek(fp_binary, regset_header.offset, SEEK_SET);
288         n = fread(buf, 1, regset_header.size, fp_binary); if (n!=regset_header.size) {
289             printf("fail to load regset data");
290             goto out;
291         }
292         regset.iov_len = regset_header.size;
293         x = ptrace(PTRACE_SETREGSET, pid, regset_header.regset, &regset);
294         if (x<0) {
295             printf("fail to load regset\n");
296             goto out;
297         }
298     }
299 
300 out:
301     // ptrace(PTRACE_CONT, pid, 0, 0);
302     if (fd>0) close(fd);
303     if (fp_header) fclose(fp_header);
304     if (fp_binary) fclose(fp_binary);
305     return 0;
306 }
307