Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New API for safe(r) encoding #47

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
* libsixel 1.11 (not yet released)
* Resolve CVE-2020-36120 by marking `sixel_encoder_encode_bytes()` as
deprecated and unsafe. Replace it with `sixel_encoder_encode_buffer()`,
which takes an additional size argument, and can be used safely. The
former function will be removed in 1.12.

* libsixel 1.10.2 (2021-10-08)
* Update python bindings to use python3. Python 3.9 is preferred. File issues
if bugs are found in python 3.6-8. Thanks, @wsluser
Expand Down
52 changes: 46 additions & 6 deletions include/sixel.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
# define SIXELAPI
#endif

#define SIXELDEPRECATED __attribute__ ((deprecated))

#define LIBSIXEL_VERSION "@PACKAGE_VERSION@"
#define PACKAGE_VERSION LIBSIXEL_VERSION
#define LIBSIXEL_ABI_VERSION "@LS_LTVERSION@"
Expand Down Expand Up @@ -708,7 +710,10 @@ SIXELAPI void
sixel_dither_unref(sixel_dither_t *dither); /* dither context object */

/* initialize internal palette from specified pixel buffer */
SIXELAPI SIXELSTATUS
/* this function is fundamentally unsafe. it has been disabled for
* libsixel 1.11, and will be removed entirely for libsixel 1.12.
* use sixel_dither_init() instead. */
SIXELAPI SIXELSTATUS SIXELDEPRECATED
sixel_dither_initialize(
sixel_dither_t *dither, /* dither context object */
unsigned char /* in */ *data, /* sample image */
Expand All @@ -719,6 +724,18 @@ sixel_dither_initialize(
int /* in */ method_for_rep, /* method for choosing a color from the box */
int /* in */ quality_mode); /* quality of histogram processing */

SIXELAPI SIXELSTATUS
sixel_dither_init(
sixel_dither_t *dither, /* dither context object */
unsigned char /* in */ *data, /* sample image */
int /* in */ len, /* number of bytes in data */
int /* in */ width, /* image width */
int /* in */ height, /* image height */
int /* in */ pixelformat, /* one of enum pixelFormat */
int /* in */ method_for_largest, /* method for finding the largest dimension */
int /* in */ method_for_rep, /* method for choosing a color from the box */
int /* in */ quality_mode); /* quality of histogram processing */

/* set diffusion type, choose from enum methodForDiffuse */
SIXELAPI void
sixel_dither_set_diffusion_type(
Expand Down Expand Up @@ -796,9 +813,10 @@ extern "C" {
SIXELAPI SIXELSTATUS
sixel_encode(
unsigned char /* in */ *pixels, /* pixel bytes */
int /* in */ width, /* image width */
int /* in */ height, /* image height */
int /* in */ depth, /* color depth: now unused */
int /* in */ len, /* source size in bytes */
int /* in */ width, /* image width */
int /* in */ height, /* image height */
int /* in */ depth, /* color depth: now unused */
sixel_dither_t /* in */ *dither, /* dither context */
sixel_output_t /* in */ *context); /* output context */

Expand Down Expand Up @@ -861,6 +879,7 @@ sixel_helper_normalize_pixelformat(
unsigned char /* out */ *dst, /* destination buffer */
int /* out */ *dst_pixelformat, /* converted pixelformat */
unsigned char const /* in */ *src, /* source pixels */
int /* in */ len, /* size of src in bytes */
int /* in */ src_pixelformat, /* format of source image */
int /* in */ width, /* width of source image */
int /* in */ height /* height of source image */
Expand Down Expand Up @@ -953,6 +972,10 @@ sixel_frame_init(
SIXELAPI unsigned char *
sixel_frame_get_pixels(sixel_frame_t /* in */ *frame); /* frame object */

/* get content length in bytes */
SIXELAPI int
sixel_frame_get_length(sixel_frame_t /* in */ *frame); /* frame object */

/* get palette */
SIXELAPI unsigned char *
sixel_frame_get_palette(sixel_frame_t /* in */ *frame); /* frame object */
Expand Down Expand Up @@ -1100,8 +1123,12 @@ sixel_encoder_encode(
char const /* in */ *filename);

/* encode specified pixel data to SIXEL format
* output to encoder->outfd */
SIXELAPI SIXELSTATUS
* output to encoder->outfd
* this function is *unsafe*! do not use it in new code! it will be removed
* in libsixel 1.12, and no longer works as of libsixel 1.11.
* use sixel_encoder_encode_buffer() instead.
**/
SIXELAPI SIXELSTATUS SIXELDEPRECATED
sixel_encoder_encode_bytes(
sixel_encoder_t /* in */ *encoder,
unsigned char /* in */ *bytes,
Expand All @@ -1111,6 +1138,19 @@ sixel_encoder_encode_bytes(
unsigned char /* in */ *palette,
int /* in */ ncolors);

/* encode specified pixel data having len bytes to SIXEL format
* output to encoder->outfd
**/
SIXELAPI SIXELSTATUS
sixel_encoder_encode_buffer(
sixel_encoder_t /* in */ *encoder,
unsigned char /* in */ *bytes,
int /* in */ len,
int /* in */ width,
int /* in */ height,
int /* in */ pixelformat,
unsigned char /* in */ *palette,
int /* in */ ncolors);
#ifdef __cplusplus
}
#endif
Expand Down
3 changes: 2 additions & 1 deletion meson.build
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
project('libsixel', ['c'], version: '1.10.2', license: 'MIT', default_options: ['buildtype=release', 'c_std=c99', 'warning_level=3'])
project('libsixel', ['c'], version: '1.11.0', license: 'MIT', default_options: ['buildtype=release', 'c_std=c99', 'warning_level=3'])

datadir = get_option('datadir')
if (get_option('bashcompletiondir') == '')
Expand Down Expand Up @@ -39,6 +39,7 @@ c_args = [
'-Wunused-function',
'-Wunused-but-set-variable',
'-Bsymbolic',
'-g',
]

foreach a : c_args
Expand Down
18 changes: 16 additions & 2 deletions src/chunk.c
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,8 @@ static SIXELSTATUS
sixel_chunk_from_url(
char const /* in */ *url,
sixel_chunk_t /* in */ *pchunk,
int /* in */ finsecure)
int /* in */ finsecure,
size_t* /* out */ len)
{
SIXELSTATUS status = SIXEL_FALSE;
# ifdef HAVE_LIBCURL
Expand Down Expand Up @@ -350,6 +351,17 @@ sixel_chunk_from_url(
sixel_helper_set_additional_message("curl_easy_perform() failed.");
goto end;
}
double cl;
code = curl_easy_getinfo(curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &cl);
if (code != CURLE_OK) {
sixel_helper_set_additional_message("coudln't get content length.");
goto end;
}
if (cl <= 0 || cl > SIZE_MAX) {
sixel_helper_set_additional_message("bad content length.");
goto end;
}
*len = cl;

status = SIXEL_OK;
# else
Expand All @@ -361,6 +373,7 @@ sixel_chunk_from_url(
"configure this program with --with-libcurl "
"option at compile time.\n");
status = SIXEL_NOT_IMPLEMENTED;
*len = 0;
goto end;
# endif /* HAVE_LIBCURL */

Expand Down Expand Up @@ -418,8 +431,9 @@ sixel_chunk_new(

sixel_allocator_ref(allocator);

size_t len;
if (filename != NULL && strstr(filename, "://")) {
status = sixel_chunk_from_url(filename, *ppchunk, finsecure);
status = sixel_chunk_from_url(filename, *ppchunk, finsecure, &len);
} else {
status = sixel_chunk_from_file(filename, *ppchunk, cancel_flag);
}
Expand Down
30 changes: 29 additions & 1 deletion src/dither.c
Original file line number Diff line number Diff line change
Expand Up @@ -513,6 +513,32 @@ sixel_dither_initialize(
int /* in */ method_for_largest,
int /* in */ method_for_rep,
int /* in */ quality_mode)
{
(void)dither;
(void)data;
(void)width;
(void)height;
(void)pixelformat;
(void)method_for_largest;
(void)method_for_rep;
(void)quality_mode;
fprintf(stderr, "sixel_dither_initialize() has been disabled, as it"
" is unsafe.\nuse sixel_dither_init() instead.\n");
return SIXEL_FALSE;
}


SIXELAPI SIXELSTATUS
sixel_dither_init(
sixel_dither_t /* in */ *dither,
unsigned char /* in */ *data,
int /* in */ len,
int /* in */ width,
int /* in */ height,
int /* in */ pixelformat,
int /* in */ method_for_largest,
int /* in */ method_for_rep,
int /* in */ quality_mode)
{
unsigned char *buf = NULL;
unsigned char *normalized_pixels = NULL;
Expand Down Expand Up @@ -551,6 +577,7 @@ sixel_dither_initialize(
normalized_pixels,
&pixelformat,
data,
len,
pixelformat,
width,
height);
Expand Down Expand Up @@ -719,6 +746,7 @@ SIXELAPI sixel_index_t *
sixel_dither_apply_palette(
sixel_dither_t /* in */ *dither,
unsigned char /* in */ *pixels,
int /* in */ len,
int /* in */ width,
int /* in */ height)
{
Expand Down Expand Up @@ -779,7 +807,7 @@ sixel_dither_apply_palette(
}
status = sixel_helper_normalize_pixelformat(normalized_pixels,
&dither->pixelformat,
pixels, dither->pixelformat,
pixels, len, dither->pixelformat,
width, height);
if (SIXEL_FAILED(status)) {
goto end;
Expand Down
1 change: 1 addition & 0 deletions src/dither.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ extern "C" {
sixel_index_t *
sixel_dither_apply_palette(struct sixel_dither /* in */ *dither,
unsigned char /* in */ *pixels,
int /* in */ len,
int /* in */ width,
int /* in */ height);

Expand Down
81 changes: 55 additions & 26 deletions src/encoder.c
Original file line number Diff line number Diff line change
Expand Up @@ -388,14 +388,16 @@ load_image_callback_for_palette(
}

/* create adaptive palette from given frame object */
status = sixel_dither_initialize(callback_context->dither,
sixel_frame_get_pixels(frame),
sixel_frame_get_width(frame),
sixel_frame_get_height(frame),
sixel_frame_get_pixelformat(frame),
SIXEL_LARGE_NORM,
SIXEL_REP_CENTER_BOX,
SIXEL_QUALITY_HIGH);
status = sixel_dither_init(callback_context->dither,
sixel_frame_get_pixels(frame),
sixel_frame_get_width(frame) *
sixel_frame_get_height(frame),
sixel_frame_get_width(frame),
sixel_frame_get_height(frame),
sixel_frame_get_pixelformat(frame),
SIXEL_LARGE_NORM,
SIXEL_REP_CENTER_BOX,
SIXEL_QUALITY_HIGH);
if (SIXEL_FAILED(status)) {
sixel_dither_unref(callback_context->dither);
goto end;
Expand Down Expand Up @@ -550,14 +552,16 @@ sixel_encoder_prepare_palette(
goto end;
}

status = sixel_dither_initialize(*dither,
sixel_frame_get_pixels(frame),
sixel_frame_get_width(frame),
sixel_frame_get_height(frame),
sixel_frame_get_pixelformat(frame),
encoder->method_for_largest,
encoder->method_for_rep,
encoder->quality_mode);
status = sixel_dither_init(*dither,
sixel_frame_get_pixels(frame),
sixel_frame_get_width(frame) *
sixel_frame_get_height(frame),
sixel_frame_get_width(frame),
sixel_frame_get_height(frame),
sixel_frame_get_pixelformat(frame),
encoder->method_for_largest,
encoder->method_for_rep,
encoder->quality_mode);
if (SIXEL_FAILED(status)) {
goto end;
}
Expand Down Expand Up @@ -781,13 +785,14 @@ sixel_encoder_output_without_macro(
}

pixbuf = sixel_frame_get_pixels(frame);
memcpy(p, pixbuf, (size_t)(width * height * depth));
int len = sixel_frame_get_length(frame);
memcpy(p, pixbuf, (size_t)len);

if (encoder->cancel_flag && *encoder->cancel_flag) {
goto end;
}

status = sixel_encode(p, width, height, depth, dither, output);
status = sixel_encode(p, len, width, height, depth, dither, output);
if (status != SIXEL_OK) {
goto end;
}
Expand All @@ -814,9 +819,6 @@ sixel_encoder_output_with_macro(
int lag = 0;
struct timespec tv;
clock_t start;
unsigned char *pixbuf;
int width;
int height;
int delay;

start = clock();
Expand All @@ -840,10 +842,11 @@ sixel_encoder_output_with_macro(
goto end;
}

pixbuf = sixel_frame_get_pixels(frame),
width = sixel_frame_get_width(frame),
height = sixel_frame_get_height(frame),
status = sixel_encode(pixbuf, width, height, /* unused */ 3, dither, output);
unsigned char* pixbuf = sixel_frame_get_pixels(frame);
int width = sixel_frame_get_width(frame);
int height = sixel_frame_get_height(frame);
int len = sixel_frame_get_length(frame);
status = sixel_encode(pixbuf, len, width, height, /* unused */ 3, dither, output);
if (SIXEL_FAILED(status)) {
goto end;
}
Expand Down Expand Up @@ -1734,12 +1737,37 @@ sixel_encoder_encode(
}


/* this function cannot be used safely, since it has no indication of how
* many bytes are viable. it now always returns failure. remove in 1.12. */
SIXELAPI SIXELSTATUS
sixel_encoder_encode_bytes(
sixel_encoder_t /* in */ *encoder,
unsigned char /* in */ *bytes,
int /* in */ width,
int /* in */ height,
int /* in */ pixelformat,
unsigned char /* in */ *palette,
int /* in */ ncolors)
{
(void)encoder;
(void)bytes;
(void)width;
(void)height;
(void)pixelformat;
(void)palette;
(void)ncolors;
fprintf(stderr, "sixel_encoder_encode_bytes() has been disabled, as it"
" is unsafe.\nuse sixel_encoder_encode_buffer() instead.\n");
return SIXEL_FALSE;
}

/* encode specified pixel data to SIXEL format
* output to encoder->outfd */
SIXELAPI SIXELSTATUS
sixel_encoder_encode_bytes(
sixel_encoder_encode_buffer(
sixel_encoder_t /* in */ *encoder,
unsigned char /* in */ *bytes,
int /* in */ len,
int /* in */ width,
int /* in */ height,
int /* in */ pixelformat,
Expand All @@ -1749,6 +1777,7 @@ sixel_encoder_encode_bytes(
SIXELSTATUS status = SIXEL_FALSE;
sixel_frame_t *frame;

(void)len; // FIXME
if (encoder == NULL || bytes == NULL) {
status = SIXEL_BAD_ARGUMENT;
goto end;
Expand Down
Loading