Add libslirp with glib shim

This commit is contained in:
Nadia Holmquist Pedersen 2024-05-15 15:48:56 +02:00
parent 747f50de98
commit 22afac315b
151 changed files with 22496 additions and 0 deletions

View File

@ -0,0 +1,58 @@
# https://clang.llvm.org/docs/ClangFormat.html
# https://clang.llvm.org/docs/ClangFormatStyleOptions.html
---
Language: Cpp
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: false # although we like it, it creates churn
AlignConsecutiveDeclarations: false
AlignEscapedNewlinesLeft: true
AlignOperands: true
AlignTrailingComments: false # churn
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: None
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterReturnType: None # AlwaysBreakAfterDefinitionReturnType is taken into account
AlwaysBreakBeforeMultilineStrings: false
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
AfterControlStatement: false
AfterEnum: false
AfterFunction: true
AfterStruct: false
AfterUnion: false
BeforeElse: false
IndentBraces: false
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Custom
BreakBeforeTernaryOperators: false
BreakStringLiterals: true
ColumnLimit: 80
ContinuationIndentWidth: 4
Cpp11BracedListStyle: false
DerivePointerAlignment: false
DisableFormat: false
IndentCaseLabels: false
IndentWidth: 4
IndentWrappedFunctionNames: false
KeepEmptyLinesAtTheStartOfBlocks: false
MacroBlockBegin: '.*_BEGIN$' # only PREC_BEGIN ?
MacroBlockEnd: '.*_END$'
MaxEmptyLinesToKeep: 2
PointerAlignment: Right
ReflowComments: true
SortIncludes: false
SpaceAfterCStyleCast: false
SpaceBeforeAssignmentOperators: true
SpaceBeforeParens: ControlStatements
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInContainerLiterals: true
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Auto
UseTab: Never
...

11
src/frontend/libslirp/.gitignore vendored Normal file
View File

@ -0,0 +1,11 @@
*.[aod]
*.gcda
*.gcno
*.gcov
*.lib
*.obj
/build/
/TAGS
/cscope*
/src/libslirp-version.h
/tags

View File

@ -0,0 +1,110 @@
image: fedora:latest
variables:
DEPS: meson ninja-build
gcc libasan liblsan libubsan pkg-config glib2-devel
mingw64-gcc mingw64-pkg-config mingw64-glib2
clang-analyzer git-core
before_script:
- dnf install -y $DEPS
- git fetch --tags https://gitlab.freedesktop.org/slirp/libslirp.git
- git describe
build:
script:
- meson --werror build || (cat build/meson-logs/meson-log.txt && exit 1)
- ninja -C build
- (cd build && meson test) || (cat build/meson-logs/testlog.txt && exit 1)
- ninja -C build scan-build
build-asan:
script:
- CFLAGS=-fsanitize=address meson --werror build || (cat build/meson-logs/meson-log.txt && exit 1)
- ninja -C build
- (cd build && ASAN_OPTIONS=detect_leaks=0 meson test) || (cat build/meson-logs/testlog.txt && exit 1)
build-lsan:
script:
- CFLAGS=-fsanitize=leak meson --werror build || (cat build/meson-logs/meson-log.txt && exit 1)
- ninja -C build
- (cd build && meson test) || (cat build/meson-logs/testlog.txt && exit 1)
build-usan:
script:
- CFLAGS=-fsanitize=undefined meson --werror build || (cat build/meson-logs/meson-log.txt && exit 1)
- ninja -C build
- (cd build && meson test) || (cat build/meson-logs/testlog.txt && exit 1)
fuzz:
parallel:
matrix:
- TARGET: [arp, ip-header, udp, udp-h, tftp, dhcp, icmp, tcp, tcp-h, ndp, ip6-header, udp6, udp6-h, tftp6, icmp6, tcp6, tcp6-h]
script:
- CC=clang CXX=clang++ meson build -Dllvm-fuzz=true || (cat build/meson-logs/meson-log.txt && exit 1)
- ninja -C build
- build/fuzzing/fuzz-$TARGET -seed=1234 -runs=1000000 fuzzing/IN_$TARGET
artifacts:
when: on_failure
paths:
- crash-*
- leak-*
- oom-*
- timeout-*
build-mingw64:
script:
- (mkdir buildw && cd buildw && mingw64-meson --werror) || (cat buildw/meson-logs/meson-log.txt && exit 1)
- ninja -C buildw
Coverity:
only:
refs:
- master
- coverity
script:
- dnf update -y
- dnf install -y curl clang
- curl -o /tmp/cov-analysis-linux64.tgz https://scan.coverity.com/download/linux64
--form project=$COVERITY_SCAN_PROJECT_NAME --form token=$COVERITY_SCAN_TOKEN
- tar xfz /tmp/cov-analysis-linux64.tgz
- CC=clang meson build
- cov-analysis-linux64-*/bin/cov-build --dir cov-int ninja -C build
- tar cfz cov-int.tar.gz cov-int
- curl https://scan.coverity.com/builds?project=$COVERITY_SCAN_PROJECT_NAME
--form token=$COVERITY_SCAN_TOKEN --form email=$GITLAB_USER_EMAIL
--form file=@cov-int.tar.gz --form version="`git describe --tags`"
--form description="`git describe --tags` / $CI_COMMIT_TITLE / $CI_COMMIT_REF_NAME:$CI_PIPELINE_ID "
integration-slirp4netns:
variables:
SLIRP4NETNS_VERSION: "v1.1.12"
# Consumed by `make benchmark`
BENCHMARK_IPERF3_DURATION: "10"
script:
# Install libslirp
- meson build
- ninja -C build install
# Register the path of libslirp.so.0
- echo /usr/local/lib64 >/etc/ld.so.conf.d/libslirp.conf
- ldconfig
# Install the dependencies of slirp4netns and its test suite
# TODO: install udhcpc for `slirp4netns/tests/test-slirp4netns-dhcp.sh` (currently skipped, due to lack of udhcpc)
- dnf install -y autoconf automake findutils iperf3 iproute iputils jq libcap-devel libseccomp-devel nmap-ncat util-linux
# Check whether the runner environment is configured correctly
- unshare -rn true || (echo Make sure you have relaxed seccomp and appamor && exit 1)
- unshare -rn ip tap add tap0 mode tap || (echo Make sure you have /dev/net/tun && exit 1)
# Install slirp4netns
- git clone https://github.com/rootless-containers/slirp4netns -b "${SLIRP4NETNS_VERSION}"
- cd slirp4netns
- ./autogen.sh
- ./configure
- make
- make install
- slirp4netns --version
# Run slirp4netns integration test
- make distcheck || (cat $(find . -name 'test-suite.log' ) && exit 1)
# Run benchmark test to ensure that libslirp can actually handle packets, with several MTU configurations
- make benchmark MTU=1500
- make benchmark MTU=512
- make benchmark MTU=65520

View File

@ -0,0 +1,3 @@
[gitpublishprofile "default"]
base = master
to = slirp@lists.freedesktop.org

View File

