Skip to content

Commit a3db798

Browse files
authored
feat: cleanup event error cases (#1886)
1. Fail with LimitExceeded where it makes sense. 2. Validate that we comsume all keys/values.
1 parent 790537f commit a3db798

File tree

2 files changed

+151
-18
lines changed

2 files changed

+151
-18
lines changed

fvm/src/kernel/default.rs

+34-12
Original file line numberDiff line numberDiff line change
@@ -1053,12 +1053,11 @@ where
10531053
))?;
10541054

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

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

10641063
// We validate utf8 all at once for better performance.
@@ -1079,23 +1078,19 @@ where
10791078
.into(),
10801079
);
10811080
}
1081+
10821082
if header.key_len > MAX_KEY_LEN as u32 {
10831083
let tmp = header.key_len;
1084-
return Err(syscall_error!(IllegalArgument; "event key exceeded max size: {} > {MAX_KEY_LEN}", tmp).into());
1084+
return Err(syscall_error!(LimitExceeded; "event key exceeded max size: {} > {MAX_KEY_LEN}", tmp).into());
10851085
}
1086-
// We check this here purely to detect/prevent integer overflows.
1086+
1087+
// We check this here purely to detect/prevent integer overflows below. That's why we
1088+
// return IllegalArgument, not LimitExceeded.
10871089
if header.val_len > MAX_TOTAL_VALUES_LEN as u32 {
10881090
return Err(
10891091
syscall_error!(IllegalArgument; "event entry value out of range").into(),
10901092
);
10911093
}
1092-
if header.codec != IPLD_RAW {
1093-
let tmp = header.codec;
1094-
return Err(
1095-
syscall_error!(IllegalCodec; "event codec must be IPLD_RAW, was: {}", tmp)
1096-
.into(),
1097-
);
1098-
}
10991094

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

1106+
// Check the codec. We currently only allow IPLD_RAW.
1107+
if header.codec != IPLD_RAW {
1108+
let tmp = header.codec;
1109+
return Err(
1110+
syscall_error!(IllegalCodec; "event codec must be IPLD_RAW, was: {}", tmp)
1111+
.into(),
1112+
);
1113+
}
1114+
11111115
// we have all we need to construct a new Entry
11121116
let entry = Entry {
11131117
flags: header.flags,
@@ -1123,6 +1127,24 @@ where
11231127
entries.push(entry);
11241128
}
11251129

1130+
if key_offset != event_keys.len() {
1131+
return Err(syscall_error!(IllegalArgument;
1132+
"event key buffer length is too large: {} < {}",
1133+
key_offset,
1134+
event_keys.len()
1135+
)
1136+
.into());
1137+
}
1138+
1139+
if val_offset != event_values.len() {
1140+
return Err(syscall_error!(IllegalArgument;
1141+
"event value buffer length is too large: {} < {}",
1142+
val_offset,
1143+
event_values.len()
1144+
)
1145+
.into());
1146+
}
1147+
11261148
let actor_evt = ActorEvent::from(entries);
11271149

11281150
let stamped_evt = StampedEvent::new(self.actor_id, actor_evt);

testing/test_actors/actors/fil-events-actor/src/actor.rs

+117-6
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use fvm_ipld_encoding::IPLD_RAW;
77
use fvm_sdk as sdk;
88
use fvm_shared::address::Address;
99
use fvm_shared::bigint::Zero;
10+
use fvm_shared::error::ErrorNumber::*;
1011
use fvm_shared::error::ExitCode;
1112
use fvm_shared::event::{Entry, Flags};
1213

