systemd icon indicating copy to clipboard operation
systemd copied to clipboard

Inconsistency in sd_session_get_tty()

Open MJ-LAMARC opened this issue 6 months ago • 3 comments

systemd version the issue has been seen with

systemd-257.6-1.fc42.x86_64

Used distribution

Fedora 42

Linux kernel version used

6.14.11-300.fc42.x86_64

CPU architectures issue was seen on

x86_64

Component

other

Expected behaviour you didn't see

By analysing an error in the write command, which is able to send messages to users which are directly connected to the system (e.g. tty1), but not able to send messages to users, which are connected via ssh, I came across the following anomaly

root@training2:~# loginctl
SESSION  UID USER SEAT  LEADER CLASS         TTY   IDLE SINCE       
      1 1077 mcj  -     1053   user          -     no   -           
     10    0 root -     7191   manager-early -     no   -           
     11 1077 mcj  -     7285   user          **pts/1** yes  2h 5min ago
     12    0 root -     7388   user          **pts/0** no   -           
     14    0 root seat0 60565  user-early    **tty1**  yes  2h 33min ago
      2 1077 mcj  -     1094   manager       -     no   -           

and

root@training2:~# utmpdump /run/utmp 
Utmp dump of /run/utmp
[2] [00000] [~~  ] [reboot  ] [~           ] [6.14.11-300.fc42.x86_64] [0.0.0.0        ] [2025-06-17T18:21:14,080339+00:00]
[1] [00051] [~~  ] [runlevel] [~           ] [6.14.11-300.fc42.x86_64] [0.0.0.0        ] [2025-06-17T18:21:18,002586+00:00]
[7] [60565] [**tty1**] [root    ] [**tty1**        ] [                    ] [0.0.0.0        ] [2025-06-18T08:53:38,998951+00:00]
[7] [07388] [**ts/0**] [root    ] [**pts/0**       ] [2001:db8::1000] [2001:db8::1000] [2025-06-18T07:12:58,218188+00:00]
[7] [07285] [**ts/1**] [mcj     ] [**pts/1**       ] [2001:db8::1000] [2001:db8::1000] [2025-06-18T07:09:24,347860+00:00]
[8] [03912] [ts/2] [        ] [pts/2       ] [2001:db8:19ee:7d84:53a9:bd44] [2001:db8:19ee:7d84:53a9:bd44] [2025-06-17T19:13:26,651383+00:00]
[8] [03917] [ts/3] [        ] [pts/3       ] [2001:db8:19ee:7d84:53a9:bd44] [2001:db8:19ee:7d84:53a9:bd44] [2025-06-17T19:13:26,643437+00:00]
[8] [04230] [423 ] [        ] [web console ] [                    ] [0.0.0.0        ] [2025-06-17T20:40:47,024294+00:00]

In utmpdump the third column is crippled to ts/0 where it should read pts/0 This resulted in a failure when calling sd_session_get_tty() in write.c giving you ENODEV

157                         if ((r=sd_session_get_tty(sessions_list[i], &tty)) < 0) {
158                                 printf("Debug: TTY error for %s - %s\n", name, strerror(-r));
159                                 free(name);
160                                 continue;
161                         }

Unexpected behaviour you saw

see above

Steps to reproduce the problem

Double check:

# chgrp tty /usr/bin/write
# chmod g+s /usr/bin/write

SessionA: One user log in via ssh; will result in e.g. pts/0 SessionB: another user log in via ssh, doing a write userA pts/0

Additional program output to the terminal or log subsystem illustrating the issue


MJ-LAMARC avatar Jun 18 '25 11:06 MJ-LAMARC

In utmpdump the third column is crippled to ts/0 where it should read pts/0

Yes, it definitely is, see utmpx(5) man page. The third column is the ut_id[] field of struct utmp, and on Linux that's sized to 4. Hence we must truncate. And this is even documented: "Terminal name suffix" according to man page.

sd_session_get_tty() doesn't bother with utmp though. hence not sure i grok what your report precisely is about?

poettering avatar Jun 18 '25 14:06 poettering

note that the venerable write tool does not interface with logind though, i.e. it does not care about sd_session_get_tty().

most likely your ssh ttys are just 0600 or so, while the other ttys are 0622 or so. Which is entirely unrelated to systemd...

poettering avatar Jun 18 '25 14:06 poettering

Perms and SGID are ok:

# ll /usr/local/bin/write 
-rwxr-sr-x. 1 root tty 59120 Jun 18 11:11 /usr/local/bin/write

Code from util-linux/*/write.c pls look at line 156

131 /*
132  * check_utmp - checks that the given user is actually logged in on
133  *     the given tty
134  */
135 static int check_utmp(const struct write_control *ctl)
136 {
137         struct utmpx *u;
138         int res = 1;
139 #if defined(USE_SYSTEMD) && HAVE_DECL_SD_SESSION_GET_USERNAME == 1
140         if (sd_booted() > 0) {
141                 char **sessions_list;
142                 int sessions = sd_get_sessions(&sessions_list);
143                 if (sessions < 0)
144                         errx(EXIT_FAILURE, _("error getting sessions: %s"),
145                                 strerror(-sessions));
146 
147                 for (int i = 0; i < sessions; i++) {
148 
149                         char *name, *tty;
150                         int r;
151                         printf("Debug: Checking session %d\n", i);
152                         if ((r = sd_session_get_username(sessions_list[i], &name)) < 0)
153                                 errx(EXIT_FAILURE, _("get user name failed: %s"), strerror (-r));
154                         printf("Debug: Username: %s\n", name);
155                         if ((r=sd_session_get_tty(sessions_list[i], &tty)) < 0) {
156                                 printf("Debug: TTY error for %s - %s\n", name, strerror(-r));
157                                 free(name);
158                                 continue;
159                         }
160                         printf("Debug: TTY: %s, Expected: %s\n", tty, ctl->dst_tty_name);
161                         if  (strcmp(ctl->dst_login, name) == 0 &&
162                                         strcmp(ctl->dst_tty_name, tty) == 0) {
163                                 free(name);
164                                 free(tty);
165                                 res = 0;
166                                 break;
167                         }
168                         free(name);
169                         free(tty);
170                 }
171                 for (int i = 0; i < sessions; i++)
172                         free(sessions_list[i]);
173                 free(sessions_list);
174         } else {
175 #endif

root is logged in twice. on tty1 and via ssh on pts/0 giving me with the code above

$ /usr/local/bin/write root pts/0
Debug: Checking session 0
Debug: Username: root
Debug: TTY: tty1, Expected: pts/0
Debug: Checking session 1
Debug: Username: root
Debug: TTY error for root - No data available
Debug: Checking session 2
Debug: Username: mcj
Debug: TTY error for mcj - No data available
Debug: Checking session 3
Debug: Username: root
Debug: TTY error for root - No data available
Debug: Checking session 4
Debug: Username: mcj
Debug: TTY error for mcj - No data available
Debug: Checking session 5
Debug: Username: mcj
Debug: TTY error for mcj - No data available
write: root is not logged in on pts/0

MJ-LAMARC avatar Jun 18 '25 15:06 MJ-LAMARC