fix(gateway): bound the zstd decompression window (#2351)

This commit is contained in:
Hampus
2026-09-02 17:24:35 +02:00
committed by GitHub
parent bea4a6dcbc
commit 4021a2d697
@@ -19,6 +19,7 @@
-define(MAX_DECOMPRESSED_SIZE, 10 * 1024 * 1024).
-define(ZSTD_STREAM_BUFFER_SIZE, 64 * 1024).
-define(ZSTD_COMPRESSION_LEVEL, 3).
-define(ZSTD_DECOMPRESS_WINDOW_LOG_MAX, 23).
-define(ZSTD_AVAILABLE_KEY, {?MODULE, zstd_available}).
-define(ZSTD_STREAM_AVAILABLE_KEY, {?MODULE, zstd_stream_available}).
@@ -221,7 +222,11 @@ zstd_frame_decompress_available(Data, Ctx) ->
handle_zstd_decompress_result(Decompressed, Ctx) when is_binary(Decompressed) ->
check_decompressed_size(Decompressed, Ctx);
handle_zstd_decompress_result(Decompressed, Ctx) when is_list(Decompressed) ->
check_decompressed_size(iolist_to_binary(eqwalizer:dynamic_cast(Decompressed)), Ctx);
IoList = eqwalizer:dynamic_cast(Decompressed),
case erlang:iolist_size(IoList) > ?MAX_DECOMPRESSED_SIZE of
true -> {error, decompression_too_large};
false -> check_decompressed_size(iolist_to_binary(IoList), Ctx)
end;
handle_zstd_decompress_result({error, Reason}, _Ctx) ->
{error, {decompress_failed, Reason}};
handle_zstd_decompress_result(Other, _Ctx) ->
@@ -263,13 +268,25 @@ ensure_zstd_decompress_stream_context(
ensure_zstd_decompress_stream_context(#{type := zstd_stream} = Ctx) ->
case erlang:apply(ezstd, create_decompression_context, [?ZSTD_STREAM_BUFFER_SIZE]) of
StreamCtx when is_reference(StreamCtx) ->
{ok, StreamCtx, Ctx#{decompress_stream_ctx => StreamCtx}};
set_zstd_decompress_window_log_max(StreamCtx, Ctx);
{error, Reason} ->
{error, {decompress_failed, Reason}};
Other ->
{error, {decompress_failed, {case_clause, Other}}}
end.
-spec set_zstd_decompress_window_log_max(reference(), compress_ctx()) ->
{ok, reference(), compress_ctx()} | {error, term()}.
set_zstd_decompress_window_log_max(StreamCtx, Ctx) ->
Result = erlang:apply(ezstd, set_decompression_parameter, [
StreamCtx, zstd_d_window_log_max, ?ZSTD_DECOMPRESS_WINDOW_LOG_MAX
]),
case Result of
ok -> {ok, StreamCtx, Ctx#{decompress_stream_ctx => StreamCtx}};
{error, Reason} -> {error, {decompress_failed, Reason}};
Other -> {error, {decompress_failed, {case_clause, Other}}}
end.
-spec check_decompressed_size(binary(), compress_ctx()) ->
{ok, binary(), compress_ctx()} | {error, term()}.
check_decompressed_size(Decompressed, Ctx) ->