@@ -59,7 +60,7 @@ pub fn invoke(params: u32) -> u32 {
5960
key_len: 5,
6061
val_len: 0,
6162
};
62-
assert!(
63+
assert_eq!(
6364
sdk::sys::event::emit_event(
6465
&entry as *const fvm_shared::sys::EventEntry,
6566
1,
@@ -68,7 +69,115 @@ pub fn invoke(params: u32) -> u32 {
6869
ptr::null(),
6970
0,
7071
)
71-
.is_err(),
72+
.unwrap_err(),
73+
IllegalArgument,
74+
"expected failed syscall"
75+
);
76+
77+
// Illegal Codec
78+
let entry = fvm_shared::sys::EventEntry {
79+
flags: Flags::empty(),
80+
codec: 0x95,
81+
key_len: 0,
82+
val_len: 0,
83+
};
84+
assert_eq!(
85+
sdk::sys::event::emit_event(
86+
&entry as *const fvm_shared::sys::EventEntry,
87+
1,
88+
ptr::null(),
89+
0,
90+
ptr::null(),
91+
0,
92+
)
93+
.unwrap_err(),
94+
IllegalCodec,
95+
"expected failed syscall"
96+
);
97+
98+
let buf = vec![0; 100];
99+
100+
// Value buffer not consumed.
101+
let entry = fvm_shared::sys::EventEntry {
102+
flags: Flags::empty(),
103+
codec: IPLD_RAW,
104+
key_len: 0,
105+
val_len: 5,
106+
};
107+
assert_eq!(
108+
sdk::sys::event::emit_event(
109+
&entry as *const fvm_shared::sys::EventEntry,
110+
1,
111+
ptr::null(),
112+
0,
113+
buf.as_ptr(),
114+
buf.len() as u32,
115+
)
116+
.unwrap_err(),
117+
IllegalArgument,
118+
"expected failed syscall"
119+
);
120+
121+
// Keys buffer not consumed.
122+
let entry = fvm_shared::sys::EventEntry {
123+
flags: Flags::empty(),
124+
codec: IPLD_RAW,
125+
key_len: 5,
126+
val_len: 0,
127+
};
128+
assert_eq!(
129+
sdk::sys::event::emit_event(
130+
&entry as *const fvm_shared::sys::EventEntry,
131+
1,
132+
buf.as_ptr(),
133+
buf.len() as u32,
134+
ptr::null(),
135+
0,
136+
)
137+
.unwrap_err(),
138+
IllegalArgument,
139+
"expected failed syscall"
140+
);
141+
142+
// Key too large.
143+
let entry = fvm_shared::sys::EventEntry {
144+
flags: Flags::empty(),
145+
codec: IPLD_RAW,
146+
key_len: 32,
147+
val_len: 0,
148+
};
149+
assert_eq!(
150+
sdk::sys::event::emit_event(
151+
&entry as *const fvm_shared::sys::EventEntry,
152+
1,
153+
ptr::null(),
154+
0,
155+
buf.as_ptr(),
156+
buf.len() as u32,
157+
)
158+
.unwrap_err(),
159+
LimitExceeded,
160+
"expected failed syscall"
161+
);
162+
163+
// Value too large.
164+
let entry = fvm_shared::sys::EventEntry {
165+
flags: Flags::empty(),
166+
codec: IPLD_RAW,
167+
key_len: 0,
168+
val_len: 0,
169+
};
170+
assert_eq!(
171+
sdk::sys::event::emit_event(
172+
&entry as *const fvm_shared::sys::EventEntry,
173+
1,
174+
ptr::null(),
175+
0,
176+
buf.as_ptr(),
177+
8192 + 1,
178+
)
179+
.unwrap_err(),
180+
LimitExceeded,
72181
"expected failed syscall"
73182
);
74183

@@ -82,7 +191,7 @@ pub fn invoke(params: u32) -> u32 {
82191
key_len: 1,
83192
val_len: 0,
84193
};
85-
assert!(
194+
assert_eq!(
86195
sdk::sys::event::emit_event(
87196
&entry as *const fvm_shared::sys::EventEntry,
88197
1,
@@ -91,7 +200,8 @@ pub fn invoke(params: u32) -> u32 {
91200
ptr::null(),
92201
0,
93202
)
94-
.is_err(),
203+
.unwrap_err(),
204+
IllegalArgument,
95205
"expected failed syscall"
96206
);
97207
// Correct utf8 but invalid boundaries.
@@ -109,7 +219,7 @@ pub fn invoke(params: u32) -> u32 {
109219
val_len: 0,
110220
},
111221
];
112-
assert!(
222+
assert_eq!(
113223
sdk::sys::event::emit_event(
114224
entries.as_ptr(),
115225
2,
@@ -118,7 +228,8 @@ pub fn invoke(params: u32) -> u32 {
118228
ptr::null(),
119229
0,
120230
)
121-
.is_err(),
231+
.unwrap_err(),
232+
IllegalArgument,
122233
"expected failed syscall"
123234
);
124235
},

0 commit comments

Comments
 (0)