Skip to content

Commit

Permalink
feat: cleanup event error cases (#1886)
Browse files Browse the repository at this point in the history
1. Fail with LimitExceeded where it makes sense.
2. Validate that we comsume all keys/values.
  • Loading branch information
Stebalien authored Sep 20, 2023
1 parent 790537f commit a3db798
Show file tree
Hide file tree
Showing 2 changed files with 151 additions and 18 deletions.
46 changes: 34 additions & 12 deletions fvm/src/kernel/default.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1053,12 +1053,11 @@ where
))?;

if event_headers.len() > MAX_NR_ENTRIES {
return Err(syscall_error!(IllegalArgument; "event exceeded max entries: {} > {MAX_NR_ENTRIES}", event_headers.len()).into());
return Err(syscall_error!(LimitExceeded; "event exceeded max entries: {} > {MAX_NR_ENTRIES}", event_headers.len()).into());
}

// We check this here purely to detect/prevent integer overflows.
if event_values.len() > MAX_TOTAL_VALUES_LEN {
return Err(syscall_error!(IllegalArgument; "total event value lengths exceeded the max size: {} > {MAX_TOTAL_VALUES_LEN}", event_values.len()).into());
return Err(syscall_error!(LimitExceeded; "total event value lengths exceeded the max size: {} > {MAX_TOTAL_VALUES_LEN}", event_values.len()).into());
}

// We validate utf8 all at once for better performance.
Expand All @@ -1079,23 +1078,19 @@ where
.into(),
);
}

if header.key_len > MAX_KEY_LEN as u32 {
let tmp = header.key_len;
return Err(syscall_error!(IllegalArgument; "event key exceeded max size: {} > {MAX_KEY_LEN}", tmp).into());
return Err(syscall_error!(LimitExceeded; "event key exceeded max size: {} > {MAX_KEY_LEN}", tmp).into());
}
// We check this here purely to detect/prevent integer overflows.

// We check this here purely to detect/prevent integer overflows below. That's why we
// return IllegalArgument, not LimitExceeded.
if header.val_len > MAX_TOTAL_VALUES_LEN as u32 {
return Err(
syscall_error!(IllegalArgument; "event entry value out of range").into(),
);
}
if header.codec != IPLD_RAW {
let tmp = header.codec;
return Err(
syscall_error!(IllegalCodec; "event codec must be IPLD_RAW, was: {}", tmp)
.into(),
);
}

// parse the variable sized fields from the raw_key/raw_val buffers
let key = &event_keys
Expand All @@ -1108,6 +1103,15 @@ where
.context("event entry value out of range")
.or_illegal_argument()?;

// Check the codec. We currently only allow IPLD_RAW.
if header.codec != IPLD_RAW {
let tmp = header.codec;
return Err(
syscall_error!(IllegalCodec; "event codec must be IPLD_RAW, was: {}", tmp)
.into(),
);
}

// we have all we need to construct a new Entry
let entry = Entry {
flags: header.flags,
Expand All @@ -1123,6 +1127,24 @@ where
entries.push(entry);
}

if key_offset != event_keys.len() {
return Err(syscall_error!(IllegalArgument;
"event key buffer length is too large: {} < {}",
key_offset,
event_keys.len()
)
.into());
}

if val_offset != event_values.len() {
return Err(syscall_error!(IllegalArgument;
"event value buffer length is too large: {} < {}",
val_offset,
event_values.len()
)
.into());
}

let actor_evt = ActorEvent::from(entries);

let stamped_evt = StampedEvent::new(self.actor_id, actor_evt);
Expand Down
123 changes: 117 additions & 6 deletions testing/test_actors/actors/fil-events-actor/src/actor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use fvm_ipld_encoding::IPLD_RAW;
use fvm_sdk as sdk;
use fvm_shared::address::Address;
use fvm_shared::bigint::Zero;
use fvm_shared::error::ErrorNumber::*;
use fvm_shared::error::ExitCode;
use fvm_shared::event::{Entry, Flags};