@ -0,0 +1,238 @@
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [4.8.0] - TODO
## Security
- tcp: Fix testing for last fragment
- tftp: Fix use-after-free
### Added
- Add support for Haiku !123
- ncsi: Add manufacturer's ID !122
- ncsi: Add Get Version ID command !122
- ncsi: Add out-of-band ethernet address !125
- ncsi: Add Mellanox Get Mac Address handler !125
- icmp6: Add echo request forwarding support
- Add fuzzing infrastructure
### Fixed
- Fix missing cleanups
- windows: Build fixes
- ipv6: Use target address from Neighbor Advertisement !129
- dns: Reject domain-search when any entry ends with ".."
- dns: Use localhost as dns when /etc/resolv.conf empty !130
- icmp: Handle ICMP packets as IPPROTO_IP on BSD !133
- eth: pad ethernet frames to 60 bytes #34
### Removed
- windows: Bump the minimum Windows version to Windows 7
## [4.7.0] - 2022-04-26
### Added
- Allow disabling the internal DHCP server !22
- icmp: Support falling back on trying a SOCK_RAW socket !92
- Support Unix sockets in hostfwd !103
- IPv6 DNS proxying support !110
- bootp: add support for UEFI HTTP boot !111
- New callback that supports CFI better !117
### Fixed
- dhcp: Always send DHCP_OPT_LEN bytes in options !97
- Fix Haiku build !98 !99
- Fix memory leak when using libresolv !100
- Ensure sin6_scope_id is zero for global addresses !102
- resolv: fix IPv6 resolution on Darwin !104
- socket: Initialize so_type in socreate !109
- Handle ECONNABORTED from recv !116
## [4.6.1] - 2021-06-18
### Fixed
- Fix DHCP regression introduced in 4.6.0. !95
## [4.6.0] - 2021-06-14
### Added
- mbuf: Add debugging helpers for allocation. !90
### Changed
- Revert "Set macOS deployment target to macOS 10.4". !93
### Fixed
- mtod()-related buffer overflows (CVE-2021-3592 #44, CVE-2021-3593 #45,
CVE-2021-3594 #47, CVE-2021-3595 #46).
- poll_fd: add missing fd registration for UDP and ICMP
- ncsi: make ncsi_calculate_checksum work with unaligned data. !89
- Various typos and doc fixes. !88
## [4.5.0] - 2021-05-18
### Added
- IPv6 forwarding. !62 !75 !77
- slirp_neighbor_info() to dump the ARP/NDP tables. !71
### Changed
- Lazy guest address resolution for IPv6. !81
- Improve signal handling when spawning a child. !61
- Set macOS deployment target to macOS 10.4. !72
- slirp_add_hostfwd: Ensure all error paths set errno. !80
- More API documentation.
### Fixed
- Assertion failure on unspecified IPv6 address. !86
- Disable polling for PRI on MacOS, fixing some closing streams issues. !73
- Various memory leak fixes on fastq/batchq. !68
- Memory leak on IPv6 fast-send. !67
- Slow socket response on Windows. !64
- Misc build and code cleanups. !60 !63 !76 !79 !84
## [4.4.0] - 2020-12-02
### Added
- udp, udp6, icmp: handle TTL value. !48
- Enable forwarding ICMP errors. !49
- Add DNS resolving for iOS. !54
### Changed
- Improve meson subproject() support. !53
- Removed Makefile-based build system. !56
### Fixed
- socket: consume empty packets. !55
- check pkt_len before reading protocol header (CVE-2020-29129). !57
- ip_stripoptions use memmove (fixes undefined behaviour). !47
- various Coverity-related changes/fixes.
## [4.3.1] - 2020-07-08
### Changed
- A silent truncation could occur in `slirp_fmt()`, which will now print a
critical message. See also #22.
### Fixed
- CVE-2020-10756 - Drop bogus IPv6 messages that could lead to data leakage.
See !44 and !42.
- Fix win32 builds by using the SLIRP_PACKED definition.
- Various coverity scan errors fixed. !41
- Fix new GCC warnings. !43
## [4.3.0] - 2020-04-22
### Added
- `SLIRP_VERSION_STRING` macro, with the git sha suffix when building from git
- `SlirpConfig.disable_dns`, to disable DNS redirection #16
### Changed
- `slirp_version_string()` now has the git sha suffix when building form git
- Limit DNS redirection to port 53 #16
### Fixed
- Fix build regression with mingw & NetBSD
- Fix use-afte-free in `ip_reass()` (CVE-2020-1983)
## [4.2.0] - 2020-03-17
### Added
- New API function `slirp_add_unix`: add a forward rule to a Unix socket.
- New API function `slirp_remove_guestfwd`: remove a forward rule previously
added by `slirp_add_exec`, `slirp_add_unix` or `slirp_add_guestfwd`
- New `SlirpConfig.outbound_addr{,6}` fields to bind output socket to a
specific address
### Changed
- socket: do not fallback on host loopback if `get_dns_addr()` failed
or the address is in slirp network
### Fixed
- ncsi: fix checksum OOB memory access
- `tcp_emu()`: fix OOB accesses
- tftp: restrict relative path access
- state: fix loading of guestfwd state
## [4.1.0] - 2019-12-02
### Added
- The `slirp_new()` API, simpler and more extensible than `slirp_init()`.
- Allow custom MTU configuration.
- Option to disable host loopback connections.
- CI now runs scan-build too.
### Changed
- Disable `tcp_emu()` by default. `tcp_emu()` is known to have caused
several CVEs, and not useful today in most cases. The feature can
be still enabled by setting `SlirpConfig.enable_emu` to true.
- meson build system is now `subproject()` friendly.
- Replace remaining `malloc()`/`free()` with glib (which aborts on OOM)
- Various code cleanups.
### Deprecated
- The `slirp_init()` API.
### Fixed
- `getpeername()` error after `shutdown(SHUT_WR)`.
- Exec forward: correctly parse command lines that contain spaces.
- Allow 0.0.0.0 destination address.
- Make host receive broadcast packets.
- Various memory related fixes (heap overflow, leaks, NULL
dereference).
- Compilation warnings, dead code.
## [4.0.0] - 2019-05-24
### Added
- Installable as a shared library.
- meson build system
(& make build system for in-tree QEMU integration)
### Changed
- Standalone project, removing any QEMU dependency.
- License clarifications.
[Unreleased]: https://gitlab.freedesktop.org/slirp/libslirp/compare/v4.8.0...master
[4.8.0]: https://gitlab.freedesktop.org/slirp/libslirp/compare/v4.7.0...v4.8.0
[4.7.0]: https://gitlab.freedesktop.org/slirp/libslirp/compare/v4.6.1...v4.7.0
[4.6.1]: https://gitlab.freedesktop.org/slirp/libslirp/compare/v4.6.0...v4.6.1
[4.6.0]: https://gitlab.freedesktop.org/slirp/libslirp/compare/v4.5.0...v4.6.0
[4.5.0]: https://gitlab.freedesktop.org/slirp/libslirp/compare/v4.4.0...v4.5.0
[4.4.0]: https://gitlab.freedesktop.org/slirp/libslirp/compare/v4.3.1...v4.4.0
[4.3.1]: https://gitlab.freedesktop.org/slirp/libslirp/compare/v4.3.0...v4.3.1
[4.3.0]: https://gitlab.freedesktop.org/slirp/libslirp/compare/v4.2.0...v4.3.0
[4.2.0]: https://gitlab.freedesktop.org/slirp/libslirp/compare/v4.1.0...v4.2.0
[4.1.0]: https://gitlab.freedesktop.org/slirp/libslirp/compare/v4.0.0...v4.1.0
[4.0.0]: https://gitlab.freedesktop.org/slirp/libslirp/commits/v4.0.0

View File

@ -0,0 +1,64 @@
cmake_minimum_required(VERSION 3.16)
project(libslirp VERSION 4.8.0 LANGUAGES C)
set(SLIRP_MAJOR_VERSION "${libslirp_VERSION_MAJOR}")
set(SLIRP_MINOR_VERSION "${libslirp_VERSION_MINOR}")
set(SLIRP_MICRO_VERSION "${libslirp_VERSION_PATCH}")
set(SLIRP_VERSION_STRING "\"${libslirp_VERSION}\"")
set(SOURCES
src/arp_table.c
src/bootp.c
src/cksum.c
src/dhcpv6.c
src/dnssearch.c
src/if.c
src/ip6_icmp.c
src/ip6_input.c
src/ip6_output.c
src/ip_icmp.c
src/ip_input.c
src/ip_output.c
src/mbuf.c
src/misc.c
src/ncsi.c
src/ndp_table.c
src/sbuf.c
src/slirp.c
src/socket.c
src/state.c
src/stream.c
src/tcp_input.c
src/tcp_output.c
src/tcp_subr.c
src/tcp_timer.c
src/tftp.c
src/udp6.c
src/udp.c
src/util.c
src/version.c
src/vmstate.c
# glib shim
glib/glib.c
)
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/src/libslirp-version.h.in" "${CMAKE_CURRENT_BINARY_DIR}/libslirp-version.h")
add_library(slirp STATIC ${SOURCES})
target_include_directories(slirp PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/glib")
target_include_directories(slirp PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/src")
target_include_directories(slirp PRIVATE "${CMAKE_CURRENT_BINARY_DIR}")
target_compile_definitions(slirp PRIVATE BUILDING_LIBSLIRP)
set_target_properties(slirp PROPERTIES INTERPROCEDURAL_OPTIMIZATION OFF)
set_target_properties(slirp PROPERTIES INTERPROCEDURAL_OPTIMIZATION_RELEASE OFF)
if (WIN32)
target_link_libraries(slirp PRIVATE ws2_32 iphlpapi)
elseif(HAIKU)
target_Link_libraries(slirp PRIVATE network)
elseif(APPLE)
target_link_libraries(slirp PRIVATE resolv)
endif()

View File

@ -0,0 +1,62 @@
Slirp was written by Danny Gasparovski.
Copyright (c), 1995,1996 All Rights Reserved.
Slirp is free software; "free" as in you don't have to pay for it, and you
are free to do whatever you want with it. I do not accept any donations,
monetary or otherwise, for Slirp. Instead, I would ask you to pass this
potential donation to your favorite charity. In fact, I encourage
*everyone* who finds Slirp useful to make a small donation to their
favorite charity (for example, GreenPeace). This is not a requirement, but
a suggestion from someone who highly values the service they provide.
The copyright terms and conditions:
---BEGIN---
Copyright (c) 1995,1996 Danny Gasparovski. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
DANNY GASPAROVSKI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---END---
This basically means you can do anything you want with the software, except
1) call it your own, and 2) claim warranty on it. There is no warranty for
this software. None. Nada. If you lose a million dollars while using
Slirp, that's your loss not mine. So, ***USE AT YOUR OWN RISK!***.
If these conditions cannot be met due to legal restrictions (E.g. where it
is against the law to give out Software without warranty), you must cease
using the software and delete all copies you have.
Slirp uses code that is copyrighted by the following people/organizations:
Juha Pirkola.
Gregory M. Christy.
The Regents of the University of California.
Carnegie Mellon University.
The Australian National University.
RSA Data Security, Inc.
Please read the top of each source file for the details on the various
copyrights.

View File

@ -0,0 +1,60 @@
# libslirp
libslirp is a user-mode networking library used by virtual machines,
containers or various tools.
## Getting Started
### Prerequisites
A C compiler, meson and glib2 development libraries.
(see also [.gitlab-ci.yml](.gitlab-ci.yml) DEPS variable for the list
of dependencies on Fedora)
### Building
You may build and install the shared library with meson:
``` sh
meson build
ninja -C build install
```
And configure QEMU with --enable-slirp=system to link against it.
(QEMU may build with the submodule static library using --enable-slirp=git)
### Testing
Unfortunately, there are no automated tests available.
You may run QEMU ``-net user`` linked with your development version.
## Contributing
Feel free to open issues on the [project
issues](https://gitlab.freedesktop.org/slirp/libslirp/issues) page.
You may clone the [gitlab
project](https://gitlab.freedesktop.org/slirp/libslirp) and create a
merge request.
Contributing with gitlab allows gitlab workflow, tracking issues,
running CI etc.
Alternatively, you may send patches to slirp@lists.freedesktop.org
mailing list.
## Versioning
We intend to use [libtool's
versioning](https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html)
for the shared libraries and use [SemVer](http://semver.org/) for
project versions.
For the versions available, see the [tags on this
repository](https://gitlab.freedesktop.org/slirp/libslirp/releases).
## License
See the [COPYRIGHT](COPYRIGHT) file for details.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1 @@
../IN_ndp/ndp.pcap

View File

@ -0,0 +1 @@
../IN_udp/DNS_freedesktop_1-1-1-1.pcap

View File

@ -0,0 +1 @@
../IN_dhcp/dhcp.pkt

View File

@ -0,0 +1 @@
../IN_dhcp/dhcp_capture.pcap

View File

@ -0,0 +1 @@
../IN_icmp/icmp_capture.pcap

View File

@ -0,0 +1 @@
../IN_tcp/nc-10.0.2.2-8080.pcap

View File

@ -0,0 +1 @@
../IN_tcp/nc-ident.pcap

View File

@ -0,0 +1 @@
../IN_icmp/ping_10-0-2-2.pcap

View File

@ -0,0 +1 @@
../IN_tcp/tcp_qemucapt.pcap

View File

@ -0,0 +1 @@
../IN_tftp/tftp-get-blah.pkt

View File

@ -0,0 +1 @@
../IN_tftp/tftp_capture.pcap

View File

@ -0,0 +1 @@
../IN_tftp/tftp_get_libslirp-txt.pcap

View File

@ -0,0 +1 @@
../IN_udp6/DNS_freedesktop_1-1-1-1.pcap

View File

@ -0,0 +1 @@
../IN_icmp6/icmp_capture.pcap

View File

@ -0,0 +1 @@
../IN_icmp6/ping_10-0-2-2.pcap

View File

@ -0,0 +1 @@
../IN_tcp6/tcp_qemucapt.pcap

View File

@ -0,0 +1 @@
../IN_udp6/tftp_capture.pcap

View File

@ -0,0 +1 @@
../IN_udp6/tftp_get_libslirp-txt.pcap

Binary file not shown.

View File

@ -0,0 +1 @@
IN_tcp

View File

@ -0,0 +1 @@
IN_tcp

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1 @@
IN_tcp6

View File

@ -0,0 +1 @@
IN_tcp6

View File

@ -0,0 +1 @@
IN_udp

View File

@ -0,0 +1 @@
../IN_dhcp/dhcp.pkt

View File

@ -0,0 +1 @@
../IN_dhcp/dhcp_capture.pcap

View File

@ -0,0 +1 @@
../IN_tftp/tftp-get-blah.pkt

View File

@ -0,0 +1 @@
../IN_tftp/tftp_capture.pcap

View File

@ -0,0 +1 @@
../IN_tftp/tftp_get_libslirp-txt.pcap

View File

@ -0,0 +1 @@
IN_udp6

View File

@ -0,0 +1 @@
../IN_tftp6/tftp_capture.pcap

View File

@ -0,0 +1 @@
../IN_tftp6/tftp_get_libslirp-txt.pcap

View File

@ -0,0 +1,59 @@
# Fuzzing libslirp state and instructions
## Current state
We chose to use libFuzzer because of its custom mutator feature, which allows to keep coherent informations inside the packets being sent to libslirp. This ease the process of fuzzing as packets are less likely to be rejected early during processing them.
In the current state, the `meson.build` file is not compatible with the original one used by libSlirp main repository but it should be easy to merge them in a clean way. Also **in the current state, it seems that there is a memory leak inside the fuzzing code**, which make it run out of memory. The current goal is to find and get rid of this leak to allow fuzzing for longer without the process being interrupted because of it.
Six harness are currently available, more are to be added later to focus on other parts of the code :
- **fuzz-ip-header** : the mutator focuses on the ip header field informations,
- **fuzz-udp** : the mutator only work on udp packets, mutating the udp header and content, or only one or the other (-h,-d),
- **fuzz-tcp** : the mutator targets tcp packets, header+data or only one or the other, or only one or the other (-h,-d),
- **fuzz-icmp** : the mutator focuses on icmp packets,
These harness should be good starting examples on how to fuzz libslirp using libFuzzer.
## Running the fuzzer
Building the fuzzers/harness requires the use of clang as libFuzzer is part of LLVM.
You can build it running :
`CC=clang meson build && ninja -C build`
It will build the fuzzer in the ./build/fuzzing/ directory.
A script named `fuzzing/coverage.py` is available to generate coverage informations. **It makes a lot of assumptions on the directory structure** and should be read before use.
To run the fuzzer, simply run some of:
- `build/fuzzing/fuzz-ip-header fuzzing/IN_ip-header`
- `build/fuzzing/fuzz-udp fuzzing/IN_udp`
- `build/fuzzing/fuzz-udp-h fuzzing/IN_udp-h`
- `build/fuzzing/fuzz-tftp fuzzing/IN_tftp`
- `build/fuzzing/fuzz-dhcp fuzzing/IN_dhcp`
- `build/fuzzing/fuzz-icmp fuzzing/IN_icmp`
- `build/fuzzing/fuzz-tcp fuzzing/IN_tcp`
Your current directory should be a separate directory as crashes to it. New inputs found by the fuzzer will go directly in the `IN` folder.
# Adding new files to the corpus
In its current state, the fuzzing code is taking pcap files as input, we produced some using `tcpdump` on linux inside qemu with default settings.
Those files should be captured using the `EN10MB (Ethernet)` data link type, this can be set with the flag `-y` but it seems this can't be done while listening on all interfaces (`-i any`).
New files should give new coverage, to ensure a new file is usefull the `coverage.py` script (see next section) can be used to compare the coverage with and without that new file.
# Coverage
The `coverage.py` script allows to see coverage informations about the corpus. It makes a lot of assumptions on the directory structure so it should be read and probably modified before running it.
It must be called with the protocol to cover: `python coverage.py udp report`.
To generate coverage informations, the following flags are passed to the fuzzer and libslirp :
- g
- fsanitize-coverage=edge,indirect-calls,trace-cmp
- fprofile-instr-generate
- fcoverage-mapping
The last 2 arguments should also be passed to the linker.
Then the `llvm-profdata` and `llvm-cov` tools can be used to generate a report and a fancy set of HTML files with line-coverage informations.

View File

@ -0,0 +1,37 @@
from os import chdir,listdir,environ
from os.path import isfile,join,isdir
from subprocess import DEVNULL, run
import sys
ignored_files = "-ignore-filename-regex=glib -ignore-filename-regex=fuzz -ignore-filename-regex=helper -ignore-filename-regex=h$"
if __name__ == "__main__":
chdir("build/fuzzing/out")
available_targets = [exe for exe in listdir("../") if isfile(join("..", exe))]
available_corpus_path = [exe for exe in listdir("../../../fuzzing/") if isdir(join("../../../fuzzing/", exe))]
available_result_types = ["export", "show", "report"]
if len(sys.argv) != 4 or sys.argv[1] not in available_targets or sys.argv[2] not in available_corpus_path or sys.argv[3] not in available_result_types:
print("usage : python coverage.py fuzz_target IN_protol result_type")
print(" - available targets : ")
print(available_targets)
print(" - available_corpus_path : ")
print(available_corpus_path)
print(" - available result types : ")
print(available_result_types)
exit(0)
fuzzing_target = sys.argv[1]
corpus_path = "../../../fuzzing/"+sys.argv[2]+"/"
result_type = sys.argv[3]
if fuzzing_target in available_targets:
environ["LLVM_PROFILE_FILE"] = fuzzing_target + "_%p.profraw"
corpus = listdir(corpus_path)
for f in corpus:
#print(corpus_path+f)
run(["../" + fuzzing_target, corpus_path+f,"-detect_leaks=0"], stdin=DEVNULL, stdout=DEVNULL, stderr=DEVNULL)
run(["llvm-profdata merge -sparse " + fuzzing_target + "_*.profraw -o " + fuzzing_target + ".profdata"], shell=True)
if result_type == "export" :
run(["llvm-cov show ../" + fuzzing_target + " -format=html -output-dir=../report -instr-profile=" + fuzzing_target + ".profdata " + ignored_files], shell=True)
elif result_type == "show" :
run(["llvm-cov show ../" + fuzzing_target + " -instr-profile=" + fuzzing_target + ".profdata " + ignored_files], shell=True)
else:
run(["llvm-cov report ../" + fuzzing_target + " -instr-profile=" + fuzzing_target + ".profdata " + ignored_files], shell=True)

View File

@ -0,0 +1,2 @@
[libfuzzer]
max_len = 1024

View File

@ -0,0 +1,35 @@
#include <glib.h>
#include <stdlib.h>
#define MIN_NUMBER_OF_RUNS 1
#define EXIT_TEST_SKIP 77
extern int LLVMFuzzerTestOneInput(const unsigned char *data, size_t size);
int main(int argc, char **argv)
{
int i, j;
for (i = 1; i < argc; i++) {
GError *err = NULL;
char *name = argv[i];
char *buf;
size_t size;
if (!g_file_get_contents(name, &buf, &size, &err)) {
g_warning("Failed to read '%s': %s", name, err->message);
g_clear_error(&err);
return EXIT_FAILURE;
}
g_print("%s...\n", name);
for (j = 0; j < MIN_NUMBER_OF_RUNS; j++) {
if (LLVMFuzzerTestOneInput((void *)buf, size) == EXIT_TEST_SKIP) {
return EXIT_TEST_SKIP;
}
}
g_free(buf);
}
return EXIT_SUCCESS;
}

View File

@ -0,0 +1,271 @@
#include "helper.h"
#include <glib.h>
#include <stdlib.h>
#include "../src/libslirp.h"
#include "../src/ip6.h"
#include "slirp_base_fuzz.h"
#define MIN_NUMBER_OF_RUNS 1
#define EXIT_TEST_SKIP 77
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
struct in6_addr ip6_host;
struct in6_addr ip6_dns;
/// Function to compute the checksum of the ip header, should be compatible with
/// TCP and UDP checksum calculation too.
uint16_t compute_checksum(uint8_t *Data, size_t Size)
{
uint32_t sum = 0;
uint16_t *Data_as_u16 = (uint16_t *)Data;
for (size_t i = 0; i < Size / 2; i++) {
uint16_t val = ntohs(*(Data_as_u16 + i));
sum += val;
}
if (Size % 2 == 1)
sum += Data[Size - 1] << 8;
uint16_t carry = sum >> 16;
uint32_t sum_val = carry + (sum & 0xFFFF);
uint16_t result = (sum_val >> 16) + (sum_val & 0xFFFF);
return ~result;
}
int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
{
/* FIXME: fail on some addr? */
return 0;
}
int listen(int sockfd, int backlog)
{
return 0;
}
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen)
{
/* FIXME: fail on some addr? */
return 0;
}
ssize_t send(int sockfd, const void *buf, size_t len, int flags)
{
/* FIXME: partial send? */
return len;
}
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen)
{
/* FIXME: partial send? */
return len;
}
ssize_t recv(int sockfd, void *buf, size_t len, int flags)
{
memset(buf, 0, len);
return len / 2;
}
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
struct sockaddr *src_addr, socklen_t *addrlen)
{
memset(buf, 0, len);
memset(src_addr, 0, *addrlen);
return len / 2;
}
int setsockopt(int sockfd, int level, int optname, const void *optval,
socklen_t optlen)
{
return 0;
}
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
static void empty_logging_func(const gchar *log_domain,
GLogLevelFlags log_level, const gchar *message,
gpointer user_data)
{
}
#endif
/* Disables logging for oss-fuzz. Must be used with each target. */
static void fuzz_set_logging_func(void)
{
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
g_log_set_default_handler(empty_logging_func, NULL);
#endif
}
static ssize_t send_packet(const void *pkt, size_t pkt_len, void *opaque)
{
return pkt_len;
}
static int64_t clock_get_ns(void *opaque)
{
return 0;
}
static void *timer_new(SlirpTimerCb cb, void *cb_opaque, void *opaque)
{
return NULL;
}
static void timer_mod(void *timer, int64_t expire_timer, void *opaque)
{
}
static void timer_free(void *timer, void *opaque)
{
}
static void guest_error(const char *msg, void *opaque)
{
}
static void register_poll_fd(int fd, void *opaque)
{
}
static void unregister_poll_fd(int fd, void *opaque)
{
}
static void notify(void *opaque)
{
}
static const SlirpCb slirp_cb = {
.send_packet = send_packet,
.guest_error = guest_error,
.clock_get_ns = clock_get_ns,
.timer_new = timer_new,
.timer_mod = timer_mod,
.timer_free = timer_free,
.register_poll_fd = register_poll_fd,
.unregister_poll_fd = unregister_poll_fd,
.notify = notify,
};
#define MAX_EVID 1024
static int fake_events[MAX_EVID];
static int add_poll_cb(int fd, int events, void *opaque)
{
g_assert(fd < G_N_ELEMENTS(fake_events));
fake_events[fd] = events;
return fd;
}
static int get_revents_cb(int idx, void *opaque)
{
return fake_events[idx] & ~(SLIRP_POLL_ERR | SLIRP_POLL_HUP);
}
// Fuzzing strategy is the following :
// LLVMFuzzerTestOneInput :
// - build a slirp instance,
// - extract the packets from the pcap one by one,
// - send the data to `slirp_input`
// - call `slirp_pollfds_fill` and `slirp_pollfds_poll` to advance slirp
// - cleanup slirp when the whole pcap has been unwrapped.
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{
Slirp *slirp = NULL;
struct in_addr net = { .s_addr = htonl(0x0a000200) }; /* 10.0.2.0 */
struct in_addr mask = { .s_addr = htonl(0xffffff00) }; /* 255.255.255.0 */
struct in_addr host = { .s_addr = htonl(0x0a000202) }; /* 10.0.2.2 */
struct in_addr fwd = { .s_addr = htonl(0x0a000205) }; /* 10.0.2.5 */
struct in_addr dhcp = { .s_addr = htonl(0x0a00020f) }; /* 10.0.2.15 */
struct in_addr dns = { .s_addr = htonl(0x0a000203) }; /* 10.0.2.3 */
struct in6_addr ip6_prefix;
int ret, vprefix6_len = 64;
const char *vhostname = NULL;
const char *tftp_server_name = NULL;
const char *tftp_export = "fuzzing/tftp";
const char *bootfile = NULL;
const char **dnssearch = NULL;
const char *vdomainname = NULL;
const pcap_hdr_t *hdr = (const void *)data;
const pcaprec_hdr_t *rec = NULL;
uint32_t timeout = 0;
if (size < sizeof(pcap_hdr_t)) {
return 0;
}
data += sizeof(*hdr);
size -= sizeof(*hdr);
if (hdr->magic_number == 0xd4c3b2a1) {
g_debug("FIXME: byteswap fields");
return 0;
} /* else assume native pcap file */
if (hdr->network != 1) {
return 0;
}
setenv("SLIRP_FUZZING", "1", 0);
fuzz_set_logging_func();
ret = inet_pton(AF_INET6, "fec0::", &ip6_prefix);
g_assert_cmpint(ret, ==, 1);
ip6_host = ip6_prefix;
ip6_host.s6_addr[15] |= 2;
ip6_dns = ip6_prefix;
ip6_dns.s6_addr[15] |= 3;
slirp =
slirp_init(false, true, net, mask, host, true, ip6_prefix, vprefix6_len,
ip6_host, vhostname, tftp_server_name, tftp_export, bootfile,
dhcp, dns, ip6_dns, dnssearch, vdomainname, &slirp_cb, NULL);
slirp_add_exec(slirp, "cat", &fwd, 1234);
for ( ; size > sizeof(*rec); data += rec->incl_len, size -= rec->incl_len) {
rec = (const void *)data;
data += sizeof(*rec);
size -= sizeof(*rec);
if (rec->incl_len != rec->orig_len) {
g_debug("unsupported rec->incl_len != rec->orig_len");
break;
}
if (rec->incl_len > size) {
break;
}
if (rec->incl_len >= 14) {
if (data[12] == 0x08 && data[13] == 0x00) {
/* IPv4 */
if (rec->incl_len >= 14 + 16) {
uint32_t ipsource = * (uint32_t*) (data + 14 + 12);
// This an answer, which we will produce, so don't receive
if (ipsource == htonl(0x0a000202) || ipsource == htonl(0x0a000203))
continue;
}
} else if (data[12] == 0x86 && data[13] == 0xdd) {
if (rec->incl_len >= 14 + 24) {
struct in6_addr *ipsource = (struct in6_addr *) (data + 14 + 8);
// This an answer, which we will produce, so don't receive
if (in6_equal(ipsource, &ip6_host) || in6_equal(ipsource, &ip6_dns))
continue;
}
}
}
slirp_input(slirp, data, rec->incl_len);
slirp_pollfds_fill(slirp, &timeout, add_poll_cb, NULL);
slirp_pollfds_poll(slirp, 0, get_revents_cb, NULL);
}
slirp_cleanup(slirp);
return 0;
}

View File

@ -0,0 +1,24 @@
#ifndef _HELPER_H
#define _HELPER_H
#ifdef _WIN32
/* as defined in sdkddkver.h */
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0600 /* Vista */
#endif
#include <ws2tcpip.h>
#endif
#include <stdlib.h>
#include <stdint.h>
#include <netinet/in.h>
#define PSEUDO_IP_SIZE (4*2 + 4)
#define PSEUDO_IPV6_SIZE (16*2 + 4)
uint16_t compute_checksum(uint8_t *Data, size_t Size);
extern struct in6_addr ip6_host;
extern struct in6_addr ip6_dns;
#endif /* _HELPER_H */

View File

@ -0,0 +1,64 @@
extra_sources = []
extra_cargs = []
extra_ldargs = []
fuzzing_engine = []
extra_cargs += '-g'
if fuzzer_build
extra_cargs += '-fsanitize=fuzzer,address'
extra_cargs += '-fsanitize-coverage=edge,indirect-calls,trace-cmp'
extra_cargs += '-DCUSTOM_MUTATOR'
extra_cargs += '-fprofile-instr-generate'
extra_cargs += '-fcoverage-mapping'
extra_ldargs += '-fsanitize=fuzzer,address'
extra_ldargs += '-fprofile-instr-generate'
extra_ldargs += '-fcoverage-mapping'
endif
deps = [glib_dep, libslirp_dep, platform_deps]
exes = [
['fuzz-arp', ['slirp_fuzz_arp.c', 'helper.c']],
['fuzz-ip-header', ['slirp_fuzz_ip_header.c', 'helper.c']],
['fuzz-udp', ['slirp_fuzz_udp.c', 'helper.c']],
['fuzz-udp-h', ['slirp_fuzz_udp_header.c', 'helper.c']],
['fuzz-udp-d', ['slirp_fuzz_udp_data.c', 'helper.c']],
['fuzz-tftp', ['slirp_fuzz_udp_data.c', 'helper.c']],
['fuzz-dhcp', ['slirp_fuzz_udp_data.c', 'helper.c']],
['fuzz-tcp', ['slirp_fuzz_tcp.c', 'helper.c']],
['fuzz-tcp-h', ['slirp_fuzz_tcp_header.c', 'helper.c']],
['fuzz-tcp-d', ['slirp_fuzz_tcp_data.c', 'helper.c']],
['fuzz-icmp', ['slirp_fuzz_icmp.c', 'helper.c']],
['fuzz-ndp', ['slirp_fuzz_icmp6.c', 'helper.c']],
['fuzz-ip6-header', ['slirp_fuzz_ip6_header.c', 'helper.c']],
['fuzz-udp6', ['slirp_fuzz_udp6.c', 'helper.c']],
['fuzz-udp6-h', ['slirp_fuzz_udp6_header.c', 'helper.c']],
['fuzz-udp6-d', ['slirp_fuzz_udp6_data.c', 'helper.c']],
['fuzz-tftp6', ['slirp_fuzz_udp6_data.c', 'helper.c']],
['fuzz-tcp6', ['slirp_fuzz_tcp6.c', 'helper.c']],
['fuzz-tcp6-h', ['slirp_fuzz_tcp6_header.c', 'helper.c']],
['fuzz-tcp6-d', ['slirp_fuzz_tcp6_data.c', 'helper.c']],
['fuzz-icmp6', ['slirp_fuzz_icmp6.c', 'helper.c']],
]
if fuzzer_build
foreach exe : exes
executable(
exe[0], exe[1],
dependencies : deps,
c_args: extra_cargs,
link_args: extra_ldargs,
)
endforeach
endif
if fuzz_reproduce
executable(['reproducer', ['reproducer.c', 'helper.c']],
dependencies: deps,
c_args: extra_cargs,
link_args: extra_ldargs,
)
endif

View File

@ -0,0 +1,48 @@
#!/bin/bash
set -ex
export CC=${CC:-clang}
export CXX=${CXX:-clang++}
export WORK=${WORK:-$(pwd)}
export OUT=${OUT:-$(pwd)/out}
build=$WORK/build
rm -rf $build
mkdir -p $build
mkdir -p $OUT
fuzzflag="oss-fuzz=true"
if [ -z "$FUZZING_ENGINE" ]; then
fuzzflag="llvm-fuzz=true"
fi
meson $build \
-D$fuzzflag \
-Db_lundef=false \
-Ddefault_library=static \
-Dstatic=true \
-Dbuildtype=debugoptimized
ninja -C $build
zip -jqr $OUT/fuzz-arp_seed_corpus.zip "$(dirname "$0")/IN_arp"
zip -jqr $OUT/fuzz-ip-header_seed_corpus.zip "$(dirname "$0")/IN_ip-header"
zip -jqr $OUT/fuzz-udp_seed_corpus.zip "$(dirname "$0")/IN_udp"
zip -jqr $OUT/fuzz-udp-h_seed_corpus.zip "$(dirname "$0")/IN_udp-h"
zip -jqr $OUT/fuzz-tftp_seed_corpus.zip "$(dirname "$0")/IN_tftp"
zip -jqr $OUT/fuzz-dhcp_seed_corpus.zip "$(dirname "$0")/IN_dhcp"
zip -jqr $OUT/fuzz-icmp_seed_corpus.zip "$(dirname "$0")/IN_icmp"
zip -jqr $OUT/fuzz-tcp_seed_corpus.zip "$(dirname "$0")/IN_tcp"
zip -jqr $OUT/fuzz-tcp-h_seed_corpus.zip "$(dirname "$0")/IN_tcp-h"
zip -jqr $OUT/fuzz-ndp_seed_corpus.zip "$(dirname "$0")/IN_ndp"
zip -jqr $OUT/fuzz-ip6-header_seed_corpus.zip "$(dirname "$0")/IN_ip6-header"
zip -jqr $OUT/fuzz-udp6_seed_corpus.zip "$(dirname "$0")/IN_udp6"
zip -jqr $OUT/fuzz-udp6-h_seed_corpus.zip "$(dirname "$0")/IN_udp6-h"
zip -jqr $OUT/fuzz-tftp6_seed_corpus.zip "$(dirname "$0")/IN_tftp6"
zip -jqr $OUT/fuzz-icmp6_seed_corpus.zip "$(dirname "$0")/IN_icmp6"
zip -jqr $OUT/fuzz-tcp6_seed_corpus.zip "$(dirname "$0")/IN_tcp6"
find $build -type f -executable -name "fuzz-*" -exec mv {} $OUT \;
find $build -type f -name "*.options" -exec mv {} $OUT \;

View File

@ -0,0 +1,45 @@
#ifdef _WIN32
/* as defined in sdkddkver.h */
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0600 /* Vista */
#endif
#include <ws2tcpip.h>
#endif
#include <glib.h>
#include <stdlib.h>
#include "../src/libslirp.h"
#include "helper.h"
#define MIN_NUMBER_OF_RUNS 1
#define EXIT_TEST_SKIP 77
extern int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
int main(int argc, char **argv)
{
int i, j;
for (i = 1; i < argc; i++) {
GError *err = NULL;
char *name = argv[i];
char *buf;
size_t size;
if (!g_file_get_contents(name, &buf, &size, &err)) {
g_warning("Failed to read '%s': %s", name, err->message);
g_clear_error(&err);
return EXIT_FAILURE;
}
g_print("%s...\n", name);
for (j = 0; j < MIN_NUMBER_OF_RUNS; j++) {
if (LLVMFuzzerTestOneInput((void *)buf, size) == EXIT_TEST_SKIP) {
return EXIT_TEST_SKIP;
}
}
g_free(buf);
}
return EXIT_SUCCESS;
}

View File

@ -0,0 +1,23 @@
#include <glib.h>
#include <stdlib.h>
#include <stdio.h>
#include "../src/libslirp.h"
#include "helper.h"
/* Structure for the fuzzers */
typedef struct pcap_hdr_s {
guint32 magic_number; /* magic number */
guint16 version_major; /* major version number */
guint16 version_minor; /* minor version number */
gint32 thiszone; /* GMT to local correction */
guint32 sigfigs; /* accuracy of timestamps */
guint32 snaplen; /* max length of captured packets, in octets */
guint32 network; /* data link type */
} pcap_hdr_t;
typedef struct pcaprec_hdr_s {
guint32 ts_sec; /* timestamp seconds */
guint32 ts_usec; /* timestamp microseconds */
guint32 incl_len; /* number of octets of packet saved in file */
guint32 orig_len; /* actual length of packet */
} pcaprec_hdr_t;

View File

@ -0,0 +1,90 @@
#include <glib.h>
#include <stdlib.h>
#include <stdio.h>
#include "../src/libslirp.h"
#include "../src/ip6.h"
#include "helper.h"
#include "slirp_base_fuzz.h"
#ifdef CUSTOM_MUTATOR
extern size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize);
size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, size_t MaxSize, unsigned int Seed);
/// This is a custom mutator, this allows us to mutate only specific parts of
/// the input and fix the checksum so the packet isn't rejected for bad reasons.
extern size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size,
size_t MaxSize, unsigned int Seed)
{
size_t current_size = Size;
uint8_t *Data_ptr = Data;
uint8_t *arp_data;
bool mutated = false;
pcap_hdr_t *hdr = (void *)Data_ptr;
pcaprec_hdr_t *rec = NULL;
if (current_size < sizeof(pcap_hdr_t)) {
return 0;
}
Data_ptr += sizeof(*hdr);
current_size -= sizeof(*hdr);
if (hdr->magic_number == 0xd4c3b2a1) {
g_debug("FIXME: byteswap fields");
return 0;
} /* else assume native pcap file */
if (hdr->network != 1) {
return 0;
}
for ( ; current_size > sizeof(*rec); Data_ptr += rec->incl_len, current_size -= rec->incl_len) {
rec = (void *)Data_ptr;
Data_ptr += sizeof(*rec);
current_size -= sizeof(*rec);
if (rec->incl_len != rec->orig_len) {
return 0;
}
if (rec->incl_len > current_size) {
return 0;
}
if (rec->incl_len < 14 + 1) {
return 0;
}
arp_data = Data_ptr + 14;
uint8_t Data_to_mutate[MaxSize];
uint16_t arp_size = rec->incl_len - 14;
// Copy interesting data to the `Data_to_mutate` array
// here we want to fuzz everything in the ip header, maybe the IPs or
// total length should be excluded ?
memset(Data_to_mutate, 0, MaxSize);
memcpy(Data_to_mutate, arp_data, arp_size);
// Call to libfuzzer's mutation function.
// For now we dont want to change the header size as it would require to
// resize the `Data` array to include the new bytes inside the whole
// packet.
// This should be easy as LibFuzzer probably does it by itself or
// reserved enough space in Data beforehand, needs some research to
// confirm.
// FIXME: allow up to grow header size to 60 bytes,
// requires to update the `header length` before calculating
// checksum
LLVMFuzzerMutate(Data_to_mutate, arp_size, arp_size);
// Copy the mutated data back to the `Data` array
memcpy(arp_data, Data_to_mutate, arp_size);
mutated = true;
}
if (!mutated)
return 0;
return Size;
}
#endif // CUSTOM_MUTATOR

