diff --git a/libical-2.0.0-rscale-use-after-free.patch b/libical-2.0.0-rscale-use-after-free.patch new file mode 100644 index 0000000..1dfcc7a --- /dev/null +++ b/libical-2.0.0-rscale-use-after-free.patch @@ -0,0 +1,210 @@ +diff -up libical-2.0.0/src/libical/icalrecur.c.rscale libical-2.0.0/src/libical/icalrecur.c +--- libical-2.0.0/src/libical/icalrecur.c.rscale 2016-02-11 13:27:37.626579781 +0100 ++++ libical-2.0.0/src/libical/icalrecur.c 2016-02-11 14:49:56.751367100 +0100 +@@ -134,6 +134,7 @@ + #endif + + #include "icalrecur.h" ++#include "icalarray.h" + #include "icalerror.h" + #include "icalmemory.h" + #include "icaltimezone.h" +@@ -186,6 +187,139 @@ + + #define LEAP_MONTH 0x1000 + ++#if defined(HAVE_PTHREAD) ++#include ++static pthread_mutex_t rscale_texts_mutex = PTHREAD_MUTEX_INITIALIZER; ++#endif ++ ++static icalarray *rscale_texts = NULL; ++ ++static void initialize_rscale_texts(void) ++{ ++#if defined(HAVE_LIBICU) ++ UErrorCode status = U_ZERO_ERROR; ++ UEnumeration *en; ++ const char *cal; ++#endif ++ ++#if defined(HAVE_PTHREAD) ++ pthread_mutex_lock(&rscale_texts_mutex); ++#endif ++ ++ if (rscale_texts != NULL) { ++ #if defined(HAVE_PTHREAD) ++ pthread_mutex_unlock(&rscale_texts_mutex); ++ #endif ++ return; ++ } ++ ++ rscale_texts = icalarray_new(sizeof(char **), 20); ++ ++#if defined(HAVE_LIBICU) ++ en = ucal_getKeywordValuesForLocale("calendar", NULL, FALSE, &status); ++ while ((cal = uenum_next(en, NULL, &status))) { ++ char *copy = icalmemory_strdup(cal); ++ icalarray_append(rscale_texts, ©); ++ } ++ uenum_close(en); ++#endif ++ ++#if defined(HAVE_PTHREAD) ++ pthread_mutex_unlock(&rscale_texts_mutex); ++#endif ++} ++ ++static const char *match_rscale_text(const char *text) ++{ ++ size_t ii; ++ const char *res = NULL; ++ ++ if(!text) { ++ return NULL; ++ } ++ ++ initialize_rscale_texts(); ++ ++#if defined(HAVE_PTHREAD) ++ pthread_mutex_lock(&rscale_texts_mutex); ++#endif ++ ++ for(ii = 0; rscale_texts && ii < rscale_texts->num_elements; ii++) { ++ const char **stored, *p1, *p2; ++ ++ stored = icalarray_element_at(rscale_texts, ii); ++ if(!stored || !*stored) ++ continue; ++ ++ for(p1 = *stored, p2 = text; *p1 && *p2; p1++, p2++) { ++ if (tolower(*p1) != tolower(*p2)) ++ break; ++ } ++ ++ if(!*p1 && !*p2) { ++ res = *stored; ++ break; ++ } ++ } ++ ++#if defined(HAVE_PTHREAD) ++ pthread_mutex_unlock(&rscale_texts_mutex); ++#endif ++ ++ return res; ++} ++ ++static const char *match_or_add_rscale_text(const char *text) ++{ ++ const char *res; ++ ++ if(!text) { ++ return NULL; ++ } ++ ++ res = match_rscale_text (text); ++ ++#if defined(HAVE_PTHREAD) ++ pthread_mutex_lock(&rscale_texts_mutex); ++#endif ++ ++ if(!res && rscale_texts) { ++ res = icalmemory_strdup(text); ++ icalarray_append(rscale_texts, &res); ++ } ++ ++#if defined(HAVE_PTHREAD) ++ pthread_mutex_unlock(&rscale_texts_mutex); ++#endif ++ ++ return res; ++} ++ ++void icalrecur_free_rscale_texts(void) ++{ ++#if defined(HAVE_PTHREAD) ++ pthread_mutex_lock(&rscale_texts_mutex); ++#endif ++ ++ if(rscale_texts) { ++ size_t ii; ++ for(ii = 0; rscale_texts && ii < rscale_texts->num_elements; ii++) { ++ char **stored; ++ ++ stored = icalarray_element_at(rscale_texts, ii); ++ if(stored && *stored) ++ icalmemory_free_buffer(*stored); ++ } ++ ++ icalarray_free(rscale_texts); ++ rscale_texts = NULL; ++ } ++ ++#if defined(HAVE_PTHREAD) ++ pthread_mutex_unlock(&rscale_texts_mutex); ++#endif ++} ++ + int icalrecurrencetype_rscale_is_supported(void) + { + return RSCALE_IS_SUPPORTED; +@@ -585,7 +719,7 @@ struct icalrecurrencetype icalrecurrence + if (parser.rt.freq == ICAL_NO_RECURRENCE) r = -1; + } else if (icalrecurrencetype_rscale_is_supported() && + strcasecmp(name, "RSCALE") == 0) { +- parser.rt.rscale = icalmemory_tmp_copy(value); ++ parser.rt.rscale = match_or_add_rscale_text(value); + } else if (icalrecurrencetype_rscale_is_supported() && + strcasecmp(name, "SKIP") == 0) { + parser.rt.skip = icalrecur_string_to_skip(value); +@@ -1359,19 +1493,16 @@ static int initialize_iterator(icalrecur + impl->greg = NULL; + } else { + UEnumeration *en; +- const char *cal; +- char *r; ++ const char *cal, *rrscale; + +- /* Lowercase the specified calendar */ +- for (r = rule.rscale; *r; r++) { +- *r = tolower((int)*r); +- } ++ /* This can be a user-created string, thus not a one from the pool */ ++ rrscale = match_or_add_rscale_text (rule.rscale); + + /* Check if specified calendar is supported */ + en = ucal_getKeywordValuesForLocale("calendar", NULL, FALSE, &status); + while ((cal = uenum_next(en, NULL, &status))) { +- if (!strcmp(cal, rule.rscale)) { +- is_hebrew = !strcmp(rule.rscale, "hebrew"); ++ if (rrscale == match_rscale_text(cal)) { ++ is_hebrew = rrscale == match_rscale_text("hebrew"); + break; + } + } +diff -up libical-2.0.0/src/libical/icalrecur.h.rscale libical-2.0.0/src/libical/icalrecur.h +--- libical-2.0.0/src/libical/icalrecur.h.rscale 2016-02-11 14:08:38.754473804 +0100 ++++ libical-2.0.0/src/libical/icalrecur.h 2016-02-11 14:51:58.542361856 +0100 +@@ -181,7 +181,7 @@ struct icalrecurrencetype + short by_set_pos[ICAL_BY_SETPOS_SIZE]; + + /* For RSCALE extension (RFC 7529) */ +- char *rscale; ++ const char *rscale; + icalrecurrencetype_skip skip; + }; + +@@ -191,6 +191,12 @@ LIBICAL_ICAL_EXPORT icalarray *icalrecur + + LIBICAL_ICAL_EXPORT void icalrecurrencetype_clear(struct icalrecurrencetype *r); + ++/* Frees pool of calendar names used by icalrecurrencetype::rscale. ++ * Do not call if anything else can use it (like components or other ++ * icalrecurrencetype structures). ++ */ ++LIBICAL_ICAL_EXPORT void icalrecur_free_rscale_texts(void); ++ + /** + * Array Encoding + * diff --git a/libical.spec b/libical.spec index a7204e5..33ec9af 100644 --- a/libical.spec +++ b/libical.spec @@ -1,12 +1,13 @@ Summary: Reference implementation of the iCalendar data type and serialization format Name: libical Version: 2.0.0 -Release: 6%{?dist} +Release: 7%{?dist} License: LGPLv2 or MPLv1.1 URL: http://freeassociation.sourceforge.net/ Source: https://github.com/%{name}/%{name}/archive/v%{version}/%{name}-%{version}.tar.gz Patch0: libical-2.0.0-arm.patch Patch1: libical-2.0.0-funcnamefix.patch +Patch2: libical-2.0.0-rscale-use-after-free.patch BuildRequires: bison, byacc, flex BuildRequires: cmake @@ -32,6 +33,7 @@ applications that use libical. %setup -q %patch0 -p1 -b .arm %patch1 -p1 -b .funcnamefix +%patch2 -p1 -b .rscale-use-after-free %build mkdir -p %{_target_platform} @@ -74,6 +76,9 @@ make test ARGS="-V" -C %{_target_platform} %{_includedir}/libical/ %changelog +* Thu Feb 11 2016 Milan Crha - 2.0.0-7 +- Add patch for possible use-after-free of icalrecurrencetype::rscale + * Mon Feb 08 2016 Milan Crha - 2.0.0-6 - Add libicu dependency to libical-devel subpackage