-+ guint8* data = g_malloc(entry.length);
-+ if (read(tzdata_fd, data, entry.length) < entry.length) {
-+ g_warning("Failed reading tzdata entry");
-+ g_free(data);
-+ goto error;
++
++ if (strcmp (entry_name, identifier) == 0)
++ {
++ entry_offset = gint32_from_be (*(gint32_be*) (entry_name + 40));
++ entry_length = gint32_from_be (*(gint32_be*) (entry_name + 44));
++ if (entry_length == 0 || entry_length > 65536)
++ {
++ /* Use a reasonable but arbitrary max length of an entry. */
++ g_warning ("Invalid zoneinfo entry length");
++ goto error;
++ }
++
++ if (!g_uint_checked_add(&zoneinfo_start, header_data_offset, entry_offset) ||
++ !g_uint_checked_add(&zoneinfo_end, zoneinfo_start, entry_length) ||
++ zoneinfo_end > tzdata_length)
++ {
++ g_warning ("Too large zoneinfo entry length");
++ goto error;
++ }
++
++ zoneinfo = g_bytes_new_with_free_func (tzdata + zoneinfo_start,
++ entry_length,
++ (GDestroyNotify)g_mapped_file_unref,
++ g_mapped_file_ref (file));
++ g_mapped_file_unref (file);
++ return zoneinfo;