ecal file backend: avoid manipulating the UID inside component_add()
authorPatrick Ohly <patrick.ohly@intel.com>
Thu, 4 Aug 2011 15:55:07 +0000 (17:55 +0200)
committerPatrick Ohly <patrick.ohly@intel.com>
Wed, 10 Aug 2011 16:05:56 +0000 (18:05 +0200)
commitae4f4292b0e5ecbbdc74c90b75cc31367d0d270a
treeaac9d51868b4f542d23fa4a436d4c7d3d88d4d36
parent0cad263feb940c802535a20c33faa4bf6cfa8805
ecal file backend: avoid manipulating the UID inside component_add()

This commit fixes the following memory handling problem:
==10069== Invalid read of size 1
==10069==    at 0x4C25812: __GI_strlen (mc_replace_strmem.c:284)
==10069==    by 0x8EF011E: g_strdup (gstrfuncs.c:99)
==10069==    by 0xF4E08B6: e_cal_backend_file_create_object (e-cal-backend-file.c:2363)
==10069==    by 0x93E6061: e_cal_backend_sync_create_object (e-cal-backend-sync.c:214)
==10069==    by 0x93E86D3: _e_cal_backend_create_object (e-cal-backend-sync.c:630)
==10069==    by 0x93DD40B: e_cal_backend_create_object (e-cal-backend.c:1017)
==10069==    by 0x93F0C34: impl_Cal_createObject (e-data-cal.c:401)
==10069==    by 0x4E75383: _e_gdbus_gdbus_cclosure_marshaller_BOOLEAN__OBJECT_STRING (e-gdbus-marshallers.c:377)
==10069==    by 0x820999E: g_closure_invoke (gclosure.c:773)
==10069==    by 0x8225972: signal_emit_unlocked_R (gsignal.c:3256)
==10069==    by 0x82248D0: g_signal_emit_valist (gsignal.c:2997)
==10069==    by 0x8224DBC: g_signal_emit (gsignal.c:3044)
==10069==  Address 0x1499c7b0 is 0 bytes inside a block of size 39 free'd
==10069==    at 0x4C240FD: free (vg_replace_malloc.c:366)
==10069==    by 0x9DE952C: icalvalue_free (in /usr/lib/libical.so.0.44.0)
==10069==    by 0x9DDB796: icalproperty_set_value (in /usr/lib/libical.so.0.44.0)
==10069==    by 0x4E4FFA2: e_cal_component_set_uid (e-cal-component.c:1479)
==10069==    by 0xF4DB8F3: check_dup_uid (e-cal-backend-file.c:498)
==10069==    by 0xF4DBD9B: add_component (e-cal-backend-file.c:614)
==10069==    by 0xF4E0894: e_cal_backend_file_create_object (e-cal-backend-file.c:2356)
==10069==    by 0x93E6061: e_cal_backend_sync_create_object (e-cal-backend-sync.c:214)
==10069==    by 0x93E86D3: _e_cal_backend_create_object (e-cal-backend-sync.c:630)
==10069==    by 0x93DD40B: e_cal_backend_create_object (e-cal-backend.c:1017)
==10069==    by 0x93F0C34: impl_Cal_createObject (e-data-cal.c:401)
==10069==    by 0x4E75383: _e_gdbus_gdbus_cclosure_marshaller_BOOLEAN__OBJECT_STRING (e-gdbus-marshallers.c:377)

This occurs when a client (incorrectly) tries to create a VEVENT with
RECURRENCE-ID for a UID which already exists. The sequence of events is this:
- e_cal_backend_file_create_object() calls lookup_component(),
  which returns NULL because it only checks for the parent event
  (will be fixed separately).
- e_cal_backend_file_create_object() keeps a pointer to the UID.
- check_dup_uid() repeats the UID check, but this time finds that it
  is already taken and replaces the existing UID in the component
  before adding it. The pointer in e_cal_backend_file_create_object()
  points to freed memory.

I've seen cases where the hash ended up using the original UID as key,
with a component inside that had the new, replaced UID. As a result,
retrieving the event as reported by e_cal_get_object_list() (= rewritten UID)
failed in e_cal_get_object() (= original UID).

The UID should not be overwritten. I can't verify it anymore (events where it occured
have already been deleted), but this rewriting might explain why some of my
meeting update emails couldn't be applied to previously imported events.

Therefore this patch moves check_dup_uid() out of component_add(). This check
and rewriting only makes sense when reading the existing calendar file,
as a safe-guard against on-disk corruption. When adding or modifying events
via the API, the right reaction is to add a missing UID or or reject the
operation with an error.

All places where component_add() is used should have the necessary checks
or are preceeded by a remove_component(), which removes the UID first.
calendar/backends/file/e-cal-backend-file.c