mirror of
https://github.com/mpv-player/mpv
synced 2024-12-29 10:32:15 +00:00
zimg: fix out of bounds memory accesses due to broken zmask
We've set all planes to the same zmask. But for subsampled chroma, the zmask obviously needs to be smaller. This could lead to out of bounds memory read and write accesses. Move the align repacker to a single function, since this is now more convenient.
This commit is contained in:
parent
871900f562
commit
4b3666329e
76
video/zimg.c
76
video/zimg.c
@ -76,7 +76,7 @@ struct mp_zimg_repack {
|
||||
struct mp_image_params fmt; // original mp format (possibly packed format)
|
||||
int zimgfmt; // zimg equivalent unpacked format
|
||||
int zplanes; // number of planes (zimgfmt)
|
||||
unsigned zmask; // zimg_image_buffer.mask
|
||||
unsigned zmask[4]; // zmask[n] = zimg_image_buffer.plane[n].mask
|
||||
int z_planes[4]; // z_planes[zimg_index] = mp_index
|
||||
|
||||
// If set, the pack/unpack callback to pass to zimg.
|
||||
@ -214,43 +214,32 @@ void mp_zimg_enable_cmdline_opts(struct mp_zimg_context *ctx,
|
||||
mp_zimg_update_from_cmdline(ctx); // first update
|
||||
}
|
||||
|
||||
static void copy_rect(struct mp_image *dst, unsigned dst_mask,
|
||||
struct mp_image *src, unsigned src_mask,
|
||||
unsigned i, unsigned x0, unsigned x1)
|
||||
static int repack_align(void *user, unsigned i, unsigned x0, unsigned x1)
|
||||
{
|
||||
for (int p = 0; p < dst->fmt.num_planes; p++) {
|
||||
int bpp = dst->fmt.bytes[p];
|
||||
int xs = dst->fmt.xs[p];
|
||||
int ys = dst->fmt.ys[p];
|
||||
struct mp_zimg_repack *r = user;
|
||||
|
||||
for (int p = 0; p < r->mpi->fmt.num_planes; p++) {
|
||||
int bpp = r->mpi->fmt.bytes[p];
|
||||
int xs = r->mpi->fmt.xs[p];
|
||||
int ys = r->mpi->fmt.ys[p];
|
||||
// Number of lines on this plane.
|
||||
int h = (1 << dst->fmt.chroma_ys) - (1 << ys) + 1;
|
||||
int h = (1 << r->mpi->fmt.chroma_ys) - (1 << ys) + 1;
|
||||
|
||||
for (int y = i; y < i + h; y++) {
|
||||
void *psrc = src->planes[p] +
|
||||
src->stride[p] * (ptrdiff_t)((y >> ys) & src_mask) +
|
||||
bpp * (x0 >> xs);
|
||||
void *pdst = dst->planes[p] +
|
||||
dst->stride[p] * (ptrdiff_t)((y >> ys) & dst_mask) +
|
||||
bpp * (x0 >> xs);
|
||||
memcpy(pdst, psrc, ((x1 - x0) >> xs) * bpp);
|
||||
void *a = r->mpi->planes[p] +
|
||||
r->mpi->stride[p] * (ptrdiff_t)(y >> ys) +
|
||||
bpp * (x0 >> xs);
|
||||
void *b = r->tmp->planes[p] +
|
||||
r->tmp->stride[p] * (ptrdiff_t)((y >> ys) & r->zmask[p]) +
|
||||
bpp * (x0 >> xs);
|
||||
size_t size = ((x1 - x0) >> xs) * bpp;
|
||||
if (r->pack) {
|
||||
memcpy(a, b, size);
|
||||
} else {
|
||||
memcpy(b, a, size);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int align_pack(void *user, unsigned i, unsigned x0, unsigned x1)
|
||||
{
|
||||
struct mp_zimg_repack *r = user;
|
||||
|
||||
copy_rect(r->mpi, ZIMG_BUFFER_MAX, r->tmp, r->zmask, i, x0, x1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int align_unpack(void *user, unsigned i, unsigned x0, unsigned x1)
|
||||
{
|
||||
struct mp_zimg_repack *r = user;
|
||||
|
||||
copy_rect(r->tmp, r->zmask, r->mpi, ZIMG_BUFFER_MAX, i, x0, x1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -351,7 +340,8 @@ static int packed_repack(void *user, unsigned i, unsigned x0, unsigned x1)
|
||||
void *p2[3];
|
||||
for (int p = 0; p < 3; p++) {
|
||||
int s = r->components[p];
|
||||
p2[p] = r->tmp->planes[s] + r->tmp->stride[s] * (ptrdiff_t)(i & r->zmask);
|
||||
p2[p] = r->tmp->planes[s] +
|
||||
r->tmp->stride[s] * (ptrdiff_t)(i & r->zmask[s]);
|
||||
}
|
||||
|
||||
r->packed_repack_scanline(p1, p2, x0, x1);
|
||||
@ -379,7 +369,7 @@ static void wrap_buffer(struct mp_zimg_repack *r,
|
||||
if (aligned) {
|
||||
wrap_mpi = mpi;
|
||||
} else {
|
||||
*cb = r->pack ? align_pack : align_unpack;
|
||||
*cb = repack_align;
|
||||
}
|
||||
}
|
||||
|
||||
@ -387,7 +377,7 @@ static void wrap_buffer(struct mp_zimg_repack *r,
|
||||
int mplane = r->z_planes[n];
|
||||
buf->plane[n].data = wrap_mpi->planes[mplane];
|
||||
buf->plane[n].stride = wrap_mpi->stride[mplane];
|
||||
buf->plane[n].mask = wrap_mpi == mpi ? ZIMG_BUFFER_MAX : r->zmask;
|
||||
buf->plane[n].mask = wrap_mpi == mpi ? ZIMG_BUFFER_MAX : r->zmask[n];
|
||||
}
|
||||
|
||||
r->mpi = mpi;
|
||||
@ -584,20 +574,28 @@ static bool allocate_buffer(struct mp_zimg_context *ctx,
|
||||
if (err)
|
||||
return false;
|
||||
|
||||
r->zmask = zimg_select_buffer_mask(lines);
|
||||
r->zmask[0] = zimg_select_buffer_mask(lines);
|
||||
|
||||
// Either ZIMG_BUFFER_MAX, or a power-of-2 slice buffer.
|
||||
assert(r->zmask == ZIMG_BUFFER_MAX || MP_IS_POWER_OF_2(r->zmask + 1));
|
||||
assert(r->zmask[0] == ZIMG_BUFFER_MAX || MP_IS_POWER_OF_2(r->zmask[0] + 1));
|
||||
|
||||
int h = r->zmask == ZIMG_BUFFER_MAX ? r->fmt.h : r->zmask + 1;
|
||||
int h = r->zmask[0] == ZIMG_BUFFER_MAX ? r->fmt.h : r->zmask[0] + 1;
|
||||
if (h >= r->fmt.h) {
|
||||
h = r->fmt.h;
|
||||
r->zmask = ZIMG_BUFFER_MAX;
|
||||
r->zmask[0] = ZIMG_BUFFER_MAX;
|
||||
}
|
||||
|
||||
r->tmp = mp_image_alloc(r->zimgfmt, r->fmt.w, h);
|
||||
talloc_steal(r, r->tmp);
|
||||
|
||||
if (r->tmp) {
|
||||
for (int n = 1; n < r->tmp->fmt.num_planes; n++) {
|
||||
r->zmask[n] = r->zmask[0];
|
||||
if (r->zmask[0] != ZIMG_BUFFER_MAX)
|
||||
r->zmask[n] = r->zmask[n] >> r->tmp->fmt.ys[n];
|
||||
}
|
||||
}
|
||||
|
||||
return !!r->tmp;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user