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