[libav-devel] [PATCH 2/4] opus: Fix arithmetic overflows (per RFC8251)

Andrew D'Addesio modchipv12 at gmail.com
Sun Dec 3 22:33:30 CET 2017


The relevant sections from the RFC are:

Sec.6. Integer Wrap-Around in Inverse Gain Computation
    32-bit integer overflow in Levinson recursion. Affects
    silk_is_lpc_stable().

Sec.7. Integer Wrap-Around in LSF Decoding
    16-bit integer overflow when stabilizing NLSFs. Affects
    silk_stabilize_lsf().

Sec.8. Cap on Band Energy
    NaN due to large log-energy value. Affects celt_denormalize().

Signed-off-by: Andrew D'Addesio <modchipv12 at gmail.com>
---
 libavcodec/opus_celt.c |  3 ++-
 libavcodec/opus_silk.c | 31 +++++++++++++++++++------------
 2 files changed, 21 insertions(+), 13 deletions(-)

diff --git a/libavcodec/opus_celt.c b/libavcodec/opus_celt.c
index 07a4f77..17298ac 100644
--- a/libavcodec/opus_celt.c
+++ b/libavcodec/opus_celt.c
@@ -1677,7 +1677,8 @@ static void celt_denormalize(CeltContext *s, CeltFrame *frame, float *data)
 
     for (i = s->startband; i < s->endband; i++) {
         float *dst = data + (celt_freq_bands[i] << s->duration);
-        float norm = pow(2, frame->energy[i] + celt_mean_energy[i]);
+        float log_norm = frame->energy[i] + celt_mean_energy[i];
+        float norm = pow(2, FFMIN(log_norm, 32.0f));
 
         for (j = 0; j < celt_freq_range[i] << s->duration; j++)
             dst[j] *= norm;
diff --git a/libavcodec/opus_silk.c b/libavcodec/opus_silk.c
index e5d1a99..dda254b 100644
--- a/libavcodec/opus_silk.c
+++ b/libavcodec/opus_silk.c
@@ -848,18 +848,18 @@ static inline void silk_stabilize_lsf(int16_t nlsf[16], int order, const uint16_
     }
 
     /* push forwards to increase distance */
-    if (nlsf[0] < min_delta[0])
-        nlsf[0] = min_delta[0];
-    for (i = 1; i < order; i++)
-        if (nlsf[i] < nlsf[i - 1] + min_delta[i])
-            nlsf[i] = nlsf[i - 1] + min_delta[i];
+    nlsf[0] = FFMAX(nlsf[0], 0 + min_delta[0]);
+    for (i = 1; i < order; i++) {
+        int x = FFMAX(nlsf[i], nlsf[i - 1] + min_delta[i]);
+        nlsf[i] = av_clip_uintp2(x, 15);
+    }
 
     /* push backwards to increase distance */
-    if (nlsf[order-1] > 32768 - min_delta[order])
-        nlsf[order-1] = 32768 - min_delta[order];
-    for (i = order-2; i >= 0; i--)
-        if (nlsf[i] > nlsf[i + 1] - min_delta[i+1])
-            nlsf[i] = nlsf[i + 1] - min_delta[i+1];
+    nlsf[order-1] = FFMIN(nlsf[order-1], 32768 - min_delta[order]);
+    for (i = order-2; i >= 0; i--) {
+        int x = FFMIN(nlsf[i], nlsf[i + 1] - min_delta[i + 1]);
+        nlsf[i] = av_clip_uintp2(x, 15);
+    }
 
     return;
 }
@@ -909,8 +909,15 @@ static inline int silk_is_lpc_stable(const int16_t lpc[16], int order)
         row = lpc32[k & 1];
 
         for (j = 0; j < k; j++) {
-            int x = prevrow[j] - ROUND_MULL(prevrow[k - j - 1], rc, 31);
-            row[j] = ROUND_MULL(x, gain, fbits);
+            int x = av_sat_sub32(prevrow[j], ROUND_MULL(prevrow[k - j - 1], rc, 31));
+            int64_t tmp = ROUND_MULL(x, gain, fbits);
+
+            /* per RFC 8251 section 6, if this calculation overflows, the filter
+               is considered unstable. */
+            if (tmp < INT32_MIN || tmp > INT32_MAX)
+                return 0;
+
+            row[j] = (int32_t)tmp;
         }
     }
 }
-- 
2.15.1.windows.2



More information about the libav-devel mailing list