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 653570 - eventfd syscall check is unsafe
eventfd syscall check is unsafe
Status: RESOLVED FIXED
Product: glib
Classification: Platform
Component: mainloop
unspecified
Other All
: Normal normal
: ---
Assigned To: gtkdev
gtkdev
Depends on:
Blocks:
 
 
Reported: 2011-06-28 13:17 UTC by Allison Karlitskaya (desrt)
Modified: 2011-06-30 18:08 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
gmain: Fall back to pipes if kernel doesn't support EFD_CLOEXEC for eventfd() (2.89 KB, patch)
2011-06-28 14:03 UTC, Colin Walters
accepted-commit_now Details | Review

Description Allison Karlitskaya (desrt) 2011-06-28 13:17:42 UTC
The eventfd support for the mainloop is careful to check that the eventfd() syscall is supported before using it.

It does it with the following check:

      efd = eventfd (0, EFD_CLOEXEC);
      if (efd == -1 && errno == ENOSYS)

the problem is that, according to the manpage:

       EINVAL An unsupported value was specified in flags.

and

       EFD_CLOEXEC (since Linux 2.6.27)
              Set the close-on-exec (FD_CLOEXEC) flag on the new file descrip‐
              tor.  See the description of the O_CLOEXEC flag in  open(2)  for
              reasons why this may be useful.


So if you have a kernel before 2.6.27, you'll have eventfd but not EFD_CLOEXEC and the syscall will return EINVAL.  That will cause you to hit:

      else
        g_error ("Cannot create eventfd for main loop wake-up: %s", g_strerror (errno));


Two options:

  1) Use pipes in this case

  2) Create it and then fnctl() (in the style of g_unix_open_pipe())
Comment 1 Allison Karlitskaya (desrt) 2011-06-28 13:33:04 UTC
side-note: the use of the bitfields in the 'state' structure here is really unnecessarily confusing.

Worse, it could possibly lead to some bad effects due to the non-atomic nature of bitfield updates and the fact that you access it without a lock from the supposedly-threadsafe GMainContext.

The way you're using it, you could actually just have one variable:

  gboolean eventfd_unsupported;

You can set it to TRUE the when you notice that eventfd() fails and then you can check it on access to the fd to determine if you should treat it as eventfd (FALSE) or pipe (TRUE).
Comment 2 Colin Walters 2011-06-28 14:03:31 UTC
Created attachment 190862 [details] [review]
gmain: Fall back to pipes if kernel doesn't support EFD_CLOEXEC for eventfd()

Also remove the caching of checking for eventfd; just try it every time, it's
cheap enough to do so.
Comment 3 Allison Karlitskaya (desrt) 2011-06-28 14:29:16 UTC
Review of attachment 190862 [details] [review]:

Looks good.

Nice idea to use the second pipe fd as a flag for having eventfd or not.  That's cleaner than my proposed solution.

::: glib/gmain.c
@@ +575,3 @@
+    else if (efd >= 0)
+      {
+	context->wake_up_pipe[0] = efd;

should you have context->wake_up_pipe[1] = -1; here?
Comment 4 Colin Walters 2011-06-28 14:39:53 UTC
(In reply to comment #3)
> Review of attachment 190862 [details] [review]:
> 
> Looks good.
> 
> Nice idea to use the second pipe fd as a flag for having eventfd or not. 
> That's cleaner than my proposed solution.

Yeah, I came up with it when doing the GCancellable change.

> ::: glib/gmain.c
> @@ +575,3 @@
> +    else if (efd >= 0)
> +      {
> +    context->wake_up_pipe[0] = efd;
> 
> should you have context->wake_up_pipe[1] = -1; here?

That's actually done in g_main_context_new()
Comment 5 Allison Karlitskaya (desrt) 2011-06-28 14:58:45 UTC
Comment on attachment 190862 [details] [review]
gmain: Fall back to pipes if kernel doesn't support EFD_CLOEXEC for eventfd()

+1.
Comment 6 Matthias Clasen 2011-06-30 18:00:45 UTC
Comment on attachment 190862 [details] [review]
gmain: Fall back to pipes if kernel doesn't support EFD_CLOEXEC for eventfd()

Looks fine to me too