An semi-automated auxiliary tool which helps to translate C to safe Rust. We aim to demonstrate that those vulnerabilities in C will no longer exist when we translate it to safe Rust. So we choose to use a simple UAF demo to show the complete process.
C2SafeRust
├───── src
│ ├─── uaf_c
| | ├─── build (after running build.sh)
| | | ├─── compile_commands.json
| | | ├─── uaf
| | | └─── ...
| | |
│ | ├─── CMakeLists.txt
│ | ├─── uaf.c
│ | └─── build.sh
│ |
│ ├─── uaf_rust
| | ├─── uaf (after running cargo new)
| | | ├─── Cargo.toml
| | | └─── src
| | | └─── main.rs
| | |
│ | └─── uaf_origin.rs
│ |
| |
| └──── uaf_ir
| ├─── uaf.ll
│ ├─── uaf.c
| ├─── gen_deptree.py
| └─── uaf.ll.txt (after building)
|
├─── report
| ├─── template
| └─── ...
|
└───── README.md
Go to the directory ./src/uaf_c
and run the build.sh via bash
cd ./src/uaf_c && bash build.sh
build.sh
involves two steps:
- generate
compile_commands.json
anduaf
executable in the build directory - generate
uaf.rs
in the parenet directory of build using the c2rust tool. After building the project, you can clean it using
rm -rf build uaf.rs
First, we need to change the dir to uaf_rust, and generate a new cargo project uaf
cd ./src/uaf_rust && cargo new uaf
Then, we need to add libc to the library dependency in the ./uaf/Cargo.toml, as follows:
[dependencies]
libc = "0.2"
Next, we can replace the main.rs
in the rust project with the uaf.rs
generated previously (or simply use the uaf_org.rs
, they're the same). Note that when you run cargo +nightly build
command with the original file, you wil get several errors. Those errors can be solved by making following modification to the main.rs
- Change the
as libc::c_ulong
in thosemalloc
function toas u32
. So the result for A's malloc would belet mut a: *mut A = malloc(::std::mem::size_of::<A>() as libc::c_ulong) as *mut A;
- Change the sentence:
into the following:
(*b).B1 = ::std::mem::transmute::<Option<unsafe extern "C" fn() -> ()>, libc::c_int>(Some(vuln as unsafe extern "C" fn() -> ()));
(*b).B1 = ::std::mem::transmute_copy::<Option<unsafe extern "C" fn() -> ()>, libc::c_int>(&Some(vuln as unsafe extern "C" fn() -> ()));
Then, it can successfully pass the cargo +nightly build
.
But you will get Segmentation fault
when running this project. I think the reason is that the size of Option<T>
is 8, but libc::c_int
is 4... So we need to set B1 and B2 to i64
. The uaf_mod.rs
file under the src/uaf_rust
directory is the final modification result, which will output 'In vuln function!' as expected.
Size of struct A: 16
Size of Option<fnptr>: 8
Size of *mut libc::c_char: 8
Size of struct B: 8
Size of libc::c_int: 4
Size of i64: 8
Go to directory of uaf_ir, and running the following command
export LLVM_DIR=<installation/dir/of/llvm/12>
$LLVM_DIR/bin/clang -emit-llvm uaf.c -S -fno-discard-value-names -o uaf.ll
We use anytree as the implementation of the dependency tree. To intall it, you should run
sudo apt install graphviz
pip install anytree
Then, you can simply run the following cammands to generate the dependency tree
cp uaf.ll uaf.ll.txt
python test.py
The unsafe Rust in uaf_org.rs
can be translated to safe Rust by executing src/uaf_rust/modify.py
.
Replace the original src/uaf_rust/uaf/src/main.rs
with the generated safe Rust code, you can see that the UAF bug is detected by the compiler.