View File

@ -0,0 +1,129 @@
#include <glib.h>
#include <stdlib.h>
#include <stdio.h>
#include "../src/libslirp.h"
#include "helper.h"
#include "slirp_base_fuzz.h"
#ifdef CUSTOM_MUTATOR
extern size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize);
size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, size_t MaxSize, unsigned int Seed);
/// This is a custom mutator, this allows us to mutate only specific parts of
/// the input and fix the checksum so the packet isn't rejected for bad reasons.
extern size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size,
size_t MaxSize, unsigned int Seed)
{
size_t current_size = Size;
uint8_t *Data_ptr = Data;
uint8_t *ip_data;
uint32_t ipsource;
bool mutated = false;
pcap_hdr_t *hdr = (void *)Data_ptr;
pcaprec_hdr_t *rec = NULL;
if (current_size < sizeof(pcap_hdr_t)) {
return 0;
}
Data_ptr += sizeof(*hdr);
current_size -= sizeof(*hdr);
if (hdr->magic_number == 0xd4c3b2a1) {
g_debug("FIXME: byteswap fields");
return 0;
} /* else assume native pcap file */
if (hdr->network != 1) {
return 0;
}
for ( ; current_size > sizeof(*rec); Data_ptr += rec->incl_len, current_size -= rec->incl_len) {
rec = (void *)Data_ptr;
Data_ptr += sizeof(*rec);
current_size -= sizeof(*rec);
if (rec->incl_len != rec->orig_len) {
return 0;
}
if (rec->incl_len > current_size) {
return 0;
}
if (rec->incl_len < 14 + 1) {
return 0;
}
ip_data = Data_ptr + 14;
if (rec->incl_len >= 14 + 16) {
ipsource = * (uint32_t*) (ip_data + 12);
// This an answer, which we will produce, so don't mutate
if (ipsource == htonl(0x0a000202) || ipsource == htonl(0x0a000203))
continue;
}
// Exclude packets that are not ICMP from the mutation strategy
if (ip_data[9] != IPPROTO_ICMP)
continue;
uint8_t Data_to_mutate[MaxSize];
uint8_t ip_hl = (ip_data[0] & 0xF);
uint8_t ip_hl_in_bytes = ip_hl * 4; /* ip header length */
// The size inside the packet can't be trusted, if it is too big it can
// lead to heap overflows in the fuzzing code.
// Fixme : don't use ip_hl_in_bytes inside the fuzzing code, maybe use the
// rec->incl_len and manually calculate the size.
if (ip_hl_in_bytes > rec->incl_len - 14)
return 0;
uint8_t *start_of_icmp = ip_data + ip_hl_in_bytes;
uint16_t total_length =
ntohs(*((uint16_t *)ip_data + 1)); // network order to host order
uint16_t icmp_size =
(total_length - ip_hl_in_bytes); /* total length -> is stored at the
offset 2 in the header */
// The size inside the packet can't be trusted, if it is too big it can
// lead to heap overflows in the fuzzing code.
// Fixme : don't use udp_size inside the fuzzing code, maybe use the
// rec->incl_len and manually calculate the size.
if (icmp_size > MaxSize || icmp_size > rec->incl_len - 14 - ip_hl_in_bytes)
return 0;
// Copy interesting data to the `Data_to_mutate` array
// here we want to fuzz everything in icmp
memset(Data_to_mutate, 0, MaxSize);
memcpy(Data_to_mutate, start_of_icmp, icmp_size);
// Call to libfuzzer's mutation function.
// For now we dont want to change the header size as it would require to
// resize the `Data` array to include the new bytes inside the whole
// packet.
// This should be easy as LibFuzzer probably does it by itself or
// reserved enough space in Data beforehand, needs some research to
// confirm.
// FIXME: allow up to grow header size to 60 bytes,
// requires to update the `header length` before calculating
// checksum
LLVMFuzzerMutate(Data_to_mutate, icmp_size, icmp_size);
// Set the `checksum` field to 0 and calculate the new checksum
*(uint16_t *)(Data_to_mutate + 2) = 0;
uint16_t new_checksum =
compute_checksum(Data_to_mutate, icmp_size);
*(uint16_t *)(Data_to_mutate + 2) = htons(new_checksum);
// Copy the mutated data back to the `Data` array
memcpy(start_of_icmp, Data_to_mutate, icmp_size);
mutated = true;
}
if (!mutated)
return 0;
return Size;
}
#endif // CUSTOM_MUTATOR

View File

@ -0,0 +1,134 @@
#include <glib.h>
#include <stdlib.h>
#include <stdio.h>
#include "../src/libslirp.h"
#include "../src/ip6.h"
#include "helper.h"
#include "slirp_base_fuzz.h"
#ifdef CUSTOM_MUTATOR
extern size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize);
size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, size_t MaxSize, unsigned int Seed);
/// This is a custom mutator, this allows us to mutate only specific parts of
/// the input and fix the checksum so the packet isn't rejected for bad reasons.
extern size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size,
size_t MaxSize, unsigned int Seed)
{
size_t current_size = Size;
uint8_t *Data_ptr = Data;
uint8_t *ip_data;
bool mutated = false;
pcap_hdr_t *hdr = (void *)Data_ptr;
pcaprec_hdr_t *rec = NULL;
if (current_size < sizeof(pcap_hdr_t)) {
return 0;
}
Data_ptr += sizeof(*hdr);
current_size -= sizeof(*hdr);
if (hdr->magic_number == 0xd4c3b2a1) {
g_debug("FIXME: byteswap fields");
return 0;
} /* else assume native pcap file */
if (hdr->network != 1) {
return 0;
}
for ( ; current_size > sizeof(*rec); Data_ptr += rec->incl_len, current_size -= rec->incl_len) {
rec = (void *)Data_ptr;
Data_ptr += sizeof(*rec);
current_size -= sizeof(*rec);
if (rec->incl_len != rec->orig_len) {
return 0;
}
if (rec->incl_len > current_size) {
return 0;
}
if (rec->incl_len < 14 + 1) {
return 0;
}
ip_data = Data_ptr + 14;
if (rec->incl_len >= 14 + 24) {
struct in6_addr *ipsource = (struct in6_addr *) (ip_data + 8);
// This an answer, which we will produce, so don't receive
if (in6_equal(ipsource, &ip6_host) || in6_equal(ipsource, &ip6_dns))
continue;
}
// Exclude packets that are not ICMP from the mutation strategy
if (ip_data[6] != IPPROTO_ICMPV6)
continue;
// Allocate a bit more than needed, this is useful for
// checksum calculation.
uint8_t Data_to_mutate[MaxSize + PSEUDO_IPV6_SIZE];
uint8_t ip_hl_in_bytes = sizeof(struct ip6); /* ip header length */
// Fixme : don't use ip_hl_in_bytes inside the fuzzing code, maybe use the
// rec->incl_len and manually calculate the size.
if (ip_hl_in_bytes > rec->incl_len - 14)
return 0;
uint8_t *start_of_icmp = ip_data + ip_hl_in_bytes;
uint16_t icmp_size = ntohs(*(uint16_t *)(ip_data + 4));
// The size inside the packet can't be trusted, if it is too big it can
// lead to heap overflows in the fuzzing code.
// Fixme : don't use udp_size inside the fuzzing code, maybe use the
// rec->incl_len and manually calculate the size.
if (icmp_size > MaxSize || icmp_size > rec->incl_len - 14 - ip_hl_in_bytes)
return 0;
// Copy interesting data to the `Data_to_mutate` array
// here we want to fuzz everything in icmp
memset(Data_to_mutate, 0, MaxSize + PSEUDO_IPV6_SIZE);
memcpy(Data_to_mutate, start_of_icmp, icmp_size);
// Call to libfuzzer's mutation function.
// For now we dont want to change the header size as it would require to
// resize the `Data` array to include the new bytes inside the whole
// packet.
// This should be easy as LibFuzzer probably does it by itself or
// reserved enough space in Data beforehand, needs some research to
// confirm.
// FIXME: allow up to grow header size to 60 bytes,
// requires to update the `header length` before calculating
// checksum
LLVMFuzzerMutate(Data_to_mutate, icmp_size, icmp_size);
// Set the `checksum` field to 0 and calculate the new checksum
*(uint16_t *)(Data_to_mutate + 2) = 0;
// Copy the source and destination IP addresses, the tcp length and
// protocol number at the end of the `Data_to_mutate` array to calculate
// the new checksum.
memcpy(Data_to_mutate + icmp_size, ip_data + 8, 16*2);
*(Data_to_mutate + icmp_size + 16*2 + 1) = IPPROTO_ICMPV6;
*(Data_to_mutate + icmp_size + 16*2 + 2) = (uint8_t)(icmp_size / 256);
*(Data_to_mutate + icmp_size + 16*2 + 3) = (uint8_t)(icmp_size % 256);
uint16_t new_checksum =
compute_checksum(Data_to_mutate, icmp_size + PSEUDO_IPV6_SIZE);
*(uint16_t *)(Data_to_mutate + 2) = htons(new_checksum);
// Copy the mutated data back to the `Data` array
memcpy(start_of_icmp, Data_to_mutate, icmp_size);
mutated = true;
}
if (!mutated)
return 0;
return Size;
}
#endif // CUSTOM_MUTATOR

View File

@ -0,0 +1,103 @@
#include <glib.h>
#include <stdlib.h>
#include <stdio.h>
#include "../src/libslirp.h"
#include "../src/ip6.h"
#include "helper.h"
#include "slirp_base_fuzz.h"
#ifdef CUSTOM_MUTATOR
extern size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize);
size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, size_t MaxSize, unsigned int Seed);
/// This is a custom mutator, this allows us to mutate only specific parts of
/// the input and fix the checksum so the packet isn't rejected for bad reasons.
extern size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size,
size_t MaxSize, unsigned int Seed)
{
size_t current_size = Size;
uint8_t *Data_ptr = Data;
uint8_t *ip_data;
bool mutated = false;
pcap_hdr_t *hdr = (void *)Data_ptr;
pcaprec_hdr_t *rec = NULL;
if (current_size < sizeof(pcap_hdr_t)) {
return 0;
}
Data_ptr += sizeof(*hdr);
current_size -= sizeof(*hdr);
if (hdr->magic_number == 0xd4c3b2a1) {
g_debug("FIXME: byteswap fields");
return 0;
} /* else assume native pcap file */
if (hdr->network != 1) {
return 0;
}
for ( ; current_size > sizeof(*rec); Data_ptr += rec->incl_len, current_size -= rec->incl_len) {
rec = (void *)Data_ptr;
Data_ptr += sizeof(*rec);
current_size -= sizeof(*rec);
if (rec->incl_len != rec->orig_len) {
return 0;
}
if (rec->incl_len > current_size) {
return 0;
}
if (rec->incl_len < 14 + 1) {
return 0;
}
ip_data = Data_ptr + 14;
if (rec->incl_len >= 14 + 24) {
struct in6_addr *ipsource = (struct in6_addr *) (ip_data + 8);
// This an answer, which we will produce, so don't receive
if (in6_equal(ipsource, &ip6_host) || in6_equal(ipsource, &ip6_dns))
continue;
}
uint8_t Data_to_mutate[MaxSize];
uint8_t ip_hl_in_bytes = sizeof(struct ip6); /* ip header length */
// Fixme : don't use ip_hl_in_bytes inside the fuzzing code, maybe use the
// rec->incl_len and manually calculate the size.
if (ip_hl_in_bytes > rec->incl_len - 14)
return 0;
// Copy interesting data to the `Data_to_mutate` array
// here we want to fuzz everything in the ip header, maybe the IPs or
// total length should be excluded ?
memset(Data_to_mutate, 0, MaxSize);
memcpy(Data_to_mutate, ip_data, ip_hl_in_bytes);
// Call to libfuzzer's mutation function.
// For now we dont want to change the header size as it would require to
// resize the `Data` array to include the new bytes inside the whole
// packet.
// This should be easy as LibFuzzer probably does it by itself or
// reserved enough space in Data beforehand, needs some research to
// confirm.
// FIXME: allow up to grow header size to 60 bytes,
// requires to update the `header length` before calculating
// checksum
LLVMFuzzerMutate(Data_to_mutate, ip_hl_in_bytes, ip_hl_in_bytes);
// Copy the mutated data back to the `Data` array
memcpy(ip_data, Data_to_mutate, ip_hl_in_bytes);
mutated = true;
}
if (!mutated)
return 0;
return Size;
}
#endif // CUSTOM_MUTATOR

View File

@ -0,0 +1,112 @@
#include <glib.h>
#include <stdlib.h>
#include <stdio.h>
#include "../src/libslirp.h"
#include "helper.h"
#include "slirp_base_fuzz.h"
#ifdef CUSTOM_MUTATOR
extern size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize);
size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, size_t MaxSize, unsigned int Seed);
/// This is a custom mutator, this allows us to mutate only specific parts of
/// the input and fix the checksum so the packet isn't rejected for bad reasons.
extern size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size,
size_t MaxSize, unsigned int Seed)
{
size_t current_size = Size;
uint8_t *Data_ptr = Data;
uint8_t *ip_data;
uint32_t ipsource;
bool mutated = false;
pcap_hdr_t *hdr = (void *)Data_ptr;
pcaprec_hdr_t *rec = NULL;
if (current_size < sizeof(pcap_hdr_t)) {
return 0;
}
Data_ptr += sizeof(*hdr);
current_size -= sizeof(*hdr);
if (hdr->magic_number == 0xd4c3b2a1) {
g_debug("FIXME: byteswap fields");
return 0;
} /* else assume native pcap file */
if (hdr->network != 1) {
return 0;
}
for ( ; current_size > sizeof(*rec); Data_ptr += rec->incl_len, current_size -= rec->incl_len) {
rec = (void *)Data_ptr;
Data_ptr += sizeof(*rec);
current_size -= sizeof(*rec);
if (rec->incl_len != rec->orig_len) {
return 0;
}
if (rec->incl_len > current_size) {
return 0;
}
if (rec->incl_len < 14 + 1) {
return 0;
}
ip_data = Data_ptr + 14;
if (rec->incl_len >= 14 + 16) {
ipsource = * (uint32_t*) (ip_data + 12);
// This an answer, which we will produce, so don't mutate
if (ipsource == htonl(0x0a000202) || ipsource == htonl(0x0a000203))
continue;
}
uint8_t Data_to_mutate[MaxSize];
uint8_t ip_hl = (ip_data[0] & 0xF);
uint8_t ip_hl_in_bytes = ip_hl * 4; /* ip header length */
// The size inside the packet can't be trusted, if it is too big it can
// lead to heap overflows in the fuzzing code.
// Fixme : don't use ip_hl_in_bytes inside the fuzzing code, maybe use the
// rec->incl_len and manually calculate the size.
if (ip_hl_in_bytes > MaxSize || ip_hl_in_bytes > rec->incl_len - 14)
return 0;
// Copy interesting data to the `Data_to_mutate` array
// here we want to fuzz everything in the ip header, maybe the IPs or
// total length should be excluded ?
memset(Data_to_mutate, 0, MaxSize);
memcpy(Data_to_mutate, ip_data, ip_hl_in_bytes);
// Call to libfuzzer's mutation function.
// For now we dont want to change the header size as it would require to
// resize the `Data` array to include the new bytes inside the whole
// packet.
// This should be easy as LibFuzzer probably does it by itself or
// reserved enough space in Data beforehand, needs some research to
// confirm.
// FIXME: allow up to grow header size to 60 bytes,
// requires to update the `header length` before calculating
// checksum
LLVMFuzzerMutate(Data_to_mutate, ip_hl_in_bytes, ip_hl_in_bytes);
// Set the `checksum` field to 0 and calculate the new checksum
*(uint16_t *)(Data_to_mutate + 10) = 0;
uint16_t new_checksum =
compute_checksum(Data_to_mutate, ip_hl_in_bytes);
*(uint16_t *)(Data_to_mutate + 10) = htons(new_checksum);
// Copy the mutated data back to the `Data` array
memcpy(ip_data, Data_to_mutate, ip_hl_in_bytes);
mutated = true;
}
if (!mutated)
return 0;
return Size;
}
#endif // CUSTOM_MUTATOR

View File

@ -0,0 +1,138 @@
#include <glib.h>
#include <stdlib.h>
#include <stdio.h>
#include "../src/libslirp.h"
#include "helper.h"
#include "slirp_base_fuzz.h"
#ifdef CUSTOM_MUTATOR
extern size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize);
size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, size_t MaxSize, unsigned int Seed);
/// This is a custom mutator, this allows us to mutate only specific parts of
/// the input and fix the checksum so the packet isn't rejected for bad reasons.
extern size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size,
size_t MaxSize, unsigned int Seed)
{
size_t current_size = Size;
uint8_t *Data_ptr = Data;
uint8_t *ip_data;
uint32_t ipsource;
bool mutated = false;
pcap_hdr_t *hdr = (void *)Data_ptr;
pcaprec_hdr_t *rec = NULL;
if (current_size < sizeof(pcap_hdr_t)) {
return 0;
}
Data_ptr += sizeof(*hdr);
current_size -= sizeof(*hdr);
if (hdr->magic_number == 0xd4c3b2a1) {
g_debug("FIXME: byteswap fields");
return 0;
} /* else assume native pcap file */
if (hdr->network != 1) {
return 0;
}
for ( ; current_size > sizeof(*rec); Data_ptr += rec->incl_len, current_size -= rec->incl_len) {
rec = (void *)Data_ptr;
Data_ptr += sizeof(*rec);
current_size -= sizeof(*rec);
if (rec->incl_len != rec->orig_len) {
return 0;
}
if (rec->incl_len > current_size) {
return 0;
}
if (rec->incl_len < 14 + 1) {
return 0;
}
ip_data = Data_ptr + 14;
if (rec->incl_len >= 14 + 16) {
ipsource = * (uint32_t*) (ip_data + 12);
// This an answer, which we will produce, so don't mutate
if (ipsource == htonl(0x0a000202) || ipsource == htonl(0x0a000203))
continue;
}
// Exclude packets that are not TCP from the mutation strategy
if (ip_data[9] != IPPROTO_TCP)
continue;
// Allocate a bit more than needed, this is useful for
// checksum calculation.
uint8_t Data_to_mutate[MaxSize + PSEUDO_IP_SIZE];
uint8_t ip_hl = (ip_data[0] & 0xF);
uint8_t ip_hl_in_bytes = ip_hl * 4; /* ip header length */
// The size inside the packet can't be trusted, if it is too big it can
// lead to heap overflows in the fuzzing code.
// Fixme : don't use ip_hl_in_bytes inside the fuzzing code, maybe use the
// rec->incl_len and manually calculate the size.
if (ip_hl_in_bytes > rec->incl_len - 14)
return 0;
uint8_t *start_of_tcp = ip_data + ip_hl_in_bytes;
uint16_t total_length = ntohs(*((uint16_t *)ip_data + 1));
uint16_t tcp_size = (total_length - (uint16_t)ip_hl_in_bytes);
// The size inside the packet can't be trusted, if it is too big it can
// lead to heap overflows in the fuzzing code.
// Fixme : don't use tcp_size inside the fuzzing code, maybe use the
// rec->incl_len and manually calculate the size.
if (tcp_size > MaxSize || tcp_size > rec->incl_len - 14 - ip_hl_in_bytes)
return 0;
// Copy interesting data to the `Data_to_mutate` array
// here we want to fuzz everything in the tcp packet
memset(Data_to_mutate, 0, MaxSize + PSEUDO_IP_SIZE);
memcpy(Data_to_mutate, start_of_tcp, tcp_size);
// Call to libfuzzer's mutation function.
// Pass the whole TCP packet, mutate it and then fix checksum value
// so the packet isn't rejected.
// The new size of the data is returned by LLVMFuzzerMutate.
// Fixme: allow to change the size of the TCP packet, this will require
// to fix the size before calculating the new checksum and change
// how the Data_ptr is advanced.
// Most offsets bellow should be good for when the switch will be
// done to avoid overwriting new/mutated data.
LLVMFuzzerMutate(Data_to_mutate, tcp_size, tcp_size);
// Set the `checksum` field to 0 to calculate the new checksum
*(uint16_t *)(Data_to_mutate + 16) = (uint16_t)0;
// Copy the source and destination IP addresses, the tcp length and
// protocol number at the end of the `Data_to_mutate` array to calculate
// the new checksum.
memcpy(Data_to_mutate + tcp_size, ip_data + 12, 4*2);
*(Data_to_mutate + tcp_size + 9) = IPPROTO_TCP;
*(Data_to_mutate + tcp_size + 10) = (uint8_t)(tcp_size / 256);
*(Data_to_mutate + tcp_size + 11) = (uint8_t)(tcp_size % 256);
uint16_t new_checksum =
compute_checksum(Data_to_mutate, tcp_size + PSEUDO_IP_SIZE);
*(uint16_t *)(Data_to_mutate + 16) = htons(new_checksum);
// Copy the mutated data back to the `Data` array
memcpy(start_of_tcp, Data_to_mutate, tcp_size);
mutated = true;
}
if (!mutated)
return 0;
return Size;
}
#endif // CUSTOM_MUTATOR

