123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120 |
- From 6aa11df549114ebda520dde4cdaea2f9357b2c89 Mon Sep 17 00:00:00 2001
- From: Dan Fandrich <dan@coneharvesters.com>
- Date: Fri, 12 Oct 2018 16:01:45 +0200
- Subject: [PATCH] Improve deep recursion detection in
- exif_data_load_data_content.
- The existing detection was still vulnerable to pathological cases
- causing DoS by wasting CPU. The new algorithm takes the number of tags
- into account to make it harder to abuse by cases using shallow recursion
- but with a very large number of tags. This improves on commit 5d28011c
- which wasn't sufficient to counter this kind of case.
- The limitation in the previous fix was discovered by Laurent Delosieres,
- Secunia Research at Flexera (Secunia Advisory SA84652) and is assigned
- the identifier CVE-2018-20030.
- [Peter: drop NEWS change]
- Signed-off-by: Peter Korsgaard <peter@korsgaard.com>
- ---
- libexif/exif-data.c | 45 +++++++++++++++++++++++++++++++++++++--------
- 1 file changed, 37 insertions(+), 8 deletions(-)
- diff --git a/libexif/exif-data.c b/libexif/exif-data.c
- index e35403d..a6f9c94 100644
- --- a/libexif/exif-data.c
- +++ b/libexif/exif-data.c
- @@ -35,6 +35,7 @@
- #include <libexif/olympus/exif-mnote-data-olympus.h>
- #include <libexif/pentax/exif-mnote-data-pentax.h>
-
- +#include <math.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
- @@ -350,6 +351,20 @@ if (data->ifd[(i)]->count) { \
- break; \
- }
-
- +/*! Calculate the recursion cost added by one level of IFD loading.
- + *
- + * The work performed is related to the cost in the exponential relation
- + * work=1.1**cost
- + */
- +static unsigned int
- +level_cost(unsigned int n)
- +{
- + static const double log_1_1 = 0.09531017980432493;
- +
- + /* Adding 0.1 protects against the case where n==1 */
- + return ceil(log(n + 0.1)/log_1_1);
- +}
- +
- /*! Load data for an IFD.
- *
- * \param[in,out] data #ExifData
- @@ -357,13 +372,13 @@ if (data->ifd[(i)]->count) { \
- * \param[in] d pointer to buffer containing raw IFD data
- * \param[in] ds size of raw data in buffer at \c d
- * \param[in] offset offset into buffer at \c d at which IFD starts
- - * \param[in] recursion_depth number of times this function has been
- - * recursively called without returning
- + * \param[in] recursion_cost factor indicating how expensive this recursive
- + * call could be
- */
- static void
- exif_data_load_data_content (ExifData *data, ExifIfd ifd,
- const unsigned char *d,
- - unsigned int ds, unsigned int offset, unsigned int recursion_depth)
- + unsigned int ds, unsigned int offset, unsigned int recursion_cost)
- {
- ExifLong o, thumbnail_offset = 0, thumbnail_length = 0;
- ExifShort n;
- @@ -378,9 +393,20 @@ exif_data_load_data_content (ExifData *data, ExifIfd ifd,
- if ((((int)ifd) < 0) || ( ((int)ifd) >= EXIF_IFD_COUNT))
- return;
-
- - if (recursion_depth > 12) {
- + if (recursion_cost > 170) {
- + /*
- + * recursion_cost is a logarithmic-scale indicator of how expensive this
- + * recursive call might end up being. It is an indicator of the depth of
- + * recursion as well as the potential for worst-case future recursive
- + * calls. Since it's difficult to tell ahead of time how often recursion
- + * will occur, this assumes the worst by assuming every tag could end up
- + * causing recursion.
- + * The value of 170 was chosen to limit typical EXIF structures to a
- + * recursive depth of about 6, but pathological ones (those with very
- + * many tags) to only 2.
- + */
- exif_log (data->priv->log, EXIF_LOG_CODE_CORRUPT_DATA, "ExifData",
- - "Deep recursion detected!");
- + "Deep/expensive recursion detected!");
- return;
- }
-
- @@ -422,15 +448,18 @@ exif_data_load_data_content (ExifData *data, ExifIfd ifd,
- switch (tag) {
- case EXIF_TAG_EXIF_IFD_POINTER:
- CHECK_REC (EXIF_IFD_EXIF);
- - exif_data_load_data_content (data, EXIF_IFD_EXIF, d, ds, o, recursion_depth + 1);
- + exif_data_load_data_content (data, EXIF_IFD_EXIF, d, ds, o,
- + recursion_cost + level_cost(n));
- break;
- case EXIF_TAG_GPS_INFO_IFD_POINTER:
- CHECK_REC (EXIF_IFD_GPS);
- - exif_data_load_data_content (data, EXIF_IFD_GPS, d, ds, o, recursion_depth + 1);
- + exif_data_load_data_content (data, EXIF_IFD_GPS, d, ds, o,
- + recursion_cost + level_cost(n));
- break;
- case EXIF_TAG_INTEROPERABILITY_IFD_POINTER:
- CHECK_REC (EXIF_IFD_INTEROPERABILITY);
- - exif_data_load_data_content (data, EXIF_IFD_INTEROPERABILITY, d, ds, o, recursion_depth + 1);
- + exif_data_load_data_content (data, EXIF_IFD_INTEROPERABILITY, d, ds, o,
- + recursion_cost + level_cost(n));
- break;
- case EXIF_TAG_JPEG_INTERCHANGE_FORMAT:
- thumbnail_offset = o;
- --
- 2.20.1
|