Expand Down Expand Up @@ -59,7 +60,7 @@ pub fn invoke(params: u32) -> u32 {
key_len: 5,
val_len: 0,
};
assert!(
assert_eq!(
sdk::sys::event::emit_event(
&entry as *const fvm_shared::sys::EventEntry,
1,
Expand All @@ -68,7 +69,115 @@ pub fn invoke(params: u32) -> u32 {
ptr::null(),
0,
)
.is_err(),
.unwrap_err(),
IllegalArgument,
"expected failed syscall"
);

// Illegal Codec
let entry = fvm_shared::sys::EventEntry {
flags: Flags::empty(),
codec: 0x95,
key_len: 0,
val_len: 0,
};
assert_eq!(
sdk::sys::event::emit_event(
&entry as *const fvm_shared::sys::EventEntry,
1,
ptr::null(),
0,
ptr::null(),
0,
)
.unwrap_err(),
IllegalCodec,
"expected failed syscall"
);

let buf = vec![0; 100];

// Value buffer not consumed.
let entry = fvm_shared::sys::EventEntry {
flags: Flags::empty(),
codec: IPLD_RAW,
key_len: 0,
val_len: 5,
};
assert_eq!(
sdk::sys::event::emit_event(
&entry as *const fvm_shared::sys::EventEntry,
1,
ptr::null(),
0,
buf.as_ptr(),
buf.len() as u32,
)
.unwrap_err(),
IllegalArgument,
"expected failed syscall"
);

// Keys buffer not consumed.
let entry = fvm_shared::sys::EventEntry {
flags: Flags::empty(),
codec: IPLD_RAW,
key_len: 5,
val_len: 0,
};
assert_eq!(
sdk::sys::event::emit_event(
&entry as *const fvm_shared::sys::EventEntry,
1,
buf.as_ptr(),
buf.len() as u32,
ptr::null(),
0,
)
.unwrap_err(),
IllegalArgument,
"expected failed syscall"
);

// Key too large.
let entry = fvm_shared::sys::EventEntry {
flags: Flags::empty(),
codec: IPLD_RAW,
key_len: 32,
val_len: 0,
};
assert_eq!(
sdk::sys::event::emit_event(
&entry as *const fvm_shared::sys::EventEntry,
1,
ptr::null(),
0,
buf.as_ptr(),
buf.len() as u32,
)
.unwrap_err(),
LimitExceeded,
"expected failed syscall"
);

// Value too large.
let entry = fvm_shared::sys::EventEntry {
flags: Flags::empty(),
codec: IPLD_RAW,
key_len: 0,
val_len: 0,
};
assert_eq!(
sdk::sys::event::emit_event(
&entry as *const fvm_shared::sys::EventEntry,
1,
ptr::null(),
0,
buf.as_ptr(),
8192 + 1,
)
.unwrap_err(),
LimitExceeded,
"expected failed syscall"
);

Expand All @@ -82,7 +191,7 @@ pub fn invoke(params: u32) -> u32 {
key_len: 1,
val_len: 0,
};
assert!(
assert_eq!(
sdk::sys::event::emit_event(
&entry as *const fvm_shared::sys::EventEntry,
1,
Expand All @@ -91,7 +200,8 @@ pub fn invoke(params: u32) -> u32 {
ptr::null(),
0,
)
.is_err(),
.unwrap_err(),
IllegalArgument,
"expected failed syscall"
);
// Correct utf8 but invalid boundaries.
Expand All @@ -109,7 +219,7 @@ pub fn invoke(params: u32) -> u32 {
val_len: 0,
},
];
assert!(
assert_eq!(
sdk::sys::event::emit_event(
entries.as_ptr(),
2,
Expand All @@ -118,7 +228,8 @@ pub fn invoke(params: u32) -> u32 {
ptr::null(),
0,
)
.is_err(),
.unwrap_err(),
IllegalArgument,
"expected failed syscall"
);
},
Expand Down

0 comments on commit a3db798

Please sign in to comment.