View File

@ -0,0 +1,134 @@
#include <glib.h>
#include <stdlib.h>
#include <stdio.h>
#include "../src/libslirp.h"
#include "../src/ip6.h"
#include "helper.h"
#include "slirp_base_fuzz.h"
#ifdef CUSTOM_MUTATOR
extern size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize);
size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, size_t MaxSize, unsigned int Seed);
/// This is a custom mutator, this allows us to mutate only specific parts of
/// the input and fix the checksum so the packet isn't rejected for bad reasons.
extern size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size,
size_t MaxSize, unsigned int Seed)
{
size_t current_size = Size;
uint8_t *Data_ptr = Data;
uint8_t *ip_data;
bool mutated = false;
pcap_hdr_t *hdr = (void *)Data_ptr;
pcaprec_hdr_t *rec = NULL;
if (current_size < sizeof(pcap_hdr_t)) {
return 0;
}
Data_ptr += sizeof(*hdr);
current_size -= sizeof(*hdr);
if (hdr->magic_number == 0xd4c3b2a1) {
g_debug("FIXME: byteswap fields");
return 0;
} /* else assume native pcap file */
if (hdr->network != 1) {
return 0;
}
for ( ; current_size > sizeof(*rec); Data_ptr += rec->incl_len, current_size -= rec->incl_len) {
rec = (void *)Data_ptr;
Data_ptr += sizeof(*rec);
current_size -= sizeof(*rec);
if (rec->incl_len != rec->orig_len) {
return 0;
}
if (rec->incl_len > current_size) {
return 0;
}
if (rec->incl_len < 14 + 1) {
return 0;
}
ip_data = Data_ptr + 14;
if (rec->incl_len >= 14 + 24) {
struct in6_addr *ipsource = (struct in6_addr *) (ip_data + 8);
// This an answer, which we will produce, so don't receive
if (in6_equal(ipsource, &ip6_host) || in6_equal(ipsource, &ip6_dns))
continue;
}
// Exclude packets that are not TCP from the mutation strategy
if (ip_data[6] != IPPROTO_TCP)
continue;
// Allocate a bit more than needed, this is useful for
// checksum calculation.
uint8_t Data_to_mutate[MaxSize + PSEUDO_IPV6_SIZE];
uint8_t ip_hl_in_bytes = sizeof(struct ip6); /* ip header length */
// Fixme : don't use ip_hl_in_bytes inside the fuzzing code, maybe use the
// rec->incl_len and manually calculate the size.
if (ip_hl_in_bytes > rec->incl_len - 14)
return 0;
uint8_t *start_of_tcp = ip_data + ip_hl_in_bytes;
uint16_t tcp_size = ntohs(*(uint16_t *)(ip_data + 4));
// The size inside the packet can't be trusted, if it is too big it can
// lead to heap overflows in the fuzzing code.
// Fixme : don't use tcp_size inside the fuzzing code, maybe use the
// rec->incl_len and manually calculate the size.
if (tcp_size > MaxSize || tcp_size > rec->incl_len - 14 - ip_hl_in_bytes)
return 0;
// Copy interesting data to the `Data_to_mutate` array
// here we want to fuzz everything in the tcp packet
memset(Data_to_mutate, 0, MaxSize + PSEUDO_IPV6_SIZE);
memcpy(Data_to_mutate, start_of_tcp, tcp_size);
// Call to libfuzzer's mutation function.
// Pass the whole TCP packet, mutate it and then fix checksum value
// so the packet isn't rejected.
// The new size of the data is returned by LLVMFuzzerMutate.
// Fixme: allow to change the size of the TCP packet, this will require
// to fix the size before calculating the new checksum and change
// how the Data_ptr is advanced.
// Most offsets bellow should be good for when the switch will be
// done to avoid overwriting new/mutated data.
LLVMFuzzerMutate(Data_to_mutate, tcp_size, tcp_size);
// Set the `checksum` field to 0 to calculate the new checksum
*(uint16_t *)(Data_to_mutate + 16) = (uint16_t)0;
// Copy the source and destination IP addresses, the tcp length and
// protocol number at the end of the `Data_to_mutate` array to calculate
// the new checksum.
memcpy(Data_to_mutate + tcp_size, ip_data + 8, 16*2);
*(Data_to_mutate + tcp_size + 16*2 + 1) = IPPROTO_TCP;
*(Data_to_mutate + tcp_size + 16*2 + 2) = (uint8_t)(tcp_size / 256);
*(Data_to_mutate + tcp_size + 16*2 + 3) = (uint8_t)(tcp_size % 256);
uint16_t new_checksum =
compute_checksum(Data_to_mutate, tcp_size + PSEUDO_IPV6_SIZE);
*(uint16_t *)(Data_to_mutate + 16) = htons(new_checksum);
// Copy the mutated data back to the `Data` array
memcpy(start_of_tcp, Data_to_mutate, tcp_size);
mutated = true;
}
if (!mutated)
return 0;
return Size;
}
#endif // CUSTOM_MUTATOR

View File

@ -0,0 +1,137 @@
#include <glib.h>
#include <stdlib.h>
#include <stdio.h>
#include "../src/libslirp.h"
#include "../src/ip6.h"
#include "helper.h"
#include "slirp_base_fuzz.h"
#ifdef CUSTOM_MUTATOR
extern size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize);
size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, size_t MaxSize, unsigned int Seed);
/// This is a custom mutator, this allows us to mutate only specific parts of
/// the input and fix the checksum so the packet isn't rejected for bad reasons.
extern size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size,
size_t MaxSize, unsigned int Seed)
{
size_t current_size = Size;
uint8_t *Data_ptr = Data;
uint8_t *ip_data;
bool mutated = false;
pcap_hdr_t *hdr = (void *)Data_ptr;
pcaprec_hdr_t *rec = NULL;
if (current_size < sizeof(pcap_hdr_t)) {
return 0;
}
Data_ptr += sizeof(*hdr);
current_size -= sizeof(*hdr);
if (hdr->magic_number == 0xd4c3b2a1) {
g_debug("FIXME: byteswap fields");
return 0;
} /* else assume native pcap file */
if (hdr->network != 1) {
return 0;
}
for ( ; current_size > sizeof(*rec); Data_ptr += rec->incl_len, current_size -= rec->incl_len) {
rec = (void *)Data_ptr;
Data_ptr += sizeof(*rec);
current_size -= sizeof(*rec);
if (rec->incl_len != rec->orig_len) {
return 0;
}
if (rec->incl_len > current_size) {
return 0;
}
if (rec->incl_len < 14 + 1) {
return 0;
}
ip_data = Data_ptr + 14;
if (rec->incl_len >= 14 + 24) {
struct in6_addr *ipsource = (struct in6_addr *) (ip_data + 8);
// This an answer, which we will produce, so don't receive
if (in6_equal(ipsource, &ip6_host) || in6_equal(ipsource, &ip6_dns))
continue;
}
// Exclude packets that are not TCP from the mutation strategy
if (ip_data[6] != IPPROTO_TCP)
continue;
// Allocate a bit more than needed, this is useful for
// checksum calculation.
uint8_t Data_to_mutate[MaxSize + PSEUDO_IPV6_SIZE];
uint8_t ip_hl_in_bytes = sizeof(struct ip6); /* ip header length */
// Fixme : don't use ip_hl_in_bytes inside the fuzzing code, maybe use the
// rec->incl_len and manually calculate the size.
if (ip_hl_in_bytes > rec->incl_len - 14)
return 0;
uint8_t *start_of_tcp = ip_data + ip_hl_in_bytes;
uint8_t tcp_header_size = 4 * (*(start_of_tcp + 12) >> 4);
uint8_t *start_of_data = ip_data + ip_hl_in_bytes + tcp_header_size;
uint16_t tcp_size = ntohs(*(uint16_t *)(ip_data + 4));
uint16_t tcp_data_size = (tcp_size - (uint16_t)tcp_header_size);
// The size inside the packet can't be trusted, if it is too big it can
// lead to heap overflows in the fuzzing code.
// Fixme : don't use tcp_size inside the fuzzing code, maybe use the
// rec->incl_len and manually calculate the size.
if (tcp_data_size > MaxSize || tcp_data_size > rec->incl_len - 14 - ip_hl_in_bytes - tcp_header_size)
return 0;
// Copy interesting data to the `Data_to_mutate` array
// here we want to fuzz everything in the tcp packet
memset(Data_to_mutate, 0, MaxSize + PSEUDO_IPV6_SIZE);
memcpy(Data_to_mutate, start_of_tcp, tcp_size);
// Call to libfuzzer's mutation function.
// Pass the whole TCP packet, mutate it and then fix checksum value
// so the packet isn't rejected.
// The new size of the data is returned by LLVMFuzzerMutate.
// Fixme: allow to change the size of the TCP packet, this will require
// to fix the size before calculating the new checksum and change
// how the Data_ptr is advanced.
// Most offsets bellow should be good for when the switch will be
// done to avoid overwriting new/mutated data.
LLVMFuzzerMutate(Data_to_mutate + tcp_header_size, tcp_data_size, tcp_data_size);
// Set the `checksum` field to 0 to calculate the new checksum
*(uint16_t *)(Data_to_mutate + 16) = (uint16_t)0;
// Copy the source and destination IP addresses, the tcp length and
// protocol number at the end of the `Data_to_mutate` array to calculate
// the new checksum.
memcpy(Data_to_mutate + tcp_size, ip_data + 8, 16*2);
*(Data_to_mutate + tcp_size + 16*2 + 1) = IPPROTO_TCP;
*(Data_to_mutate + tcp_size + 16*2 + 2) = (uint8_t)(tcp_size / 256);
*(Data_to_mutate + tcp_size + 16*2 + 3) = (uint8_t)(tcp_size % 256);
uint16_t new_checksum =
compute_checksum(Data_to_mutate, tcp_size + PSEUDO_IPV6_SIZE);
*(uint16_t *)(Data_to_mutate + 16) = htons(new_checksum);
// Copy the mutated data back to the `Data` array
memcpy(start_of_tcp, Data_to_mutate, tcp_size);
mutated = true;
}
if (!mutated)
return 0;
return Size;
}
#endif // CUSTOM_MUTATOR

View File

@ -0,0 +1,136 @@
#include <glib.h>
#include <stdlib.h>
#include <stdio.h>
#include "../src/libslirp.h"
#include "../src/ip6.h"
#include "helper.h"
#include "slirp_base_fuzz.h"
#ifdef CUSTOM_MUTATOR
extern size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize);
size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, size_t MaxSize, unsigned int Seed);
/// This is a custom mutator, this allows us to mutate only specific parts of
/// the input and fix the checksum so the packet isn't rejected for bad reasons.
extern size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size,
size_t MaxSize, unsigned int Seed)
{
size_t current_size = Size;
uint8_t *Data_ptr = Data;
uint8_t *ip_data;
bool mutated = false;
pcap_hdr_t *hdr = (void *)Data_ptr;
pcaprec_hdr_t *rec = NULL;
if (current_size < sizeof(pcap_hdr_t)) {
return 0;
}
Data_ptr += sizeof(*hdr);
current_size -= sizeof(*hdr);
if (hdr->magic_number == 0xd4c3b2a1) {
g_debug("FIXME: byteswap fields");
return 0;
} /* else assume native pcap file */
if (hdr->network != 1) {
return 0;
}
for ( ; current_size > sizeof(*rec); Data_ptr += rec->incl_len, current_size -= rec->incl_len) {
rec = (void *)Data_ptr;
Data_ptr += sizeof(*rec);
current_size -= sizeof(*rec);
if (rec->incl_len != rec->orig_len) {
return 0;
}
if (rec->incl_len > current_size) {
return 0;
}
if (rec->incl_len < 14 + 1) {
return 0;
}
ip_data = Data_ptr + 14;
if (rec->incl_len >= 14 + 24) {
struct in6_addr *ipsource = (struct in6_addr *) (ip_data + 8);
// This an answer, which we will produce, so don't receive
if (in6_equal(ipsource, &ip6_host) || in6_equal(ipsource, &ip6_dns))
continue;
}
// Exclude packets that are not TCP from the mutation strategy
if (ip_data[6] != IPPROTO_TCP)
continue;
// Allocate a bit more than needed, this is useful for
// checksum calculation.
uint8_t Data_to_mutate[MaxSize + PSEUDO_IPV6_SIZE];
uint8_t ip_hl_in_bytes = sizeof(struct ip6); /* ip header length */
// Fixme : don't use ip_hl_in_bytes inside the fuzzing code, maybe use the
// rec->incl_len and manually calculate the size.
if (ip_hl_in_bytes > rec->incl_len - 14)
return 0;
uint8_t *start_of_tcp = ip_data + ip_hl_in_bytes;
uint8_t tcp_header_size = (*(start_of_tcp + 12) >> 4) * 4;
uint16_t tcp_size = ntohs(*(uint16_t *)(ip_data + 4));
// The size inside the packet can't be trusted, if it is too big it can
// lead to heap overflows in the fuzzing code.
// Fixme : don't use tcp_size inside the fuzzing code, maybe use the
// rec->incl_len and manually calculate the size.
if (tcp_size > MaxSize || tcp_size > rec->incl_len - 14 - ip_hl_in_bytes ||
tcp_header_size > MaxSize || tcp_header_size > rec->incl_len - 14 - ip_hl_in_bytes)
return 0;
// Copy interesting data to the `Data_to_mutate` array
// here we want to fuzz everything in the tcp packet
memset(Data_to_mutate, 0, MaxSize + PSEUDO_IPV6_SIZE);
memcpy(Data_to_mutate, start_of_tcp, tcp_size);
// Call to libfuzzer's mutation function.
// Pass the whole TCP packet, mutate it and then fix checksum value
// so the packet isn't rejected.
// The new size of the data is returned by LLVMFuzzerMutate.
// Fixme: allow to change the size of the TCP packet, this will require
// to fix the size before calculating the new checksum and change
// how the Data_ptr is advanced.
// Most offsets bellow should be good for when the switch will be
// done to avoid overwriting new/mutated data.
LLVMFuzzerMutate(Data_to_mutate, tcp_header_size, tcp_header_size);
// Set the `checksum` field to 0 to calculate the new checksum
*(uint16_t *)(Data_to_mutate + 16) = (uint16_t)0;
// Copy the source and destination IP addresses, the tcp length and
// protocol number at the end of the `Data_to_mutate` array to calculate
// the new checksum.
memcpy(Data_to_mutate + tcp_size, ip_data + 8, 16*2);
*(Data_to_mutate + tcp_size + 16*2 + 1) = IPPROTO_TCP;
*(Data_to_mutate + tcp_size + 16*2 + 2) = (uint8_t)(tcp_size / 256);
*(Data_to_mutate + tcp_size + 16*2 + 3) = (uint8_t)(tcp_size % 256);
uint16_t new_checksum =
compute_checksum(Data_to_mutate, tcp_size + PSEUDO_IPV6_SIZE);
*(uint16_t *)(Data_to_mutate + 16) = htons(new_checksum);
// Copy the mutated data back to the `Data` array
memcpy(start_of_tcp, Data_to_mutate, tcp_size);
mutated = true;
}
if (!mutated)
return 0;
return Size;
}
#endif // CUSTOM_MUTATOR

View File

@ -0,0 +1,141 @@
#include <glib.h>
#include <stdlib.h>
#include <stdio.h>
#include "../src/libslirp.h"
#include "helper.h"
#include "slirp_base_fuzz.h"
#ifdef CUSTOM_MUTATOR
extern size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize);
size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, size_t MaxSize, unsigned int Seed);
/// This is a custom mutator, this allows us to mutate only specific parts of
/// the input and fix the checksum so the packet isn't rejected for bad reasons.
extern size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size,
size_t MaxSize, unsigned int Seed)
{
size_t current_size = Size;
uint8_t *Data_ptr = Data;
uint8_t *ip_data;
uint32_t ipsource;
bool mutated = false;
pcap_hdr_t *hdr = (void *)Data_ptr;
pcaprec_hdr_t *rec = NULL;
if (current_size < sizeof(pcap_hdr_t)) {
return 0;
}
Data_ptr += sizeof(*hdr);
current_size -= sizeof(*hdr);
if (hdr->magic_number == 0xd4c3b2a1) {
g_debug("FIXME: byteswap fields");
return 0;
} /* else assume native pcap file */
if (hdr->network != 1) {
return 0;
}
for ( ; current_size > sizeof(*rec); Data_ptr += rec->incl_len, current_size -= rec->incl_len) {
rec = (void *)Data_ptr;
Data_ptr += sizeof(*rec);
current_size -= sizeof(*rec);
if (rec->incl_len != rec->orig_len) {
return 0;
}
if (rec->incl_len > current_size) {
return 0;
}
if (rec->incl_len < 14 + 1) {
return 0;
}
ip_data = Data_ptr + 14;
if (rec->incl_len >= 14 + 16) {
ipsource = * (uint32_t*) (ip_data + 12);
// This an answer, which we will produce, so don't mutate
if (ipsource == htonl(0x0a000202) || ipsource == htonl(0x0a000203))
continue;
}
// Exclude packets that are not TCP from the mutation strategy
if (ip_data[9] != IPPROTO_TCP)
continue;
// Allocate a bit more than needed, this is useful for
// checksum calculation.
uint8_t Data_to_mutate[MaxSize + PSEUDO_IP_SIZE];
uint8_t ip_hl = (ip_data[0] & 0xF);
uint8_t ip_hl_in_bytes = ip_hl * 4; /* ip header length */
// The size inside the packet can't be trusted, if it is too big it can
// lead to heap overflows in the fuzzing code.
// Fixme : don't use ip_hl_in_bytes inside the fuzzing code, maybe use the
// rec->incl_len and manually calculate the size.
if (ip_hl_in_bytes > rec->incl_len - 14)
return 0;
uint8_t *start_of_tcp = ip_data + ip_hl_in_bytes;
uint8_t tcp_header_size = 4 * (*(start_of_tcp + 12) >> 4);
uint8_t *start_of_data = ip_data + ip_hl_in_bytes + tcp_header_size;
uint16_t total_length = ntohs(*((uint16_t *)ip_data + 1));
uint16_t tcp_size = (total_length - (uint16_t)ip_hl_in_bytes);
uint16_t tcp_data_size = (tcp_size - (uint16_t)tcp_header_size);
// The size inside the packet can't be trusted, if it is too big it can
// lead to heap overflows in the fuzzing code.
// Fixme : don't use tcp_size inside the fuzzing code, maybe use the
// rec->incl_len and manually calculate the size.
if (tcp_data_size > MaxSize || tcp_data_size > rec->incl_len - 14 - ip_hl_in_bytes - tcp_header_size)
return 0;
// Copy interesting data to the `Data_to_mutate` array
// here we want to fuzz everything in the tcp packet
memset(Data_to_mutate, 0, MaxSize + PSEUDO_IP_SIZE);
memcpy(Data_to_mutate, start_of_tcp, tcp_size);
// Call to libfuzzer's mutation function.
// Pass the whole TCP packet, mutate it and then fix checksum value
// so the packet isn't rejected.
// The new size of the data is returned by LLVMFuzzerMutate.
// Fixme: allow to change the size of the TCP packet, this will require
// to fix the size before calculating the new checksum and change
// how the Data_ptr is advanced.
// Most offsets bellow should be good for when the switch will be
// done to avoid overwriting new/mutated data.
LLVMFuzzerMutate(Data_to_mutate + tcp_header_size, tcp_data_size, tcp_data_size);
// Set the `checksum` field to 0 to calculate the new checksum
*(uint16_t *)(Data_to_mutate + 16) = (uint16_t)0;
// Copy the source and destination IP addresses, the tcp length and
// protocol number at the end of the `Data_to_mutate` array to calculate
// the new checksum.
memcpy(Data_to_mutate + tcp_size, ip_data + 12, 4*2);
*(Data_to_mutate + tcp_size + 9) = IPPROTO_TCP;
*(Data_to_mutate + tcp_size + 10) = (uint8_t)(tcp_size / 256);
*(Data_to_mutate + tcp_size + 11) = (uint8_t)(tcp_size % 256);
uint16_t new_checksum =
compute_checksum(Data_to_mutate, tcp_size + PSEUDO_IP_SIZE);
*(uint16_t *)(Data_to_mutate + 16) = htons(new_checksum);
// Copy the mutated data back to the `Data` array
memcpy(start_of_tcp, Data_to_mutate, tcp_size);
mutated = true;
}
if (!mutated)
return 0;
return Size;
}
#endif // CUSTOM_MUTATOR

View File

