Skip to content

Commit 85af646

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 85af646

File tree

1 file changed

+50
-1
lines changed

1 file changed

+50
-1
lines changed

src/x-server-local.c

Lines changed: 50 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,44 @@ 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+
406+
if ( g_stat (socketpath, &statbuf) == 0 )
407+
{
408+
uid_t uid = priv->user ? user_get_uid(priv->user) : 0;
409+
410+
/* It has to be a valid socket file */
411+
if (!(statbuf.st_mode & S_IFSOCK))
412+
l_debug (server, "X11 socket file is not a socket: %s", socketpath);
413+
414+
/* It has to be owned by the correct user */
415+
else if (statbuf.st_uid != uid)
416+
l_debug (server, "X11 socket file is not owned by uid %d: %s", uid, socketpath);
417+
418+
/* Consider SIGUSR1 to have been recieved */
419+
else {
420+
priv->got_signal = TRUE;
421+
l_debug (server, "Detected valid X11 socket for X server :%d", priv->display_number);
422+
423+
// FIXME: Check return value
424+
DISPLAY_SERVER_CLASS (x_server_local_parent_class)->start (DISPLAY_SERVER (server));
425+
}
426+
427+
/* Cancel the timer as the file showed up */
428+
return FALSE;
429+
}
430+
431+
/* Wait another second and check again */
432+
return TRUE;
433+
}
434+
394435
static void
395436
stopped_cb (Process *process, XServerLocal *server)
396437
{
@@ -468,7 +509,10 @@ x_server_local_start (DisplayServer *display_server)
468509
ProcessRunFunc run_cb = X_SERVER_LOCAL_GET_CLASS (server)->get_run_function (server);
469510
priv->x_server_process = process_new (run_cb, server);
470511
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);
512+
if (priv->user == NULL || user_get_uid (priv->user) == getuid ())
513+
g_signal_connect (priv->x_server_process, PROCESS_SIGNAL_GOT_SIGNAL, G_CALLBACK (got_signal_cb), server);
514+
else if (!priv->poll_for_socket_source)
515+
priv->poll_for_socket_source = g_timeout_add_seconds (1, (GSourceFunc)poll_for_socket_cb, server);
472516
g_signal_connect (priv->x_server_process, PROCESS_SIGNAL_STOPPED, G_CALLBACK (stopped_cb), server);
473517

474518
/* Setup logging */
@@ -594,6 +638,11 @@ x_server_local_finalize (GObject *object)
594638

595639
if (priv->x_server_process)
596640
g_signal_handlers_disconnect_matched (priv->x_server_process, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, self);
641+
if (priv->poll_for_socket_source)
642+
{
643+
g_source_remove (priv->poll_for_socket_source);
644+
priv->poll_for_socket_source = 0;
645+
}
597646
g_clear_object (&priv->x_server_process);
598647
g_clear_pointer (&priv->command, g_free);
599648
g_clear_object (&priv->user);

0 commit comments

Comments
 (0)