Skip to content

Commit 1e59ef4

Browse files
committed
Detect local X start by socket creation if dropping privileges
* A depriviledged X cannot send back a SIGUSR1 when it is ready
1 parent 5fd7e78 commit 1e59ef4

File tree

1 file changed

+52
-1
lines changed

1 file changed

+52
-1
lines changed

src/x-server-local.c

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@ typedef struct
6464
/* TRUE when received ready signal */
6565
gboolean got_signal;
6666

67+
/* Poll source ID (fallback for signal if uids differ) */
68+
guint poll_for_socket_source;
69+
6770
/* VT to run on */
6871
gint vt;
6972
gboolean have_vt_ref;
@@ -391,6 +394,46 @@ got_signal_cb (Process *process, int signum, XServerLocal *server)
391394
}
392395
}
393396

397+
static gboolean
398+
poll_for_socket_cb (XServerLocal *server)
399+
{
400+
XServerLocalPrivate *priv = x_server_local_get_instance_private (server);
401+
402+
/* Check is X11 socket file exists as an alternative startup test to SIGUSR1 */
403+
GStatBuf statbuf;
404+
g_autofree gchar *socketpath = g_strdup_printf ("/tmp/.X11-unix/X%d", priv->display_number);
405+
if ( g_stat (socketpath, &statbuf) == 0 )
406+
{
407+
uid_t uid = priv->user ? user_get_uid(priv->user) : 0;
408+
409+
/* It has to be a valid socket file */
410+
if (!(statbuf.st_mode & S_IFSOCK))
411+
{
412+
l_debug (server, "X11 socket file is not a socket: %s", socketpath);
413+
return G_SOURCE_REMOVE;
414+
}
415+
416+
/* It has to be owned by the correct user */
417+
if (statbuf.st_uid != uid)
418+
{
419+
l_debug (server, "X11 socket file is not owned by uid %d: %s", uid, socketpath);
420+
return G_SOURCE_REMOVE;
421+
}
422+
423+
/* Consider SIGUSR1 to have been recieved */
424+
priv->got_signal = TRUE;
425+
l_debug (server, "Detected valid X11 socket for X server :%d", priv->display_number);
426+
427+
// FIXME: Check return value
428+
DISPLAY_SERVER_CLASS (x_server_local_parent_class)->start (DISPLAY_SERVER (server));
429+
430+
return G_SOURCE_REMOVE;
431+
}
432+
433+
/* Wait another second and check again */
434+
return G_SOURCE_CONTINUE;
435+
}
436+
394437
static void
395438
stopped_cb (Process *process, XServerLocal *server)
396439
{
@@ -468,7 +511,10 @@ x_server_local_start (DisplayServer *display_server)
468511
ProcessRunFunc run_cb = X_SERVER_LOCAL_GET_CLASS (server)->get_run_function (server);
469512
priv->x_server_process = process_new (run_cb, server);
470513
process_set_clear_environment (priv->x_server_process, TRUE);
471-
g_signal_connect (priv->x_server_process, PROCESS_SIGNAL_GOT_SIGNAL, G_CALLBACK (got_signal_cb), server);
514+
if (priv->user == NULL || user_get_uid (priv->user) == getuid ())
515+
g_signal_connect (priv->x_server_process, PROCESS_SIGNAL_GOT_SIGNAL, G_CALLBACK (got_signal_cb), server);
516+
else if (!priv->poll_for_socket_source)
517+
priv->poll_for_socket_source = g_timeout_add_seconds (1, (GSourceFunc)poll_for_socket_cb, server);
472518
g_signal_connect (priv->x_server_process, PROCESS_SIGNAL_STOPPED, G_CALLBACK (stopped_cb), server);
473519

474520
/* Setup logging */
@@ -594,6 +640,11 @@ x_server_local_finalize (GObject *object)
594640

595641
if (priv->x_server_process)
596642
g_signal_handlers_disconnect_matched (priv->x_server_process, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, self);
643+
if (priv->poll_for_socket_source)
644+
{
645+
g_source_remove (priv->poll_for_socket_source);
646+
priv->poll_for_socket_source = 0;
647+
}
597648
g_clear_object (&priv->x_server_process);
598649
g_clear_pointer (&priv->command, g_free);
599650
g_clear_object (&priv->user);

0 commit comments

Comments
 (0)