@ -0,0 +1,140 @@
#include <glib.h>
#include <stdlib.h>
#include <stdio.h>
#include "../src/libslirp.h"
#include "helper.h"
#include "slirp_base_fuzz.h"
#ifdef CUSTOM_MUTATOR
extern size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize);
size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, size_t MaxSize, unsigned int Seed);
/// This is a custom mutator, this allows us to mutate only specific parts of
/// the input and fix the checksum so the packet isn't rejected for bad reasons.
extern size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size,
size_t MaxSize, unsigned int Seed)
{
size_t current_size = Size;
uint8_t *Data_ptr = Data;
uint8_t *ip_data;
uint32_t ipsource;
bool mutated = false;
pcap_hdr_t *hdr = (void *)Data_ptr;
pcaprec_hdr_t *rec = NULL;
if (current_size < sizeof(pcap_hdr_t)) {
return 0;
}
Data_ptr += sizeof(*hdr);
current_size -= sizeof(*hdr);
if (hdr->magic_number == 0xd4c3b2a1) {
g_debug("FIXME: byteswap fields");
return 0;
} /* else assume native pcap file */
if (hdr->network != 1) {
return 0;
}
for ( ; current_size > sizeof(*rec); Data_ptr += rec->incl_len, current_size -= rec->incl_len) {
rec = (void *)Data_ptr;
Data_ptr += sizeof(*rec);
current_size -= sizeof(*rec);
if (rec->incl_len != rec->orig_len) {
return 0;
}
if (rec->incl_len > current_size) {
return 0;
}
if (rec->incl_len < 14 + 1) {
return 0;
}
ip_data = Data_ptr + 14;
if (rec->incl_len >= 14 + 16) {
ipsource = * (uint32_t*) (ip_data + 12);
// This an answer, which we will produce, so don't mutate
if (ipsource == htonl(0x0a000202) || ipsource == htonl(0x0a000203))
continue;
}
// Exclude packets that are not TCP from the mutation strategy
if (ip_data[9] != IPPROTO_TCP)
continue;
// Allocate a bit more than needed, this is useful for
// checksum calculation.
uint8_t Data_to_mutate[MaxSize + PSEUDO_IP_SIZE];
uint8_t ip_hl = (ip_data[0] & 0xF);
uint8_t ip_hl_in_bytes = ip_hl * 4; /* ip header length */
// The size inside the packet can't be trusted, if it is too big it can
// lead to heap overflows in the fuzzing code.
// Fixme : don't use ip_hl_in_bytes inside the fuzzing code, maybe use the
// rec->incl_len and manually calculate the size.
if (ip_hl_in_bytes > rec->incl_len - 14)
return 0;
uint8_t *start_of_tcp = ip_data + ip_hl_in_bytes;
uint8_t tcp_header_size = (*(start_of_tcp + 12) >> 4) * 4;
uint16_t total_length = ntohs(*((uint16_t *)ip_data + 1));
uint16_t tcp_size = (total_length - (uint16_t)ip_hl_in_bytes);
// The size inside the packet can't be trusted, if it is too big it can
// lead to heap overflows in the fuzzing code.
// Fixme : don't use tcp_size inside the fuzzing code, maybe use the
// rec->incl_len and manually calculate the size.
if (tcp_size > MaxSize || tcp_size > rec->incl_len - 14 - ip_hl_in_bytes ||
tcp_header_size > MaxSize || tcp_header_size > rec->incl_len - 14 - ip_hl_in_bytes)
return 0;
// Copy interesting data to the `Data_to_mutate` array
// here we want to fuzz everything in the tcp packet
memset(Data_to_mutate, 0, MaxSize + PSEUDO_IP_SIZE);
memcpy(Data_to_mutate, start_of_tcp, tcp_size);
// Call to libfuzzer's mutation function.
// Pass the whole TCP packet, mutate it and then fix checksum value
// so the packet isn't rejected.
// The new size of the data is returned by LLVMFuzzerMutate.
// Fixme: allow to change the size of the TCP packet, this will require
// to fix the size before calculating the new checksum and change
// how the Data_ptr is advanced.
// Most offsets bellow should be good for when the switch will be
// done to avoid overwriting new/mutated data.
LLVMFuzzerMutate(Data_to_mutate, tcp_header_size, tcp_header_size);
// Set the `checksum` field to 0 to calculate the new checksum
*(uint16_t *)(Data_to_mutate + 16) = (uint16_t)0;
// Copy the source and destination IP addresses, the tcp length and
// protocol number at the end of the `Data_to_mutate` array to calculate
// the new checksum.
memcpy(Data_to_mutate + tcp_size, ip_data + 12, 4*2);
*(Data_to_mutate + tcp_size + 9) = IPPROTO_TCP;
*(Data_to_mutate + tcp_size + 10) = (uint8_t)(tcp_size / 256);
*(Data_to_mutate + tcp_size + 11) = (uint8_t)(tcp_size % 256);
uint16_t new_checksum =
compute_checksum(Data_to_mutate, tcp_size + PSEUDO_IP_SIZE);
*(uint16_t *)(Data_to_mutate + 16) = htons(new_checksum);
// Copy the mutated data back to the `Data` array
memcpy(start_of_tcp, Data_to_mutate, tcp_size);
mutated = true;
}
if (!mutated)
return 0;
return Size;
}
#endif // CUSTOM_MUTATOR

View File

@ -0,0 +1,121 @@
#include <glib.h>
#include <stdlib.h>
#include <stdio.h>
#include "../src/libslirp.h"
#include "helper.h"
#include "slirp_base_fuzz.h"
#ifdef CUSTOM_MUTATOR
extern size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize);
size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, size_t MaxSize, unsigned int Seed);
/// This is a custom mutator, this allows us to mutate only specific parts of
/// the input and fix the checksum so the packet isn't rejected for bad reasons.
extern size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size,
size_t MaxSize, unsigned int Seed)
{
size_t current_size = Size;
uint8_t *Data_ptr = Data;
uint8_t *ip_data;
uint32_t ipsource;
bool mutated = false;
pcap_hdr_t *hdr = (void *)Data_ptr;
pcaprec_hdr_t *rec = NULL;
if (current_size < sizeof(pcap_hdr_t)) {
return 0;
}
Data_ptr += sizeof(*hdr);
current_size -= sizeof(*hdr);
if (hdr->magic_number == 0xd4c3b2a1) {
g_debug("FIXME: byteswap fields");
return 0;
} /* else assume native pcap file */
if (hdr->network != 1) {
return 0;
}
for ( ; current_size > sizeof(*rec); Data_ptr += rec->incl_len, current_size -= rec->incl_len) {
rec = (void *)Data_ptr;
Data_ptr += sizeof(*rec);
current_size -= sizeof(*rec);
if (rec->incl_len != rec->orig_len) {
return 0;
}
if (rec->incl_len > current_size) {
return 0;
}
if (rec->incl_len < 14 + 1) {
return 0;
}
ip_data = Data_ptr + 14;
if (rec->incl_len >= 14 + 16) {
ipsource = * (uint32_t*) (ip_data + 12);
// This an answer, which we will produce, so don't mutate
if (ipsource == htonl(0x0a000202) || ipsource == htonl(0x0a000203))
continue;
}
// Exclude packets that are not UDP from the mutation strategy
if (ip_data[9] != IPPROTO_UDP)
continue;
uint8_t Data_to_mutate[MaxSize];
uint8_t ip_hl = (ip_data[0] & 0xF);
uint8_t ip_hl_in_bytes = ip_hl * 4; /* ip header length */
// The size inside the packet can't be trusted, if it is too big it can
// lead to heap overflows in the fuzzing code.
// Fixme : don't use ip_hl_in_bytes inside the fuzzing code, maybe use the
// rec->incl_len and manually calculate the size.
if (ip_hl_in_bytes > rec->incl_len - 14)
return 0;
uint8_t *start_of_udp = ip_data + ip_hl_in_bytes;
uint16_t udp_size = ntohs(*(uint16_t *)(start_of_udp + 4));
// The size inside the packet can't be trusted, if it is too big it can
// lead to heap overflows in the fuzzing code.
// Fixme : don't use udp_size inside the fuzzing code, maybe use the
// rec->incl_len and manually calculate the size.
if (udp_size > MaxSize || udp_size > rec->incl_len - 14 - ip_hl_in_bytes)
return 0;
// Copy interesting data to the `Data_to_mutate` array
// here we want to fuzz everything in the udp packet
memset(Data_to_mutate, 0, MaxSize);
memcpy(Data_to_mutate, start_of_udp, udp_size);
// Call to libfuzzer's mutation function.
// Pass the whole UDP packet, mutate it and then fix checksum value
// so the packet isn't rejected.
// The new size of the data is returned by LLVMFuzzerMutate.
// Fixme: allow to change the size of the UDP packet, this will require
// to fix the size before calculating the new checksum and change
// how the Data_ptr is advanced.
// Most offsets bellow should be good for when the switch will be
// done to avoid overwriting new/mutated data.
LLVMFuzzerMutate(Data_to_mutate, udp_size, udp_size);
// Drop checksum
*(uint16_t *)(Data_to_mutate + 6) = 0;
// Copy the mutated data back to the `Data` array
memcpy(start_of_udp, Data_to_mutate, udp_size);
mutated = true;
}
if (!mutated)
return 0;
return Size;
}
#endif // CUSTOM_MUTATOR

View File

@ -0,0 +1,120 @@
#include <glib.h>
#include <stdlib.h>
#include <stdio.h>
#include "../src/libslirp.h"
#include "../src/ip6.h"
#include "helper.h"
#include "slirp_base_fuzz.h"
#ifdef CUSTOM_MUTATOR
extern size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize);
size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, size_t MaxSize, unsigned int Seed);
/// This is a custom mutator, this allows us to mutate only specific parts of
/// the input and fix the checksum so the packet isn't rejected for bad reasons.
extern size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size,
size_t MaxSize, unsigned int Seed)
{
size_t current_size = Size;
uint8_t *Data_ptr = Data;
uint8_t *ip_data;
bool mutated = false;
pcap_hdr_t *hdr = (void *)Data_ptr;
pcaprec_hdr_t *rec = NULL;
if (current_size < sizeof(pcap_hdr_t)) {
return 0;
}
Data_ptr += sizeof(*hdr);
current_size -= sizeof(*hdr);
if (hdr->magic_number == 0xd4c3b2a1) {
g_debug("FIXME: byteswap fields");
return 0;
} /* else assume native pcap file */
if (hdr->network != 1) {
return 0;
}
for ( ; current_size > sizeof(*rec); Data_ptr += rec->incl_len, current_size -= rec->incl_len) {
rec = (void *)Data_ptr;
Data_ptr += sizeof(*rec);
current_size -= sizeof(*rec);
if (rec->incl_len != rec->orig_len) {
return 0;
}
if (rec->incl_len > current_size) {
return 0;
}
if (rec->incl_len < 14 + 1) {
return 0;
}
ip_data = Data_ptr + 14;
if (rec->incl_len >= 14 + 24) {
struct in6_addr *ipsource = (struct in6_addr *) (ip_data + 8);
// This an answer, which we will produce, so don't receive
if (in6_equal(ipsource, &ip6_host) || in6_equal(ipsource, &ip6_dns))
continue;
}
// Exclude packets that are not UDP from the mutation strategy
if (ip_data[6] != IPPROTO_UDP)
continue;
uint8_t Data_to_mutate[MaxSize];
uint8_t ip_hl_in_bytes = sizeof(struct ip6); /* ip header length */
// Fixme : don't use ip_hl_in_bytes inside the fuzzing code, maybe use the
// rec->incl_len and manually calculate the size.
if (ip_hl_in_bytes > rec->incl_len - 14)
return 0;
uint8_t *start_of_udp = ip_data + ip_hl_in_bytes;
uint16_t udp_size = ntohs(*(uint16_t *)(ip_data + 4));
// The size inside the packet can't be trusted, if it is too big it can
// lead to heap overflows in the fuzzing code.
// Fixme : don't use udp_size inside the fuzzing code, maybe use the
// rec->incl_len and manually calculate the size.
if (udp_size > MaxSize || udp_size > rec->incl_len - 14 - ip_hl_in_bytes)
return 0;
// Copy interesting data to the `Data_to_mutate` array
// here we want to fuzz everything in the udp packet
memset(Data_to_mutate, 0, MaxSize);
memcpy(Data_to_mutate, start_of_udp, udp_size);
// Call to libfuzzer's mutation function.
// Pass the whole UDP packet, mutate it and then fix checksum value
// so the packet isn't rejected.
// The new size of the data is returned by LLVMFuzzerMutate.
// Fixme: allow to change the size of the UDP packet, this will require
// to fix the size before calculating the new checksum and change
// how the Data_ptr is advanced.
// Most offsets bellow should be good for when the switch will be
// done to avoid overwriting new/mutated data.
LLVMFuzzerMutate(Data_to_mutate, udp_size, udp_size);
// Drop checksum
// Stricto sensu, UDPv6 makes checksums mandatory, but libslirp doesn't
// check that actually
*(uint16_t *)(Data_to_mutate + 6) = 0;
// Copy the mutated data back to the `Data` array
memcpy(start_of_udp, Data_to_mutate, udp_size);
mutated = true;
}
if (!mutated)
return 0;
return Size;
}
#endif // CUSTOM_MUTATOR

View File

@ -0,0 +1,122 @@
#include <glib.h>
#include <stdlib.h>
#include <stdio.h>
#include "../src/libslirp.h"
#include "../src/ip6.h"
#include "helper.h"
#include "slirp_base_fuzz.h"
#ifdef CUSTOM_MUTATOR
extern size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize);
size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, size_t MaxSize, unsigned int Seed);
/// This is a custom mutator, this allows us to mutate only specific parts of
/// the input and fix the checksum so the packet isn't rejected for bad reasons.
extern size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size,
size_t MaxSize, unsigned int Seed)
{
size_t current_size = Size;
uint8_t *Data_ptr = Data;
uint8_t *ip_data;
bool mutated = false;
pcap_hdr_t *hdr = (void *)Data_ptr;
pcaprec_hdr_t *rec = NULL;
if (current_size < sizeof(pcap_hdr_t)) {
return 0;
}
Data_ptr += sizeof(*hdr);
current_size -= sizeof(*hdr);
if (hdr->magic_number == 0xd4c3b2a1) {
g_debug("FIXME: byteswap fields");
return 0;
} /* else assume native pcap file */
if (hdr->network != 1) {
return 0;
}
for ( ; current_size > sizeof(*rec); Data_ptr += rec->incl_len, current_size -= rec->incl_len) {
rec = (void *)Data_ptr;
Data_ptr += sizeof(*rec);
current_size -= sizeof(*rec);
if (rec->incl_len != rec->orig_len) {
return 0;
}
if (rec->incl_len > current_size) {
return 0;
}
if (rec->incl_len < 14 + 1) {
return 0;
}
ip_data = Data_ptr + 14;
if (rec->incl_len >= 14 + 24) {
struct in6_addr *ipsource = (struct in6_addr *) (ip_data + 8);
// This an answer, which we will produce, so don't receive
if (in6_equal(ipsource, &ip6_host) || in6_equal(ipsource, &ip6_dns))
continue;
}
// Exclude packets that are not UDP from the mutation strategy
if (ip_data[6] != IPPROTO_UDP)
continue;
uint8_t Data_to_mutate[MaxSize];
uint8_t ip_hl_in_bytes = sizeof(struct ip6); /* ip header length */
// Fixme : don't use ip_hl_in_bytes inside the fuzzing code, maybe use the
// rec->incl_len and manually calculate the size.
if (ip_hl_in_bytes > rec->incl_len - 14)
return 0;
uint8_t *start_of_udp = ip_data + ip_hl_in_bytes;
uint8_t udp_header_size = 8;
uint16_t udp_size = ntohs(*(uint16_t *)(ip_data + 4));
uint16_t udp_data_size = (udp_size - (uint16_t)udp_header_size);
// The size inside the packet can't be trusted, if it is too big it can
// lead to heap overflows in the fuzzing code.
// Fixme : don't use udp_size inside the fuzzing code, maybe use the
// rec->incl_len and manually calculate the size.
if (udp_data_size > MaxSize || udp_data_size > rec->incl_len - 14 - ip_hl_in_bytes - udp_header_size)
return 0;
// Copy interesting data to the `Data_to_mutate` array
// here we want to fuzz everything in the udp packet
memset(Data_to_mutate, 0, MaxSize);
memcpy(Data_to_mutate, start_of_udp, udp_size);
// Call to libfuzzer's mutation function.
// Pass the whole UDP packet, mutate it and then fix checksum value
// so the packet isn't rejected.
// The new size of the data is returned by LLVMFuzzerMutate.
// Fixme: allow to change the size of the UDP packet, this will require
// to fix the size before calculating the new checksum and change
// how the Data_ptr is advanced.
// Most offsets bellow should be good for when the switch will be
// done to avoid overwriting new/mutated data.
LLVMFuzzerMutate(Data_to_mutate + udp_header_size, udp_data_size, udp_data_size);
// Drop checksum
// Stricto sensu, UDPv6 makes checksums mandatory, but libslirp doesn't
// check that actually
*(uint16_t *)(Data_to_mutate + 6) = 0;
// Copy the mutated data back to the `Data` array
memcpy(start_of_udp, Data_to_mutate, udp_size);
mutated = true;
}
if (!mutated)
return 0;
return Size;
}
#endif // CUSTOM_MUTATOR

View File

@ -0,0 +1,121 @@
#include <glib.h>
#include <stdlib.h>
#include <stdio.h>
#include "../src/libslirp.h"
#include "../src/ip6.h"
#include "helper.h"
#include "slirp_base_fuzz.h"
#ifdef CUSTOM_MUTATOR
extern size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize);
size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, size_t MaxSize, unsigned int Seed);
/// This is a custom mutator, this allows us to mutate only specific parts of
/// the input and fix the checksum so the packet isn't rejected for bad reasons.
extern size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size,
size_t MaxSize, unsigned int Seed)
{
size_t current_size = Size;
uint8_t *Data_ptr = Data;
uint8_t *ip_data;
bool mutated = false;
pcap_hdr_t *hdr = (void *)Data_ptr;
pcaprec_hdr_t *rec = NULL;
if (current_size < sizeof(pcap_hdr_t)) {
return 0;
}
Data_ptr += sizeof(*hdr);
current_size -= sizeof(*hdr);
if (hdr->magic_number == 0xd4c3b2a1) {
g_debug("FIXME: byteswap fields");
return 0;
} /* else assume native pcap file */
if (hdr->network != 1) {
return 0;
}
for ( ; current_size > sizeof(*rec); Data_ptr += rec->incl_len, current_size -= rec->incl_len) {
rec = (void *)Data_ptr;
Data_ptr += sizeof(*rec);
current_size -= sizeof(*rec);
if (rec->incl_len != rec->orig_len) {
return 0;
}
if (rec->incl_len > current_size) {
return 0;
}
if (rec->incl_len < 14 + 1) {
return 0;
}
ip_data = Data_ptr + 14;
if (rec->incl_len >= 14 + 24) {
struct in6_addr *ipsource = (struct in6_addr *) (ip_data + 8);
// This an answer, which we will produce, so don't receive
if (in6_equal(ipsource, &ip6_host) || in6_equal(ipsource, &ip6_dns))
continue;
}
// Exclude packets that are not UDP from the mutation strategy
if (ip_data[6] != IPPROTO_UDP)
continue;
uint8_t Data_to_mutate[MaxSize];
uint8_t ip_hl_in_bytes = sizeof(struct ip6); /* ip header length */
// Fixme : don't use ip_hl_in_bytes inside the fuzzing code, maybe use the
// rec->incl_len and manually calculate the size.
if (ip_hl_in_bytes > rec->incl_len - 14)
return 0;
uint8_t *start_of_udp = ip_data + ip_hl_in_bytes;
uint8_t udp_header_size = 8;
uint16_t udp_size = ntohs(*(uint16_t *)(ip_data + 4));
// The size inside the packet can't be trusted, if it is too big it can
// lead to heap overflows in the fuzzing code.
// Fixme : don't use udp_size inside the fuzzing code, maybe use the
// rec->incl_len and manually calculate the size.
if (udp_size > MaxSize || udp_size > rec->incl_len - 14 - ip_hl_in_bytes)
return 0;
// Copy interesting data to the `Data_to_mutate` array
// here we want to fuzz everything in the udp packet
memset(Data_to_mutate, 0, MaxSize);
memcpy(Data_to_mutate, start_of_udp, udp_size);
// Call to libfuzzer's mutation function.
// Pass the whole UDP packet, mutate it and then fix checksum value
// so the packet isn't rejected.
// The new size of the data is returned by LLVMFuzzerMutate.
// Fixme: allow to change the size of the UDP packet, this will require
// to fix the size before calculating the new checksum and change
// how the Data_ptr is advanced.
// Most offsets bellow should be good for when the switch will be
// done to avoid overwriting new/mutated data.
LLVMFuzzerMutate(Data_to_mutate, udp_header_size, udp_header_size);
// Drop checksum
// Stricto sensu, UDPv6 makes checksums mandatory, but libslirp doesn't
// check that actually
*(uint16_t *)(Data_to_mutate + 6) = 0;
// Copy the mutated data back to the `Data` array
memcpy(start_of_udp, Data_to_mutate, udp_size);
mutated = true;
}
if (!mutated)
return 0;
return Size;
}
#endif // CUSTOM_MUTATOR

View File

@ -0,0 +1,123 @@
#include <glib.h>
#include <stdlib.h>
#include <stdio.h>
#include "../src/libslirp.h"
#include "helper.h"
#include "slirp_base_fuzz.h"
#ifdef CUSTOM_MUTATOR
extern size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize);
size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, size_t MaxSize, unsigned int Seed);
/// This is a custom mutator, this allows us to mutate only specific parts of
/// the input and fix the checksum so the packet isn't rejected for bad reasons.
extern size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size,
size_t MaxSize, unsigned int Seed)
{
size_t current_size = Size;
uint8_t *Data_ptr = Data;
uint8_t *ip_data;
uint32_t ipsource;
bool mutated = false;
pcap_hdr_t *hdr = (void *)Data_ptr;
pcaprec_hdr_t *rec = NULL;
if (current_size < sizeof(pcap_hdr_t)) {
return 0;
}
Data_ptr += sizeof(*hdr);
current_size -= sizeof(*hdr);
if (hdr->magic_number == 0xd4c3b2a1) {
g_debug("FIXME: byteswap fields");
return 0;
} /* else assume native pcap file */
if (hdr->network != 1) {
return 0;
}
for ( ; current_size > sizeof(*rec); Data_ptr += rec->incl_len, current_size -= rec->incl_len) {
rec = (void *)Data_ptr;
Data_ptr += sizeof(*rec);
current_size -= sizeof(*rec);
if (rec->incl_len != rec->orig_len) {
return 0;
}
if (rec->incl_len > current_size) {
return 0;
}
if (rec->incl_len < 14 + 1) {
return 0;
}
ip_data = Data_ptr + 14;
if (rec->incl_len >= 14 + 16) {
ipsource = * (uint32_t*) (ip_data + 12);
// This an answer, which we will produce, so don't mutate
if (ipsource == htonl(0x0a000202) || ipsource == htonl(0x0a000203))
continue;
}
// Exclude packets that are not UDP from the mutation strategy
if (ip_data[9] != IPPROTO_UDP)
continue;
uint8_t Data_to_mutate[MaxSize];
uint8_t ip_hl = (ip_data[0] & 0xF);
uint8_t ip_hl_in_bytes = ip_hl * 4; /* ip header length */
// The size inside the packet can't be trusted, if it is too big it can
// lead to heap overflows in the fuzzing code.
// Fixme : don't use ip_hl_in_bytes inside the fuzzing code, maybe use the
// rec->incl_len and manually calculate the size.
if (ip_hl_in_bytes > rec->incl_len - 14)
return 0;
uint8_t *start_of_udp = ip_data + ip_hl_in_bytes;
uint8_t udp_header_size = 8;
uint16_t udp_size = ntohs(*(uint16_t *)(start_of_udp + 4));
uint16_t udp_data_size = (udp_size - (uint16_t)udp_header_size);
// The size inside the packet can't be trusted, if it is too big it can
// lead to heap overflows in the fuzzing code.
// Fixme : don't use udp_size inside the fuzzing code, maybe use the
// rec->incl_len and manually calculate the size.
if (udp_data_size > MaxSize || udp_data_size > rec->incl_len - 14 - ip_hl_in_bytes - udp_header_size)
return 0;
// Copy interesting data to the `Data_to_mutate` array
// here we want to fuzz everything in the udp packet
memset(Data_to_mutate, 0, MaxSize);
memcpy(Data_to_mutate, start_of_udp, udp_size);
// Call to libfuzzer's mutation function.
// Pass the whole UDP packet, mutate it and then fix checksum value
// so the packet isn't rejected.
// The new size of the data is returned by LLVMFuzzerMutate.
// Fixme: allow to change the size of the UDP packet, this will require
// to fix the size before calculating the new checksum and change
// how the Data_ptr is advanced.
// Most offsets bellow should be good for when the switch will be
// done to avoid overwriting new/mutated data.
LLVMFuzzerMutate(Data_to_mutate + udp_header_size, udp_data_size, udp_data_size);
// Drop checksum
*(uint16_t *)(Data_to_mutate + 6) = 0;
// Copy the mutated data back to the `Data` array
memcpy(start_of_udp, Data_to_mutate, udp_size);
mutated = true;
}
if (!mutated)
return 0;
return Size;
}
#endif // CUSTOM_MUTATOR

