sframe fre sanity checks
Indu Bhagat
indu.bhagat@oracle.com
Thu Jan 22 06:57:00 GMT 2026
On 1/20/26 3:38 PM, Alan Modra wrote:
> I noticed the fre esz check in flip_sframe_fdes_with_fres_* was wrong,
> testing against the full buffer size rather than the remaining size.
> It is also ineffective at stopping buffer overflows to check after the
> buffer accesses have occurred.
>
> Likely many more buffer overflow checks in the sframe code are needed
> before anyone can claim it is secure. Even in the fre code, I see
> things like sframe_decoder_get_fres_buf merrily iterating over fres
> without a concern for buffer overflow.
>
Hmm, I think I need to keep the size of the original buffer in the
sframe_decoder_ctx object, and always check against that before
returning the fres_buf_size.
> * sframe.c (flip_fre): Add fp_size param. Use it to avoid
> buffer overflow on fuzzed input.
> (flip_sframe_fdes_with_fres_v2): Pass remaining buffer size to
> flip_fre. Remove now redundant and wrong esz check.
> (flip_sframe_fdes_with_fres_v3): Likewise.
>
> OK to apply?
>
LGTM. Thanks.
> diff --git a/libsframe/sframe.c b/libsframe/sframe.c
> index e915d363ca2..a0d4a408be0 100644
> --- a/libsframe/sframe.c
> +++ b/libsframe/sframe.c
> @@ -657,35 +657,44 @@ sframe_decode_fde_attr_v3 (const char *buf, size_t buf_size,
> *fre_type = SFRAME_V3_FDE_FRE_TYPE (fdap->sfda_func_info);
> return 0;
> }
> +
> static int
> -flip_fre (char *fp, uint32_t fre_type, size_t *fre_size)
> +flip_fre (char *fp, size_t fp_size, uint32_t fre_type, size_t *fre_size)
> {
> uint8_t fre_info;
> uint8_t offset_size, offset_cnt;
> - size_t addr_size, fre_info_size = 0;
> + size_t addr_size, fre_info_size, offset_bytes_size;
> int err = 0;
>
> if (fre_size == NULL)
> return sframe_set_errno (&err, SFRAME_ERR_INVAL);
>
> + addr_size = sframe_fre_start_addr_size (fre_type);
> + if (addr_size > fp_size)
> + return SFRAME_ERR;
> flip_fre_start_address (fp, fre_type);
>
> /* Advance the buffer pointer to where the FRE info is. */
> - addr_size = sframe_fre_start_addr_size (fre_type);
> fp += addr_size;
> + fp_size -= addr_size;
>
> /* FRE info is uint8_t. No need to flip. */
> + fre_info_size = sizeof (uint8_t);
> + if (fre_info_size > fp_size)
> + return SFRAME_ERR;
> fre_info = *(uint8_t*)fp;
> offset_size = sframe_fre_get_offset_size (fre_info);
> offset_cnt = sframe_fre_get_offset_count (fre_info);
>
> /* Advance the buffer pointer to where the stack offsets are. */
> - fre_info_size = sizeof (uint8_t);
> fp += fre_info_size;
> + fp_size -= fre_info_size;
> + offset_bytes_size = sframe_fre_offset_bytes_size (fre_info);
> + if (offset_bytes_size > fp_size)
> + return SFRAME_ERR;
> flip_fre_stack_offsets (fp, offset_size, offset_cnt);
>
> - *fre_size
> - = addr_size + fre_info_size + sframe_fre_offset_bytes_size (fre_info);
> + *fre_size = addr_size + fre_info_size + offset_bytes_size;
>
> return 0;
> }
> @@ -758,12 +767,9 @@ flip_sframe_fdes_with_fres_v2 (char *frame_buf, size_t buf_size,
> fp = fres + fre_offset;
> for (; j < prev_frep_index + num_fres; j++)
> {
> - if (flip_fre (fp, fre_type, &esz))
> + if (flip_fre (fp, buf_end - fp, fre_type, &esz))
> goto bad;
> fre_bytes_flipped += esz;
> -
> - if (esz == 0 || esz > buf_size)
> - goto bad;
> fp += esz;
> }
> prev_frep_index = j;
> @@ -870,12 +876,9 @@ flip_sframe_fdes_with_fres_v3 (char *frame_buf, size_t buf_size,
> fp += sizeof (sframe_func_desc_attr_v3);
> for (; j < prev_frep_index + num_fres; j++)
> {
> - if (flip_fre (fp, fre_type, &esz))
> + if (flip_fre (fp, buf_end - fp, fre_type, &esz))
> goto bad;
> fre_bytes_flipped += esz;
> -
> - if (esz == 0 || esz > buf_size)
> - goto bad;
> fp += esz;
> }
> prev_frep_index = j;
>
More information about the Binutils
mailing list