Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
BIND
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
591
Issues
591
List
Boards
Labels
Service Desk
Milestones
Merge Requests
113
Merge Requests
113
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Incidents
Environments
Packages & Registries
Packages & Registries
Container Registry
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
ISC Open Source Projects
BIND
Commits
f7c66b31
Commit
f7c66b31
authored
Apr 21, 2017
by
Mukund Sivaraman
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Update fuzzing support to test validating resolver (#44787)
parent
5d01eab0
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
363 additions
and
66 deletions
+363
-66
CHANGES
CHANGES
+8
-0
bin/named/fuzz.c
bin/named/fuzz.c
+355
-66
No files found.
CHANGES
View file @
f7c66b31
4598. [func] Update fuzzing code to (1) reply to a DNSKEY
query from named with appropriate DNSKEY used in
fuzzing; (2) patch the QTYPE correctly in
resolver fuzzing; (3) comment things so the rest
of us are able to understand how fuzzing is
implemented in named; (4) Coding style changes,
cleanup, etc. [RT #44787]
4597. [bug] The validator now ignores SHA-1 DS digest type
when a DS record with SHA-384 digest type is
present and is a supported digest type.
...
...
bin/named/fuzz.c
View file @
f7c66b31
...
...
@@ -35,17 +35,22 @@
#endif
/*
* We are using pthreads directly because we might be using it with
unthreaded
*
version of BIND, where all thread functions are mocks. Since AFL for now only
* works on Linux it's not a problem.
* We are using pthreads directly because we might be using it with
*
unthreaded version of BIND, where all thread functions are
*
mocks. Since AFL for now only
works on Linux it's not a problem.
*/
static
pthread_cond_t
cond
;
static
pthread_mutex_t
mutex
;
static
isc_boolean_t
ready
;
/*
* In "client:" mode, this thread reads fuzzed query messages from AFL
* from standard input and sends it to named's listening port (DNS) that
* is passed in the -A client:<address>:<port> option. It can be used to
* test named from the client side.
*/
static
void
*
fuzz_
main
_client
(
void
*
arg
)
{
fuzz_
thread
_client
(
void
*
arg
)
{
char
*
host
;
char
*
port
;
struct
sockaddr_in
servaddr
;
...
...
@@ -59,9 +64,9 @@ fuzz_main_client(void *arg) {
* Parse named -A argument in the "address:port" syntax. Due to
* the syntax used, this only supports IPv4 addresses.
*/
host
=
strdup
(
ns_g_fuzz_named_addr
);
RUNTIME_CHECK
(
host
!=
NULL
);
port
=
strchr
(
host
,
':'
);
RUNTIME_CHECK
(
port
!=
NULL
);
*
port
=
0
;
...
...
@@ -74,7 +79,10 @@ fuzz_main_client(void *arg) {
free
(
host
);
/* Wait for named to start. */
/*
* Wait for named to start. This is set in run_server() in the
* named thread.
*/
while
(
!
ns_g_run_done
)
{
usleep
(
10000
);
}
...
...
@@ -85,9 +93,13 @@ fuzz_main_client(void *arg) {
buf
=
malloc
(
65536
);
RUNTIME_CHECK
(
buf
!=
NULL
);
loop
=
100000
;
while
(
loop
--
)
{
/*
* Processing fuzzed packets 100,000 times before shutting down
* the app.
*/
for
(
loop
=
0
;
loop
<
100000
;
loop
++
)
{
ssize_t
length
;
ssize_t
sent
;
length
=
read
(
0
,
buf
,
65536
);
if
(
length
<=
0
)
{
...
...
@@ -95,8 +107,17 @@ fuzz_main_client(void *arg) {
continue
;
}
/*
* Ignore packets that are larger than 4096 bytes.
*/
if
(
length
>
4096
)
{
/*
* AFL_CMIN doesn't support persistent mode, so
* shutdown the server.
*/
if
(
getenv
(
"AFL_CMIN"
))
{
free
(
buf
);
close
(
sockfd
);
ns_server_flushonshutdown
(
ns_g_server
,
ISC_FALSE
);
isc_app_shutdown
();
...
...
@@ -106,23 +127,24 @@ fuzz_main_client(void *arg) {
continue
;
}
RUNTIME_CHECK
(
pthread_mutex_lock
(
&
mutex
)
==
ISC_R_SUCCESS
);
RUNTIME_CHECK
(
pthread_mutex_lock
(
&
mutex
)
==
0
);
ready
=
ISC_FALSE
;
ssize_t
sent
;
sent
=
sendto
(
sockfd
,
buf
,
length
,
0
,
(
struct
sockaddr
*
)
&
servaddr
,
sizeof
(
servaddr
));
RUNTIME_CHECK
(
sent
==
length
);
/* unclog */
/*
* Read the reply message from named to unclog it. Don't
* bother if there isn't a reply.
*/
recvfrom
(
sockfd
,
buf
,
65536
,
MSG_DONTWAIT
,
NULL
,
NULL
);
while
(
!
ready
)
pthread_cond_wait
(
&
cond
,
&
mutex
);
RUNTIME_CHECK
(
pthread_mutex_unlock
(
&
mutex
)
==
ISC_R_SUCCESS
);
RUNTIME_CHECK
(
pthread_mutex_unlock
(
&
mutex
)
==
0
);
}
free
(
buf
);
...
...
@@ -134,44 +156,168 @@ fuzz_main_client(void *arg) {
return
(
NULL
);
}
/*
* In "resolver:" mode, this thread reads fuzzed reply messages from AFL
* from standard input. It also sets up a listener as a remote
* authoritative server and sends a driver query to the client side of
* named(resolver). When named(resolver) connects to this authoritative
* server, this thread writes the fuzzed reply message from AFL to it.
*
* -A resolver:<saddress>:<sport>:<raddress>:<rport>
*
* Here, <saddress>:<sport> is where named(resolver) is listening on.
* <raddress>:<rport> is where the thread is supposed to setup the
* authoritative server. This address should be configured via the root
* zone to be the authoritiative server for aaaaaaaaaa.example.
*
* named(resolver) when being fuzzed will not cache answers.
*/
static
void
*
fuzz_
main
_resolver
(
void
*
arg
)
{
fuzz_
thread
_resolver
(
void
*
arg
)
{
char
*
sqtype
,
*
shost
,
*
sport
,
*
rhost
,
*
rport
;
/* Query for A? aaaaaaaaaa.example. */
char
respacket
[]
=
"
\0\0\1
\0\1\0\0\0\0\0\0\n
aaaaaaaaaa
\7
example
\0\0\1\0\1
"
;
struct
sockaddr_in
servaddr
,
recaddr
,
recvaddr
;
/*
* Query for aaaaaaaaaa.example./A in wire format with RD=1,
* EDNS and DO=1. 0x88, 0x0c at the start is the ID field which
* will be updated for each query.
*/
char
respacket
[]
=
{
0x88
,
0x0c
,
0x01
,
0x20
,
0x00
,
0x01
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x01
,
0x0a
,
0x61
,
0x61
,
0x61
,
0x61
,
0x61
,
0x61
,
0x61
,
0x61
,
0x61
,
0x61
,
0x07
,
0x65
,
0x78
,
0x61
,
0x6d
,
0x70
,
0x6c
,
0x65
,
0x00
,
0x00
,
0x01
,
0x00
,
0x01
,
0x00
,
0x00
,
0x29
,
0x10
,
0x00
,
0x00
,
0x00
,
0x80
,
0x00
,
0x00
,
0x00
};
/*
* Response for example./DNSKEY in wire format. Note that RRSIGs
* were generated with this DNSKEY that are used as seeds for
* AFL in the DNSSEC fuzzing job. So the DNSKEY content of this
* message must not change, or the corresponding RRSIGs will
* have to be updated. 0x8d, 0xf6 at the start is the ID field
* which will be made to match the query.
*/
const
isc_uint8_t
dnskey_wireformat
[]
=
{
0x8d
,
0xf6
,
0x84
,
0x00
,
0x00
,
0x01
,
0x00
,
0x02
,
0x00
,
0x00
,
0x00
,
0x01
,
0x07
,
0x65
,
0x78
,
0x61
,
0x6d
,
0x70
,
0x6c
,
0x65
,
0x00
,
0x00
,
0x30
,
0x00
,
0x01
,
0xc0
,
0x0c
,
0x00
,
0x30
,
0x00
,
0x01
,
0x00
,
0x00
,
0x01
,
0x2c
,
0x01
,
0x08
,
0x01
,
0x00
,
0x03
,
0x08
,
0x03
,
0x01
,
0x00
,
0x01
,
0xbd
,
0x81
,
0xdc
,
0x7f
,
0x16
,
0xd4
,
0x81
,
0x7c
,
0x1f
,
0x9f
,
0x6a
,
0x68
,
0xdd
,
0xd4
,
0xda
,
0x48
,
0xd9
,
0x1c
,
0xbd
,
0xa6
,
0x46
,
0x1a
,
0xf0
,
0xb4
,
0xb9
,
0xec
,
0x3d
,
0x6c
,
0x0b
,
0x57
,
0xc7
,
0xd6
,
0x54
,
0x66
,
0xe6
,
0x6c
,
0xd5
,
0x90
,
0x3a
,
0x78
,
0x7d
,
0x7f
,
0x78
,
0x80
,
0xa2
,
0x89
,
0x61
,
0x6d
,
0x8a
,
0x2b
,
0xcd
,
0x0a
,
0x77
,
0x7a
,
0xad
,
0xc9
,
0x61
,
0x53
,
0x53
,
0x8c
,
0x99
,
0x72
,
0x86
,
0x14
,
0x74
,
0x9c
,
0x49
,
0x2a
,
0x47
,
0x23
,
0xf7
,
0x02
,
0x07
,
0x73
,
0x1c
,
0x5c
,
0x2e
,
0xb4
,
0x9a
,
0xa4
,
0xd7
,
0x98
,
0x42
,
0xc3
,
0xd2
,
0xfe
,
0xbf
,
0xf3
,
0xb3
,
0x6a
,
0x52
,
0x92
,
0xd5
,
0xfa
,
0x47
,
0x00
,
0xe3
,
0xd9
,
0x59
,
0x31
,
0x95
,
0x48
,
0x40
,
0xfc
,
0x06
,
0x73
,
0x90
,
0xc6
,
0x73
,
0x96
,
0xba
,
0x29
,
0x91
,
0xe2
,
0xac
,
0xa3
,
0xa5
,
0x6d
,
0x91
,
0x6d
,
0x52
,
0xb9
,
0x34
,
0xba
,
0x68
,
0x4f
,
0xad
,
0xf0
,
0xc3
,
0xf3
,
0x1d
,
0x6d
,
0x61
,
0x76
,
0xe5
,
0x3d
,
0xa3
,
0x9b
,
0x2a
,
0x0c
,
0x92
,
0xb3
,
0x78
,
0x6b
,
0xf1
,
0x20
,
0xd6
,
0x90
,
0xb7
,
0xac
,
0xe2
,
0xf8
,
0x2b
,
0x94
,
0x10
,
0x79
,
0xce
,
0xa8
,
0x60
,
0x42
,
0xea
,
0x6a
,
0x18
,
0x2f
,
0xc0
,
0xd8
,
0x05
,
0x0a
,
0x3b
,
0x06
,
0x0f
,
0x02
,
0x7e
,
0xff
,
0x33
,
0x46
,
0xee
,
0xb6
,
0x21
,
0x25
,
0x90
,
0x63
,
0x4b
,
0x3b
,
0x5e
,
0xb2
,
0x72
,
0x3a
,
0xcb
,
0x91
,
0x41
,
0xf4
,
0x20
,
0x50
,
0x78
,
0x1c
,
0x93
,
0x95
,
0xda
,
0xfa
,
0xae
,
0x85
,
0xc5
,
0xd7
,
0x6b
,
0x92
,
0x0c
,
0x70
,
0x6b
,
0xe4
,
0xb7
,
0x29
,
0x3a
,
0x2e
,
0x18
,
0x88
,
0x82
,
0x33
,
0x7c
,
0xa8
,
0xea
,
0xb8
,
0x31
,
0x8f
,
0xaf
,
0x50
,
0xc5
,
0x9c
,
0x08
,
0x56
,
0x8f
,
0x09
,
0x76
,
0x4e
,
0xdf
,
0x97
,
0x75
,
0x9d
,
0x00
,
0x52
,
0x7f
,
0xdb
,
0xec
,
0x30
,
0xcb
,
0x1c
,
0x4c
,
0x2a
,
0x21
,
0x93
,
0xc4
,
0x6d
,
0x85
,
0xa9
,
0x40
,
0x3b
,
0xc0
,
0x0c
,
0x00
,
0x2e
,
0x00
,
0x01
,
0x00
,
0x00
,
0x01
,
0x2c
,
0x01
,
0x1b
,
0x00
,
0x30
,
0x08
,
0x01
,
0x00
,
0x00
,
0x01
,
0x2c
,
0x67
,
0x74
,
0x85
,
0x80
,
0x58
,
0xb3
,
0xc5
,
0x17
,
0x36
,
0x90
,
0x07
,
0x65
,
0x78
,
0x61
,
0x6d
,
0x70
,
0x6c
,
0x65
,
0x00
,
0x45
,
0xac
,
0xd3
,
0x82
,
0x69
,
0xf3
,
0x10
,
0x3a
,
0x97
,
0x2c
,
0x6a
,
0xa9
,
0x78
,
0x99
,
0xea
,
0xb0
,
0xcc
,
0xf7
,
0xaf
,
0x33
,
0x51
,
0x5b
,
0xdf
,
0x77
,
0x04
,
0x18
,
0x14
,
0x99
,
0x61
,
0xeb
,
0x8d
,
0x76
,
0x3f
,
0xd1
,
0x71
,
0x14
,
0x43
,
0x80
,
0x53
,
0xc2
,
0x3b
,
0x9f
,
0x09
,
0x4f
,
0xb3
,
0x51
,
0x04
,
0x89
,
0x0e
,
0xc8
,
0x54
,
0x12
,
0xcd
,
0x07
,
0x20
,
0xbe
,
0x94
,
0xc2
,
0xda
,
0x99
,
0xdd
,
0x1e
,
0xf8
,
0xb0
,
0x84
,
0x2e
,
0xf9
,
0x19
,
0x35
,
0x36
,
0xf5
,
0xd0
,
0x5d
,
0x82
,
0x18
,
0x74
,
0xa0
,
0x00
,
0xb6
,
0x15
,
0x57
,
0x40
,
0x5f
,
0x78
,
0x2d
,
0x27
,
0xac
,
0xc7
,
0x8a
,
0x29
,
0x55
,
0xa9
,
0xcd
,
0xbc
,
0xf7
,
0x3e
,
0xff
,
0xae
,
0x1a
,
0x5a
,
0x1d
,
0xac
,
0x0d
,
0x78
,
0x0e
,
0x08
,
0x33
,
0x6c
,
0x59
,
0x70
,
0x40
,
0xb9
,
0x65
,
0xbd
,
0x35
,
0xbb
,
0x9a
,
0x70
,
0xdc
,
0x93
,
0x66
,
0xb0
,
0xef
,
0xfe
,
0xf0
,
0x32
,
0xa6
,
0xee
,
0xb7
,
0x03
,
0x89
,
0xa2
,
0x4d
,
0xe0
,
0xf1
,
0x20
,
0xdf
,
0x39
,
0xe8
,
0xe3
,
0xcc
,
0x95
,
0xe9
,
0x9a
,
0xad
,
0xbf
,
0xbd
,
0x7c
,
0xf7
,
0xd7
,
0xde
,
0x47
,
0x9e
,
0xf6
,
0x17
,
0xbb
,
0x84
,
0xa9
,
0xed
,
0xf2
,
0x45
,
0x61
,
0x6d
,
0x13
,
0x0b
,
0x06
,
0x29
,
0x50
,
0xde
,
0xfd
,
0x42
,
0xb0
,
0x66
,
0x2c
,
0x1c
,
0x2b
,
0x63
,
0xcb
,
0x4e
,
0xb9
,
0x31
,
0xc4
,
0xea
,
0xd2
,
0x07
,
0x3a
,
0x08
,
0x79
,
0x19
,
0x4b
,
0x4c
,
0x50
,
0x97
,
0x02
,
0xd7
,
0x26
,
0x41
,
0x2f
,
0xdd
,
0x57
,
0xaa
,
0xb0
,
0xa0
,
0x21
,
0x4e
,
0x74
,
0xb6
,
0x97
,
0x4b
,
0x8b
,
0x09
,
0x9c
,
0x3d
,
0x29
,
0xfb
,
0x12
,
0x27
,
0x47
,
0x8f
,
0xb8
,
0xc5
,
0x8e
,
0x65
,
0xcd
,
0xca
,
0x2f
,
0xba
,
0xf5
,
0x3e
,
0xec
,
0x56
,
0xc3
,
0xc9
,
0xa1
,
0x62
,
0x7d
,
0xf2
,
0x9f
,
0x90
,
0x16
,
0x1d
,
0xbf
,
0x97
,
0x28
,
0xe1
,
0x92
,
0xb1
,
0x53
,
0xab
,
0xc4
,
0xe0
,
0x99
,
0xbb
,
0x19
,
0x90
,
0x7c
,
0x00
,
0x00
,
0x29
,
0x10
,
0x00
,
0x00
,
0x00
,
0x80
,
0x00
,
0x00
,
0x00
};
int
sockfd
;
int
listenfd
;
int
loop
;
isc_uint16_t
qtype
;
char
*
buf
,
*
rbuf
;
char
*
nameptr
;
unsigned
int
i
;
isc_uint8_t
llen
;
isc_uint64_t
seed
;
UNUSED
(
arg
);
/*
* Parse named -A argument in the "qtype:
l
address:sport:raddress:rport"
* Parse named -A argument in the "qtype:
s
address:sport:raddress:rport"
* syntax. Due to the syntax used, this only supports IPv4 addresses.
*/
sqtype
=
strdup
(
ns_g_fuzz_named_addr
);
RUNTIME_CHECK
(
sqtype
!=
NULL
);
shost
=
strchr
(
sqtype
,
':'
);
RUNTIME_CHECK
(
shost
!=
NULL
);
*
shost
=
0
;
shost
++
;
sport
=
strchr
(
shost
,
':'
);
RUNTIME_CHECK
(
sport
!=
NULL
);
*
sport
=
0
;
sport
++
;
rhost
=
strchr
(
sport
,
':'
);
RUNTIME_CHECK
(
rhost
!=
NULL
);
*
rhost
=
0
;
rhost
++
;
rport
=
strchr
(
rhost
,
':'
);
RUNTIME_CHECK
(
rport
!=
NULL
);
*
rport
=
0
;
rport
++
;
/*
* Patch in the qtype into the question section of respacket.
*/
qtype
=
atoi
(
sqtype
);
respacket
[
32
]
=
(
qtype
>>
8
)
&
0xff
;
respacket
[
33
]
=
qtype
&
0xff
;
...
...
@@ -188,7 +334,10 @@ fuzz_main_resolver(void *arg) {
free
(
sqtype
);
/* Wait for named to start */
/*
* Wait for named to start. This is set in run_server() in the
* named thread.
*/
while
(
!
ns_g_run_done
)
{
usleep
(
10000
);
}
...
...
@@ -198,6 +347,7 @@ fuzz_main_resolver(void *arg) {
listenfd
=
socket
(
AF_INET
,
SOCK_DGRAM
,
0
);
RUNTIME_CHECK
(
listenfd
!=
-
1
);
RUNTIME_CHECK
(
bind
(
listenfd
,
(
struct
sockaddr
*
)
&
recaddr
,
sizeof
(
struct
sockaddr_in
))
==
0
);
...
...
@@ -206,10 +356,19 @@ fuzz_main_resolver(void *arg) {
RUNTIME_CHECK
(
buf
!=
NULL
);
RUNTIME_CHECK
(
rbuf
!=
NULL
);
loop
=
100000
;
while
(
loop
--
)
{
seed
=
42
;
/*
* Processing fuzzed packets 100,000 times before shutting down
* the app.
*/
for
(
loop
=
0
;
loop
<
100000
;
loop
++
)
{
ssize_t
length
;
memset
(
buf
,
0
,
16
);
ssize_t
sent
;
unsigned
short
id
;
socklen_t
socklen
;
memset
(
buf
,
0
,
12
);
length
=
read
(
0
,
buf
,
65536
);
if
(
length
<=
0
)
{
usleep
(
1000000
);
...
...
@@ -218,6 +377,10 @@ fuzz_main_resolver(void *arg) {
if
(
length
>
4096
)
{
if
(
getenv
(
"AFL_CMIN"
))
{
free
(
buf
);
free
(
rbuf
);
close
(
sockfd
);
close
(
listenfd
);
ns_server_flushonshutdown
(
ns_g_server
,
ISC_FALSE
);
isc_app_shutdown
();
...
...
@@ -227,47 +390,96 @@ fuzz_main_resolver(void *arg) {
continue
;
}
if
(
length
<
1
6
)
{
length
=
1
6
;
if
(
length
<
1
2
)
{
length
=
1
2
;
}
RUNTIME_CHECK
(
pthread_mutex_lock
(
&
mutex
)
==
ISC_R_SUCCESS
);
RUNTIME_CHECK
(
pthread_mutex_lock
(
&
mutex
)
==
0
);
ready
=
ISC_FALSE
;
ssize_t
sent
;
/* Randomize query ID. */
i
nt
id
=
random
()
;
respacket
[
0
]
=
id
>>
8
;
/* Use a unique query ID. */
seed
=
1664525
*
seed
+
1013904223
;
i
d
=
seed
&
0xffff
;
respacket
[
0
]
=
(
id
>>
8
)
&
0xff
;
respacket
[
1
]
=
id
&
0xff
;
/* flush */
socklen_t
socklen
=
sizeof
(
recvaddr
);
/*
* Flush any pending data on the authoritative server.
*/
socklen
=
sizeof
(
recvaddr
);
sent
=
recvfrom
(
listenfd
,
rbuf
,
65536
,
MSG_DONTWAIT
,
(
struct
sockaddr
*
)
&
recvaddr
,
&
socklen
);
/*
* Send a fixed client query to named(resolver) of
* aaaaaaaaaa.example./A. This is the starting query
* driver.
*/
sent
=
sendto
(
sockfd
,
respacket
,
sizeof
(
respacket
),
0
,
(
struct
sockaddr
*
)
&
servaddr
,
sizeof
(
servaddr
));
RUNTIME_CHECK
(
sent
==
sizeof
(
respacket
));
/*
* named(resolver) will process the query above and send
* an upstream query to the authoritative server. We
* handle that here as the upstream authoritative server
* on listenfd.
*/
socklen
=
sizeof
(
recvaddr
);
sent
=
recvfrom
(
listenfd
,
rbuf
,
65536
,
0
,
(
struct
sockaddr
*
)
&
recvaddr
,
&
socklen
);
RUNTIME_CHECK
(
sent
>
0
);
/* Copy QID and set QR so that response is always processed. */
/*
* Copy QID and set QR so that response is always
* accepted by named(resolver).
*/
buf
[
0
]
=
rbuf
[
0
];
buf
[
1
]
=
rbuf
[
1
];
buf
[
2
]
|=
0x80
;
/*
* A hack - set QTYPE to the one from query so that we can easily
* share packets between instances. If we write over something else
* we'll get FORMERR anyway.
* NOTE: We are not copying the QNAME or setting
* rcode=NOERROR each time. So the resolver may fail the
* client query (driver) / wander due to this. AA flag
* may also not be set based on the contents of the AFL
* fuzzed packet.
*/
buf
[
32
]
=
(
qtype
>>
8
)
&
0xff
;
buf
[
33
]
=
qtype
&
0xff
;
/*
* A hack - set QTYPE to the one from query so that we
* can easily share packets between instances. If we
* write over something else we'll get FORMERR anyway.
*/
/* Skip DNS header to get to the name */
nameptr
=
buf
+
12
;
/* Skip the name to get to the qtype */
i
=
0
;
while
(((
llen
=
nameptr
[
i
])
!=
0
)
&&
(
i
<
255
)
&&
(((
nameptr
+
i
+
1
+
llen
)
-
buf
)
<
length
))
i
+=
1
+
llen
;
if
(
i
<=
255
)
{
nameptr
+=
1
+
i
;
/* Patch the qtype */
if
((
nameptr
-
buf
)
<
(
length
-
2
))
{
*
nameptr
++
=
(
qtype
>>
8
)
&
0xff
;
*
nameptr
++
=
qtype
&
0xff
;
}
/* Patch the qclass */
if
((
nameptr
-
buf
)
<
(
length
-
2
))
{
*
nameptr
++
=
0
;
*
nameptr
++
=
1
;
}
}
/*
* Send the reply to named(resolver).
*/
sent
=
sendto
(
listenfd
,
buf
,
length
,
0
,
(
struct
sockaddr
*
)
&
recvaddr
,
sizeof
(
recvaddr
));
RUNTIME_CHECK
(
sent
==
length
);
...
...
@@ -290,19 +502,63 @@ fuzz_main_resolver(void *arg) {
RUNTIME_CHECK
(
rv
>
0
);
if
(
FD_ISSET
(
sockfd
,
&
fds
))
{
/* It's the reply, we're done. */
/*
* It's the reply from named(resolver)
* to the client(query driver), so we're
* done.
*/
recvfrom
(
sockfd
,
buf
,
65536
,
0
,
NULL
,
NULL
);
break
;
}
/*
* We've got additional question (eg.
cname chain)
*
We are bouncing it - setting QR flag and NOERROR
* rcode and sending it back.
* We've got additional question (eg.
due to
*
CNAME). Bounce it - setting QR flag and
*
NOERROR
rcode and sending it back.
*/
length
=
recvfrom
(
listenfd
,
buf
,
65536
,
0
,
(
struct
sockaddr
*
)
&
recvaddr
,
&
socklen
);
/*
* If this is a DNSKEY query, send the DNSKEY,
* otherwise, bounce the query.
*/
/* Skip DNS header to get to the name */
nameptr
=
buf
+
12
;
/* Skip the name to get to the qtype */
i
=
0
;
while
(((
llen
=
nameptr
[
i
])
!=
0
)
&&
(
i
<
255
)
&&
(((
nameptr
+
i
+
1
+
llen
)
-
buf
)
<
length
))
i
+=
1
+
llen
;
if
(
i
<=
255
)
{
nameptr
+=
1
+
i
;
/*
* Patch in the DNSKEY reply without
* touching the ID field. Note that we
* don't compare the name in the
* question section in the query, but we
* don't expect to receive any query for
* type DNSKEY but for the name
* "example."
*/
if
((
nameptr
-
buf
)
<
(
length
-
2
))
{
isc_uint8_t
hb
,
lb
;
hb
=
*
nameptr
++
;
lb
=
*
nameptr
++
;
qtype
=
(
hb
<<
8
)
|
lb
;
if
(
qtype
==
48
)
{
memmove
(
buf
+
2
,
dnskey_wireformat
+
2
,
sizeof
(
dnskey_wireformat
)
-
2
);
length
=
sizeof
(
dnskey_wireformat
);
}
}
}
buf
[
2
]
|=
0x80
;
buf
[
3
]
&=
0xF0
;
sent
=
sendto
(
listenfd
,
buf
,
length
,
0
,
...
...
@@ -319,20 +575,32 @@ fuzz_main_resolver(void *arg) {
free
(
buf
);
close
(
sockfd
);
close
(
listenfd
);
ns_server_flushonshutdown
(
ns_g_server
,
ISC_FALSE
);
isc_app_shutdown
();
/*
* It's here just for the signature, that's how AFL detects if it's
* a 'persistent mode' binary.
* This is here just for the signature, that's how AFL detects
* if it's a 'persistent mode' binary. It has to occur somewhere
* in the file, that's all. < wpk_> AFL checks the binary for
* this signature ("##SIG_AFL_PERSISTENT##") and runs the binary
* in persistent mode if it's present.
*/
__AFL_LOOP
(
0
);
return
(
NULL
);
}
/*
* In "tcp:", "http:" and "rndc:" modes, this thread reads fuzzed query
* blobs from AFL from standard input and sends it to the corresponding
* TCP listening port of named (port 53 DNS, or the HTTP statistics
* channels listener or the rndc port) that is passed in the -A
* <mode>:<address>:<port> option. It can be used to test named from the
* client side.
*/
static
void
*
fuzz_
main
_tcp
(
void
*
arg
)
{
fuzz_
thread
_tcp
(
void
*
arg
)
{
char
*
host
;
char
*
port
;
struct
sockaddr_in
servaddr
;
...
...
@@ -346,9 +614,9 @@ fuzz_main_tcp(void *arg) {
* Parse named -A argument in the "address:port" syntax. Due to
* the syntax used, this only supports IPv4 addresses.
*/
host
=
strdup
(
ns_g_fuzz_named_addr
);
RUNTIME_CHECK
(
host
!=
NULL
);
port
=
strchr
(
host
,
':'
);
RUNTIME_CHECK
(
port
!=
NULL
);
*
port
=
0
;
...
...
@@ -361,7 +629,10 @@ fuzz_main_tcp(void *arg) {
free
(
host
);
/* Wait for named to start */
/*
* Wait for named to start. This is set in run_server() in the
* named thread.
*/
while
(
!
ns_g_run_done
)
{
usleep
(
10000
);
}
...
...
@@ -369,20 +640,29 @@ fuzz_main_tcp(void *arg) {
buf
=
malloc
(
65539
);
RUNTIME_CHECK
(
buf
!=
NULL
);
loop
=
100000
;
while
(
loop
--
)
{
/*
* Processing fuzzed packets 100,000 times before shutting down
* the app.
*/
for
(
loop
=
0
;
loop
<
100000
;
loop
++
)
{
ssize_t
length
;
ssize_t
sent
;
int
yes
;
int
r
;
if
(
ns_g_fuzz_type
==
ns_fuzz_tcpclient
)
{
/*
* To fuzz
TCP client we have to put length a
t
* the start of packet.
* To fuzz
DNS TCP client we have to put 16-bi
t
*
message length preceding
the start of packet.
*/
length
=
read
(
0
,
buf
+
2
,
65535
);
buf
[
0
]
=
length
>>
8
;
buf
[
0
]
=
(
length
>>
8
)
&
0xff
;
buf
[
1
]
=
length
&
0xff
;
length
+=
2
;
}
else
{
/*
* Other types of TCP clients such as HTTP, etc.
*/
length
=
read
(
0
,
buf
,
65535
);
}
if
(
length
<=
0
)
{
...
...
@@ -391,21 +671,20 @@ fuzz_main_tcp(void *arg) {
}
if
(
ns_g_fuzz_type
==
ns_fuzz_http
)
{
/*
* This guarantees that the request will be processed.
* This guarantees that the request will be
* processed.
*/
INSIST
(
length
<=
65535
);
buf
[
length
++
]
=
'\r'
;
buf
[
length
++
]
=
'\n'
;
buf
[
length
++
]
=
'\r'
;
buf
[
length
++
]
=
'\n'
;
}
RUNTIME_CHECK
(
pthread_mutex_lock
(
&
mutex
)
==
ISC_R_SUCCESS
);
RUNTIME_CHECK
(
pthread_mutex_lock
(
&
mutex
)
==
0
);
ready
=
ISC_FALSE
;
ssize_t
sent
;
int
yes
=
1
;
int
r
;
yes
=
1
;
sockfd
=
socket
(
AF_INET
,
SOCK_STREAM
,
0
);
RUNTIME_CHECK
(
sockfd
!=
-
1
);
...
...
@@ -415,19 +694,22 @@ fuzz_main_tcp(void *arg) {