-
Notifications
You must be signed in to change notification settings - Fork 20
Expand file tree
/
Copy pathredir_filter.c
More file actions
158 lines (134 loc) · 4.28 KB
/
redir_filter.c
File metadata and controls
158 lines (134 loc) · 4.28 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <stddef.h>
#include <sys/ptrace.h>
#include <sys/reg.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <sys/user.h>
#include <sys/prctl.h>
#include <fcntl.h>
#include <linux/limits.h>
#include <linux/filter.h>
#include <linux/seccomp.h>
#include <linux/unistd.h>
static void process_signals(pid_t child);
static int wait_for_open(pid_t child);
static void read_file(pid_t child, char *file);
static void redirect_file(pid_t child, const char *file);
int main(int argc, char **argv)
{
pid_t pid;
int status;
if (argc < 2) {
fprintf(stderr, "Usage: %s <prog> <arg1> ... <argN>\n", argv[0]);
return 1;
}
if ((pid = fork()) == 0) {
/* If open syscall, trace */
struct sock_filter filter[] = {
BPF_STMT(BPF_LD+BPF_W+BPF_ABS, offsetof(struct seccomp_data, nr)),
BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, __NR_open, 0, 1),
BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_TRACE),
BPF_STMT(BPF_RET+BPF_K, SECCOMP_RET_ALLOW),
};
struct sock_fprog prog = {
.filter = filter,
.len = (unsigned short) (sizeof(filter)/sizeof(filter[0])),
};
ptrace(PTRACE_TRACEME, 0, 0, 0);
/* To avoid the need for CAP_SYS_ADMIN */
if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) == -1) {
perror("prctl(PR_SET_NO_NEW_PRIVS)");
return 1;
}
if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) == -1) {
perror("when setting seccomp filter");
return 1;
}
kill(getpid(), SIGSTOP);
return execvp(argv[1], argv + 1);
} else {
waitpid(pid, &status, 0);
ptrace(PTRACE_SETOPTIONS, pid, 0, PTRACE_O_TRACESECCOMP);
process_signals(pid);
return 0;
}
}
static void process_signals(pid_t child)
{
const char *file_to_redirect = "ONE.txt";
const char *file_to_avoid = "TWO.txt";
while(1) {
char orig_file[PATH_MAX];
/* Wait for open syscall start */
if (wait_for_open(child) != 0) break;
/* Find out file and re-direct if it is the target */
read_file(child, orig_file);
printf("[Opening %s]\n", orig_file);
if (strcmp(file_to_avoid, orig_file) == 0)
redirect_file(child, file_to_redirect);
}
}
static int wait_for_open(pid_t child)
{
int status;
while (1) {
ptrace(PTRACE_CONT, child, 0, 0);
waitpid(child, &status, 0);
printf("[waitpid status: 0x%08x]\n", status);
/* Is it our filter for the open syscall? */
if (status >> 8 == (SIGTRAP | (PTRACE_EVENT_SECCOMP << 8)) &&
ptrace(PTRACE_PEEKUSER, child,
sizeof(long)*ORIG_RAX, 0) == __NR_open)
return 0;
if (WIFEXITED(status))
return 1;
}
}
static void read_file(pid_t child, char *file)
{
char *child_addr;
int i;
child_addr = (char *) ptrace(PTRACE_PEEKUSER, child, sizeof(long)*RDI, 0);
do {
long val;
char *p;
val = ptrace(PTRACE_PEEKTEXT, child, child_addr, NULL);
if (val == -1) {
fprintf(stderr, "PTRACE_PEEKTEXT error: %s", strerror(errno));
exit(1);
}
child_addr += sizeof (long);
p = (char *) &val;
for (i = 0; i < sizeof (long); ++i, ++file) {
*file = *p++;
if (*file == '\0') break;
}
} while (i == sizeof (long));
}
static void redirect_file(pid_t child, const char *file)
{
char *stack_addr, *file_addr;
stack_addr = (char *) ptrace(PTRACE_PEEKUSER, child, sizeof(long)*RSP, 0);
/* Move further of red zone and make sure we have space for the file name */
stack_addr -= 128 + PATH_MAX;
file_addr = stack_addr;
/* Write new file in lower part of the stack */
do {
int i;
char val[sizeof (long)];
for (i = 0; i < sizeof (long); ++i, ++file) {
val[i] = *file;
if (*file == '\0') break;
}
ptrace(PTRACE_POKETEXT, child, stack_addr, *(long *) val);
stack_addr += sizeof (long);
} while (*file);
/* Change argument to open */
ptrace(PTRACE_POKEUSER, child, sizeof(long)*RDI, file_addr);
}