Skip to content

Commit 6928350

Browse files
committed
Merge pull request #1587 from bettio/fix-use-after-free
Fix use after free in `bs_append` and `bs_get_binary2` CI should pass also with OTP-21 now. Note: this appears to be an OTP-21 compiler bug, however the fix is still an improvement on opcode parameters handling. These changes are made under both the "Apache 2.0" and the "GNU Lesser General Public License 2.1 or later" license terms (dual license). SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later
2 parents a580744 + 564a0e7 commit 6928350

File tree

2 files changed

+9
-12
lines changed

2 files changed

+9
-12
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ memory error
5959
- Fixed concurrency and memory leak related to links and monitors
6060
- Fixed issues with parsing of line references for stack traces
6161
- Fixed memory corruption issue with `erlang:make_tuple/2`
62+
- Fix potential use after free with code generated from OTP <= 24
6263

6364
### Changed
6465

src/libAtomVM/opcodesswitch.h

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4337,9 +4337,6 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb)
43374337
uint32_t unit;
43384338
DECODE_LITERAL(unit, pc);
43394339
term src;
4340-
#ifdef IMPL_EXECUTE_LOOP
4341-
const uint8_t *src_pc = pc;
4342-
#endif
43434340
DECODE_COMPACT_TERM(src, pc)
43444341
term flags;
43454342
UNUSED(flags);
@@ -4367,8 +4364,10 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb)
43674364

43684365
size_t src_size = term_binary_size(src);
43694366
TRIM_LIVE_REGS(live);
4367+
// there is always room for a MAX_REG + 1 register, used as working register
4368+
x_regs[live] = src;
43704369
// TODO: further investigate extra_val
4371-
if (UNLIKELY(memory_ensure_free_with_roots(ctx, src_size + term_binary_heap_size(size_val / 8) + extra_val, live, x_regs, MEMORY_CAN_SHRINK) != MEMORY_GC_OK)) {
4370+
if (UNLIKELY(memory_ensure_free_with_roots(ctx, src_size + term_binary_heap_size(size_val / 8) + extra_val, live + 1, x_regs, MEMORY_CAN_SHRINK) != MEMORY_GC_OK)) {
43724371
RAISE_ERROR(OUT_OF_MEMORY_ATOM);
43734372
}
43744373
#endif
@@ -4378,7 +4377,7 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb)
43784377

43794378
#ifdef IMPL_EXECUTE_LOOP
43804379
TRACE("bs_append/8, fail=%u size=%li unit=%u src=0x%lx dreg=%c%i\n", (unsigned) fail, size_val, (unsigned) unit, src, T_DEST_REG(dreg));
4381-
DECODE_COMPACT_TERM(src, src_pc)
4380+
src = x_regs[live];
43824381
term t = term_create_empty_binary(src_size + size_val / 8, &ctx->heap, ctx->global);
43834382
memcpy((void *) term_binary_data(t), (void *) term_binary_data(src), src_size);
43844383

@@ -5104,9 +5103,6 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb)
51045103
uint32_t fail;
51055104
DECODE_LABEL(fail, pc)
51065105
term src;
5107-
#ifdef IMPL_EXECUTE_LOOP
5108-
const uint8_t *src_pc = pc;
5109-
#endif
51105106
DECODE_COMPACT_TERM(src, pc);
51115107
uint32_t live;
51125108
DECODE_LITERAL(live, pc);
@@ -5158,8 +5154,10 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb)
51585154
term_set_match_state_offset(src, bs_offset + size_val * unit);
51595155

51605156
TRIM_LIVE_REGS(live);
5157+
// there is always room for a MAX_REG + 1 register, used as working register
5158+
x_regs[live] = bs_bin;
51615159
size_t heap_size = term_sub_binary_heap_size(bs_bin, size_val);
5162-
if (UNLIKELY(memory_ensure_free_with_roots(ctx, heap_size, live, x_regs, MEMORY_CAN_SHRINK) != MEMORY_GC_OK)) {
5160+
if (UNLIKELY(memory_ensure_free_with_roots(ctx, heap_size, live + 1, x_regs, MEMORY_CAN_SHRINK) != MEMORY_GC_OK)) {
51635161
RAISE_ERROR(OUT_OF_MEMORY_ATOM);
51645162
}
51655163
#endif
@@ -5168,9 +5166,7 @@ HOT_FUNC int scheduler_entry_point(GlobalContext *glb)
51685166
DECODE_DEST_REGISTER(dreg, pc);
51695167

51705168
#ifdef IMPL_EXECUTE_LOOP
5171-
// re-compute src
5172-
DECODE_COMPACT_TERM(src, src_pc);
5173-
bs_bin = term_get_match_state_binary(src);
5169+
bs_bin = x_regs[live];
51745170

51755171
term t = term_maybe_create_sub_binary(bs_bin, bs_offset / unit, size_val, &ctx->heap, ctx->global);
51765172
WRITE_REGISTER(dreg, t);

0 commit comments

Comments
 (0)