summaryrefslogtreecommitdiff
path: root/daemon
diff options
context:
space:
mode:
authorMayank Sharma <mayank8019@gmail.com>2019-11-26 11:20:30 +0530
committerOndrej Holy <oholy@redhat.com>2020-01-31 06:54:02 +0000
commit0a69b25c98a71abf75a3b5b5a3367b83dfe3f140 (patch)
treec35df1c7c1339b8367e2ce9b2a06c5f197d223b5 /daemon
parent8b47b09a5adf35ee52d5a1e5f52fb5a6597b2598 (diff)
downloadgvfs-0a69b25c98a71abf75a3b5b5a3367b83dfe3f140.tar.gz
google: Fixed a bug in copy function which caused crash after rename
Copy function had the classic time-of-check-to-time-of-use (TOCTOU) bug with the source_entry, which resulted into backend crash due to an entry getting invalidated between two uses. More precisely, we used to check for `existing_entry` using `resolve_child()` which internally calls `rebuild_dir()`. At the beginning of function, we resolve `source_entry`, but if resolve_child rebuilds the directory, our initial reference to source_entry will get freed, resulting into a crash. This commit refactors some of the copy function's code to fix this issue.
Diffstat (limited to 'daemon')
-rw-r--r--daemon/gvfsbackendgoogle.c59
1 files changed, 41 insertions, 18 deletions
diff --git a/daemon/gvfsbackendgoogle.c b/daemon/gvfsbackendgoogle.c
index c8a70030..e5989895 100644
--- a/daemon/gvfsbackendgoogle.c
+++ b/daemon/gvfsbackendgoogle.c
@@ -1436,26 +1436,9 @@ g_vfs_backend_google_copy (GVfsBackend *_self,
goto out;
}
- id = gdata_entry_get_id (source_entry);
+ title = gdata_entry_get_title (source_entry);
source_parent_id = gdata_entry_get_id (source_parent);
destination_parent_id = gdata_entry_get_id (destination_parent);
- etag = gdata_entry_get_etag (source_entry);
- summary = gdata_entry_get_summary (source_entry);
- title = gdata_entry_get_title (source_entry);
-
- /* When a file is copied to the same folder, Google Drive provides a "Make a
- * copy" option which creates a new file and changes its title from "Foobar.pdf"
- * to "Copy of Foobar". But instead here, nautilus does the heavy-lifting and
- * creates the destination file name as "Foobar (copy).pdf".
- *
- * Moreover, just after copy operation, a query_info operation is performed
- * and it needs the ("Foobar (copy).pdf", destination_parent_id) -> Entry mapping
- * in the cache. Hence, we set the new entry's filename conditionally. */
- if (g_strcmp0 (source_parent_id, destination_parent_id) != 0 &&
- g_strcmp0 (destination_basename, id) == 0)
- dummy_entry_filename = gdata_entry_get_title (source_entry);
- else
- dummy_entry_filename = destination_basename;
existing_entry = resolve_child (self, destination_parent, destination_basename, cancellable, NULL);
if (existing_entry != NULL)
@@ -1526,6 +1509,26 @@ g_vfs_backend_google_copy (GVfsBackend *_self,
}
}
+ /* We again resolve the source_entry after checking existing_entry. This is
+ * because when we try to find existing_entry, resolve_child is called which
+ * internally calls rebuild_dir function. Now, if between the initial
+ * resolution of source_entry and the resolution of existing_entry, the
+ * source_entry gets invalidated (possibly due to elapsing of
+ * REBUILD_ENTRIES_TIMEOUT seconds), rebuild_dir will update the entry
+ * internally in the structures but will free our source_entry. This results
+ * in a segfault in the below step.
+ *
+ * This case was observed when doing the following set of operations:
+ * copy --> rename copied file (but don't refresh nautilus) --> copy renamed file
+ * in same directory */
+ source_entry = resolve (self, source, cancellable, NULL, &error);
+ if (error != NULL)
+ {
+ g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
+ g_error_free (error);
+ goto out;
+ }
+
if (GDATA_IS_DOCUMENTS_FOLDER (source_entry))
{
g_vfs_job_failed (G_VFS_JOB (job),
@@ -1535,7 +1538,27 @@ g_vfs_backend_google_copy (GVfsBackend *_self,
goto out;
}
+ id = gdata_entry_get_id (source_entry);
+ etag = gdata_entry_get_etag (source_entry);
+ summary = gdata_entry_get_summary (source_entry);
+ title = gdata_entry_get_title (source_entry);
+
source_entry_type = G_OBJECT_TYPE (source_entry);
+
+ /* When a file is copied to the same folder, Google Drive provides a "Make a
+ * copy" option which creates a new file and changes its title from "Foobar.pdf"
+ * to "Copy of Foobar". But instead here, nautilus does the heavy-lifting and
+ * creates the destination file name as "Foobar (copy).pdf".
+ *
+ * Moreover, just after copy operation, a query_info operation is performed
+ * and it needs the ("Foobar (copy).pdf", destination_parent_id) -> Entry mapping
+ * in the cache. Hence, we set the new entry's filename conditionally. */
+ if (g_strcmp0 (source_parent_id, destination_parent_id) != 0 &&
+ g_strcmp0 (destination_basename, id) == 0)
+ dummy_entry_filename = gdata_entry_get_title (source_entry);
+ else
+ dummy_entry_filename = destination_basename;
+
dummy_source_entry = g_object_new (source_entry_type,
"etag", etag,
"id", id,