Branch data Line data Source code
1 : : #include <unistd.h>
2 : : #include <string.h>
3 : : #include <stdlib.h>
4 : : #include "crtools.h"
5 : : #include "ptrace.h"
6 : : #include "parasite-syscall.h"
7 : : #include "vma.h"
8 : : #include "log.h"
9 : :
10 : : struct syscall_exec_desc {
11 : : char *name;
12 : : unsigned nr;
13 : : };
14 : :
15 : : static struct syscall_exec_desc sc_exec_table[] = {
16 : : #define SYSCALL(__name, __nr) { .name = #__name, .nr = __nr, },
17 : : #include "sys-exec-tbl.c"
18 : : #undef SYSCALL
19 : : { }, /* terminator */
20 : : };
21 : :
22 : 0 : static struct syscall_exec_desc *find_syscall(char *name)
23 : : {
24 : : int i;
25 : :
26 [ # # ]: 0 : for (i = 0; sc_exec_table[i].name != NULL; i++)
27 [ # # ]: 0 : if (!strcmp(sc_exec_table[i].name, name))
28 : 0 : return &sc_exec_table[i];
29 : :
30 : : return NULL;
31 : : }
32 : :
33 : : #define MAX_ARGS 6
34 : :
35 : 0 : static int execute_syscall(struct parasite_ctl *ctl,
36 : : struct syscall_exec_desc *scd, char **opt)
37 : : {
38 : : int i, err;
39 : 0 : unsigned long args[MAX_ARGS] = {}, ret, r_mem_size = 0;
40 : 0 : unsigned int ret_args[MAX_ARGS] = {};
41 : : void *r_mem = NULL;
42 : :
43 [ # # ]: 0 : for (i = 0; i < MAX_ARGS; i++) {
44 [ # # ]: 0 : if (opt[i] == NULL)
45 : : break;
46 : :
47 : : /*
48 : : * &foo -- argument string "foo"
49 : : * @<size> -- ret-arg of size <size>
50 : : */
51 : :
52 [ # # ]: 0 : if ((opt[i][0] == '&') || (opt[i][0] == '@')) {
53 : : int len;
54 : :
55 [ # # ]: 0 : if (!r_mem) {
56 : 0 : err = parasite_map_exchange(ctl, PAGE_SIZE);
57 [ # # ]: 0 : if (err)
58 : : return err;
59 : :
60 : : r_mem_size = PAGE_SIZE;
61 : 0 : r_mem = ctl->local_map;
62 : : }
63 : :
64 [ # # ]: 0 : if (opt[i][0] == '&') {
65 : 0 : len = strlen(opt[i]);
66 [ # # ]: 0 : if (r_mem_size < len) {
67 : 0 : pr_err("Arg size overflow\n");
68 : : return -1;
69 : : }
70 : :
71 : 0 : memcpy(r_mem, opt[i] + 1, len);
72 : : } else {
73 : 0 : len = strtol(opt[i] + 1, NULL, 0);
74 [ # # ][ # # ]: 0 : if (!len || (r_mem_size < len)) {
75 : 0 : pr_err("Bad argument size %d\n", len);
76 : : return -1;
77 : : }
78 : :
79 : 0 : ret_args[i] = len;
80 : : }
81 : :
82 : 0 : args[i] = (unsigned long)ctl->remote_map + (r_mem - ctl->local_map);
83 : 0 : pr_info("Pushing %c mem arg [%s]\n", opt[i][0], (char *)r_mem);
84 : 0 : r_mem_size -= len;
85 : 0 : r_mem += len;
86 : : } else
87 : 0 : args[i] = strtol(opt[i], NULL, 0);
88 : : }
89 : :
90 : 0 : pr_info("Calling %d with %lu %lu %lu %lu %lu %lu\n", scd->nr,
91 : : args[0], args[1], args[2], args[3], args[4], args[5]);
92 : :
93 : 0 : err = syscall_seized(ctl, scd->nr, &ret,
94 : : args[0], args[1], args[2], args[3], args[4], args[5]);
95 [ # # ]: 0 : if (err)
96 : : return err;
97 : :
98 : 0 : pr_msg("Syscall returned %lx(%d)\n", ret, (int)ret);
99 [ # # ]: 0 : for (i = 0; i < MAX_ARGS; i++) {
100 : : unsigned long addr;
101 : :
102 [ # # ]: 0 : if (!ret_args[i])
103 : 0 : continue;
104 : :
105 : 0 : pr_msg("Argument %d returns:\n", i);
106 : 0 : addr = (unsigned long)ctl->local_map + (args[i] - (unsigned long)ctl->remote_map);
107 : 0 : print_data(0, (unsigned char *)addr, ret_args[i]);
108 : : }
109 : :
110 : : return 0;
111 : : }
112 : :
113 : 0 : int cr_exec(int pid, char **opt)
114 : : {
115 : 0 : char *sys_name = opt[0];
116 : : struct syscall_exec_desc *si;
117 : : struct parasite_ctl *ctl;
118 : : struct vm_area_list vmas;
119 : : int ret = -1, prev_state;
120 : :
121 [ # # ]: 0 : if (!sys_name) {
122 : 0 : pr_err("Syscall name required\n");
123 : 0 : goto out;
124 : : }
125 : :
126 : 0 : si = find_syscall(sys_name);
127 [ # # ]: 0 : if (!si) {
128 : 0 : pr_err("Unknown syscall [%s]\n", sys_name);
129 : 0 : goto out;
130 : : }
131 : :
132 : 0 : prev_state = ret = seize_task(pid, -1, NULL, NULL);
133 [ # # ]: 0 : if (ret < 0) {
134 : 0 : pr_err("Can't seize task %d\n", pid);
135 : 0 : goto out;
136 : : }
137 : :
138 : 0 : ret = collect_mappings(pid, &vmas);
139 [ # # ]: 0 : if (ret) {
140 : 0 : pr_err("Can't collect vmas for %d\n", pid);
141 : 0 : goto out_unseize;
142 : : }
143 : :
144 : 0 : ctl = parasite_prep_ctl(pid, &vmas);
145 [ # # ]: 0 : if (!ctl) {
146 : 0 : pr_err("Can't prep ctl %d\n", pid);
147 : 0 : goto out_unseize;
148 : : }
149 : :
150 : 0 : ret = execute_syscall(ctl, si, opt + 1);
151 [ # # ]: 0 : if (ret < 0)
152 : 0 : pr_err("Can't execute syscall remotely\n");
153 : :
154 : 0 : parasite_cure_seized(ctl);
155 : : out_unseize:
156 : 0 : unseize_task(pid, prev_state, prev_state);
157 : : out:
158 : 0 : return ret;
159 : : }
|