Blame SOURCES/0044-session-worker-ensure-initial-vt-is-never-picked-for.patch

400dab
From 75b65846ca77bd2d42e25365b4b7242a406330cf Mon Sep 17 00:00:00 2001
400dab
From: Ray Strode <rstrode@redhat.com>
400dab
Date: Tue, 7 Apr 2020 14:37:41 -0400
400dab
Subject: [PATCH 44/51] session-worker: ensure initial vt is never picked for
400dab
 !is_initial displays
400dab
400dab
Normally, a !is_initial display would never "get" tty1, since the system
400dab
boots to tty1.  But if, for some reason, the user booted to runlevel 3,
400dab
then switched to runlevel 5, the login screen could get started when
400dab
tty1 is free.
400dab
400dab
That means, e.g., an autologin user can end up getting allocated tty1,
400dab
which is bad, since we assume tty1 is used for the login screen.
400dab
400dab
This commit opens up /dev/tty1 when querying for available VTs, so that
400dab
it never gets returned by the kernel as available.
400dab
---
400dab
 daemon/gdm-session-worker.c | 39 +++++++++++++++++++++++++------------
400dab
 1 file changed, 27 insertions(+), 12 deletions(-)
400dab
400dab
diff --git a/daemon/gdm-session-worker.c b/daemon/gdm-session-worker.c
400dab
index 0bd78cfaf..42c415837 100644
400dab
--- a/daemon/gdm-session-worker.c
400dab
+++ b/daemon/gdm-session-worker.c
400dab
@@ -2167,105 +2167,120 @@ gdm_session_worker_start_session (GdmSessionWorker  *worker,
400dab
 
400dab
         /* If we end up execing again, make sure we don't use the executable context set up
400dab
          * by pam_selinux durin pam_open_session
400dab
          */
400dab
 #ifdef HAVE_SELINUX
400dab
         setexeccon (NULL);
400dab
 #endif
400dab
 
400dab
         worker->priv->child_pid = session_pid;
400dab
 
400dab
         g_debug ("GdmSessionWorker: session opened creating reply...");
400dab
         g_assert (sizeof (GPid) <= sizeof (int));
400dab
 
400dab
         g_debug ("GdmSessionWorker: state SESSION_STARTED");
400dab
         gdm_session_worker_set_state (worker, GDM_SESSION_WORKER_STATE_SESSION_STARTED);
400dab
 
400dab
         gdm_session_worker_watch_child (worker);
400dab
 
400dab
  out:
400dab
         if (error_code != PAM_SUCCESS) {
400dab
                 gdm_session_worker_uninitialize_pam (worker, error_code);
400dab
                 return FALSE;
400dab
         }
400dab
 
400dab
         return TRUE;
400dab
 }
400dab
 
400dab
 static gboolean
400dab
 set_up_for_new_vt (GdmSessionWorker *worker)