View File

@ -0,0 +1,122 @@
#include <glib.h>
#include <stdlib.h>
#include <stdio.h>
#include "../src/libslirp.h"
#include "helper.h"
#include "slirp_base_fuzz.h"
#ifdef CUSTOM_MUTATOR
extern size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize);
size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, size_t MaxSize, unsigned int Seed);
/// This is a custom mutator, this allows us to mutate only specific parts of
/// the input and fix the checksum so the packet isn't rejected for bad reasons.
extern size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size,
size_t MaxSize, unsigned int Seed)
{
size_t current_size = Size;
uint8_t *Data_ptr = Data;
uint8_t *ip_data;
uint32_t ipsource;
bool mutated = false;
pcap_hdr_t *hdr = (void *)Data_ptr;
pcaprec_hdr_t *rec = NULL;
if (current_size < sizeof(pcap_hdr_t)) {
return 0;
}
Data_ptr += sizeof(*hdr);
current_size -= sizeof(*hdr);
if (hdr->magic_number == 0xd4c3b2a1) {
g_debug("FIXME: byteswap fields");
return 0;
} /* else assume native pcap file */
if (hdr->network != 1) {
return 0;
}
for ( ; current_size > sizeof(*rec); Data_ptr += rec->incl_len, current_size -= rec->incl_len) {
rec = (void *)Data_ptr;
Data_ptr += sizeof(*rec);
current_size -= sizeof(*rec);
if (rec->incl_len != rec->orig_len) {
return 0;
}
if (rec->incl_len > current_size) {
return 0;
}
if (rec->incl_len < 14 + 1) {
return 0;
}
ip_data = Data_ptr + 14;
if (rec->incl_len >= 14 + 16) {
ipsource = * (uint32_t*) (ip_data + 12);
// This an answer, which we will produce, so don't mutate
if (ipsource == htonl(0x0a000202) || ipsource == htonl(0x0a000203))
continue;
}
// Exclude packets that are not UDP from the mutation strategy
if (ip_data[9] != IPPROTO_UDP)
continue;
uint8_t Data_to_mutate[MaxSize];
uint8_t ip_hl = (ip_data[0] & 0xF);
uint8_t ip_hl_in_bytes = ip_hl * 4; /* ip header length */
// The size inside the packet can't be trusted, if it is too big it can
// lead to heap overflows in the fuzzing code.
// Fixme : don't use ip_hl_in_bytes inside the fuzzing code, maybe use the
// rec->incl_len and manually calculate the size.
if (ip_hl_in_bytes > rec->incl_len - 14)
return 0;
uint8_t *start_of_udp = ip_data + ip_hl_in_bytes;
uint8_t udp_header_size = 8;
uint16_t udp_size = ntohs(*(uint16_t *)(start_of_udp + 4));
// The size inside the packet can't be trusted, if it is too big it can
// lead to heap overflows in the fuzzing code.
// Fixme : don't use udp_size inside the fuzzing code, maybe use the
// rec->incl_len and manually calculate the size.
if (udp_size > MaxSize || udp_size > rec->incl_len - 14 - ip_hl_in_bytes)
return 0;
// Copy interesting data to the `Data_to_mutate` array
// here we want to fuzz everything in the udp packet
memset(Data_to_mutate, 0, MaxSize);
memcpy(Data_to_mutate, start_of_udp, udp_size);
// Call to libfuzzer's mutation function.
// Pass the whole UDP packet, mutate it and then fix checksum value
// so the packet isn't rejected.
// The new size of the data is returned by LLVMFuzzerMutate.
// Fixme: allow to change the size of the UDP packet, this will require
// to fix the size before calculating the new checksum and change
// how the Data_ptr is advanced.
// Most offsets bellow should be good for when the switch will be
// done to avoid overwriting new/mutated data.
LLVMFuzzerMutate(Data_to_mutate, udp_header_size, udp_header_size);
// Drop checksum
*(uint16_t *)(Data_to_mutate + 6) = 0;
// Copy the mutated data back to the `Data` array
memcpy(start_of_udp, Data_to_mutate, udp_size);
mutated = true;
}
if (!mutated)
return 0;
return Size;
}
#endif // CUSTOM_MUTATOR

Binary file not shown.

View File

@ -0,0 +1,132 @@
//
// Created by nhp on 14-05-24.
//
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <stdio.h>
#include <stdarg.h>
#include "glib.h"
GString* g_string_new(gchar* initial) {
GString* str = g_new0(GString, 1);
if (initial != NULL) {
int len = strlen(initial);
gchar* p = malloc(len);
memcpy(p, initial, len);
str->str = p;
str->len = len;
str->allocated_len = len;
} else {
gchar* p = malloc(64);
str->str = p;
str->len = 0;
str->allocated_len = 64;
}
return str;
}
gchar* g_string_free(GString* str, gboolean free_segment) {
char* seg = str->str;
free(str);
if (free_segment) {
free(str->str);
return NULL;
}
return seg;
}
void g_string_append_printf(GString* str, const gchar* format, ...) {
va_list args;
va_start(args, format);
int need_len = vsnprintf(NULL, 0, format, args);
va_end(args);
if (str->len + need_len + 1 < str->allocated_len) {
gsize new_len = str->len + need_len + 1;
gchar* newp = realloc(str->str, new_len);
str->str = newp;
str->allocated_len = new_len;
str->len = new_len - 1;
}
gchar* temp = malloc(need_len + 1);
va_start(args, format);
vsnprintf(temp, need_len, format, args);
va_end(args);
strcat(str->str, temp);
free(temp);
}
gchar* g_strstr_len(const gchar* haystack, int len, const gchar* needle) {
if (len == -1) return strstr(haystack, needle);
size_t needle_len = strlen(needle);
for (int i = 0; i < len; i++) {
size_t found = 0;
for (int j = i; j < len; j++) {
if (haystack[j] == needle[j - i]) found++;
else break;
if (found == needle_len) return (gchar*) haystack + j;
}
}
return NULL;
}
gchar* g_strdup(const gchar* str) {
if (str == NULL) return NULL;
else return strdup(str);
}
int g_strv_length(GStrv strings) {
gint count = 0;
while (count++) {
if (strings[count] == NULL) break;
}
return count;
}
void g_strfreev(GStrv strings) {
for (int i = 0; strings[i] != NULL; i++) {
free(strings[i]);
}
}
// This is not good but all we're using slirp for is beaming pokemans over the internet so it's probably okay
gint g_rand_int_range(GRand* grand, gint min, gint max) {
double r = (double) rand();
double range = (double) (max - min);
double r2 = (r / (double) RAND_MAX) * range;
return MIN(max, ((int) r2) + min);
}
GRand* g_rand_new() {
return malloc(sizeof(GRand));
}
void g_rand_free(GRand* rand) {
free(rand);
}
void g_error_free(GError* error) {
free(error);
}
gboolean g_shell_parse_argv(const gchar* command_line, gint* argcp, gchar*** argvp, GError** error) {
const gchar* message = "Unimplemented.";
GError* err = malloc(sizeof(GError));
err->message = message;
*error = err;
}
gboolean g_spawn_async_with_fds(const gchar *working_directory, gchar **argv,
gchar **envp, GSpawnFlags flags,
GSpawnChildSetupFunc child_setup,
gpointer user_data, GPid *child_pid, gint stdin_fd,
gint stdout_fd, gint stderr_fd, GError **error)
{
return false;
}

View File

@ -0,0 +1,127 @@
#ifndef GLIB_SHIM_H
#define GLIB_SHIM_H
#include <stdint.h>
#include <stdbool.h>
#include <signal.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <stddef.h>
#define G_LITTLE_ENDIAN 0
#define G_BIG_ENDIAN 1
#define G_BYTE_ORDER G_LITTLE_ENDIAN
#define GUINT16_FROM_BE(n) ntohs(n)
#define GUINT16_TO_BE(n) htons(n)
#define GUINT32_FROM_BE(n) ntohl(n)
#define GUINT32_TO_BE(n) htonl(n)
#define GINT16_TO_BE(n) (int16_t) htons(n)
#define GINT16_FROM_BE(n) (int16_t) ntohs(n)
#define GINT32_TO_BE(n) (int32_t) htonl(n)
#define GINT32_FROM_BE(n) (int32_t) ntohl(n)
#define G_N_ELEMENTS(arr) (sizeof(arr) / sizeof(arr[0]))
#define G_GNUC_PRINTF(x, y)
#define GLIB_CHECK_VERSION(x, y, z) 1
#define G_STATIC_ASSERT(...)
#define g_assert assert
#define G_UNLIKELY
#define G_LIKELY
#define g_assert_not_reached() {}
#define g_warn_if_reached() {}
#define g_warn_if_fail(cond) {}
#define g_return_val_if_fail(cond, val) if (!(cond)) return (val)
#define g_return_if_fail(cond) if (!(cond)) return;
#define GLIB_SIZEOF_VOID_P 8
#define MAX(a, b) (a > b ? a : b)
#define MIN(a, b) (a < b ? a : b)
#define TRUE true
#define FALSE false
typedef bool gboolean;
typedef char gchar;
typedef int gint;
typedef size_t gsize;
typedef void* gpointer;
#define g_debug printf
#define g_warning printf
#define g_error printf
#define g_critical printf
#define g_new(type, count) (type*) malloc(sizeof(type) * count)
#define g_new0(type, count) (type*) calloc(count, sizeof(type))
#define g_malloc malloc
#define g_malloc0(size) calloc(1, size)
#define g_realloc realloc
#define g_free free
#define g_getenv(var) getenv(var)
typedef struct GString {
gchar* str;
gsize len;
gsize allocated_len;
} GString;
typedef gchar** GStrv;
GString* g_string_new(gchar* initial);
gchar* g_string_free(GString* string, gboolean free_segment);
void g_string_append_printf(GString* gstr, const gchar* format, ...);
gchar* g_strstr_len(const gchar* haystack, int len, const gchar* needle);
gchar* g_strdup(const gchar* str);
#ifdef _MSC_VER
#define g_ascii_strcasecmp(a, b) stricmp(a, b)
#else
#define g_ascii_strcasecmp(a, b) strcasecmp(a, b)
#endif
#define g_str_has_prefix(str, pfx) (strncmp(str, pfx, strlen(pfx)) == 0)
#define g_snprintf snprintf
#define g_vsnprintf vsnprintf
gint g_strv_length(GStrv strings);
void g_strfreev(GStrv strings);
typedef struct GRand {} GRand;
gint g_rand_int_range(GRand* grand, gint min, gint max);
GRand* g_rand_new();
void g_rand_free(GRand* rand);
typedef struct GError {
const gchar* message;
} GError;
void g_error_free(GError* error);
#define g_strerror(err) strerror(err)
typedef void (*GSpawnChildSetupFunc)(gpointer ptr);
typedef enum GSpawnFlags {
G_SPAWN_SEARCH_PATH
} GSpawnFlags;
typedef gint GPid;
gboolean g_shell_parse_argv(const gchar* command_line, gint* argcp, gchar*** argvp, GError** error);
gboolean g_spawn_async_with_fds(const gchar *working_directory, gchar **argv,
gchar **envp, GSpawnFlags flags,
GSpawnChildSetupFunc child_setup,
gpointer user_data, GPid *child_pid, gint stdin_fd,
gint stdout_fd, gint stderr_fd, GError **error);
typedef struct { gchar* key; int value } GDebugKey;
#define g_parse_debug_string(str, keys, nkeys) 0
#endif

View File

@ -0,0 +1,248 @@
project('libslirp', 'c',
version : '4.8.0',
license : 'BSD-3-Clause',
default_options : ['warning_level=1', 'c_std=gnu99'],
meson_version : '>= 0.50',
)
version = meson.project_version()
varr = version.split('.')
major_version = varr[0]
minor_version = varr[1]
micro_version = varr[2]
conf = configuration_data()
conf.set('SLIRP_MAJOR_VERSION', major_version)
conf.set('SLIRP_MINOR_VERSION', minor_version)
conf.set('SLIRP_MICRO_VERSION', micro_version)
want_ossfuzz = get_option('oss-fuzz')
want_libfuzzer = get_option('llvm-fuzz')
fuzz_reproduce = get_option('fuzz-reproduce')
if want_ossfuzz and want_libfuzzer
error('only one of oss-fuzz and llvm-fuzz can be specified')
endif
fuzzer_build = want_ossfuzz or want_libfuzzer
if fuzzer_build and fuzz_reproduce
error('fuzzer build and reproducer build are mutually exclusive')
endif
cc = meson.get_compiler('c')
add_languages('cpp', required : fuzzer_build)
if get_option('static') == true
add_global_arguments('-static', language : 'c')
endif
if cc.get_argument_syntax() != 'msvc'
r = run_command('build-aux/git-version-gen',
'@0@/.tarball-version'.format(meson.current_source_dir()),
check : false)
full_version = r.stdout().strip()
if r.returncode() != 0 or full_version.startswith('UNKNOWN')
full_version = meson.project_version()
elif not full_version.startswith(meson.project_version())
error('meson.build project version @0@ does not match git-describe output @1@'
.format(meson.project_version(), full_version))
endif
else
full_version = meson.project_version()
endif
conf.set_quoted('SLIRP_VERSION_STRING', full_version + get_option('version_suffix'))
# libtool versioning - this applies to libslirp
#
# See http://sources.redhat.com/autobook/autobook/autobook_91.html#SEC91 for details
#
# - If interfaces have been changed or added, but binary compatibility
# has been preserved, change:
# CURRENT += 1
# REVISION = 0
# AGE += 1
# - If binary compatibility has been broken (eg removed or changed
# interfaces), change:
# CURRENT += 1
# REVISION = 0
# AGE = 0
# - If the interface is the same as the previous version, but bugs are
# fixed, change:
# REVISION += 1
lt_current = 4
lt_revision = 0
lt_age = 4
lt_version = '@0@.@1@.@2@'.format(lt_current - lt_age, lt_age, lt_revision)
host_system = host_machine.system()
#glib_dep = dependency('glib-2.0', static : get_option('static'))
glib_dep = declare_dependency(
include_directories: [include_directories('glib', is_system: true)],
sources: ['glib/glib.c']
)
add_project_arguments(cc.get_supported_arguments('-Wmissing-prototypes', '-Wstrict-prototypes',
'-Wredundant-decls', '-Wundef', '-Wwrite-strings'),
language: 'c', native: false)
platform_deps = []
if host_system == 'windows'
platform_deps += [
cc.find_library('ws2_32'),
cc.find_library('iphlpapi')
]
elif host_system == 'darwin'
platform_deps += [
cc.find_library('resolv')
]
elif host_system == 'haiku'
platform_deps += [
cc.find_library('network')
]
endif
cargs = [
'-DG_LOG_DOMAIN="Slirp"',
'-DBUILDING_LIBSLIRP',
]
if cc.check_header('valgrind/valgrind.h')
cargs += [ '-DHAVE_VALGRIND=1' ]
endif
sources = [
'src/arp_table.c',
'src/bootp.c',
'src/cksum.c',
'src/dhcpv6.c',
'src/dnssearch.c',
'src/if.c',
'src/ip6_icmp.c',
'src/ip6_input.c',
'src/ip6_output.c',
'src/ip_icmp.c',
'src/ip_input.c',
'src/ip_output.c',
'src/mbuf.c',
'src/misc.c',
'src/ncsi.c',
'src/ndp_table.c',
'src/sbuf.c',
'src/slirp.c',
'src/socket.c',
'src/state.c',
'src/stream.c',
'src/tcp_input.c',
'src/tcp_output.c',
'src/tcp_subr.c',
'src/tcp_timer.c',
'src/tftp.c',
'src/udp.c',
'src/udp6.c',
'src/util.c',
'src/version.c',
'src/vmstate.c',
]
mapfile = 'src/libslirp.map'
vflag = []
vflag_test = '-Wl,--version-script,@0@/@1@'.format(meson.current_source_dir(), mapfile)
if cc.has_link_argument('-Wl,--version-script,@0@/@1@'.format(meson.current_source_dir(), 'src/libslirp.test.map'))
vflag += vflag_test
endif
if fuzzer_build
cargs += '-fsanitize-coverage=edge,indirect-calls,trace-cmp'
cargs += '-fsanitize=fuzzer-no-link,address'
cargs += '-fprofile-instr-generate'
cargs += '-fcoverage-mapping'
cargs += '-g'
cargs += '-DSLIRP_DEBUG'
vflag += '-fsanitize=fuzzer-no-link,address'
vflag += '-fsanitize-coverage=edge,indirect-calls,trace-cmp'
vflag += '-fprofile-instr-generate'
vflag += '-fcoverage-mapping'
endif
if fuzz_reproduce
cargs += '-DSLIRP_DEBUG'
cargs += '-g'
endif
install_devel = not meson.is_subproject()
configure_file(
input : 'src/libslirp-version.h.in',
output : 'libslirp-version.h',
install : install_devel,
install_dir : join_paths(get_option('includedir'), 'slirp'),
configuration : conf
)
if fuzzer_build or fuzz_reproduce
lib = static_library('slirp', sources,
c_args : cargs,
link_args : vflag,
link_depends : mapfile,
dependencies : [glib_dep, platform_deps],
)
else
lib = library('slirp', sources,
version : lt_version,
c_args : cargs,
link_args : vflag,
link_depends : mapfile,
dependencies : [glib_dep, platform_deps],
install : install_devel or get_option('default_library') == 'shared',
)
endif
pingtest = executable('pingtest', 'test/pingtest.c',
link_with: [ lib ],
c_args : cargs,
link_args : vflag,
include_directories: [ 'src' ],
dependencies : [ platform_deps ]
)
test('ping', pingtest)
ncsitest = executable('ncsitest', 'test/ncsitest.c',
link_with: [lib],
c_args : cargs,
link_args : vflag,
include_directories: ['src'],
dependencies: [glib_dep, platform_deps]
)
test('ncsi', ncsitest)
if install_devel
install_headers(['src/libslirp.h'], subdir : 'slirp')
pkg = import('pkgconfig')
pkg.generate(
version : version,
libraries : lib,
requires : [
'glib-2.0',
],
name : 'slirp',
description : 'User-space network stack',
filebase : 'slirp',
subdirs : 'slirp',
)
else
if get_option('default_library') == 'both'
lib = lib.get_static_lib()
endif
endif
libslirp_dep = declare_dependency(
link_with : lib,
include_directories : [include_directories('src'), include_directories('.')],
)
subdir('fuzzing')

View File

@ -0,0 +1,14 @@
option('version_suffix', type: 'string', value: '',
description: 'Suffix to append to SLIRP_VERSION_STRING')
option('oss-fuzz', type : 'boolean', value : 'false',
description : 'build against oss-fuzz')
option('llvm-fuzz', type : 'boolean', value : 'false',
description : 'build against LLVM libFuzzer')
option('fuzz-reproduce', type : 'boolean', value : 'false',
description : 'build a standalone executable to reproduce fuzz cases')
option('static', type : 'boolean', value : 'false',
description : 'build static binary, only for debugging, otherwise rather use --default-library static')

View File

@ -0,0 +1,98 @@
/* SPDX-License-Identifier: MIT */
/*
* ARP table
*
* Copyright (c) 2011 AdaCore
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "slirp.h"
#include <string.h>
void arp_table_add(Slirp *slirp, uint32_t ip_addr,
const uint8_t ethaddr[ETH_ALEN])
{
const uint32_t broadcast_addr =
~slirp->vnetwork_mask.s_addr | slirp->vnetwork_addr.s_addr;
ArpTable *arptbl = &slirp->arp_table;
int i;
char ethaddr_str[ETH_ADDRSTRLEN];
char addr[INET_ADDRSTRLEN];
DEBUG_CALL("arp_table_add");
DEBUG_ARG("ip = %s", inet_ntop(AF_INET, &(struct in_addr){ .s_addr = ip_addr },
addr, sizeof(addr)));
DEBUG_ARG("hw addr = %s", slirp_ether_ntoa(ethaddr, ethaddr_str,
sizeof(ethaddr_str)));
if (ip_addr == 0 || ip_addr == 0xffffffff || ip_addr == broadcast_addr) {
/* Do not register broadcast addresses */
return;
}
/* Search for an entry */
for (i = 0; i < ARP_TABLE_SIZE; i++) {
if (arptbl->table[i].ar_sip == ip_addr) {
/* Update the entry */
memcpy(arptbl->table[i].ar_sha, ethaddr, ETH_ALEN);
return;
}
}
/* No entry found, create a new one */
arptbl->table[arptbl->next_victim].ar_sip = ip_addr;
memcpy(arptbl->table[arptbl->next_victim].ar_sha, ethaddr, ETH_ALEN);
arptbl->next_victim = (arptbl->next_victim + 1) % ARP_TABLE_SIZE;
}
bool arp_table_search(Slirp *slirp, uint32_t ip_addr,
uint8_t out_ethaddr[ETH_ALEN])
{
const uint32_t broadcast_addr =
~slirp->vnetwork_mask.s_addr | slirp->vnetwork_addr.s_addr;
ArpTable *arptbl = &slirp->arp_table;
int i;
char ethaddr_str[ETH_ADDRSTRLEN];
char addr[INET_ADDRSTRLEN];
DEBUG_CALL("arp_table_search");
DEBUG_ARG("ip = %s", inet_ntop(AF_INET, &(struct in_addr){ .s_addr = ip_addr },
addr, sizeof(addr)));
/* If broadcast address */
if (ip_addr == 0 || ip_addr == 0xffffffff || ip_addr == broadcast_addr) {
/* return Ethernet broadcast address */
memset(out_ethaddr, 0xff, ETH_ALEN);
return 1;
}
for (i = 0; i < ARP_TABLE_SIZE; i++) {
if (arptbl->table[i].ar_sip == ip_addr) {
memcpy(out_ethaddr, arptbl->table[i].ar_sha, ETH_ALEN);
DEBUG_ARG("found hw addr = %s",
slirp_ether_ntoa(out_ethaddr, ethaddr_str,
sizeof(ethaddr_str)));
return 1;
}
}
return 0;
}

