-
Notifications
You must be signed in to change notification settings - Fork 58
Expand file tree
/
Copy pathkpatch_file.h
More file actions
282 lines (242 loc) · 7.83 KB
/
kpatch_file.h
File metadata and controls
282 lines (242 loc) · 7.83 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
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
#ifndef __KPATCH_FILE_H__
#define __KPATCH_FILE_H__
#ifndef __ASSEMBLY__
#ifndef __KERNEL__
#include <stdint.h>
#else
#include <linux/types.h>
#include <linux/init.h>
#endif
#ifndef __MACH__
#include <linux/ioctl.h>
#endif
#ifdef __KERNEL__
#include <linux/list.h> /* for hlist_head */
#include <linux/rcupdate.h> /* for rcu_head */
struct kpatch_binding_type {
void (*dtor)(void *);
unsigned int size;
unsigned int offset;
const char *name;
unsigned long objsize;
};
struct kpatch_binding {
struct kpatch_binding_type *type;
struct kmem_cache *cache;
struct hlist_head hash[0];
};
struct kpatch_binding_node {
struct kpatch_binding *binding;
void *ptr;
struct hlist_node hlist;
struct rcu_head rcu;
};
/* functions to be used by init/exit calls */
struct kpatch_binding * kpatch_binding_create( struct kpatch_binding_type *);
void kpatch_binding_destroy(struct kpatch_binding *);
/* kpatch_binding API */
void * kpatch_binding_node_alloc(struct kpatch_binding *, gfp_t);
void kpatch_binding_node_free(struct kpatch_binding_node *);
void kpatch_binding_node_bind(struct kpatch_binding_node *, void *);
void kpatch_binding_node_unbind(struct kpatch_binding_node *);
void * kpatch_binding_lookup_entry(struct kpatch_binding *, void *);
struct kpatch_binding_node * kpatch_binding_lookup_node(struct kpatch_binding *, void *);
#ifndef __used
#define __used __attribute__((__used__))
#endif
#define kpatch_init_pre(fn) static initcall_t __kpatch_init_pre_##fn __used \
__attribute__((__section__(".kpatch.init.pre"))) = fn
#define kpatch_init(fn) static initcall_t __kpatch_init_##fn __used \
__attribute__((__section__(".kpatch.init"))) = fn
#define kpatch_init_post(fn) static initcall_t __kpatch_init_post_##fn __used \
__attribute__((__section__(".kpatch.init.post"))) = fn
#define kpatch_exit_pre(fn) static exitcall_t __kpatch_exit_pre_##fn __used \
__attribute__((__section__(".kpatch.exit.pre"))) = fn
#define kpatch_exit(fn) static exitcall_t __kpatch_exit_##fn __used \
__attribute__((__section__(".kpatch.exit"))) = fn
#define kpatch_exit_post(fn) static exitcall_t __kpatch_exit_post_##fn __used \
__attribute__((__section__(".kpatch.exit.post"))) = fn
#endif
typedef uint32_t kpatch_offset_t;
typedef uint32_t kpatch_reloc_t;
/* Load patch into memory, verifies it (checksum, etc...) and applies it */
#define KPATCH_APPLY _IOW('k', 0, struct kpatch_payload *)
/* Undo the patch */
#define KPATCH_UNDO _IO('k', 1)
/* Query info about patches */
#define KPATCH_INFO _IOR('k', 2, struct kpatch_query *)
struct kpatch_file;
struct kpatch_data;
typedef int (*kpatch_entry)(struct kpatch_file *, unsigned long size, void **);
typedef void *(*kpatch_alloc)(unsigned long);
typedef int (*kpatch_undo_patch)(struct kpatch_data *);
#define SET_BIT(r,b) ((r) |= (1 << (b)))
#define CLR_BIT(r,b) ((r) &= ~((1) << (b)))
#define TEST_BIT(r,b) ((r) & (1<<(b)))
#define KPATCH_FILE_MAGIC1 "KPATCH1"
#define KPATCH_MAX_NR_ENTRIES 16
#define KPATCH_UNAME_LEN 256
#define KPATCH_DEBUG_FLAG 0
#define KPATCH_NOFREEZE_FLAG 1 /* this flag is ignored, use safety method insted */
enum {
KPATCH_SAFETY_METHOD_DEFAULT = 0,
KPATCH_SAFETY_METHOD_FREEZE_ALL,
KPATCH_SAFETY_METHOD_FREEZE_NONE,
KPATCH_SAFETY_METHOD_FREEZE_CONFLICT,
KPATCH_SAFETY_METHOD_MAX,
};
struct kpatch_payload {
size_t size;
char *patch;
char *description; // could be NULL
};
struct kpatch_file {
char magic[8]; /* magic string */
unsigned char flags;
unsigned char safety_method;
char pad[6];
char modulename[64]; /* "vmlinux" or module name */
char uname[KPATCH_UNAME_LEN]; /* /proc/version of the kernel */
uint64_t build_time; /* build time */
uint32_t csum; /* checksum of the whole kpatch */
uint32_t nr_reloc; /* number of relocations */
kpatch_offset_t kpatch_offset; /* content offset */
kpatch_offset_t rel_offset; /* relocations offset (vmlinux) */
kpatch_offset_t total_size; /* total size = header + relocations + content */
kpatch_offset_t jmp_offset; /* jump table offset for user-space patches */
/* array of entry offsets in the patch content */
union {
kpatch_offset_t entries[KPATCH_MAX_NR_ENTRIES];
struct {
kpatch_offset_t kpatch_entry;
kpatch_offset_t kpatch_module_alloc;
kpatch_offset_t kpatch_unpatch;
kpatch_offset_t kpatch_delta;
};
struct {
kpatch_offset_t elf_hdr; /* saved offset to ELF hdr */
kpatch_offset_t extbl_start; /* exception table start for modules */
kpatch_offset_t extbl_end; /* exception table end for modules */
kpatch_offset_t bugtbl_start; /* bug table start for modules */
kpatch_offset_t bugtbl_end; /* bug table end for modules */
};
struct {
kpatch_offset_t user_undo; /* undo information for userspace */
kpatch_offset_t user_info; /* patch information */
kpatch_offset_t user_level; /* FIXME(pboldin) */
};
};
char srcversion[25]; /* srcversion of module or zeros */
uint32_t coroutine_env_offset;
char pad2[227];
/* relocations */
/* content */
};
struct kpatch_reloc {
kpatch_reloc_t offset; /* offset in file */
char type; /* relocation type */
/* possible pcrel values according to area offset points to:
* == 0 - offset points to kpatch area,
* == 1 - offset points to vmlinux area,
* == -1 - offset points to per_cpu variable */
#define KPATCH_PCREL_EXT_KPATCH (0)
#define KPATCH_PCREL_EXT_VMLINUX (1)
#define KPATCH_PCREL_EXT_PER_CPU (-1)
char pcrel; /* pcrel = 0 => code reloation +x bytes should adjust relocation value by +x, otherwise -x */
char pad[2];
char pad2[4];
kpatch_reloc_t delta; /* not used for patching, only during make stage */
};
#define KPATCH_INFO_PTR64(name) union { unsigned long name; uint64_t name ## 64; }
struct kpatch_info {
KPATCH_INFO_PTR64(daddr);
KPATCH_INFO_PTR64(saddr);
uint32_t dlen;
uint32_t slen;
KPATCH_INFO_PTR64(symstr);
KPATCH_INFO_PTR64(vaddr);
uint32_t flags;
char pad[4];
};
struct kpatch_undo_entry {
#define UNDO_ENTRY_ALLOCATED (1 << 0)
#define UNDO_ENTRY_PATCHED (1 << 1)
#define UNDO_ENTRY_EXITED (1 << 2)
long flags;
/* module name or vmlinux */
char modulename[64];
/* pointer original code (all hunks stored sequentially) */
void *orig_code;
/* pointer to original patch (for exitcalls) */
struct kpatch_file *kpatch;
};
/* data stored by kpatch-loader to support unpatching */
struct kpatch_undo {
/* number of entries */
uint32_t nr_entries;
/* size of the area */
size_t size;
/* entries */
struct kpatch_undo_entry entries[];
};
struct kpatch_query_info {
/* Patch state */
#define KPATCH_STATE_NONE 0 /* No patch applied */
#define KPATCH_STATE_APPLIED 1 /* Patch is applied */
uint32_t state;
char uname[KPATCH_UNAME_LEN];
char description[512];
uint64_t build_time;
/* Add info about patch (name?/modules?, etc.) */
char pad[1024];
};
#ifndef __kpatch_text
# define __kpatch_text
#endif /* ifndef __kpatch_text */
static inline int
__kpatch_text
is_end_info(struct kpatch_info *info)
{
return (info->daddr == 0) && (info->dlen == 0) &&
(info->saddr == 0) && (info->slen == 0);
}
static inline int
__kpatch_text
is_new_func(struct kpatch_info *info)
{
return (info->daddr == 0) && (info->dlen == 0);
}
#endif /* __ASSEMBLY__ */
#ifdef __KPATCH_ASSEMBLY__
#define KPATCH_INFO_DEFINE(fname, flags) KPATCH_INFO_DEFINE fname, flags
/* we use can CPP to define macro, but if we do it macro
* will expand in one line, which is nearly impossible to
* read in preprocessed file
*/
.macro KPATCH_INFO_DEFINE fname, flags
.pushsection .kpatch.strtab,"a",@progbits
\fname\().kpatch_strtab:
.string "\fname\().kpatch"
.popsection
.pushsection .kpatch.info,"a",@progbits
\fname\().Lpi:
.ifdef \fname
.quad \fname
.else
.quad 0
.endif
.quad \fname\().kpatch
.ifdef \fname
.long \fname\().Lfe - \fname
.else
.long 0
.endif
.long \fname\().kpatch_end - \fname\().kpatch
.quad \fname\().kpatch_strtab
.quad 0
.long \flags
.byte 0, 0, 0, 0
.popsection
.endm
#endif /* __KPATCH_ASSEMBLY__ */
#endif