Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions libcc2rs/src/fd.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// Copyright (c) 2022-present INESC-ID.
// Distributed under the MIT license that can be found in the LICENSE file.

use std::cell::RefCell;
use std::os::fd::{AsFd, AsRawFd, BorrowedFd, OwnedFd};

pub struct FdRegistry {
fds: Vec<Option<OwnedFd>>,
}

thread_local! {
static FD_REGISTRY: RefCell<FdRegistry> = const { RefCell::new(FdRegistry { fds: Vec::new() }) };
}

impl FdRegistry {
pub fn register(fd: OwnedFd) -> i32 {
let raw = fd.as_raw_fd();
FD_REGISTRY.with(|r| {
let fds = &mut r.borrow_mut().fds;
let idx = raw as usize;
if fds.len() <= idx {
fds.resize_with(idx + 1, || None);
}
assert!(fds[idx].is_none(), "ub: fd registry collision on fd {raw}");
fds[idx] = Some(fd);
});
raw
}

pub fn with_fd<R>(fd: i32, f: impl FnOnce(BorrowedFd<'_>) -> R) -> R {
FD_REGISTRY.with(|r| {
let reg = r.borrow();
let owned = reg
.fds
.get(fd as usize)
.and_then(|slot| slot.as_ref())
.unwrap_or_else(|| panic!("ub: bad fd {fd}"));
f(owned.as_fd())
})
}

pub fn close(fd: i32) -> i32 {
FD_REGISTRY.with(|r| {
r.borrow_mut()
.fds
.get_mut(fd as usize)
.and_then(|slot| slot.take())
.unwrap_or_else(|| panic!("ub: bad fd {fd}"))
});
0
}
}
3 changes: 3 additions & 0 deletions libcc2rs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ pub use compat::*;
mod va_args;
pub use va_args::*;

mod fd;
pub use fd::*;

mod format;
pub use format::*;

Expand Down
10 changes: 10 additions & 0 deletions rules/fcntl/src.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,13 @@ template <typename... Args>
int f2(const char *a0, int a1, Args... args) {
return open(a0, a1, args...);
}

int f3(void) { return O_CREAT; }
int f4(void) { return O_TRUNC; }
int f5(void) { return O_APPEND; }
int f6(void) { return O_EXCL; }
int f7(void) { return O_NONBLOCK; }
int f8(void) { return O_CLOEXEC; }
int f9(void) { return O_RDONLY; }
int f10(void) { return O_WRONLY; }
int f11(void) { return O_RDWR; }
57 changes: 51 additions & 6 deletions rules/fcntl/tgt_refcount.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,55 @@ fn f1(a0: i32, a1: i32, va: &[VaArg]) -> i32 {
}

fn f2(a0: Ptr<u8>, a1: i32, va: &[VaArg]) -> i32 {
panic!(
"open is not supported in the refcount model (path={:?}, flags={}, varargs={})",
a0.to_rust_string(),
a1,
va.len()
)
let __mode = match va.first() {
Some(__m) => nix::sys::stat::Mode::from_bits_truncate(i32::get(__m) as ::libc::mode_t),
None => nix::sys::stat::Mode::empty(),
};
match nix::fcntl::open(
a0.to_rust_string().as_str(),
nix::fcntl::OFlag::from_bits_retain(a1),
__mode,
) {
Ok(__ofd) => FdRegistry::register(__ofd),
Err(__e) => {
libcc2rs::cpp2rust_errno().write(__e as i32);
-1
}
}
}

fn f3() -> i32 {
::libc::O_CREAT
}

fn f4() -> i32 {
::libc::O_TRUNC
}

fn f5() -> i32 {
::libc::O_APPEND
}

fn f6() -> i32 {
::libc::O_EXCL
}

fn f7() -> i32 {
::libc::O_NONBLOCK
}

fn f8() -> i32 {
::libc::O_CLOEXEC
}

fn f9() -> i32 {
::libc::O_RDONLY
}

fn f10() -> i32 {
::libc::O_WRONLY
}

fn f11() -> i32 {
::libc::O_RDWR
}
36 changes: 36 additions & 0 deletions rules/fcntl/tgt_unsafe.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,39 @@ unsafe extern "C" {
fn f1(a0: i32, a1: i32, ...) -> i32;
fn f2(a0: *const i8, a1: i32, ...) -> i32;
}

unsafe fn f3() -> i32 {
::libc::O_CREAT
}

unsafe fn f4() -> i32 {
::libc::O_TRUNC
}

unsafe fn f5() -> i32 {
::libc::O_APPEND
}

unsafe fn f6() -> i32 {
::libc::O_EXCL
}

unsafe fn f7() -> i32 {
::libc::O_NONBLOCK
}

unsafe fn f8() -> i32 {
::libc::O_CLOEXEC
}

unsafe fn f9() -> i32 {
::libc::O_RDONLY
}

unsafe fn f10() -> i32 {
::libc::O_WRONLY
}

unsafe fn f11() -> i32 {
::libc::O_RDWR
}
30 changes: 30 additions & 0 deletions rules/unistd/tgt_refcount.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,23 @@

use libcc2rs::*;

fn f1(a0: i32) -> i32 {
FdRegistry::close(a0)
}

fn f3(a0: i32, a1: AnyPtr, a2: usize) -> isize {
match FdRegistry::with_fd(a0, |__fd| {
a1.reinterpret_cast::<u8>()
.with_slice_mut(a2, |__buf| nix::unistd::read(__fd, __buf))
}) {
Ok(__n) => __n as isize,
Err(__e) => {
libcc2rs::cpp2rust_errno().write(__e as i32);
-1
}
}
}

fn f4(a0: Ptr<u8>) -> i32 {
match nix::unistd::unlink(a0.to_rust_string().as_str()) {
Ok(()) => 0,
Expand Down Expand Up @@ -37,6 +54,19 @@ fn f9(a0: Ptr<u8>, a1: usize) -> i32 {
}
}

fn f10(a0: i32, a1: AnyPtr, a2: usize) -> isize {
match FdRegistry::with_fd(a0, |__fd| {
a1.reinterpret_cast::<u8>()
.with_slice(a2, |__buf| nix::unistd::write(__fd, __buf))
}) {
Ok(__n) => __n as isize,
Err(__e) => {
libcc2rs::cpp2rust_errno().write(__e as i32);
-1
}
}
}

fn f11(a0: Ptr<u8>) -> i32 {
match ::std::fs::remove_dir(a0.to_rust_string()) {
Ok(()) => 0,
Expand Down
4 changes: 4 additions & 0 deletions tests/ub/fd_close_invalid.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// panic-ub: refcount
#include <unistd.h>

int main(void) { return close(1234) == -1 ? 0 : 1; }
9 changes: 9 additions & 0 deletions tests/ub/fd_double_close.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// panic-ub: refcount
#include <fcntl.h>
#include <unistd.h>

int main(void) {
int fd = open("/dev/null", O_RDONLY);
close(fd);
return close(fd) == -1 ? 0 : 1;
}
11 changes: 11 additions & 0 deletions tests/ub/fd_use_after_close.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// panic-ub: refcount
#include <fcntl.h>
#include <unistd.h>

int main(void) {
int fd = open("/dev/null", O_RDONLY);
close(fd);
char buf[4];
ssize_t n = read(fd, buf, sizeof(buf));
return n == -1 ? 0 : 1;
}
18 changes: 18 additions & 0 deletions tests/ub/out/refcount/fd_close_invalid.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
extern crate libcc2rs;
use libcc2rs::*;
use std::cell::RefCell;
use std::collections::BTreeMap;
use std::io::prelude::*;
use std::io::{Read, Seek, Write};
use std::os::fd::AsFd;
use std::rc::{Rc, Weak};
pub fn main() {
std::process::exit(main_0());
}
fn main_0() -> i32 {
return if (((FdRegistry::close(1234) == -1_i32) as i32) != 0) {
0
} else {
1
};
}
38 changes: 38 additions & 0 deletions tests/ub/out/refcount/fd_double_close.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
extern crate libcc2rs;
use libcc2rs::*;
use std::cell::RefCell;
use std::collections::BTreeMap;
use std::io::prelude::*;
use std::io::{Read, Seek, Write};
use std::os::fd::AsFd;
use std::rc::{Rc, Weak};
pub fn main() {
std::process::exit(main_0());
}
fn main_0() -> i32 {
let fd: Value<i32> = Rc::new(RefCell::new({
let __mode = match &[].first() {
Some(__m) => nix::sys::stat::Mode::from_bits_truncate(i32::get(__m) as ::libc::mode_t),
None => nix::sys::stat::Mode::empty(),
};
match nix::fcntl::open(
Ptr::from_string_literal(b"/dev/null")
.to_rust_string()
.as_str(),
nix::fcntl::OFlag::from_bits_retain(::libc::O_RDONLY),
__mode,
) {
Ok(__ofd) => FdRegistry::register(__ofd),
Err(__e) => {
libcc2rs::cpp2rust_errno().write(__e as i32);
-1
}
}
}));
FdRegistry::close((*fd.borrow()));
return if (((FdRegistry::close((*fd.borrow())) == -1_i32) as i32) != 0) {
0
} else {
1
};
}
57 changes: 57 additions & 0 deletions tests/ub/out/refcount/fd_use_after_close.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
extern crate libcc2rs;
use libcc2rs::*;
use std::cell::RefCell;
use std::collections::BTreeMap;
use std::io::prelude::*;
use std::io::{Read, Seek, Write};
use std::os::fd::AsFd;
use std::rc::{Rc, Weak};
pub fn main() {
std::process::exit(main_0());
}
fn main_0() -> i32 {
let fd: Value<i32> = Rc::new(RefCell::new({
let __mode = match &[].first() {
Some(__m) => nix::sys::stat::Mode::from_bits_truncate(i32::get(__m) as ::libc::mode_t),
None => nix::sys::stat::Mode::empty(),
};
match nix::fcntl::open(
Ptr::from_string_literal(b"/dev/null")
.to_rust_string()
.as_str(),
nix::fcntl::OFlag::from_bits_retain(::libc::O_RDONLY),
__mode,
) {
Ok(__ofd) => FdRegistry::register(__ofd),
Err(__e) => {
libcc2rs::cpp2rust_errno().write(__e as i32);
-1
}
}
}));
FdRegistry::close((*fd.borrow()));
let buf: Value<Box<[u8]>> = Rc::new(RefCell::new(
(0..4).map(|_| <u8>::default()).collect::<Box<[u8]>>(),
));
let n: Value<isize> = Rc::new(RefCell::new(
match FdRegistry::with_fd((*fd.borrow()), |__fd| {
((buf.as_pointer() as Ptr<u8>) as Ptr<u8>)
.to_any()
.reinterpret_cast::<u8>()
.with_slice_mut(::std::mem::size_of::<[u8; 4]>(), |__buf| {
nix::unistd::read(__fd, __buf)
})
}) {
Ok(__n) => __n as isize,
Err(__e) => {
libcc2rs::cpp2rust_errno().write(__e as i32);
-1
}
},
));
return if ((((*n.borrow()) == (-1_i32 as isize)) as i32) != 0) {
0
} else {
1
};
}
20 changes: 20 additions & 0 deletions tests/ub/out/unsafe/fd_close_invalid.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
extern crate libc;
use libc::*;
extern crate libcc2rs;
use libcc2rs::*;
use std::collections::BTreeMap;
use std::io::{Read, Seek, Write};
use std::os::fd::{AsFd, FromRawFd, IntoRawFd};
use std::rc::Rc;
pub fn main() {
unsafe {
std::process::exit(main_0() as i32);
}
}
unsafe fn main_0() -> i32 {
return if ((((libc::close(1234)) == (-1_i32)) as i32) != 0) {
0
} else {
1
};
}
Loading
Loading