View File

@ -0,0 +1,398 @@
/* SPDX-License-Identifier: MIT */
/*
* QEMU BOOTP/DHCP server
*
* Copyright (c) 2004 Fabrice Bellard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "slirp.h"
#if defined(_WIN32)
/* Windows ntohl() returns an u_long value.
* Add a type cast to match the format strings. */
#define ntohl(n) ((uint32_t)ntohl(n))
#endif
/* XXX: only DHCP is supported */
#define LEASE_TIME (24 * 3600)
#define UEFI_HTTP_VENDOR_CLASS_ID "HTTPClient"
static const uint8_t rfc1533_cookie[] = { RFC1533_COOKIE };
#define DPRINTF(...) DEBUG_RAW_CALL(__VA_ARGS__)
static BOOTPClient *get_new_addr(Slirp *slirp, struct in_addr *paddr,
const uint8_t *macaddr)
{
BOOTPClient *bc;
int i;
for (i = 0; i < NB_BOOTP_CLIENTS; i++) {
bc = &slirp->bootp_clients[i];
if (!bc->allocated || !memcmp(macaddr, bc->macaddr, 6))
goto found;
}
return NULL;
found:
bc = &slirp->bootp_clients[i];
bc->allocated = 1;
paddr->s_addr = slirp->vdhcp_startaddr.s_addr + htonl(i);
return bc;
}
static BOOTPClient *request_addr(Slirp *slirp, const struct in_addr *paddr,
const uint8_t *macaddr)
{
uint32_t req_addr = ntohl(paddr->s_addr);
uint32_t dhcp_addr = ntohl(slirp->vdhcp_startaddr.s_addr);
BOOTPClient *bc;
if (req_addr >= dhcp_addr && req_addr < (dhcp_addr + NB_BOOTP_CLIENTS)) {
bc = &slirp->bootp_clients[req_addr - dhcp_addr];
if (!bc->allocated || !memcmp(macaddr, bc->macaddr, 6)) {
bc->allocated = 1;
return bc;
}
}
return NULL;
}
static BOOTPClient *find_addr(Slirp *slirp, struct in_addr *paddr,
const uint8_t *macaddr)
{
BOOTPClient *bc;
int i;
for (i = 0; i < NB_BOOTP_CLIENTS; i++) {
if (!memcmp(macaddr, slirp->bootp_clients[i].macaddr, 6))
goto found;
}
return NULL;
found:
bc = &slirp->bootp_clients[i];
bc->allocated = 1;
paddr->s_addr = slirp->vdhcp_startaddr.s_addr + htonl(i);
return bc;
}
static void dhcp_decode(const struct bootp_t *bp,
const uint8_t *bp_end,
int *pmsg_type,
struct in_addr *preq_addr)
{
const uint8_t *p;
int len, tag;
*pmsg_type = 0;
preq_addr->s_addr = htonl(0L);
p = bp->bp_vend;
if (memcmp(p, rfc1533_cookie, 4) != 0)
return;
p += 4;
while (p < bp_end) {
tag = p[0];
if (tag == RFC1533_PAD) {
p++;
} else if (tag == RFC1533_END) {
break;
} else {
p++;
if (p >= bp_end)
break;
len = *p++;
if (p + len > bp_end) {
break;
}
DPRINTF("dhcp: tag=%d len=%d\n", tag, len);
switch (tag) {
case RFC2132_MSG_TYPE:
if (len >= 1)
*pmsg_type = p[0];
break;
case RFC2132_REQ_ADDR:
if (len >= 4) {
memcpy(&(preq_addr->s_addr), p, 4);
}
break;
default:
break;
}
p += len;
}
}
if (*pmsg_type == DHCPREQUEST && preq_addr->s_addr == htonl(0L) &&
bp->bp_ciaddr.s_addr) {
memcpy(&(preq_addr->s_addr), &bp->bp_ciaddr, 4);
}
}
static void bootp_reply(Slirp *slirp,
const struct bootp_t *bp,
const uint8_t *bp_end)
{
BOOTPClient *bc = NULL;
struct mbuf *m;
struct bootp_t *rbp;
struct sockaddr_in saddr, daddr;
struct in_addr preq_addr;
int dhcp_msg_type, val;
uint8_t *q;
uint8_t *end;
uint8_t client_ethaddr[ETH_ALEN];
/* extract exact DHCP msg type */
dhcp_decode(bp, bp_end, &dhcp_msg_type, &preq_addr);
DPRINTF("bootp packet op=%d msgtype=%d", bp->bp_op, dhcp_msg_type);
if (preq_addr.s_addr != htonl(0L))
DPRINTF(" req_addr=%08" PRIx32 "\n", ntohl(preq_addr.s_addr));
else {
DPRINTF("\n");
}
if (dhcp_msg_type == 0)
dhcp_msg_type = DHCPREQUEST; /* Force reply for old BOOTP clients */
if (dhcp_msg_type != DHCPDISCOVER && dhcp_msg_type != DHCPREQUEST)
return;
/* Get client's hardware address from bootp request */
memcpy(client_ethaddr, bp->bp_hwaddr, ETH_ALEN);
m = m_get(slirp);
if (!m) {
return;
}
m->m_data += IF_MAXLINKHDR;
m_inc(m, sizeof(struct bootp_t) + DHCP_OPT_LEN);
rbp = (struct bootp_t *)m->m_data;
m->m_data += sizeof(struct udpiphdr);
memset(rbp, 0, sizeof(struct bootp_t) + DHCP_OPT_LEN);
if (dhcp_msg_type == DHCPDISCOVER) {
if (preq_addr.s_addr != htonl(0L)) {
bc = request_addr(slirp, &preq_addr, client_ethaddr);
if (bc) {
daddr.sin_addr = preq_addr;
}
}
if (!bc) {
new_addr:
bc = get_new_addr(slirp, &daddr.sin_addr, client_ethaddr);
if (!bc) {
DPRINTF("no address left\n");
return;
}
}
memcpy(bc->macaddr, client_ethaddr, ETH_ALEN);
} else if (preq_addr.s_addr != htonl(0L)) {
bc = request_addr(slirp, &preq_addr, client_ethaddr);
if (bc) {
daddr.sin_addr = preq_addr;
memcpy(bc->macaddr, client_ethaddr, ETH_ALEN);
} else {
/* DHCPNAKs should be sent to broadcast */
daddr.sin_addr.s_addr = 0xffffffff;
}
} else {
bc = find_addr(slirp, &daddr.sin_addr, bp->bp_hwaddr);
if (!bc) {
/* if never assigned, behaves as if it was already
assigned (windows fix because it remembers its address) */
goto new_addr;
}
}
/* Update ARP table for this IP address */
arp_table_add(slirp, daddr.sin_addr.s_addr, client_ethaddr);
saddr.sin_addr = slirp->vhost_addr;
saddr.sin_port = htons(BOOTP_SERVER);
daddr.sin_port = htons(BOOTP_CLIENT);
rbp->bp_op = BOOTP_REPLY;
rbp->bp_xid = bp->bp_xid;
rbp->bp_htype = 1;
rbp->bp_hlen = 6;
memcpy(rbp->bp_hwaddr, bp->bp_hwaddr, ETH_ALEN);
rbp->bp_yiaddr = daddr.sin_addr; /* Client IP address */
rbp->bp_siaddr = saddr.sin_addr; /* Server IP address */
q = rbp->bp_vend;
end = rbp->bp_vend + DHCP_OPT_LEN;
memcpy(q, rfc1533_cookie, 4);
q += 4;
if (bc) {
DPRINTF("%s addr=%08" PRIx32 "\n",
(dhcp_msg_type == DHCPDISCOVER) ? "offered" : "ack'ed",
ntohl(daddr.sin_addr.s_addr));
if (dhcp_msg_type == DHCPDISCOVER) {
*q++ = RFC2132_MSG_TYPE;
*q++ = 1;
*q++ = DHCPOFFER;
} else /* DHCPREQUEST */ {
*q++ = RFC2132_MSG_TYPE;
*q++ = 1;
*q++ = DHCPACK;
}
if (slirp->bootp_filename) {
g_assert(strlen(slirp->bootp_filename) < sizeof(rbp->bp_file));
strcpy(rbp->bp_file, slirp->bootp_filename);
}
*q++ = RFC2132_SRV_ID;
*q++ = 4;
memcpy(q, &saddr.sin_addr, 4);
q += 4;
*q++ = RFC1533_NETMASK;
*q++ = 4;
memcpy(q, &slirp->vnetwork_mask, 4);
q += 4;
if (!slirp->restricted) {
*q++ = RFC1533_GATEWAY;
*q++ = 4;
memcpy(q, &saddr.sin_addr, 4);
q += 4;
*q++ = RFC1533_DNS;
*q++ = 4;
memcpy(q, &slirp->vnameserver_addr, 4);
q += 4;
}
*q++ = RFC2132_LEASE_TIME;
*q++ = 4;
val = htonl(LEASE_TIME);
memcpy(q, &val, 4);
q += 4;
if (*slirp->client_hostname) {
val = strlen(slirp->client_hostname);
if (q + val + 2 >= end) {
g_warning("DHCP packet size exceeded, "
"omitting host name option.");
} else {
*q++ = RFC1533_HOSTNAME;
*q++ = val;
memcpy(q, slirp->client_hostname, val);
q += val;
}
}
if (slirp->vdomainname) {
val = strlen(slirp->vdomainname);
if (q + val + 2 >= end) {
g_warning("DHCP packet size exceeded, "
"omitting domain name option.");
} else {
*q++ = RFC1533_DOMAINNAME;
*q++ = val;
memcpy(q, slirp->vdomainname, val);
q += val;
}
}
if (slirp->tftp_server_name) {
val = strlen(slirp->tftp_server_name);
if (q + val + 2 >= end) {
g_warning("DHCP packet size exceeded, "
"omitting tftp-server-name option.");
} else {
*q++ = RFC2132_TFTP_SERVER_NAME;
*q++ = val;
memcpy(q, slirp->tftp_server_name, val);
q += val;
}
}
if (slirp->vdnssearch) {
val = slirp->vdnssearch_len;
if (q + val >= end) {
g_warning("DHCP packet size exceeded, "
"omitting domain-search option.");
} else {
memcpy(q, slirp->vdnssearch, val);
q += val;
}
}
/* this allows to support UEFI HTTP boot: according to the UEFI
specification, DHCP server must send vendor class identifier option
set to "HTTPClient" string, when responding to DHCP requests as part
of the UEFI HTTP boot
we assume that, if the bootfile parameter was configured as an http
URL, the user intends to perform UEFI HTTP boot, so send this option
automatically */
if (slirp->bootp_filename && g_str_has_prefix(slirp->bootp_filename, "http://")) {
val = strlen(UEFI_HTTP_VENDOR_CLASS_ID);
if (q + val + 2 >= end) {
g_warning("DHCP packet size exceeded, "
"omitting vendor class id option.");
} else {
*q++ = RFC2132_VENDOR_CLASS_ID;
*q++ = val;
memcpy(q, UEFI_HTTP_VENDOR_CLASS_ID, val);
q += val;
}
}
} else {
static const char nak_msg[] = "requested address not available";
DPRINTF("nak'ed addr=%08" PRIx32 "\n", ntohl(preq_addr.s_addr));
*q++ = RFC2132_MSG_TYPE;
*q++ = 1;
*q++ = DHCPNAK;
*q++ = RFC2132_MESSAGE;
*q++ = sizeof(nak_msg) - 1;
memcpy(q, nak_msg, sizeof(nak_msg) - 1);
q += sizeof(nak_msg) - 1;
}
assert(q < end);
*q++ = RFC1533_END;
daddr.sin_addr.s_addr = 0xffffffffu;
assert(q <= end);
m->m_len = sizeof(struct bootp_t) + (end - rbp->bp_vend) - sizeof(struct ip) - sizeof(struct udphdr);
udp_output(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
}
void bootp_input(struct mbuf *m)
{
struct bootp_t *bp = mtod_check(m, sizeof(struct bootp_t));
if (!m->slirp->disable_dhcp && bp && bp->bp_op == BOOTP_REQUEST) {
bootp_reply(m->slirp, bp, m_end(m));
}
}

View File

@ -0,0 +1,131 @@
/* SPDX-License-Identifier: BSD-3-Clause */
/* bootp/dhcp defines */
#ifndef SLIRP_BOOTP_H
#define SLIRP_BOOTP_H
#define BOOTP_SERVER 67
#define BOOTP_CLIENT 68
#define BOOTP_REQUEST 1
#define BOOTP_REPLY 2
#define RFC1533_COOKIE 99, 130, 83, 99
#define RFC1533_PAD 0
#define RFC1533_NETMASK 1
#define RFC1533_TIMEOFFSET 2
#define RFC1533_GATEWAY 3
#define RFC1533_TIMESERVER 4
#define RFC1533_IEN116NS 5
#define RFC1533_DNS 6
#define RFC1533_LOGSERVER 7
#define RFC1533_COOKIESERVER 8
#define RFC1533_LPRSERVER 9
#define RFC1533_IMPRESSSERVER 10
#define RFC1533_RESOURCESERVER 11
#define RFC1533_HOSTNAME 12
#define RFC1533_BOOTFILESIZE 13
#define RFC1533_MERITDUMPFILE 14
#define RFC1533_DOMAINNAME 15
#define RFC1533_SWAPSERVER 16
#define RFC1533_ROOTPATH 17
#define RFC1533_EXTENSIONPATH 18
#define RFC1533_IPFORWARDING 19
#define RFC1533_IPSOURCEROUTING 20
#define RFC1533_IPPOLICYFILTER 21
#define RFC1533_IPMAXREASSEMBLY 22
#define RFC1533_IPTTL 23
#define RFC1533_IPMTU 24
#define RFC1533_IPMTUPLATEAU 25
#define RFC1533_INTMTU 26
#define RFC1533_INTLOCALSUBNETS 27
#define RFC1533_INTBROADCAST 28
#define RFC1533_INTICMPDISCOVER 29
#define RFC1533_INTICMPRESPOND 30
#define RFC1533_INTROUTEDISCOVER 31
#define RFC1533_INTROUTESOLICIT 32
#define RFC1533_INTSTATICROUTES 33
#define RFC1533_LLTRAILERENCAP 34
#define RFC1533_LLARPCACHETMO 35
#define RFC1533_LLETHERNETENCAP 36
#define RFC1533_TCPTTL 37
#define RFC1533_TCPKEEPALIVETMO 38
#define RFC1533_TCPKEEPALIVEGB 39
#define RFC1533_NISDOMAIN 40
#define RFC1533_NISSERVER 41
#define RFC1533_NTPSERVER 42
#define RFC1533_VENDOR 43
#define RFC1533_NBNS 44
#define RFC1533_NBDD 45
#define RFC1533_NBNT 46
#define RFC1533_NBSCOPE 47
#define RFC1533_XFS 48
#define RFC1533_XDM 49
#define RFC2132_REQ_ADDR 50
#define RFC2132_LEASE_TIME 51
#define RFC2132_MSG_TYPE 53
#define RFC2132_SRV_ID 54
#define RFC2132_PARAM_LIST 55
#define RFC2132_MESSAGE 56
#define RFC2132_MAX_SIZE 57
#define RFC2132_RENEWAL_TIME 58
#define RFC2132_REBIND_TIME 59
#define RFC2132_VENDOR_CLASS_ID 60
#define RFC2132_TFTP_SERVER_NAME 66
#define DHCPDISCOVER 1
#define DHCPOFFER 2
#define DHCPREQUEST 3
#define DHCPACK 5
#define DHCPNAK 6
#define RFC1533_VENDOR_MAJOR 0
#define RFC1533_VENDOR_MINOR 0
#define RFC1533_VENDOR_MAGIC 128
#define RFC1533_VENDOR_ADDPARM 129
#define RFC1533_VENDOR_ETHDEV 130
#define RFC1533_VENDOR_HOWTO 132
#define RFC1533_VENDOR_MNUOPTS 160
#define RFC1533_VENDOR_SELECTION 176
#define RFC1533_VENDOR_MOTD 184
#define RFC1533_VENDOR_NUMOFMOTD 8
#define RFC1533_VENDOR_IMG 192
#define RFC1533_VENDOR_NUMOFIMG 16
#define RFC1533_END 255
#define BOOTP_VENDOR_LEN 64
#define DHCP_OPT_LEN 312
struct bootp_t {
struct ip ip;
struct udphdr udp;
uint8_t bp_op;
uint8_t bp_htype;
uint8_t bp_hlen;
uint8_t bp_hops;
uint32_t bp_xid;
uint16_t bp_secs;
uint16_t unused;
struct in_addr bp_ciaddr;
struct in_addr bp_yiaddr;
struct in_addr bp_siaddr;
struct in_addr bp_giaddr;
uint8_t bp_hwaddr[16];
uint8_t bp_sname[64];
char bp_file[128];
uint8_t bp_vend[];
};
typedef struct {
uint16_t allocated;
uint8_t macaddr[6];
} BOOTPClient;
#define NB_BOOTP_CLIENTS 16
/* Process a bootp packet from the guest */
void bootp_input(struct mbuf *m);
#endif

View File

@ -0,0 +1,179 @@
/* SPDX-License-Identifier: BSD-3-Clause */
/*
* Copyright (c) 1988, 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)in_cksum.c 8.1 (Berkeley) 6/10/93
* in_cksum.c,v 1.2 1994/08/02 07:48:16 davidg Exp
*/
#include "slirp.h"
/*
* Checksum routine for Internet Protocol family headers (Portable Version).
*
* This routine is very heavily used in the network
* code and should be modified for each CPU to be as fast as possible.
*
* XXX Since we will never span more than 1 mbuf, we can optimise this
*/
#define ADDCARRY(x) (x > 65535 ? x -= 65535 : x)
#define REDUCE \
{ \
l_util.l = sum; \
sum = l_util.s[0] + l_util.s[1]; \
ADDCARRY(sum); \
}
int cksum(struct mbuf *m, int len)
{
register uint16_t *w;
register int sum = 0;
register int mlen = 0;
int byte_swapped = 0;
union {
uint8_t c[2];
uint16_t s;
} s_util;
union {
uint16_t s[2];
uint32_t l;
} l_util;
if (m->m_len == 0)
goto cont;
w = mtod(m, uint16_t *);
mlen = m->m_len;
if (len < mlen)
mlen = len;
len -= mlen;
/*
* Force to even boundary.
*/
if ((1 & (uintptr_t)w) && (mlen > 0)) {
REDUCE;
sum <<= 8;
s_util.c[0] = *(uint8_t *)w;
w = (uint16_t *)((int8_t *)w + 1);
mlen--;
byte_swapped = 1;
}
/*
* Unroll the loop to make overhead from
* branches &c small.
*/
while ((mlen -= 32) >= 0) {
sum += w[0];
sum += w[1];
sum += w[2];
sum += w[3];
sum += w[4];
sum += w[5];
sum += w[6];
sum += w[7];
sum += w[8];
sum += w[9];
sum += w[10];
sum += w[11];
sum += w[12];
sum += w[13];
sum += w[14];
sum += w[15];
w += 16;
}
mlen += 32;
while ((mlen -= 8) >= 0) {
sum += w[0];
sum += w[1];
sum += w[2];
sum += w[3];
w += 4;
}
mlen += 8;
if (mlen == 0 && byte_swapped == 0)
goto cont;
REDUCE;
while ((mlen -= 2) >= 0) {
sum += *w++;
}
if (byte_swapped) {
REDUCE;
sum <<= 8;
if (mlen == -1) {
s_util.c[1] = *(uint8_t *)w;
sum += s_util.s;
mlen = 0;
} else
mlen = -1;
} else if (mlen == -1)
s_util.c[0] = *(uint8_t *)w;
cont:
if (len) {
DEBUG_ERROR("cksum: out of data");
DEBUG_ERROR(" len = %d", len);
}
if (mlen == -1) {
/* The last mbuf has odd # of bytes. Follow the
standard (the odd byte may be shifted left by 8 bits
or not as determined by endian-ness of the machine) */
s_util.c[1] = 0;
sum += s_util.s;
}
REDUCE;
return (~sum & 0xffff);
}
int ip6_cksum(struct mbuf *m)
{
/* TODO: Optimize this by being able to pass the ip6_pseudohdr to cksum
* separately from the mbuf */
struct ip6 save_ip, *ip = mtod(m, struct ip6 *);
struct ip6_pseudohdr *ih = mtod(m, struct ip6_pseudohdr *);
int sum;
save_ip = *ip;
ih->ih_src = save_ip.ip_src;
ih->ih_dst = save_ip.ip_dst;
ih->ih_pl = htonl((uint32_t)ntohs(save_ip.ip_pl));
ih->ih_zero_hi = 0;
ih->ih_zero_lo = 0;
ih->ih_nh = save_ip.ip_nh;
sum = cksum(m, ((int)sizeof(struct ip6_pseudohdr)) + ntohl(ih->ih_pl));
*ip = save_ip;
return sum;
}

View File

@ -0,0 +1,66 @@
/* SPDX-License-Identifier: BSD-3-Clause */
/*
* Copyright (c) 1995 Danny Gasparovski.
*/
#ifndef DEBUG_H_
#define DEBUG_H_
#define DBG_CALL (1 << 0)
#define DBG_MISC (1 << 1)
#define DBG_ERROR (1 << 2)
#define DBG_TFTP (1 << 3)
#define DBG_VERBOSE_CALL (1 << 4)
extern int slirp_debug;
#define DEBUG_CALL(name) \
do { \
if (G_UNLIKELY(slirp_debug & DBG_CALL)) { \
g_debug(name "..."); \
} \
} while (0)
#define DEBUG_VERBOSE_CALL(name) \
do { \
if (G_UNLIKELY(slirp_debug & DBG_VERBOSE_CALL)) { \
g_debug(name "..."); \
} \
} while (0)
#define DEBUG_RAW_CALL(...) \
do { \
if (G_UNLIKELY(slirp_debug & DBG_CALL)) { \
g_debug(__VA_ARGS__); \
} \
} while (0)
#define DEBUG_ARG(...) \
do { \
if (G_UNLIKELY(slirp_debug & DBG_CALL)) { \
g_debug(" " __VA_ARGS__); \
} \
} while (0)
#define DEBUG_MISC(...) \
do { \
if (G_UNLIKELY(slirp_debug & DBG_MISC)) { \
g_debug(__VA_ARGS__); \
} \
} while (0)
#define DEBUG_ERROR(...) \
do { \
if (G_UNLIKELY(slirp_debug & DBG_ERROR)) { \
g_debug(__VA_ARGS__); \
} \
} while (0)
#define DEBUG_TFTP(...) \
do { \
if (G_UNLIKELY(slirp_debug & DBG_TFTP)) { \
g_debug(__VA_ARGS__); \
} \
} while (0)
#endif /* DEBUG_H_ */

View File

@ -0,0 +1,224 @@
/* SPDX-License-Identifier: BSD-3-Clause */
/*
* SLIRP stateless DHCPv6
*
* We only support stateless DHCPv6, e.g. for network booting.
* See RFC 3315, RFC 3736, RFC 3646 and RFC 5970 for details.
*
* Copyright 2016 Thomas Huth, Red Hat Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "slirp.h"
#include "dhcpv6.h"
/* DHCPv6 message types */
#define MSGTYPE_REPLY 7
#define MSGTYPE_INFO_REQUEST 11
/* DHCPv6 option types */
#define OPTION_CLIENTID 1
#define OPTION_IAADDR 5
#define OPTION_ORO 6
#define OPTION_DNS_SERVERS 23
#define OPTION_BOOTFILE_URL 59
struct requested_infos {
uint8_t *client_id;
int client_id_len;
bool want_dns;
bool want_boot_url;
};
/**
* Analyze the info request message sent by the client to see what data it
* provided and what it wants to have. The information is gathered in the
* "requested_infos" struct. Note that client_id (if provided) points into
* the odata region, thus the caller must keep odata valid as long as it
* needs to access the requested_infos struct.
*/
static int dhcpv6_parse_info_request(Slirp *slirp, uint8_t *odata, int olen,
struct requested_infos *ri)
{
int i, req_opt;
while (olen > 4) {
/* Parse one option */
int option = odata[0] << 8 | odata[1];
int len = odata[2] << 8 | odata[3];
if (len + 4 > olen) {
slirp->cb->guest_error("Guest sent bad DHCPv6 packet!",
slirp->opaque);
return -E2BIG;
}
switch (option) {
case OPTION_IAADDR:
/* According to RFC3315, we must discard requests with IA option */
return -EINVAL;
case OPTION_CLIENTID:
if (len > 256) {
/* Avoid very long IDs which could cause problems later */
return -E2BIG;
}
ri->client_id = odata + 4;
ri->client_id_len = len;
break;
case OPTION_ORO: /* Option request option */
if (len & 1) {
return -EINVAL;
}
/* Check which options the client wants to have */
for (i = 0; i < len; i += 2) {
req_opt = odata[4 + i] << 8 | odata[4 + i + 1];
switch (req_opt) {
case OPTION_DNS_SERVERS:
ri->want_dns = true;
break;
case OPTION_BOOTFILE_URL:
ri->want_boot_url = true;
break;
default:
DEBUG_MISC("dhcpv6: Unsupported option request %d",
req_opt);
}
}
break;
default:
DEBUG_MISC("dhcpv6 info req: Unsupported option %d, len=%d", option,
len);
}
odata += len + 4;
olen -= len + 4;
}
return 0;
}
/**
* Handle information request messages
*/
static void dhcpv6_info_request(Slirp *slirp, struct sockaddr_in6 *srcsas,
uint32_t xid, uint8_t *odata, int olen)
{
struct requested_infos ri = { NULL };
struct sockaddr_in6 sa6, da6;
struct mbuf *m;
uint8_t *resp;
if (dhcpv6_parse_info_request(slirp, odata, olen, &ri) < 0) {
return;
}
m = m_get(slirp);
if (!m) {
return;
}
memset(m->m_data, 0, m->m_size);
m->m_data += IF_MAXLINKHDR;
resp = (uint8_t *)m->m_data + sizeof(struct ip6) + sizeof(struct udphdr);
/* Fill in response */
*resp++ = MSGTYPE_REPLY;
*resp++ = (uint8_t)(xid >> 16);
*resp++ = (uint8_t)(xid >> 8);
*resp++ = (uint8_t)xid;
if (ri.client_id) {
*resp++ = OPTION_CLIENTID >> 8; /* option-code high byte */
*resp++ = OPTION_CLIENTID; /* option-code low byte */
*resp++ = ri.client_id_len >> 8; /* option-len high byte */
*resp++ = ri.client_id_len; /* option-len low byte */
memcpy(resp, ri.client_id, ri.client_id_len);
resp += ri.client_id_len;
}
if (ri.want_dns) {
*resp++ = OPTION_DNS_SERVERS >> 8; /* option-code high byte */
*resp++ = OPTION_DNS_SERVERS; /* option-code low byte */
*resp++ = 0; /* option-len high byte */
*resp++ = 16; /* option-len low byte */
memcpy(resp, &slirp->vnameserver_addr6, 16);
resp += 16;
}
if (ri.want_boot_url) {
uint8_t *sa = slirp->vhost_addr6.s6_addr;
int slen, smaxlen;
*resp++ = OPTION_BOOTFILE_URL >> 8; /* option-code high byte */
*resp++ = OPTION_BOOTFILE_URL; /* option-code low byte */
smaxlen = (uint8_t *)m->m_data + slirp->if_mtu - (resp + 2);
slen = slirp_fmt((char *)resp + 2, smaxlen,
"tftp://[%02x%02x:%02x%02x:%02x%02x:%02x%02x:"
"%02x%02x:%02x%02x:%02x%02x:%02x%02x]/%s",
sa[0], sa[1], sa[2], sa[3], sa[4], sa[5], sa[6], sa[7],
sa[8], sa[9], sa[10], sa[11], sa[12], sa[13], sa[14],
sa[15], slirp->bootp_filename);
*resp++ = slen >> 8; /* option-len high byte */
*resp++ = slen; /* option-len low byte */
resp += slen;
}
sa6.sin6_addr = slirp->vhost_addr6;
sa6.sin6_port = DHCPV6_SERVER_PORT;
da6.sin6_addr = srcsas->sin6_addr;
da6.sin6_port = srcsas->sin6_port;
m->m_data += sizeof(struct ip6) + sizeof(struct udphdr);
m->m_len = resp - (uint8_t *)m->m_data;
udp6_output(NULL, m, &sa6, &da6);
}
/**
* Handle DHCPv6 messages sent by the client
*/
void dhcpv6_input(struct sockaddr_in6 *srcsas, struct mbuf *m)
{
uint8_t *data = (uint8_t *)m->m_data + sizeof(struct udphdr);
int data_len = m->m_len - sizeof(struct udphdr);
uint32_t xid;
if (data_len < 4) {
return;
}
xid = ntohl(*(uint32_t *)data) & 0xffffff;
switch (data[0]) {
case MSGTYPE_INFO_REQUEST:
dhcpv6_info_request(m->slirp, srcsas, xid, &data[4], data_len - 4);
break;
default:
DEBUG_MISC("dhcpv6_input: Unsupported message type 0x%x", data[0]);
}
}

View File

@ -0,0 +1,69 @@
/* SPDX-License-Identifier: BSD-3-Clause */
/*
* Definitions and prototypes for SLIRP stateless DHCPv6
*
* Copyright 2016 Thomas Huth, Red Hat Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* 2. Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef SLIRP_DHCPV6_H
#define SLIRP_DHCPV6_H
#define DHCPV6_SERVER_PORT 547
#define ALLDHCP_MULTICAST \
{ \
.s6_addr = { \
0xff, \
0x02, \
0x00, \
0x00, \
0x00, \
0x00, \
0x00, \
0x00, \
0x00, \
0x00, \
0x00, \
0x00, \
0x00, \
0x01, \
0x00, \
0x02 \
} \
}
#define in6_dhcp_multicast(a) in6_equal(a, &(struct in6_addr)ALLDHCP_MULTICAST)
/* Process a DHCPv6 packet from the guest */
void dhcpv6_input(struct sockaddr_in6 *srcsas, struct mbuf *m);
#endif

View File

@ -0,0 +1,306 @@
/* SPDX-License-Identifier: MIT */
/*
* Domain search option for DHCP (RFC 3397)
*
* Copyright (c) 2012 Klaus Stengel
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "slirp.h"
static const uint8_t RFC3397_OPT_DOMAIN_SEARCH = 119;
static const uint8_t MAX_OPT_LEN = 255;
static const uint8_t OPT_HEADER_LEN = 2;
static const uint8_t REFERENCE_LEN = 2;
struct compact_domain;
typedef struct compact_domain {
struct compact_domain *self;
struct compact_domain *refdom;
uint8_t *labels;
size_t len;
size_t common_octets;
} CompactDomain;
static size_t domain_suffix_diffoff(const CompactDomain *a,
const CompactDomain *b)
{
size_t la = a->len, lb = b->len;
uint8_t *da = a->labels + la, *db = b->labels + lb;
size_t i, lm = (la < lb) ? la : lb;
for (i = 0; i < lm; i++) {
da--;
db--;
if (*da != *db) {
break;
}
}
return i;
}
static int domain_suffix_ord(const void *cva, const void *cvb)
{
const CompactDomain *a = cva, *b = cvb;
size_t la = a->len, lb = b->len;
size_t doff = domain_suffix_diffoff(a, b);
uint8_t ca = a->labels[la - doff];
uint8_t cb = b->labels[lb - doff];
if (ca < cb) {
return -1;
}
if (ca > cb) {
return 1;
}
if (la < lb) {
return -1;
}
if (la > lb) {
return 1;
}
return 0;
}
static size_t domain_common_label(CompactDomain *a, CompactDomain *b)
{
size_t res, doff = domain_suffix_diffoff(a, b);
uint8_t *first_eq_pos = a->labels + (a->len - doff);
uint8_t *label = a->labels;
while (*label && label < first_eq_pos) {
label += *label + 1;
}
res = a->len - (label - a->labels);
/* only report if it can help to reduce the packet size */
return (res > REFERENCE_LEN) ? res : 0;
}
static void domain_fixup_order(CompactDomain *cd, size_t n)
{
size_t i;
for (i = 0; i < n; i++) {
CompactDomain *cur = cd + i, *next = cd[i].self;
while (!cur->common_octets) {
CompactDomain *tmp = next->self; /* backup target value */
next->self = cur;
cur->common_octets++;
cur = next;
next = tmp;
}
}
}
static void domain_mklabels(CompactDomain *cd, const char *input)
{
uint8_t *len_marker = cd->labels;
uint8_t *output = len_marker; /* pre-incremented */
const char *in = input;
char cur_chr;
size_t len = 0;
if (cd->len == 0) {
goto fail;
}
cd->len++;
do {
cur_chr = *in++;
if (cur_chr == '.' || cur_chr == '\0') {
len = output - len_marker;
if ((len == 0 && cur_chr == '.') || len >= 64) {
goto fail;
}
*len_marker = len;
output++;
len_marker = output;
} else {
output++;
*output = cur_chr;
}
} while (cur_chr != '\0');
/* ensure proper zero-termination */
if (len != 0) {
*len_marker = 0;
cd->len++;
}
return;
fail:
g_warning("failed to parse domain name '%s'\n", input);
cd->len = 0;
}
static void domain_mkxrefs(CompactDomain *doms, CompactDomain *last,
size_t depth)
{
CompactDomain *i = doms, *target = doms;
do {
if (i->labels < target->labels) {
target = i;
}
} while (i++ != last);
for (i = doms; i != last; i++) {
CompactDomain *group_last;
size_t next_depth;
if (i->common_octets == depth) {
continue;
}
next_depth = -1;
for (group_last = i; group_last != last; group_last++) {
size_t co = group_last->common_octets;
if (co <= depth) {
break;
}
if (co < next_depth) {
next_depth = co;
}
}
domain_mkxrefs(i, group_last, next_depth);
i = group_last;
if (i == last) {
break;
}
}
if (depth == 0) {
return;
}
i = doms;
do {
if (i != target && i->refdom == NULL) {
i->refdom = target;
i->common_octets = depth;
}
} while (i++ != last);
}
static size_t domain_compactify(CompactDomain *domains, size_t n)
{
uint8_t *start = domains->self->labels, *outptr = start;
size_t i;
for (i = 0; i < n; i++) {
CompactDomain *cd = domains[i].self;
CompactDomain *rd = cd->refdom;
if (rd != NULL) {
size_t moff = (rd->labels - start) + (rd->len - cd->common_octets);
if (moff < 0x3FFFu) {
cd->len -= cd->common_octets - 2;
cd->labels[cd->len - 1] = moff & 0xFFu;
cd->labels[cd->len - 2] = 0xC0u | (moff >> 8);
}
}
if (cd->labels != outptr) {
memmove(outptr, cd->labels, cd->len);
cd->labels = outptr;
}
outptr += cd->len;
}
return outptr - start;
}
int translate_dnssearch(Slirp *s, const char **names)
{
size_t blocks, bsrc_start, bsrc_end, bdst_start;
size_t i, num_domains, memreq = 0;
uint8_t *result = NULL, *outptr;
CompactDomain *domains = NULL;
num_domains = g_strv_length((GStrv)(void *)names);
if (num_domains == 0) {
return -2;
}
domains = g_malloc(num_domains * sizeof(*domains));
for (i = 0; i < num_domains; i++) {
size_t nlen = strlen(names[i]);
memreq += nlen + 2; /* 1 zero octet + 1 label length octet */
domains[i].self = domains + i;
domains[i].len = nlen;
domains[i].common_octets = 0;
domains[i].refdom = NULL;
}
/* reserve extra 2 header bytes for each 255 bytes of output */
memreq += DIV_ROUND_UP(memreq, MAX_OPT_LEN) * OPT_HEADER_LEN;
result = g_malloc(memreq * sizeof(*result));
outptr = result;
for (i = 0; i < num_domains; i++) {
domains[i].labels = outptr;
domain_mklabels(domains + i, names[i]);
if (domains[i].len == 0) {
/* Bogus entry, reject it all */
g_free(domains);
g_free(result);
return -1;
}
outptr += domains[i].len;
}
qsort(domains, num_domains, sizeof(*domains), domain_suffix_ord);
domain_fixup_order(domains, num_domains);
for (i = 1; i < num_domains; i++) {
size_t cl = domain_common_label(domains + i - 1, domains + i);
domains[i - 1].common_octets = cl;
}
domain_mkxrefs(domains, domains + num_domains - 1, 0);
memreq = domain_compactify(domains, num_domains);
blocks = DIV_ROUND_UP(memreq, MAX_OPT_LEN);
bsrc_end = memreq;
bsrc_start = (blocks - 1) * MAX_OPT_LEN;
bdst_start = bsrc_start + blocks * OPT_HEADER_LEN;
memreq += blocks * OPT_HEADER_LEN;
while (blocks--) {
size_t len = bsrc_end - bsrc_start;
memmove(result + bdst_start, result + bsrc_start, len);
result[bdst_start - 2] = RFC3397_OPT_DOMAIN_SEARCH;
result[bdst_start - 1] = len;
bsrc_end = bsrc_start;
bsrc_start -= MAX_OPT_LEN;
bdst_start -= MAX_OPT_LEN + OPT_HEADER_LEN;
}
g_free(domains);
s->vdnssearch = result;
s->vdnssearch_len = memreq;
return 0;
}

