1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 
3 #include <fcntl.h>
4 #include <string.h>
5 #include <sys/ioctl.h>
6 #include <sys/types.h>
7 
8 #include "sd-device.h"
9 #include "sd-daemon.h"
10 
11 #include "alloc-util.h"
12 #include "bus-util.h"
13 #include "fd-util.h"
14 #include "logind-session-dbus.h"
15 #include "logind-session-device.h"
16 #include "missing_drm.h"
17 #include "missing_input.h"
18 #include "parse-util.h"
19 #include "util.h"
20 
21 enum SessionDeviceNotifications {
22         SESSION_DEVICE_RESUME,
23         SESSION_DEVICE_TRY_PAUSE,
24         SESSION_DEVICE_PAUSE,
25         SESSION_DEVICE_RELEASE,
26 };
27 
session_device_notify(SessionDevice * sd,enum SessionDeviceNotifications type)28 static int session_device_notify(SessionDevice *sd, enum SessionDeviceNotifications type) {
29         _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
30         _cleanup_free_ char *path = NULL;
31         const char *t = NULL;
32         uint32_t major, minor;
33         int r;
34 
35         assert(sd);
36 
37         major = major(sd->dev);
38         minor = minor(sd->dev);
39 
40         if (!sd->session->controller)
41                 return 0;
42 
43         path = session_bus_path(sd->session);
44         if (!path)
45                 return -ENOMEM;
46 
47         r = sd_bus_message_new_signal(
48                         sd->session->manager->bus,
49                         &m, path,
50                         "org.freedesktop.login1.Session",
51                         (type == SESSION_DEVICE_RESUME) ? "ResumeDevice" : "PauseDevice");
52         if (!m)
53                 return r;
54 
55         r = sd_bus_message_set_destination(m, sd->session->controller);
56         if (r < 0)
57                 return r;
58 
59         switch (type) {
60 
61         case SESSION_DEVICE_RESUME:
62                 r = sd_bus_message_append(m, "uuh", major, minor, sd->fd);
63                 if (r < 0)
64                         return r;
65                 break;
66 
67         case SESSION_DEVICE_TRY_PAUSE:
68                 t = "pause";
69                 break;
70 
71         case SESSION_DEVICE_PAUSE:
72                 t = "force";
73                 break;
74 
75         case SESSION_DEVICE_RELEASE:
76                 t = "gone";
77                 break;
78 
79         default:
80                 return -EINVAL;
81         }
82 
83         if (t) {
84                 r = sd_bus_message_append(m, "uus", major, minor, t);
85                 if (r < 0)
86                         return r;
87         }
88 
89         return sd_bus_send(sd->session->manager->bus, m, NULL);
90 }
91 
sd_eviocrevoke(int fd)92 static void sd_eviocrevoke(int fd) {
93         static bool warned = false;
94 
95         assert(fd >= 0);
96 
97         if (ioctl(fd, EVIOCREVOKE, NULL) < 0) {
98 
99                 if (errno == EINVAL && !warned) {
100                         log_warning_errno(errno, "Kernel does not support evdev-revocation: %m");
101                         warned = true;
102                 }
103         }
104 }
105 
sd_drmsetmaster(int fd)106 static int sd_drmsetmaster(int fd) {
107         assert(fd >= 0);
108         return RET_NERRNO(ioctl(fd, DRM_IOCTL_SET_MASTER, 0));
109 }
110 
sd_drmdropmaster(int fd)111 static int sd_drmdropmaster(int fd) {
112         assert(fd >= 0);
113         return RET_NERRNO(ioctl(fd, DRM_IOCTL_DROP_MASTER, 0));
114 }
115 
session_device_open(SessionDevice * sd,bool active)116 static int session_device_open(SessionDevice *sd, bool active) {
117         int fd, r;
118 
119         assert(sd);
120         assert(sd->type != DEVICE_TYPE_UNKNOWN);
121         assert(sd->node);
122 
123         /* open device and try to get an udev_device from it */
124         fd = open(sd->node, O_RDWR|O_CLOEXEC|O_NOCTTY|O_NONBLOCK);
125         if (fd < 0)
126                 return -errno;
127 
128         switch (sd->type) {
129 
130         case DEVICE_TYPE_DRM:
131                 if (active) {
132                         /* Weird legacy DRM semantics might return an error even though we're master. No way to detect
133                          * that so fail at all times and let caller retry in inactive state. */
134                         r = sd_drmsetmaster(fd);
135                         if (r < 0) {
136                                 (void) close_nointr(fd);
137                                 return r;
138                         }
139                 } else
140                         /* DRM-Master is granted to the first user who opens a device automatically (ughh,
141                          * racy!). Hence, we just drop DRM-Master in case we were the first. */
142                         (void) sd_drmdropmaster(fd);
143                 break;
144 
145         case DEVICE_TYPE_EVDEV:
146                 if (!active)
147                         sd_eviocrevoke(fd);
148                 break;
149 
150         case DEVICE_TYPE_UNKNOWN:
151         default:
152                 /* fallback for devices without synchronizations */
153                 break;
154         }
155 
156         return fd;
157 }
158 
session_device_start(SessionDevice * sd)159 static int session_device_start(SessionDevice *sd) {
160         int r;
161 
162         assert(sd);
163         assert(session_is_active(sd->session));
164 
165         if (sd->active)
166                 return 0;
167 
168         switch (sd->type) {
169 
170         case DEVICE_TYPE_DRM:
171                 if (sd->fd < 0)
172                         return log_error_errno(SYNTHETIC_ERRNO(EBADF),
173                                                "Failed to re-activate DRM fd, as the fd was lost (maybe logind restart went wrong?)");
174 
175                 /* Device is kept open. Simply call drmSetMaster() and hope there is no-one else. In case it fails, we
176                  * keep the device paused. Maybe at some point we have a drmStealMaster(). */
177                 r = sd_drmsetmaster(sd->fd);
178                 if (r < 0)
179                         return r;
180                 break;
181 
182         case DEVICE_TYPE_EVDEV:
183                 /* Evdev devices are revoked while inactive. Reopen it and we are fine. */
184                 r = session_device_open(sd, true);
185                 if (r < 0)
186                         return r;
187 
188                 /* For evdev devices, the file descriptor might be left uninitialized. This might happen while resuming
189                  * into a session and logind has been restarted right before. */
190                 CLOSE_AND_REPLACE(sd->fd, r);
191                 break;
192 
193         case DEVICE_TYPE_UNKNOWN:
194         default:
195                 /* fallback for devices without synchronizations */
196                 break;
197         }
198 
199         sd->active = true;
200         return 0;
201 }
202 
session_device_stop(SessionDevice * sd)203 static void session_device_stop(SessionDevice *sd) {
204         assert(sd);
205 
206         if (!sd->active)
207                 return;
208 
209         switch (sd->type) {
210 
211         case DEVICE_TYPE_DRM:
212                 if (sd->fd < 0) {
213                         log_error("Failed to de-activate DRM fd, as the fd was lost (maybe logind restart went wrong?)");
214                         return;
215                 }
216 
217                 /* On DRM devices we simply drop DRM-Master but keep it open.
218                  * This allows the user to keep resources allocated. The
219                  * CAP_SYS_ADMIN restriction to DRM-Master prevents users from
220                  * circumventing this. */
221                 sd_drmdropmaster(sd->fd);
222                 break;
223 
224         case DEVICE_TYPE_EVDEV:
225                 /* Revoke access on evdev file-descriptors during deactivation.
226                  * This will basically prevent any operations on the fd and
227                  * cannot be undone. Good side is: it needs no CAP_SYS_ADMIN
228                  * protection this way. */
229                 sd_eviocrevoke(sd->fd);
230                 break;
231 
232         case DEVICE_TYPE_UNKNOWN:
233         default:
234                 /* fallback for devices without synchronization */
235                 break;
236         }
237 
238         sd->active = false;
239 }
240 
detect_device_type(sd_device * dev)241 static DeviceType detect_device_type(sd_device *dev) {
242         const char *sysname, *subsystem;
243         DeviceType type = DEVICE_TYPE_UNKNOWN;
244 
245         if (sd_device_get_sysname(dev, &sysname) < 0 ||
246             sd_device_get_subsystem(dev, &subsystem) < 0)
247                 return type;
248 
249         if (streq(subsystem, "drm")) {
250                 if (startswith(sysname, "card"))
251                         type = DEVICE_TYPE_DRM;
252         } else if (streq(subsystem, "input")) {
253                 if (startswith(sysname, "event"))
254                         type = DEVICE_TYPE_EVDEV;
255         }
256 
257         return type;
258 }
259 
session_device_verify(SessionDevice * sd)260 static int session_device_verify(SessionDevice *sd) {
261         _cleanup_(sd_device_unrefp) sd_device *p = NULL;
262         const char *sp, *node;
263         sd_device *dev;
264         int r;
265 
266         r = sd_device_new_from_devnum(&p, 'c', sd->dev);
267         if (r < 0)
268                 return r;
269 
270         dev = p;
271 
272         if (sd_device_get_syspath(dev, &sp) < 0 ||
273             sd_device_get_devname(dev, &node) < 0)
274                 return -EINVAL;
275 
276         /* detect device type so we can find the correct sysfs parent */
277         sd->type = detect_device_type(dev);
278         if (sd->type == DEVICE_TYPE_UNKNOWN)
279                 return -ENODEV;
280 
281         else if (sd->type == DEVICE_TYPE_EVDEV) {
282                 /* for evdev devices we need the parent node as device */
283                 if (sd_device_get_parent_with_subsystem_devtype(p, "input", NULL, &dev) < 0)
284                         return -ENODEV;
285                 if (sd_device_get_syspath(dev, &sp) < 0)
286                         return -ENODEV;
287 
288         } else if (sd->type != DEVICE_TYPE_DRM)
289                 /* Prevent opening unsupported devices. Especially devices of
290                  * subsystem "input" must be opened via the evdev node as
291                  * we require EVIOCREVOKE. */
292                 return -ENODEV;
293 
294         /* search for an existing seat device and return it if available */
295         sd->device = hashmap_get(sd->session->manager->devices, sp);
296         if (!sd->device) {
297                 /* The caller might have gotten the udev event before we were
298                  * able to process it. Hence, fake the "add" event and let the
299                  * logind-manager handle the new device. */
300                 r = manager_process_seat_device(sd->session->manager, dev);
301                 if (r < 0)
302                         return r;
303 
304                 /* if it's still not available, then the device is invalid */
305                 sd->device = hashmap_get(sd->session->manager->devices, sp);
306                 if (!sd->device)
307                         return -ENODEV;
308         }
309 
310         if (sd->device->seat != sd->session->seat)
311                 return -EPERM;
312 
313         sd->node = strdup(node);
314         if (!sd->node)
315                 return -ENOMEM;
316 
317         return 0;
318 }
319 
session_device_new(Session * s,dev_t dev,bool open_device,SessionDevice ** out)320 int session_device_new(Session *s, dev_t dev, bool open_device, SessionDevice **out) {
321         SessionDevice *sd;
322         int r;
323 
324         assert(s);
325         assert(out);
326 
327         if (!s->seat)
328                 return -EPERM;
329 
330         sd = new0(SessionDevice, 1);
331         if (!sd)
332                 return -ENOMEM;
333 
334         sd->session = s;
335         sd->dev = dev;
336         sd->fd = -1;
337         sd->type = DEVICE_TYPE_UNKNOWN;
338 
339         r = session_device_verify(sd);
340         if (r < 0)
341                 goto error;
342 
343         r = hashmap_put(s->devices, &sd->dev, sd);
344         if (r < 0)
345                 goto error;
346 
347         if (open_device) {
348                 /* Open the device for the first time. We need a valid fd to pass back
349                  * to the caller. If the session is not active, this _might_ immediately
350                  * revoke access and thus invalidate the fd. But this is still needed
351                  * to pass a valid fd back. */
352                 sd->active = session_is_active(s);
353                 r = session_device_open(sd, sd->active);
354                 if (r < 0) {
355                         /* EINVAL _may_ mean a master is active; retry inactive */
356                         if (sd->active && r == -EINVAL) {
357                                 sd->active = false;
358                                 r = session_device_open(sd, false);
359                         }
360                         if (r < 0)
361                                 goto error;
362                 }
363                 sd->fd = r;
364         }
365 
366         LIST_PREPEND(sd_by_device, sd->device->session_devices, sd);
367 
368         *out = sd;
369         return 0;
370 
371 error:
372         hashmap_remove(s->devices, &sd->dev);
373         free(sd->node);
374         free(sd);
375         return r;
376 }
377 
session_device_free(SessionDevice * sd)378 void session_device_free(SessionDevice *sd) {
379         int r;
380 
381         assert(sd);
382 
383         /* Make sure to remove the pushed fd. */
384         if (sd->pushed_fd) {
385                 r = sd_notifyf(false,
386                                "FDSTOREREMOVE=1\n"
387                                "FDNAME=session-%s-device-%u-%u",
388                                sd->session->id, major(sd->dev), minor(sd->dev));
389                 if (r < 0)
390                         log_warning_errno(r, "Failed to remove file descriptor from the store, ignoring: %m");
391         }
392 
393         session_device_stop(sd);
394         session_device_notify(sd, SESSION_DEVICE_RELEASE);
395         safe_close(sd->fd);
396 
397         LIST_REMOVE(sd_by_device, sd->device->session_devices, sd);
398 
399         hashmap_remove(sd->session->devices, &sd->dev);
400 
401         free(sd->node);
402         free(sd);
403 }
404 
session_device_complete_pause(SessionDevice * sd)405 void session_device_complete_pause(SessionDevice *sd) {
406         SessionDevice *iter;
407 
408         if (!sd->active)
409                 return;
410 
411         session_device_stop(sd);
412 
413         /* if not all devices are paused, wait for further completion events */
414         HASHMAP_FOREACH(iter, sd->session->devices)
415                 if (iter->active)
416                         return;
417 
418         /* complete any pending session switch */
419         seat_complete_switch(sd->session->seat);
420 }
421 
session_device_resume_all(Session * s)422 void session_device_resume_all(Session *s) {
423         SessionDevice *sd;
424 
425         assert(s);
426 
427         HASHMAP_FOREACH(sd, s->devices) {
428                 if (sd->active)
429                         continue;
430 
431                 if (session_device_start(sd) < 0)
432                         continue;
433                 if (session_device_save(sd) < 0)
434                         continue;
435 
436                 session_device_notify(sd, SESSION_DEVICE_RESUME);
437         }
438 }
439 
session_device_pause_all(Session * s)440 void session_device_pause_all(Session *s) {
441         SessionDevice *sd;
442 
443         assert(s);
444 
445         HASHMAP_FOREACH(sd, s->devices) {
446                 if (!sd->active)
447                         continue;
448 
449                 session_device_stop(sd);
450                 session_device_notify(sd, SESSION_DEVICE_PAUSE);
451         }
452 }
453 
session_device_try_pause_all(Session * s)454 unsigned session_device_try_pause_all(Session *s) {
455         unsigned num_pending = 0;
456         SessionDevice *sd;
457 
458         assert(s);
459 
460         HASHMAP_FOREACH(sd, s->devices) {
461                 if (!sd->active)
462                         continue;
463 
464                 session_device_notify(sd, SESSION_DEVICE_TRY_PAUSE);
465                 num_pending++;
466         }
467 
468         return num_pending;
469 }
470 
session_device_save(SessionDevice * sd)471 int session_device_save(SessionDevice *sd) {
472         _cleanup_free_ char *m = NULL;
473         const char *id;
474         int r;
475 
476         assert(sd);
477 
478         /* Store device fd in PID1. It will send it back to us on restart so revocation will continue to work. To make
479          * things simple, send fds for all type of devices even if they don't support the revocation mechanism so we
480          * don't have to handle them differently later.
481          *
482          * Note: for device supporting revocation, PID1 will drop a stored fd automatically if the corresponding device
483          * is revoked. */
484 
485         if (sd->pushed_fd)
486                 return 0;
487 
488         /* Session ID does not contain separators. */
489         id = sd->session->id;
490         assert(*(id + strcspn(id, "-\n")) == '\0');
491 
492         r = asprintf(&m, "FDSTORE=1\n"
493                          "FDNAME=session-%s-device-%u-%u\n",
494                          id, major(sd->dev), minor(sd->dev));
495         if (r < 0)
496                 return r;
497 
498         r = sd_pid_notify_with_fds(0, false, m, &sd->fd, 1);
499         if (r < 0)
500                 return r;
501 
502         sd->pushed_fd = true;
503         return 1;
504 }
505 
session_device_attach_fd(SessionDevice * sd,int fd,bool active)506 void session_device_attach_fd(SessionDevice *sd, int fd, bool active) {
507         assert(fd >= 0);
508         assert(sd);
509         assert(sd->fd < 0);
510         assert(!sd->active);
511 
512         sd->fd = fd;
513         sd->pushed_fd = true;
514         sd->active = active;
515 }
516