Skip to content
This repository has been archived by the owner on Mar 25, 2024. It is now read-only.

Commit

Permalink
Check more arithmetic operations
Browse files Browse the repository at this point in the history
  • Loading branch information
dtolnay committed Dec 14, 2023
1 parent 97a4332 commit 5b40a9e
Show file tree
Hide file tree
Showing 9 changed files with 201 additions and 111 deletions.
36 changes: 20 additions & 16 deletions src/api.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::externs::{free, malloc, memcpy, memmove, memset, realloc, strdup, strlen};
use crate::ops::{ForceAdd as _, ForceMul as _};
use crate::success::{Success, FAIL, OK};
use crate::yaml::{size_t, yaml_char_t};
use crate::{
Expand Down Expand Up @@ -53,7 +54,7 @@ pub(crate) unsafe fn yaml_string_extend(
) {
let new_start: *mut yaml_char_t = yaml_realloc(
*start as *mut libc::c_void,
((*end).c_offset_from(*start) as libc::c_long * 2_i64) as size_t,
(((*end).c_offset_from(*start) as libc::c_long).force_mul(2_i64)) as size_t,
) as *mut yaml_char_t;
memset(
new_start.wrapping_offset((*end).c_offset_from(*start) as libc::c_long as isize)
Expand All @@ -62,8 +63,9 @@ pub(crate) unsafe fn yaml_string_extend(
(*end).c_offset_from(*start) as libc::c_long as libc::c_ulong,
);
*pointer = new_start.wrapping_offset((*pointer).c_offset_from(*start) as libc::c_long as isize);
*end =
new_start.wrapping_offset(((*end).c_offset_from(*start) as libc::c_long * 2_i64) as isize);
*end = new_start.wrapping_offset(
(((*end).c_offset_from(*start) as libc::c_long).force_mul(2_i64)) as isize,
);
*start = new_start;
}

Expand Down Expand Up @@ -99,16 +101,16 @@ pub(crate) unsafe fn yaml_stack_extend(
) {
let new_start: *mut libc::c_void = yaml_realloc(
*start,
((*end as *mut libc::c_char).c_offset_from(*start as *mut libc::c_char) as libc::c_long
* 2_i64) as size_t,
(((*end as *mut libc::c_char).c_offset_from(*start as *mut libc::c_char) as libc::c_long)
.force_mul(2_i64)) as size_t,
);
*top = (new_start as *mut libc::c_char).wrapping_offset(
(*top as *mut libc::c_char).c_offset_from(*start as *mut libc::c_char) as libc::c_long
as isize,
) as *mut libc::c_void;
*end = (new_start as *mut libc::c_char).wrapping_offset(
((*end as *mut libc::c_char).c_offset_from(*start as *mut libc::c_char) as libc::c_long
* 2_i64) as isize,
(((*end as *mut libc::c_char).c_offset_from(*start as *mut libc::c_char) as libc::c_long)
.force_mul(2_i64)) as isize,
) as *mut libc::c_void;
*start = new_start;
}
Expand All @@ -122,8 +124,9 @@ pub(crate) unsafe fn yaml_queue_extend(
if *start == *head && *tail == *end {
let new_start: *mut libc::c_void = yaml_realloc(
*start,
((*end as *mut libc::c_char).c_offset_from(*start as *mut libc::c_char) as libc::c_long
* 2_i64) as size_t,
(((*end as *mut libc::c_char).c_offset_from(*start as *mut libc::c_char)
as libc::c_long)
.force_mul(2_i64)) as size_t,
);
*head = (new_start as *mut libc::c_char).wrapping_offset(
(*head as *mut libc::c_char).c_offset_from(*start as *mut libc::c_char) as libc::c_long
Expand All @@ -134,8 +137,9 @@ pub(crate) unsafe fn yaml_queue_extend(
as isize,
) as *mut libc::c_void;
*end = (new_start as *mut libc::c_char).wrapping_offset(
((*end as *mut libc::c_char).c_offset_from(*start as *mut libc::c_char) as libc::c_long
* 2_i64) as isize,
(((*end as *mut libc::c_char).c_offset_from(*start as *mut libc::c_char)
as libc::c_long)
.force_mul(2_i64)) as isize,
) as *mut libc::c_void;
*start = new_start;
}
Expand Down Expand Up @@ -374,7 +378,7 @@ unsafe fn yaml_string_write_handler(
size,
);
let fresh153 = addr_of_mut!((*(*emitter).output.string.size_written));
*fresh153 = (*fresh153 as libc::c_ulong).wrapping_add(size) as size_t;
*fresh153 = (*fresh153 as libc::c_ulong).force_add(size) as size_t;
1
}

Expand Down Expand Up @@ -532,8 +536,8 @@ unsafe fn yaml_check_utf8(start: *const yaml_char_t, length: size_t) -> Success
if octet & 0xC0 != 0x80 {
return FAIL;
}
value = (value << 6).wrapping_add((octet & 0x3F) as libc::c_uint);
k = k.wrapping_add(1);
value = (value << 6).force_add((octet & 0x3F) as libc::c_uint);
k = k.force_add(1);
}
if !(width == 1
|| width == 2 && value >= 0x80
Expand Down Expand Up @@ -826,7 +830,7 @@ pub unsafe fn yaml_scalar_event_initialize(
length = strlen(value as *mut libc::c_char) as libc::c_int;
}
if yaml_check_utf8(value, length as size_t).ok {
value_copy = yaml_malloc((length + 1) as size_t) as *mut yaml_char_t;
value_copy = yaml_malloc(length.force_add(1) as size_t) as *mut yaml_char_t;
memcpy(
value_copy as *mut libc::c_void,
value as *const libc::c_void,
Expand Down Expand Up @@ -1333,7 +1337,7 @@ pub unsafe fn yaml_document_add_scalar(
length = strlen(value as *mut libc::c_char) as libc::c_int;
}
if yaml_check_utf8(value, length as size_t).ok {
value_copy = yaml_malloc((length + 1) as size_t) as *mut yaml_char_t;
value_copy = yaml_malloc(length.force_add(1) as size_t) as *mut yaml_char_t;
memcpy(
value_copy as *mut libc::c_void,
value as *const libc::c_void,
Expand Down
5 changes: 3 additions & 2 deletions src/dumper.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::api::{yaml_free, yaml_malloc};
use crate::externs::{memset, strcmp};
use crate::fmt::WriteToPtr;
use crate::ops::ForceMul as _;
use crate::success::{Success, FAIL, OK};
use crate::yaml::{
yaml_anchors_t, yaml_char_t, yaml_document_t, yaml_emitter_t, yaml_event_t, yaml_mark_t,
Expand Down Expand Up @@ -116,14 +117,14 @@ pub unsafe fn yaml_emitter_dump(
let fresh1 = addr_of_mut!((*emitter).anchors);
*fresh1 = yaml_malloc(
(size_of::<yaml_anchors_t>() as libc::c_ulong)
.wrapping_mul((*document).nodes.top.c_offset_from((*document).nodes.start)
.force_mul((*document).nodes.top.c_offset_from((*document).nodes.start)
as libc::c_long as libc::c_ulong),
) as *mut yaml_anchors_t;
memset(
(*emitter).anchors as *mut libc::c_void,
0,
(size_of::<yaml_anchors_t>() as libc::c_ulong)
.wrapping_mul((*document).nodes.top.c_offset_from((*document).nodes.start)
.force_mul((*document).nodes.top.c_offset_from((*document).nodes.start)
as libc::c_long as libc::c_ulong),
);
memset(
Expand Down
50 changes: 22 additions & 28 deletions src/emitter.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::api::{yaml_free, yaml_queue_extend, yaml_stack_extend, yaml_strdup};
use crate::externs::{strcmp, strlen, strncmp};
use crate::ops::{ForceAdd as _, ForceMul as _};
use crate::success::{Success, FAIL, OK};
use crate::yaml::{size_t, yaml_char_t, yaml_string_t};
use crate::{
Expand Down Expand Up @@ -296,7 +297,9 @@ unsafe fn yaml_emitter_emit_stream_start(
if (*emitter).best_indent < 2 || (*emitter).best_indent > 9 {
(*emitter).best_indent = 2;
}
if (*emitter).best_width >= 0 && (*emitter).best_width <= (*emitter).best_indent * 2 {
if (*emitter).best_width >= 0
&& (*emitter).best_width <= (*emitter).best_indent.force_mul(2)
{
(*emitter).best_width = 80;
}
if (*emitter).best_width < 0 {
Expand Down Expand Up @@ -1045,45 +1048,36 @@ unsafe fn yaml_emitter_check_simple_key(emitter: *mut yaml_emitter_t) -> bool {
let mut length: size_t = 0_u64;
match (*event).type_ {
YAML_ALIAS_EVENT => {
length = (length as libc::c_ulong).wrapping_add((*emitter).anchor_data.anchor_length)
as size_t;
length =
(length as libc::c_ulong).force_add((*emitter).anchor_data.anchor_length) as size_t;
}
YAML_SCALAR_EVENT => {
if (*emitter).scalar_data.multiline {
return false;
}
length = (length as libc::c_ulong).wrapping_add(
(*emitter)
.anchor_data
.anchor_length
.wrapping_add((*emitter).tag_data.handle_length)
.wrapping_add((*emitter).tag_data.suffix_length)
.wrapping_add((*emitter).scalar_data.length),
) as size_t;
length = (length as libc::c_ulong)
.force_add((*emitter).anchor_data.anchor_length)
.force_add((*emitter).tag_data.handle_length)
.force_add((*emitter).tag_data.suffix_length)
.force_add((*emitter).scalar_data.length) as size_t;
}
YAML_SEQUENCE_START_EVENT => {
if !yaml_emitter_check_empty_sequence(emitter) {
return false;
}
length = (length as libc::c_ulong).wrapping_add(
(*emitter)
.anchor_data
.anchor_length
.wrapping_add((*emitter).tag_data.handle_length)
.wrapping_add((*emitter).tag_data.suffix_length),
) as size_t;
length = (length as libc::c_ulong)
.force_add((*emitter).anchor_data.anchor_length)
.force_add((*emitter).tag_data.handle_length)
.force_add((*emitter).tag_data.suffix_length) as size_t;
}
YAML_MAPPING_START_EVENT => {
if !yaml_emitter_check_empty_mapping(emitter) {
return false;
}
length = (length as libc::c_ulong).wrapping_add(
(*emitter)
.anchor_data
.anchor_length
.wrapping_add((*emitter).tag_data.handle_length)
.wrapping_add((*emitter).tag_data.suffix_length),
) as size_t;
length = (length as libc::c_ulong)
.force_add((*emitter).anchor_data.anchor_length)
.force_add((*emitter).tag_data.handle_length)
.force_add((*emitter).tag_data.suffix_length) as size_t;
}
_ => return false,
}
Expand Down Expand Up @@ -1825,15 +1819,15 @@ unsafe fn yaml_emitter_write_tag_content(
}
if PUT(
emitter,
(value >> 4).wrapping_add(if (value >> 4) < 10 { b'0' } else { b'A' - 10 }),
(value >> 4).force_add(if (value >> 4) < 10 { b'0' } else { b'A' - 10 }),
)
.fail
{
return FAIL;
}
if PUT(
emitter,
(value & 0x0F).wrapping_add(if (value & 0x0F) < 10 { b'0' } else { b'A' - 10 }),
(value & 0x0F).force_add(if (value & 0x0F) < 10 { b'0' } else { b'A' - 10 }),
)
.fail
{
Expand Down Expand Up @@ -2051,7 +2045,7 @@ unsafe fn yaml_emitter_write_double_quoted_scalar(
k = 1;
while k < width as libc::c_int {
octet = *string.pointer.wrapping_offset(k as isize);
value_0 = (value_0 << 6).wrapping_add((octet & 0x3F) as libc::c_uint);
value_0 = (value_0 << 6).force_add((octet & 0x3F) as libc::c_uint);
k += 1;
}
string.pointer = string.pointer.wrapping_offset(width as isize);
Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,7 @@ mod api;
mod dumper;
mod emitter;
mod loader;
mod ops;
mod parser;
mod reader;
mod scanner;
Expand Down
88 changes: 88 additions & 0 deletions src/ops.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
pub(crate) trait ForceAdd: Sized {
fn force_add(self, rhs: Self) -> Self;
}

impl ForceAdd for u8 {
fn force_add(self, rhs: Self) -> Self {
self.checked_add(rhs).unwrap_or_else(die)
}
}

impl ForceAdd for i32 {
fn force_add(self, rhs: Self) -> Self {
self.checked_add(rhs).unwrap_or_else(die)
}
}

impl ForceAdd for u32 {
fn force_add(self, rhs: Self) -> Self {
self.checked_add(rhs).unwrap_or_else(die)
}
}

impl ForceAdd for u64 {
fn force_add(self, rhs: Self) -> Self {
self.checked_add(rhs).unwrap_or_else(die)
}
}

pub(crate) trait ForceMul: Sized {
fn force_mul(self, rhs: Self) -> Self;
}

impl ForceMul for i32 {
fn force_mul(self, rhs: Self) -> Self {
self.checked_mul(rhs).unwrap_or_else(die)
}
}

impl ForceMul for i64 {
fn force_mul(self, rhs: Self) -> Self {
self.checked_mul(rhs).unwrap_or_else(die)
}
}

impl ForceMul for u64 {
fn force_mul(self, rhs: Self) -> Self {
self.checked_mul(rhs).unwrap_or_else(die)
}
}

// Deterministically abort on arithmetic overflow, instead of wrapping and
// continuing with invalid behavior.
//
// This is impossible or nearly impossible to hit as the arithmetic computations
// in libyaml are all related to either:
//
// - small integer processing (ascii, hex digits)
// - allocation sizing
//
// and the only allocations in libyaml are for fixed-sized objects and
// geometrically growing buffers with a growth factor of 2. So in order for an
// allocation computation to overflow usize, the previous allocation for that
// container must have been filled to a size of usize::MAX/2, which is an
// allocation that would have failed in the allocator. But we check for this to
// be pedantic and to find out if it ever does happen.
//
// No-std abort is implemented using a double panic. On most platforms the
// current mechanism for this is for core::intrinsics::abort to invoke an
// invalid instruction. On Unix, the process will probably terminate with a
// signal like SIGABRT, SIGILL, SIGTRAP, SIGSEGV or SIGBUS. The precise
// behaviour is not guaranteed and not stable, but is safe.
#[cold]
pub(crate) fn die<T>() -> T {
struct PanicAgain;

impl Drop for PanicAgain {
fn drop(&mut self) {
panic!("arithmetic overflow");
}
}

fn do_die() -> ! {
let _panic_again = PanicAgain;
panic!("arithmetic overflow");
}

do_die();
}
9 changes: 4 additions & 5 deletions src/parser.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::api::{yaml_free, yaml_malloc, yaml_stack_extend, yaml_strdup};
use crate::externs::{memcpy, memset, strcmp, strlen};
use crate::ops::ForceAdd as _;
use crate::scanner::yaml_parser_fetch_more_tokens;
use crate::success::{Success, FAIL, OK};
use crate::yaml::{size_t, yaml_char_t};
Expand Down Expand Up @@ -504,9 +505,8 @@ unsafe fn yaml_parser_parse_node(
let prefix_len: size_t =
strlen((*tag_directive).prefix as *mut libc::c_char);
let suffix_len: size_t = strlen(tag_suffix as *mut libc::c_char);
tag = yaml_malloc(
prefix_len.wrapping_add(suffix_len).wrapping_add(1_u64),
) as *mut yaml_char_t;
tag = yaml_malloc(prefix_len.force_add(suffix_len).force_add(1_u64))
as *mut yaml_char_t;
memcpy(
tag as *mut libc::c_void,
(*tag_directive).prefix as *const libc::c_void,
Expand All @@ -517,8 +517,7 @@ unsafe fn yaml_parser_parse_node(
tag_suffix as *const libc::c_void,
suffix_len,
);
*tag.wrapping_offset(prefix_len.wrapping_add(suffix_len) as isize) =
b'\0';
*tag.wrapping_offset(prefix_len.force_add(suffix_len) as isize) = b'\0';
yaml_free(tag_handle as *mut libc::c_void);
yaml_free(tag_suffix as *mut libc::c_void);
tag_suffix = ptr::null_mut::<yaml_char_t>();
Expand Down
Loading

0 comments on commit 5b40a9e

Please sign in to comment.