librsvg source for verification 2026-05-22
19
afl-fuzz/Cargo.toml
Normal file
@@ -0,0 +1,19 @@
|
||||
[package]
|
||||
name = "rsvg-afl-fuzz"
|
||||
version = "0.0.1"
|
||||
authors = ["Bastien Orivel <eijebong@bananium.fr>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
afl.workspace = true
|
||||
cairo-rs.workspace = true
|
||||
glib.workspace = true
|
||||
gio.workspace = true
|
||||
librsvg.workspace = true
|
||||
|
||||
[profile.release]
|
||||
lto = true
|
||||
debug = true
|
||||
|
||||
[profile.bench]
|
||||
lto = true
|
||||
67
afl-fuzz/README.md
Normal file
@@ -0,0 +1,67 @@
|
||||
Fuzzing with afl-fuzz
|
||||
=====================
|
||||
|
||||
FIXME: Running these commands sucks. Need a script or something.
|
||||
|
||||
To use `cargo afl`:
|
||||
|
||||
* Install `binutils-gold` (your program won't build otherwise).
|
||||
* `cargo install cargo-afl`
|
||||
|
||||
To build and run the fuzzer:
|
||||
|
||||
```sh
|
||||
cargo afl build --release
|
||||
AFL_SKIP_CPUFREQ=1 cargo afl fuzz -i input/ -o out -S f0 target/release/rsvg-afl-fuzz
|
||||
```
|
||||
|
||||
For each CPU core, change `-S f0` for `-S f1`, `-S f2`, etc. To use
|
||||
multiple CPU cores, run that command with a different `-S` option for
|
||||
each core; see [the multicore
|
||||
documentation](https://github.com/AFLplusplus/AFLplusplus/blob/stable/docs/fuzzing_in_depth.md#c-using-multiple-cores)
|
||||
for details on changing the fuzz configuration for each job.
|
||||
|
||||
AFL complained when my kernel's configuration for corefiles was this:
|
||||
|
||||
```sh
|
||||
$ cat /proc/sys/kernel/core_pattern
|
||||
|/bin/false
|
||||
```
|
||||
|
||||
Set it with `echo core > /proc/sys/kernel/core_pattern` and AFL was
|
||||
happy. Alternatively, set `AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1`
|
||||
but you won't get corefiles.
|
||||
|
||||
Note: afl++ comes with pre-written dictionaries for svg/css/xml
|
||||
(slightly incomplete, but a useful starting point). However, these
|
||||
**don't work out of the box** because the `-x` option to include a
|
||||
dictionary (or a directory with dictionaries) complains if a
|
||||
dictionary file is bigger than **128 bytes**. This is... very
|
||||
limited? We may need to split the SVG dictionary into many little
|
||||
files.
|
||||
|
||||
TODO: Help Wanted
|
||||
------------------
|
||||
|
||||
* We shouldn't fuzz on the CI machines, but we should make it easy for people to
|
||||
run the fuzzing framework. Make a script (and fix the CI container image) to
|
||||
do the above well, taking the following into account.
|
||||
|
||||
* Investigate
|
||||
[the many options in afl++](https://github.com/AFLplusplus/AFLplusplus/blob/stable/docs/fuzzing_in_depth.md).
|
||||
For example, it recommends setting up a main fuzzer instance with `-M` and
|
||||
secondary fuzzers with `-S` for each additional core. Also, it recommends
|
||||
using different mutators and power schedules - no idea what those do.
|
||||
|
||||
* Improve the corpus. The files in `input/` are basic SVGs but they do not
|
||||
exercise every major feature of librsvg. Maybe pick up relevant files from the
|
||||
test suite and drop them in there.
|
||||
|
||||
* Write dictionaries that can actually be consumed by afl++. See the comment
|
||||
above on dictionary files needing to be below 128 bytes in size.
|
||||
|
||||
* The afl++ documentation mentions that its output directory is pretty taxing on
|
||||
I/O systems, and for example SSDs. It recommends using a tmpfs as a RAM disk
|
||||
for that. Integrate that into the scripts.
|
||||
|
||||
* Do we need a VM with a kernel setup up just like afl++ likes it?
|
||||
6
afl-fuzz/input/0000.svg
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="50" height="50">
|
||||
<g opacity="0.5">
|
||||
<rect x="10" y="10" width="30" height="30" fill="blue"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 198 B |
6
afl-fuzz/input/0002.svg
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100">
|
||||
<g transform="translate(20, 20)">
|
||||
<rect x="0" y="0" width="60" height="60" style="fill:blue; opacity:0.5;"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 234 B |
11
afl-fuzz/input/0003.svg
Normal file
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg version="1.1" baseProfile="basic" id="svg-root"
|
||||
width="100%" height="100%" viewBox="0 0 480 360"
|
||||
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g>
|
||||
<g opacity="0.5">
|
||||
<rect x="60" y="230" width="80" height="40" fill="#0000ff" opacity=".5"/>
|
||||
<rect x="70" y="240" width="80" height="40" fill="#00ff00" opacity=".5"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 435 B |
24
afl-fuzz/input/0004.svg
Normal file
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="321.00" height="27.00" viewBox="0 0 6420 540">
|
||||
<defs>
|
||||
<mask id="Mask_big_ex_small" maskUnits="userSpaceOnUse" x="0" y="0" width="6420" height="540">
|
||||
<g>
|
||||
<use xlink:href="#big" fill="white"/>
|
||||
<use xlink:href="#small" fill="black"/>
|
||||
</g>
|
||||
</mask>
|
||||
<g id="big_ex_small">
|
||||
<use xlink:href="#big" mask="url(#Mask_big_ex_small)"/>
|
||||
</g>
|
||||
<mask id="Region0" maskUnits="userSpaceOnUse" x="0" y="0" width="6420" height="540" fill-rule="nonzero">
|
||||
<use xlink:href="#big_ex_small" fill="white"/>
|
||||
</mask>
|
||||
<rect id="big" x="0" y="0" width="6420" height="540"/>
|
||||
<rect id="small" x="2760" y="20" width="900" height="480"/>
|
||||
</defs>
|
||||
<g mask="url(#Region0)">
|
||||
<g transform="matrix(1.66667 0 0 1.66667 0 0)">
|
||||
<rect x="0" y="0" width="6420" height="540" fill="black"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 982 B |
4
afl-fuzz/input/0005.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48">
|
||||
<rect x="8" y="8" width="32" height="32" fill="blue"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 167 B |
6
afl-fuzz/input/0007.svg
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48">
|
||||
<g transform="translate(-10, -10)">
|
||||
<path fill="blue" d="M 18 18 l 32 0 l 0 32 l -32 0 z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 215 B |
12
afl-fuzz/input/0008.svg
Normal file
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100">
|
||||
<defs>
|
||||
<clipPath id="one" clipPathUnits="objectBoundingBox">
|
||||
<path d="M 0.5 0.0 L 1.0 0.5 L 0.5 1.0 L 0.0 0.5 Z"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
<g clip-path="url(#one)">
|
||||
<rect x="10" y="10" width="40" height="40" fill="blue"/>
|
||||
<rect x="50" y="50" width="40" height="40" fill="#00ff00"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 425 B |
12
afl-fuzz/input/0009.svg
Normal file
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100">
|
||||
<defs>
|
||||
<mask id="one" maskContentUnits="objectBoundingBox">
|
||||
<path d="M 0.5 0.0 L 1.0 0.5 L 0.5 1.0 L 0.0 0.5 Z" fill="white"/>
|
||||
</mask>
|
||||
</defs>
|
||||
<g mask="url(#one)">
|
||||
<rect x="10" y="10" width="40" height="40" fill="blue"/>
|
||||
<rect x="50" y="50" width="40" height="40" fill="#00ff00"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 428 B |
2
afl-fuzz/input/0010.svg
Normal file
@@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg"/>
|
||||
|
After Width: | Height: | Size: 81 B |
2
afl-fuzz/input/0011.svg
Normal file
@@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="10cm" height="20" viewBox="0 0 100 200"/>
|
||||
|
After Width: | Height: | Size: 128 B |
4
afl-fuzz/input/0012.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%">
|
||||
<rect x="10" y="20" width="30" height="40"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 161 B |
4
afl-fuzz/input/0013.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%">
|
||||
<rect id="foo" x="10" y="20" width="30" height="40"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 170 B |
5
afl-fuzz/input/0014.svg
Normal file
@@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="400" viewBox="0 0 100 400">
|
||||
<rect id="one" x="0" y="0" width="100" height="200" fill="rgb(0,255,0)"/>
|
||||
<rect id="two" x="0" y="200" width="100" height="200" fill="rgb(0,0,255)"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 288 B |
2
afl-fuzz/input/0015.svg
Normal file
@@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%"/>
|
||||
|
After Width: | Height: | Size: 108 B |
25
afl-fuzz/src/main.rs
Normal file
@@ -0,0 +1,25 @@
|
||||
use afl::fuzz;
|
||||
use cairo;
|
||||
use glib;
|
||||
use rsvg;
|
||||
|
||||
fn main() {
|
||||
fuzz!(|data: &[u8]| {
|
||||
let width = 96.;
|
||||
let height = 96.;
|
||||
|
||||
let bytes = glib::Bytes::from(data);
|
||||
let stream = gio::MemoryInputStream::from_bytes(&bytes);
|
||||
let handle =
|
||||
rsvg::Loader::new().read_stream(&stream, None::<&gio::File>, None::<&gio::Cancellable>);
|
||||
if let Ok(handle) = handle {
|
||||
let renderer = rsvg::CairoRenderer::new(&handle);
|
||||
|
||||
let surface =
|
||||
cairo::ImageSurface::create(cairo::Format::ARgb32, width as i32, height as i32)
|
||||
.unwrap();
|
||||
let cr = cairo::Context::new(&surface).unwrap();
|
||||
let _ = renderer.render_document(&cr, &cairo::Rectangle::new(0.0, 0.0, width, height));
|
||||
}
|
||||
});
|
||||
}
|
||||