After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 678555 - Crash on unmount
Crash on unmount
Status: RESOLVED FIXED
Product: gvfs
Classification: Core
Component: udisks2 volume monitor
1.13.x
Other Linux
: Normal normal
: ---
Assigned To: gvfs-maint
gvfs-maint
: 731814 (view as bug list)
Depends on:
Blocks:
 
 
Reported: 2012-06-21 16:16 UTC by Cosimo Cecchi
Modified: 2016-02-15 08:31 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
udisks2: Prevent race between unmount reply and retry timer (6.25 KB, patch)
2015-06-18 20:46 UTC, Ross Lagerwall
none Details | Review
udisks2: Prevent race between unmount reply and retry timer (5.53 KB, patch)
2015-06-20 07:25 UTC, Ross Lagerwall
none Details | Review
udisks2: Prevent race between unmount reply and retry timer (5.43 KB, patch)
2015-06-20 07:27 UTC, Ross Lagerwall
committed Details | Review
valgrind output (2.82 KB, text/plain)
2016-02-08 09:03 UTC, Ondrej Holy
  Details
udisks2: Avoid crashes during unmount (1.10 KB, patch)
2016-02-08 09:10 UTC, Ondrej Holy
committed Details | Review

Description Cosimo Cecchi 2012-06-21 16:16:58 UTC
Got this while a demo

