@@ -1185,24 +1185,26 @@ pub fn build_slice<'ctx, 'this>(
11851185
11861186 let slice_start = entry. argument ( 2 ) ?. into ( ) ;
11871187 let slice_len = entry. argument ( 3 ) ?. into ( ) ;
1188- let slice_end = entry. append_op_result ( arith:: addi ( slice_start, slice_len, location) ) ?;
11891188
1190- let slice_lhs_bound = entry. append_op_result ( arith:: cmpi (
1189+ // Compute `slice_end = slice_start + slice_len` in 64 bits. In 32-bit
1190+ // arithmetic the sum wraps and lets an attacker-chosen `slice_len`
1191+ // sneak past the bound below. Since `slice_len` is unsigned (Sierra
1192+ // u32) it cannot be negative, so once we've checked
1193+ // `slice_end <= array_len` we also know `slice_start <= array_len`.
1194+ let wide_ty = IntegerType :: new ( context, 64 ) . into ( ) ;
1195+ let slice_start_wide = entry. extui ( slice_start, wide_ty, location) ?;
1196+ let slice_len_wide = entry. extui ( slice_len, wide_ty, location) ?;
1197+ let array_len_wide = entry. extui ( array_len, wide_ty, location) ?;
1198+ let slice_end_wide =
1199+ entry. append_op_result ( arith:: addi ( slice_start_wide, slice_len_wide, location) ) ?;
1200+
1201+ let slice_bounds = entry. append_op_result ( arith:: cmpi (
11911202 context,
11921203 CmpiPredicate :: Ule ,
1193- slice_start,
1194- array_len,
1195- location,
1196- ) ) ?;
1197- let slice_rhs_bound = entry. append_op_result ( arith:: cmpi (
1198- context,
1199- CmpiPredicate :: Ule ,
1200- slice_end,
1201- array_len,
1204+ slice_end_wide,
1205+ array_len_wide,
12021206 location,
12031207 ) ) ?;
1204- let slice_bounds =
1205- entry. append_op_result ( arith:: andi ( slice_lhs_bound, slice_rhs_bound, location) ) ?;
12061208
12071209 let valid_block = helper. append_block ( Block :: new ( & [ ] ) ) ;
12081210 let error_block = helper. append_block ( Block :: new ( & [ ] ) ) ;
0 commit comments