1
1
mirror of https://github.com/systemd/systemd-stable.git synced 2025-01-06 13:17:44 +03:00

stub: Fix unaligned read

(cherry picked from commit 024951fb22)
This commit is contained in:
Jan Janssen 2023-02-21 18:05:10 +01:00 committed by Zbigniew Jędrzejewski-Szmek
parent 44c2ff5b1e
commit 8d8240bdf6

View File

@ -5,6 +5,7 @@
#include "graphics.h" #include "graphics.h"
#include "splash.h" #include "splash.h"
#include "unaligned-fundamental.h"
#include "util.h" #include "util.h"
struct bmp_file { struct bmp_file {
@ -28,8 +29,16 @@ struct bmp_dib {
int32_t y_pixel_meter; int32_t y_pixel_meter;
uint32_t colors_used; uint32_t colors_used;
uint32_t colors_important; uint32_t colors_important;
uint32_t channel_mask_r;
uint32_t channel_mask_g;
uint32_t channel_mask_b;
uint32_t channel_mask_a;
} _packed_; } _packed_;
#define SIZEOF_BMP_DIB offsetof(struct bmp_dib, channel_mask_r)
#define SIZEOF_BMP_DIB_RGB offsetof(struct bmp_dib, channel_mask_a)
#define SIZEOF_BMP_DIB_RGBA sizeof(struct bmp_dib)
struct bmp_map { struct bmp_map {
uint8_t blue; uint8_t blue;
uint8_t green; uint8_t green;
@ -49,7 +58,7 @@ static EFI_STATUS bmp_parse_header(
assert(ret_map); assert(ret_map);
assert(pixmap); assert(pixmap);
if (size < sizeof(struct bmp_file) + sizeof(struct bmp_dib)) if (size < sizeof(struct bmp_file) + SIZEOF_BMP_DIB)
return EFI_INVALID_PARAMETER; return EFI_INVALID_PARAMETER;
/* check file header */ /* check file header */
@ -63,7 +72,7 @@ static EFI_STATUS bmp_parse_header(
/* check device-independent bitmap */ /* check device-independent bitmap */
struct bmp_dib *dib = (struct bmp_dib *) (bmp + sizeof(struct bmp_file)); struct bmp_dib *dib = (struct bmp_dib *) (bmp + sizeof(struct bmp_file));
if (dib->size < sizeof(struct bmp_dib)) if (dib->size < SIZEOF_BMP_DIB)
return EFI_UNSUPPORTED; return EFI_UNSUPPORTED;
switch (dib->depth) { switch (dib->depth) {
@ -127,22 +136,21 @@ static void read_channel_maks(
assert(dib); assert(dib);
if (IN_SET(dib->depth, 16, 32) && dib->size >= sizeof(*dib) + 3 * sizeof(uint32_t)) { if (IN_SET(dib->depth, 16, 32) && dib->size >= SIZEOF_BMP_DIB_RGB) {
uint32_t *mask = (uint32_t *) ((uint8_t *) dib + sizeof(*dib)); channel_mask[R] = dib->channel_mask_r;
channel_mask[R] = mask[R]; channel_mask[G] = dib->channel_mask_g;
channel_mask[G] = mask[G]; channel_mask[B] = dib->channel_mask_b;
channel_mask[B] = mask[B]; channel_shift[R] = __builtin_ctz(dib->channel_mask_r);
channel_shift[R] = __builtin_ctz(mask[R]); channel_shift[G] = __builtin_ctz(dib->channel_mask_g);
channel_shift[G] = __builtin_ctz(mask[G]); channel_shift[B] = __builtin_ctz(dib->channel_mask_b);
channel_shift[B] = __builtin_ctz(mask[B]); channel_scale[R] = 0xff / ((1 << __builtin_popcount(dib->channel_mask_r)) - 1);
channel_scale[R] = 0xff / ((1 << __builtin_popcount(mask[R])) - 1); channel_scale[G] = 0xff / ((1 << __builtin_popcount(dib->channel_mask_g)) - 1);
channel_scale[G] = 0xff / ((1 << __builtin_popcount(mask[G])) - 1); channel_scale[B] = 0xff / ((1 << __builtin_popcount(dib->channel_mask_b)) - 1);
channel_scale[B] = 0xff / ((1 << __builtin_popcount(mask[B])) - 1);
if (dib->size >= sizeof(*dib) + 4 * sizeof(uint32_t) && mask[A] != 0) { if (dib->size >= SIZEOF_BMP_DIB_RGBA && dib->channel_mask_a != 0) {
channel_mask[A] = mask[A]; channel_mask[A] = dib->channel_mask_a;
channel_shift[A] = __builtin_ctz(mask[A]); channel_shift[A] = __builtin_ctz(dib->channel_mask_a);
channel_scale[A] = 0xff / ((1 << __builtin_popcount(mask[A])) - 1); channel_scale[A] = 0xff / ((1 << __builtin_popcount(dib->channel_mask_a)) - 1);
} else { } else {
channel_mask[A] = 0; channel_mask[A] = 0;
channel_shift[A] = 0; channel_shift[A] = 0;
@ -233,7 +241,8 @@ static EFI_STATUS bmp_to_blt(
case 16: case 16:
case 32: { case 32: {
uint32_t i = dib->depth == 16 ? *(uint16_t *) in : *(uint32_t *) in; uint32_t i = dib->depth == 16 ? unaligned_read_ne16(in) :
unaligned_read_ne32(in);
uint8_t r = ((i & channel_mask[R]) >> channel_shift[R]) * channel_scale[R], uint8_t r = ((i & channel_mask[R]) >> channel_shift[R]) * channel_scale[R],
g = ((i & channel_mask[G]) >> channel_shift[G]) * channel_scale[G], g = ((i & channel_mask[G]) >> channel_shift[G]) * channel_scale[G],