Core was generated by `/usr/libexec/gvfs-udisks2-volume-monitor'.
Program terminated with signal 11, Segmentation fault.

Thread 1 (Thread 0x7fece2aad800 (LWP 1880))

  • #0 g_type_check_instance_is_a
    at gtype.c line 3966
  • #1 g_simple_async_result_take_error
    at gsimpleasyncresult.c line 667
  • #2 lock_cb
    at gvfsudisks2mount.c line 772
  • #3 g_simple_async_result_complete
    at gsimpleasyncresult.c line 767
  • #4 reply_cb
    at gdbusproxy.c line 2614
  • #5 g_simple_async_result_complete
    at gsimpleasyncresult.c line 767
  • #6 g_dbus_connection_call_done
    at gdbusconnection.c line 5284
  • #7 g_simple_async_result_complete
    at gsimpleasyncresult.c line 767
  • #8 complete_in_idle_cb
    at gsimpleasyncresult.c line 779
  • #9 g_main_dispatch
    at gmain.c line 2539
  • #10 g_main_context_dispatch
    at gmain.c line 3075
  • #11 g_main_context_iterate
    at gmain.c line 3146
  • #12 g_main_loop_run
    at gmain.c line 3340
  • #13 g_vfs_proxy_volume_monitor_daemon_main
    at gvfsproxyvolumemonitordaemon.c line 1942
  • #14 __libc_start_main
    at libc-start.c line 225
  • #15 _start

Comment 1 Tomas Bzatek 2012-12-04 10:37:47 UTC
Would be interesting to know how this had happened. Reading the code it seems sane to me, though the private data structure is passed there a lot and a forgotten non-cancelled callback may still use the freed memory.
Comment 2 Ondrej Holy 2015-06-16 12:11:05 UTC
It seems this is pretty common crash, see:
https://retrace.fedoraproject.org/faf2/problems/890220/
Comment 3 Ross Lagerwall 2015-06-18 11:52:14 UTC
I've got a patch for this and it may possibly fix bug 751038 as well. I just need to do some testing on it.
Comment 4 Ross Lagerwall 2015-06-18 20:46:37 UTC
Created attachment 305624 [details] [review]
udisks2: Prevent race between unmount reply and retry timer

Currently it is possible for the unmount op reply and the retry unmount
timer to race. A udisks2 unmount operation (or umount spawned command)
is started via the timer. In the meantime, a "cancel" or "force unmount"
reply is received which completes the gvfs unmount operation and frees
the private data. When the udisks2 unmount operation started by the
timer completes, it tries to use the freed data and segfaults.

To fix this, prevent starting an unmount operation when another is
already in progress.  If a timer callback is received while an unmount
operation is in progress, simply ignore it.  If an unmount op reply is
received while an unmount operation is in progress, store the result of
the reply and handle it once the unmount operation has completed.
Comment 5 Ross Lagerwall 2015-06-18 20:47:43 UTC
(In reply to Ross Lagerwall from comment #3)
> I've got a patch for this and it may possibly fix bug 751038 as well. I just
> need to do some testing on it.

Looking again, I don't think this is related to bug 751038.

I've done some basic testing and I think it fixes the issue. I'd appreciate some more testing though.
Comment 6 Ondrej Holy 2015-06-19 12:15:00 UTC
Review of attachment 305624 [details] [review]:

It is really good point, Ross! I've not tested it yet, but...

I think that also following change should be done (imagine the case when on_mount_op_reply with "force unmount" choice is invoked immediately before lsof_command_cb due to timeout)...
@@ -726,7 +726,7 @@ lsof_command_cb (GObject       *source_object,
     }
 
  out:
-  if (!data->completed)
+  if (!data->completed && !data->reply_set)
     {
       gboolean is_eject;
       gboolean is_stop;

::: monitor/udisks2/gvfsudisks2mount.c
@@ +817,3 @@
+      return;
+    }
+

It seems enough to set data->in_progress = FALSE once here and other occurrences of data->in_progress = FALSE can be removed, don't you think?
Comment 7 Ross Lagerwall 2015-06-20 07:25:49 UTC
Created attachment 305737 [details] [review]
udisks2: Prevent race between unmount reply and retry timer

Currently it is possible for the unmount op reply and the retry unmount
timer to race. A udisks2 unmount operation (or umount spawned command)
is started via the timer. In the meantime, a "cancel" or "force unmount"
reply is received which completes the gvfs unmount operation and frees
the private data. When the udisks2 unmount operation started by the
timer completes, it tries to use the freed data and segfaults.

To fix this, prevent starting an unmount operation when another is
already in progress.  If a timer callback is received while an unmount
operation is in progress, simply ignore it.  If an unmount op reply is
received while an unmount operation is in progress, store the result of
the reply and handle it once the unmount operation has completed.
Comment 8 Ross Lagerwall 2015-06-20 07:27:40 UTC
Created attachment 305738 [details] [review]
udisks2: Prevent race between unmount reply and retry timer

Currently it is possible for the unmount op reply and the retry unmount
timer to race. A udisks2 unmount operation (or umount spawned command)
is started via the timer. In the meantime, a "cancel" or "force unmount"
reply is received which completes the gvfs unmount operation and frees
the private data. When the udisks2 unmount operation started by the
timer completes, it tries to use the freed data and segfaults.

To fix this, prevent starting an unmount operation when another is
already in progress.  If a timer callback is received while an unmount
operation is in progress, simply ignore it.  If an unmount op reply is
received while an unmount operation is in progress, store the result of
the reply and handle it once the unmount operation has completed.
Comment 9 Ross Lagerwall 2015-06-20 07:28:48 UTC
(In reply to Ondrej Holy from comment #6)
> Review of attachment 305624 [details] [review] [review]:
> 
> It is really good point, Ross! I've not tested it yet, but...
> 
> I think that also following change should be done (imagine the case when
> on_mount_op_reply with "force unmount" choice is invoked immediately before
> lsof_command_cb due to timeout)...

I don't think this is a problem. unmount_show_busy holds an extra ref to data so it can't be freed before lsof_command_cb runs. And updating the list of processes should be OK during force unmount (even force-unmount may return busy in which case we need to update the list again).

> @@ -726,7 +726,7 @@ lsof_command_cb (GObject       *source_object,
>      }
>  
>   out:
> -  if (!data->completed)
> +  if (!data->completed && !data->reply_set)
>      {
>        gboolean is_eject;
>        gboolean is_stop;
> 
> ::: monitor/udisks2/gvfsudisks2mount.c
> @@ +817,3 @@
> +      return;
> +    }
> +
> 
> It seems enough to set data->in_progress = FALSE once here and other
> occurrences of data->in_progress = FALSE can be removed, don't you think?

OK, the updated patch sets in_progress to FALSE either in unmount_data_complete or unmount_show_busy.
Comment 10 Ondrej Holy 2015-06-24 10:33:29 UTC
Review of attachment 305738 [details] [review]:

Looks good, thanks!
Comment 11 Ross Lagerwall 2015-07-05 07:04:00 UTC
Pushed to master as c014b64fa17f5b725f1f13d7952ec479e45e6031. Thanks for the reviews!
Comment 12 Ondrej Holy 2015-08-05 07:37:22 UTC
Ross, please push this also into the stable branches...
Comment 13 Ross Lagerwall 2015-08-06 06:15:30 UTC
OK, pushed to gnome-3-14 and gnome-3-16.
Comment 14 Ondrej Holy 2015-08-06 06:46:25 UTC
Thanks!
Comment 15 Ondrej Holy 2015-10-29 11:34:36 UTC
It seems we introduced another bug, or didn't fix all the races here, see:
https://bugzilla.redhat.com/show_bug.cgi?id=1276236

Truncated backtrace:
Thread no. 1 (10 frames)
 #0 g_simple_async_result_set_error at gsimpleasyncresult.c:719
 #1 mount_op_reply_handle at gvfsudisks2mount.c:666
 #2 unmount_show_busy at gvfsudisks2mount.c:819
 #3 unmount_cb at gvfsudisks2mount.c:869
 #4 g_simple_async_result_complete at gsimpleasyncresult.c:763
 #5 reply_cb at gdbusproxy.c:2623
 #6 g_simple_async_result_complete at gsimpleasyncresult.c:763
 #7 g_dbus_connection_call_done at gdbusconnection.c:5502
 #8 g_simple_async_result_complete at gsimpleasyncresult.c:763
 #9 complete_in_idle_cb at gsimpleasyncresult.c:775
Comment 16 Ondrej Holy 2016-02-02 07:55:13 UTC
*** Bug 731814 has been marked as a duplicate of this bug. ***
Comment 17 Ondrej Holy 2016-02-08 09:03:34 UTC
Created attachment 320606 [details]
valgrind output

I have finally reproduce the crash in my environment and attaching valgrind output...
Comment 18 Ondrej Holy 2016-02-08 09:09:16 UTC
Review of attachment 305738 [details] [review]:

::: monitor/udisks2/gvfsudisks2mount.c
@@ +690,3 @@
+  data->reply_choice = choice;
+  data->reply_set = TRUE;
+  if (!data->completed || !data->in_progress)

The problem is that this condition is always true... there should be && instead of ||. However it seems to me that data->completed can't be true in this place ever...
Comment 19 Ondrej Holy 2016-02-08 09:10:31 UTC
Created attachment 320607 [details] [review]
udisks2: Avoid crashes during unmount

Commit c014b64 was pushed to prevent race between unmount reply and retry timer. Result of mount operation reply should be stored if unmount operation is in progress, however it isn't, because the conditional statement is always true. Fix the condition accordingly.
Comment 20 Ross Lagerwall 2016-02-14 20:08:23 UTC
Review of attachment 320607 [details] [review]:

Looks good. Thanks for working this out.
Comment 21 Ross Lagerwall 2016-02-14 20:11:45 UTC
(In reply to Ondrej Holy from comment #18)
> Review of attachment 305738 [details] [review] [review]:
> 
> ::: monitor/udisks2/gvfsudisks2mount.c
> @@ +690,3 @@
> +  data->reply_choice = choice;
> +  data->reply_set = TRUE;
> +  if (!data->completed || !data->in_progress)
> 
> The problem is that this condition is always true... there should be &&
> instead of ||. However it seems to me that data->completed can't be true in
> this place ever...

I think data->completed may be true here if unmount_data_complete() is called and then the "reply" signal is handled. This can only happen if there's still a ref for the UnmountData preventing the handler from being disconnected.
Comment 22 Ondrej Holy 2016-02-15 08:30:43 UTC
Comment on attachment 320607 [details] [review]
udisks2: Avoid crashes during unmount

Thanks for review! Pushed to master as commit 1f28d65, gnome-3-18 as commit 12f104b, and gnome-3-16 as commit 88d13b4...