Commit 4f0e3d0a77 for aom
commit 4f0e3d0a7791e7d5a1fe4aa31497dbe40a7b1b4a
Author: Marco Paniconi <marpan@google.com>
Date: Mon Jul 27 21:50:57 2026 +0000
Fix issue in SVC parameter configuration
Always clamp the spatial/temporal_layer_id in set_svc_params.
Current code was only clamping if the number of layers were
detected to change.
This fixes heap-buffer-overflow when the number of spatial
layers are set with AOME_SET_NUMBER_SPATIAL_LAYERS before
AV1E_SET_SVC_PARAMS.
Additional fixes;
-validate layer_id against both cpi->svc and ppi in AV1E_SET_SVC_LAYER_ID
-add a clamp on spatial_layer_id in AOME_SET_NUMBER_SPATIAL_LAYERS
-add condition on use_svc to return invalid_param in
AOME_SET_NUMBER_SPATIAL_LAYERS, to avoid using this control when
AV1E_SET_SVC_PARAMS is used.
Add unittest.
Bug: 538651949
Change-Id: I1ff6d0968b6d6717bf49539f48f10fb4fb2a608a
diff --git a/av1/av1_cx_iface.c b/av1/av1_cx_iface.c
index b0b2762a74..e1e8ef1ed4 100644
--- a/av1/av1_cx_iface.c
+++ b/av1/av1_cx_iface.c
@@ -4081,10 +4081,16 @@ static aom_codec_err_t ctrl_set_number_spatial_layers(aom_codec_alg_priv_t *ctx,
// it is false (the default) the actual limit is 3 for both spatial and
// temporal layers. Given the order of these calls are unpredictable the
// final check is deferred until encoder_encode() (av1_set_svc_fixed_mode()).
+ // The condition to return invalid_param when use_svc is set
+ // (set in set_svc_params) is to avoid calling this control when
+ // set_svc_params is already called (which sets the number of spatial and
+ // temporal layers).
if (number_spatial_layers <= 0 ||
- number_spatial_layers > MAX_NUM_SPATIAL_LAYERS)
+ number_spatial_layers > MAX_NUM_SPATIAL_LAYERS || ctx->ppi->use_svc)
return AOM_CODEC_INVALID_PARAM;
ctx->ppi->number_spatial_layers = number_spatial_layers;
+ ctx->ppi->cpi->common.spatial_layer_id = clamp(
+ ctx->ppi->cpi->common.spatial_layer_id, 0, number_spatial_layers - 1);
// update_encoder_cfg() is somewhat costly and this control may be called
// multiple times, so update_encoder_cfg() is only called to ensure frame and
// superblock sizes are updated before they're fixed by the first encode
@@ -4100,7 +4106,10 @@ static aom_codec_err_t ctrl_set_layer_id(aom_codec_alg_priv_t *ctx,
aom_svc_layer_id_t *const data = va_arg(args, aom_svc_layer_id_t *);
if (data->spatial_layer_id < 0 || data->temporal_layer_id < 0 ||
data->spatial_layer_id >= (int)ctx->ppi->number_spatial_layers ||
- data->temporal_layer_id >= (int)ctx->ppi->number_temporal_layers) {
+ data->temporal_layer_id >= (int)ctx->ppi->number_temporal_layers ||
+ data->spatial_layer_id >= (int)ctx->ppi->cpi->svc.number_spatial_layers ||
+ data->temporal_layer_id >=
+ (int)ctx->ppi->cpi->svc.number_temporal_layers) {
return AOM_CODEC_INVALID_PARAM;
}
ctx->ppi->cpi->common.spatial_layer_id = data->spatial_layer_id;
@@ -4152,21 +4161,17 @@ static aom_codec_err_t ctrl_set_svc_params(aom_codec_alg_priv_t *ctx,
ctx->next_frame_flags |= AOM_EFLAG_FORCE_KF;
av1_set_svc_seq_params(ppi);
av1_free_svc_cyclic_refresh(cpi);
- // Check for valid values for the spatial/temporal_layer_id here, since
- // there has been a dynamic change in the number_spatial/temporal_layers,
- // and if the ctrl_set_layer_id is not used after this call, the
- // previous (last_encoded) values of spatial/temporal_layer_id will be used,
- // which may be invalid.
- cpi->svc.spatial_layer_id =
- clamp(cpi->svc.spatial_layer_id, 0, cpi->svc.number_spatial_layers - 1);
- cpi->svc.temporal_layer_id = clamp(cpi->svc.temporal_layer_id, 0,
- cpi->svc.number_temporal_layers - 1);
- cpi->common.spatial_layer_id = clamp(cpi->common.spatial_layer_id, 0,
- cpi->svc.number_spatial_layers - 1);
- cpi->common.temporal_layer_id = clamp(cpi->common.temporal_layer_id, 0,
- cpi->svc.number_temporal_layers - 1);
}
+ // Check for valid values for the spatial/temporal_layer_id here.
+ // If ctrl_set_layer_id is not used after this call, the currently configured
+ // values of spatial/temporal_layer_id will be used, which may be out of
+ // bounds.
+ cpi->common.spatial_layer_id = cpi->svc.spatial_layer_id =
+ clamp(cpi->svc.spatial_layer_id, 0, cpi->svc.number_spatial_layers - 1);
+ cpi->common.temporal_layer_id = cpi->svc.temporal_layer_id =
+ clamp(cpi->svc.temporal_layer_id, 0, cpi->svc.number_temporal_layers - 1);
+
if (ppi->number_spatial_layers > 1 || ppi->number_temporal_layers > 1) {
unsigned int sl, tl;
// Disable svc for lag_in_frames > 0.
diff --git a/test/encode_api_test.cc b/test/encode_api_test.cc
index f406bacc10..e67282226d 100644
--- a/test/encode_api_test.cc
+++ b/test/encode_api_test.cc
@@ -254,6 +254,60 @@ TEST(EncodeAPI, InvalidSvcParams) {
EXPECT_EQ(aom_codec_destroy(&enc), AOM_CODEC_OK);
}
+// Bug: 538651949.
+TEST(EncodeAPI, SvcFixBypass) {
+ aom_codec_ctx_t enc;
+ aom_codec_enc_cfg_t cfg;
+ aom_codec_iface_t *iface = aom_codec_av1_cx();
+ aom_svc_layer_id_t layer_id = { 3, 0 };
+ aom_svc_params_t svc_params = {};
+
+ EXPECT_EQ(aom_codec_enc_config_default(iface, &cfg, kUsage), AOM_CODEC_OK);
+ cfg.g_w = 320;
+ cfg.g_h = 240;
+ cfg.g_threads = 1;
+ cfg.g_lag_in_frames = 0;
+
+ ASSERT_EQ(aom_codec_enc_init(&enc, iface, &cfg, 0), AOM_CODEC_OK);
+
+ // Set number of spatial layers to 4 via control SET_NUMBER_SPATIAL_LAYERS.
+ EXPECT_EQ(aom_codec_control(&enc, AOME_SET_NUMBER_SPATIAL_LAYERS, 4),
+ AOM_CODEC_OK);
+
+ // Set the active spatial layer id to 3. This is expected to fail since
+ // cpi->svc.number_spatial_layers is still 1 (default).
+ EXPECT_EQ(aom_codec_control(&enc, AV1E_SET_SVC_LAYER_ID, &layer_id),
+ AOM_CODEC_INVALID_PARAM);
+
+ // Set SVC params to 2x2 layer config, via AV1E_SET_SVC_PARAMS. This sets
+ // all svc layer parameters, allocates for the layer context, and sets use_svc
+ // = 1.
+ svc_params.number_spatial_layers = 2;
+ svc_params.number_temporal_layers = 2;
+ for (int i = 0; i < AOM_MAX_LAYERS; i++) {
+ svc_params.max_quantizers[i] = 52;
+ svc_params.min_quantizers[i] = 10;
+ svc_params.layer_target_bitrate[i] = 100;
+ }
+ svc_params.scaling_factor_num[0] = 1;
+ svc_params.scaling_factor_den[0] = 2;
+ svc_params.scaling_factor_num[1] = 1;
+ svc_params.scaling_factor_den[1] = 1;
+ svc_params.framerate_factor[0] = 2;
+ svc_params.framerate_factor[1] = 1;
+
+ EXPECT_EQ(aom_codec_control(&enc, AV1E_SET_SVC_PARAMS, &svc_params),
+ AOM_CODEC_OK);
+
+ // Now try setting number of spatial layers to 3 using the control
+ // SET_NUMBER_SPATIAL_LAYERS. This is expected to fail because SVC was
+ // configured via AV1E_SET_SVC_PARAMS, so use_svc = 1.
+ EXPECT_EQ(aom_codec_control(&enc, AOME_SET_NUMBER_SPATIAL_LAYERS, 3),
+ AOM_CODEC_INVALID_PARAM);
+
+ EXPECT_EQ(aom_codec_destroy(&enc), AOM_CODEC_OK);
+}
+
TEST(EncodeAPI, InvalidControlId) {
aom_codec_iface_t *iface = aom_codec_av1_cx();
aom_codec_ctx_t enc;