Commit f863f222 authored by Dafna Hirschfeld's avatar Dafna Hirschfeld Committed by Mauro Carvalho Chehab
Browse files

media: vicodec: ensure comp frame pointer kept in range



Make sure that the pointer to the compressed frame does not
get out of the buffer.

Signed-off-by: default avatarDafna Hirschfeld <dafna3@gmail.com>
Signed-off-by: default avatarHans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab+samsung@kernel.org>
parent 3b15f68e
Loading
Loading
Loading
Loading
+50 −21
Original line number Diff line number Diff line
@@ -13,6 +13,8 @@
#include <linux/kernel.h>
#include "codec-fwht.h"

#define OVERFLOW_BIT BIT(14)

/*
 * Note: bit 0 of the header must always be 0. Otherwise it cannot
 * be guaranteed that the magic 8 byte sequence (see below) can
@@ -104,16 +106,21 @@ static int rlc(const s16 *in, __be16 *output, int blocktype)
 * This function will worst-case increase rlc_in by 65*2 bytes:
 * one s16 value for the header and 8 * 8 coefficients of type s16.
 */
static s16 derlc(const __be16 **rlc_in, s16 *dwht_out)
static u16 derlc(const __be16 **rlc_in, s16 *dwht_out,
		 const __be16 *end_of_input)
{
	/* header */
	const __be16 *input = *rlc_in;
	s16 ret = ntohs(*input++);
	u16 stat;
	int dec_count = 0;
	s16 block[8 * 8 + 16];
	s16 *wp = block;
	int i;

	if (input > end_of_input)
		return OVERFLOW_BIT;
	stat = ntohs(*input++);

	/*
	 * Now de-compress, it expands one byte to up to 15 bytes
	 * (or fills the remainder of the 64 bytes with zeroes if it
@@ -123,9 +130,15 @@ static s16 derlc(const __be16 **rlc_in, s16 *dwht_out)
	 * allow for overflow if the incoming data was malformed.
	 */
	while (dec_count < 8 * 8) {
		s16 in = ntohs(*input++);
		int length = in & 0xf;
		int coeff = in >> 4;
		s16 in;
		int length;
		int coeff;

		if (input > end_of_input)
			return OVERFLOW_BIT;
		in = ntohs(*input++);
		length = in & 0xf;
		coeff = in >> 4;

		/* fill remainder with zeros */
		if (length == 15) {
@@ -150,7 +163,7 @@ static s16 derlc(const __be16 **rlc_in, s16 *dwht_out)
		dwht_out[x + y * 8] = *wp++;
	}
	*rlc_in = input;
	return ret;
	return stat;
}

static const int quant_table[] = {
@@ -808,22 +821,24 @@ u32 fwht_encode_frame(struct fwht_raw_frame *frm,
	return encoding;
}

static void decode_plane(struct fwht_cframe *cf, const __be16 **rlco, u8 *ref,
static bool decode_plane(struct fwht_cframe *cf, const __be16 **rlco, u8 *ref,
			 u32 height, u32 width, u32 coded_width,
			 bool uncompressed)
			 bool uncompressed, const __be16 *end_of_rlco_buf)
{
	unsigned int copies = 0;
	s16 copy[8 * 8];
	s16 stat;
	u16 stat;
	unsigned int i, j;

	width = round_up(width, 8);
	height = round_up(height, 8);

	if (uncompressed) {
		if (end_of_rlco_buf + 1 < *rlco + width * height / 2)
			return false;
		memcpy(ref, *rlco, width * height);
		*rlco += width * height / 2;
		return;
		return true;
	}

	/*
@@ -847,8 +862,9 @@ static void decode_plane(struct fwht_cframe *cf, const __be16 **rlco, u8 *ref,
				continue;
			}

			stat = derlc(rlco, cf->coeffs);

			stat = derlc(rlco, cf->coeffs, end_of_rlco_buf);
			if (stat & OVERFLOW_BIT)
				return false;
			if (stat & PFRAME_BIT)
				dequantize_inter(cf->coeffs);
			else
@@ -865,17 +881,22 @@ static void decode_plane(struct fwht_cframe *cf, const __be16 **rlco, u8 *ref,
			fill_decoder_block(refp, cf->de_fwht, coded_width);
		}
	}
	return true;
}

void fwht_decode_frame(struct fwht_cframe *cf, struct fwht_raw_frame *ref,
bool fwht_decode_frame(struct fwht_cframe *cf, struct fwht_raw_frame *ref,
		       u32 hdr_flags, unsigned int components_num,
		       unsigned int width, unsigned int height,
		       unsigned int coded_width)
{
	const __be16 *rlco = cf->rlc_data;
	const __be16 *end_of_rlco_buf = cf->rlc_data +
			(cf->size / sizeof(*rlco)) - 1;

	decode_plane(cf, &rlco, ref->luma, height, width, coded_width,
		     hdr_flags & FWHT_FL_LUMA_IS_UNCOMPRESSED);
	if (!decode_plane(cf, &rlco, ref->luma, height, width, coded_width,
			  hdr_flags & FWHT_FL_LUMA_IS_UNCOMPRESSED,
			  end_of_rlco_buf))
		return false;

	if (components_num >= 3) {
		u32 h = height;
@@ -888,13 +909,21 @@ void fwht_decode_frame(struct fwht_cframe *cf, struct fwht_raw_frame *ref,
			w /= 2;
			c /= 2;
		}
		decode_plane(cf, &rlco, ref->cb, h, w, c,
			     hdr_flags & FWHT_FL_CB_IS_UNCOMPRESSED);
		decode_plane(cf, &rlco, ref->cr, h, w, c,
			     hdr_flags & FWHT_FL_CR_IS_UNCOMPRESSED);
		if (!decode_plane(cf, &rlco, ref->cb, h, w, c,
				  hdr_flags & FWHT_FL_CB_IS_UNCOMPRESSED,
				  end_of_rlco_buf))
			return false;
		if (!decode_plane(cf, &rlco, ref->cr, h, w, c,
				  hdr_flags & FWHT_FL_CR_IS_UNCOMPRESSED,
				  end_of_rlco_buf))
			return false;
	}

	if (components_num == 4)
		decode_plane(cf, &rlco, ref->alpha, height, width, coded_width,
			     hdr_flags & FWHT_FL_ALPHA_IS_UNCOMPRESSED);
		if (!decode_plane(cf, &rlco, ref->alpha, height, width,
				  coded_width,
				  hdr_flags & FWHT_FL_ALPHA_IS_UNCOMPRESSED,
				  end_of_rlco_buf))
			return false;
	return true;
}
+1 −1
Original line number Diff line number Diff line
@@ -139,7 +139,7 @@ u32 fwht_encode_frame(struct fwht_raw_frame *frm,
		      bool is_intra, bool next_is_intra,
		      unsigned int width, unsigned int height,
		      unsigned int stride, unsigned int chroma_stride);
void fwht_decode_frame(struct fwht_cframe *cf, struct fwht_raw_frame *ref,
bool fwht_decode_frame(struct fwht_cframe *cf, struct fwht_raw_frame *ref,
		       u32 hdr_flags, unsigned int components_num,
		       unsigned int width, unsigned int height,
		       unsigned int coded_width);
+5 −3
Original line number Diff line number Diff line
@@ -280,6 +280,7 @@ int v4l2_fwht_decode(struct v4l2_fwht_state *state, u8 *p_in, u8 *p_out)
	state->ycbcr_enc = ntohl(state->header.ycbcr_enc);
	state->quantization = ntohl(state->header.quantization);
	cf.rlc_data = (__be16 *)p_in;
	cf.size = ntohl(state->header.size);

	hdr_width_div = (flags & FWHT_FL_CHROMA_FULL_WIDTH) ? 1 : 2;
	hdr_height_div = (flags & FWHT_FL_CHROMA_FULL_HEIGHT) ? 1 : 2;
@@ -287,9 +288,10 @@ int v4l2_fwht_decode(struct v4l2_fwht_state *state, u8 *p_in, u8 *p_out)
	    hdr_height_div != info->height_div)
		return -EINVAL;

	fwht_decode_frame(&cf, &state->ref_frame, flags, components_num,
	if (!fwht_decode_frame(&cf, &state->ref_frame, flags, components_num,
			       state->visible_width, state->visible_height,
			  state->coded_width);
			       state->coded_width))
		return -EINVAL;

	/*
	 * TODO - handle the case where the compressed stream encodes a
+4 −0
Original line number Diff line number Diff line
@@ -186,6 +186,10 @@ static int device_process(struct vicodec_ctx *ctx,
			return ret;
		vb2_set_plane_payload(&dst_vb->vb2_buf, 0, ret);
	} else {
		unsigned int comp_frame_size = ntohl(ctx->state.header.size);

		if (comp_frame_size > ctx->comp_max_size)
			return -EINVAL;
		state->info = q_dst->info;
		ret = v4l2_fwht_decode(state, p_src, p_dst);
		if (ret < 0)