400dab
 {
400dab
-        int fd;
400dab
+        int initial_vt_fd;
400dab
         char vt_string[256], tty_string[256];
400dab
         int session_vt = 0;
400dab
 
400dab
-        fd = open ("/dev/tty0", O_RDWR | O_NOCTTY);
400dab
-
400dab
-        if (fd < 0) {
400dab
-                g_debug ("GdmSessionWorker: couldn't open VT master: %m");
400dab
+        /* open the initial vt.  We need it for two scenarios:
400dab
+         *
400dab
+         * 1) display_is_initial is TRUE.  We need it directly.
400dab
+         * 2) display_is_initial is FALSE. We need it to mark
400dab
+         * the initial VT as "in use" so it doesn't get returned
400dab
+         * by VT_OPENQRY
400dab
+         * */
400dab
+        g_snprintf (tty_string, sizeof (tty_string), "/dev/tty%d", GDM_INITIAL_VT);
400dab
+        initial_vt_fd = open (tty_string, O_RDWR | O_NOCTTY);
400dab
+
400dab
+        if (initial_vt_fd < 0) {
400dab
+                g_debug ("GdmSessionWorker: couldn't open console of initial fd: %m");
400dab
                 return FALSE;
400dab
         }
400dab
 
400dab
         if (worker->priv->display_is_initial) {
400dab
                 session_vt = GDM_INITIAL_VT;
400dab
         } else {
400dab
-                if (ioctl(fd, VT_OPENQRY, &session_vt) < 0) {
400dab
+
400dab
+                /* Typically VT_OPENQRY is called on /dev/tty0, but we already
400dab
+                 * have /dev/tty1 open above, so might as well use it.
400dab
+                 */
400dab
+                if (ioctl (initial_vt_fd, VT_OPENQRY, &session_vt) < 0) {
400dab
                         g_debug ("GdmSessionWorker: couldn't open new VT: %m");
400dab
                         goto fail;
400dab
                 }
400dab
         }
400dab
 
400dab
         worker->priv->session_vt = session_vt;
400dab
 
400dab
-        close (fd);
400dab
-        fd = -1;
400dab
-
400dab
         g_assert (session_vt > 0);
400dab
 
400dab
         g_snprintf (vt_string, sizeof (vt_string), "%d", session_vt);
400dab
 
400dab
         /* Set the VTNR. This is used by logind to configure a session in
400dab
          * the logind-managed case, but it doesn't hurt to set it always.
400dab
          * When logind gains support for XDG_VTNR=auto, we can make the
400dab
          * OPENQRY and this whole path only used by the new VT code. */
400dab
         gdm_session_worker_set_environment_variable (worker,
400dab
                                                      "XDG_VTNR",
400dab
                                                      vt_string);
400dab
 
400dab
-        g_snprintf (tty_string, 256, "/dev/tty%d", session_vt);
400dab
-        worker->priv->session_tty_fd = open (tty_string, O_RDWR | O_NOCTTY);
400dab
+        if (worker->priv->display_is_initial) {
400dab
+             worker->priv->session_tty_fd = initial_vt_fd;
400dab
+        } else {
400dab
+             g_snprintf (tty_string, sizeof (tty_string), "/dev/tty%d", session_vt);
400dab
+             worker->priv->session_tty_fd = open (tty_string, O_RDWR | O_NOCTTY);
400dab
+             close (initial_vt_fd);
400dab
+        }
400dab
+
400dab
         pam_set_item (worker->priv->pam_handle, PAM_TTY, tty_string);
400dab
 
400dab
         return TRUE;
400dab
 
400dab
 fail:
400dab
-        close (fd);
400dab
+        close (initial_vt_fd);
400dab
         return FALSE;
400dab
 }
400dab
 
400dab
 static gboolean
400dab
 set_xdg_vtnr_to_current_vt (GdmSessionWorker *worker)
400dab
 {
400dab
         int fd;
400dab
         char vt_string[256];
400dab
         struct vt_stat vt_state = { 0 };
400dab
 
400dab
         fd = open ("/dev/tty0", O_RDWR | O_NOCTTY);
400dab
 
400dab
         if (fd < 0) {
400dab
                 g_debug ("GdmSessionWorker: couldn't open VT master: %m");
400dab
                 return FALSE;
400dab
         }
400dab
 
400dab
         if (ioctl (fd, VT_GETSTATE, &vt_state) < 0) {
400dab
                 g_debug ("GdmSessionWorker: couldn't get current VT: %m");
400dab
                 goto fail;
400dab
         }
400dab
 
400dab
         close (fd);
400dab
         fd = -1;
400dab
 
400dab
         g_snprintf (vt_string, sizeof (vt_string), "%d", vt_state.v_active);
400dab
 
400dab
         gdm_session_worker_set_environment_variable (worker,
400dab
                                                      "XDG_VTNR",
400dab
                                                      vt_string);
400dab
-- 
400dab
2.27.0
400dab