View File

@ -0,0 +1,201 @@
/* SPDX-License-Identifier: BSD-3-Clause */
/*
* Copyright (c) 1995 Danny Gasparovski.
*/
#include "slirp.h"
static void ifs_insque(struct mbuf *ifm, struct mbuf *ifmhead)
{
ifm->m_nextpkt = ifmhead->m_nextpkt;
ifmhead->m_nextpkt = ifm;
ifm->m_prevpkt = ifmhead;
ifm->m_nextpkt->m_prevpkt = ifm;
}
void if_init(Slirp *slirp)
{
slirp->if_fastq.qh_link = slirp->if_fastq.qh_rlink = &slirp->if_fastq;
slirp->if_batchq.qh_link = slirp->if_batchq.qh_rlink = &slirp->if_batchq;
}
/*
* if_output: Queue packet into an output queue.
* There are 2 output queue's, if_fastq and if_batchq.
* Each output queue is a doubly linked list of double linked lists
* of mbufs, each list belonging to one "session" (socket). This
* way, we can output packets fairly by sending one packet from each
* session, instead of all the packets from one session, then all packets
* from the next session, etc. Packets on the if_fastq get absolute
* priority, but if one session hogs the link, it gets "downgraded"
* to the batchq until it runs out of packets, then it'll return
* to the fastq (eg. if the user does an ls -alR in a telnet session,
* it'll temporarily get downgraded to the batchq)
*/
void if_output(struct socket *so, struct mbuf *ifm)
{
Slirp *slirp = ifm->slirp;
M_DUP_DEBUG(slirp, ifm, 0, 0);
struct mbuf *ifq;
int on_fastq = 1;
DEBUG_CALL("if_output");
DEBUG_ARG("so = %p", so);
DEBUG_ARG("ifm = %p", ifm);
/*
* First remove the mbuf from m_usedlist,
* since we're gonna use m_next and m_prev ourselves
* XXX Shouldn't need this, gotta change dtom() etc.
*/
if (ifm->m_flags & M_USEDLIST) {
slirp_remque(ifm);
ifm->m_flags &= ~M_USEDLIST;
}
/*
* See if there's already a batchq list for this session.
* This can include an interactive session, which should go on fastq,
* but gets too greedy... hence it'll be downgraded from fastq to batchq.
* We mustn't put this packet back on the fastq (or we'll send it out of
* order)
* XXX add cache here?
*/
if (so) {
for (ifq = (struct mbuf *)slirp->if_batchq.qh_rlink;
(struct slirp_quehead *)ifq != &slirp->if_batchq;
ifq = ifq->m_prev) {
if (so == ifq->m_so) {
/* A match! */
ifm->m_so = so;
ifs_insque(ifm, ifq->m_prevpkt);
goto diddit;
}
}
}
/* No match, check which queue to put it on */
if (so && (so->so_iptos & IPTOS_LOWDELAY)) {
ifq = (struct mbuf *)slirp->if_fastq.qh_rlink;
on_fastq = 1;
/*
* Check if this packet is a part of the last
* packet's session
*/
if (ifq->m_so == so) {
ifm->m_so = so;
ifs_insque(ifm, ifq->m_prevpkt);
goto diddit;
}
} else {
ifq = (struct mbuf *)slirp->if_batchq.qh_rlink;
}
/* Create a new doubly linked list for this session */
ifm->m_so = so;
ifs_init(ifm);
slirp_insque(ifm, ifq);
diddit:
if (so) {
/* Update *_queued */
so->so_queued++;
so->so_nqueued++;
/*
* Check if the interactive session should be downgraded to
* the batchq. A session is downgraded if it has queued 6
* packets without pausing, and at least 3 of those packets
* have been sent over the link
* (XXX These are arbitrary numbers, probably not optimal..)
*/
if (on_fastq &&
((so->so_nqueued >= 6) && (so->so_nqueued - so->so_queued) >= 3)) {
/* Remove from current queue... */
slirp_remque(ifm->m_nextpkt);
/* ...And insert in the new. That'll teach ya! */
slirp_insque(ifm->m_nextpkt, &slirp->if_batchq);
}
}
/*
* This prevents us from malloc()ing too many mbufs
*/
if_start(ifm->slirp);
}
void if_start(Slirp *slirp)
{
uint64_t now = slirp->cb->clock_get_ns(slirp->opaque);
bool from_batchq = false;
struct mbuf *ifm, *ifm_next, *ifqt;
DEBUG_VERBOSE_CALL("if_start");
if (slirp->if_start_busy) {
return;
}
slirp->if_start_busy = true;
struct mbuf *batch_head = NULL;
if (slirp->if_batchq.qh_link != &slirp->if_batchq) {
batch_head = (struct mbuf *)slirp->if_batchq.qh_link;
}
if (slirp->if_fastq.qh_link != &slirp->if_fastq) {
ifm_next = (struct mbuf *)slirp->if_fastq.qh_link;
} else if (batch_head) {
/* Nothing on fastq, pick up from batchq */
ifm_next = batch_head;
from_batchq = true;
} else {
ifm_next = NULL;
}
while (ifm_next) {
ifm = ifm_next;
ifm_next = ifm->m_next;
if ((struct slirp_quehead *)ifm_next == &slirp->if_fastq) {
/* No more packets in fastq, switch to batchq */
ifm_next = batch_head;
from_batchq = true;
}
if ((struct slirp_quehead *)ifm_next == &slirp->if_batchq) {
/* end of batchq */
ifm_next = NULL;
}
/* Try to send packet unless it already expired */
if (ifm->expiration_date >= now && !if_encap(slirp, ifm)) {
/* Packet is delayed due to pending ARP or NDP resolution */
continue;
}
/* Remove it from the queue */
ifqt = ifm->m_prev;
slirp_remque(ifm);
/* If there are more packets for this session, re-queue them */
if (ifm->m_nextpkt != ifm) {
struct mbuf *next = ifm->m_nextpkt;
slirp_insque(next, ifqt);
ifs_remque(ifm);
if (!from_batchq) {
ifm_next = next;
}
}
/* Update so_queued */
if (ifm->m_so && --ifm->m_so->so_queued == 0) {
/* If there's no more queued, reset nqueued */
ifm->m_so->so_nqueued = 0;
}
m_free(ifm);
}
slirp->if_start_busy = false;
}

View File

@ -0,0 +1,25 @@
/* SPDX-License-Identifier: BSD-3-Clause */
/*
* Copyright (c) 1995 Danny Gasparovski.
*/
#ifndef IF_H
#define IF_H
#define IF_COMPRESS 0x01 /* We want compression */
#define IF_NOCOMPRESS 0x02 /* Do not do compression */
#define IF_AUTOCOMP 0x04 /* Autodetect (default) */
#define IF_NOCIDCOMP 0x08 /* CID compression */
#define IF_MTU_DEFAULT 1500
#define IF_MTU_MIN 68
#define IF_MTU_MAX 65521
#define IF_MRU_DEFAULT 1500
#define IF_MRU_MIN 68
#define IF_MRU_MAX 65521
#define IF_COMP IF_AUTOCOMP /* Flags for compression */
/* 2 for alignment, 14 for ethernet */
#define IF_MAXLINKHDR (2 + ETH_HLEN)
#endif

Some files were not shown because too many files have changed in this diff Show More