99#include <stdlib.h>
1010#include <stdio.h>
1111#include <stdint.h>
12+ #include <stdatomic.h>
1213#include <inttypes.h>
1314#include <ctype.h>
1415#include <grp.h>
2930#include <stdlib.h>
3031#include <string.h>
3132#include <unistd.h>
33+ #include "platform.h"
34+
35+ static uint64_t watchdog_anr_sent ;
3236
3337#if defined(__OpenBSD__ ) || defined(__FreeBSD__ )
3438#include <sys/event.h>
@@ -378,7 +382,7 @@ static int access_device(const char* path, int arg, bool release, bool* keep)
378382 struct stat devst ;
379383 * keep = false;
380384
381- /* special case, substitute TTY for the active tty device (if known) */
385+ /* special case 1 , substitute TTY for the active tty device (if known) */
382386 if (strcmp (path , "TTY" ) == 0 ){
383387 if (!got_tty .active )
384388 return -1 ;
@@ -388,7 +392,7 @@ static int access_device(const char* path, int arg, bool release, bool* keep)
388392 }
389393 }
390394
391- /* special case 2 - activate TTY (GRAPHICS switch) deferred to the first frame
395+ /* special case 3 - activate TTY (GRAPHICS switch) deferred to the first frame
392396 * so that any error output is actually visible after init but before first
393397 * composition, return this as an 'invalid file'. */
394398 if (strcmp (path , "TTYGRAPHICS" ) == 0 ){
@@ -430,6 +434,8 @@ static int access_device(const char* path, int arg, bool release, bool* keep)
430434 }
431435 * keep = true;
432436 if (whitelist [ind ].mode & MODE_DRM ){
437+ if (arcan_watchdog_ping )
438+ atomic_store (arcan_watchdog_ping , arcan_timemillis ());
433439 drmSetMaster (whitelist [ind ].fd );
434440 }
435441 return whitelist [ind ].fd ;
@@ -573,13 +579,47 @@ static void check_child(pid_t child, bool die)
573579 }
574580 }
575581/* or we want the child to soft-die? */
576- else if (die )
577- kill (SIGTERM , child );
578-
579- if (die ){
582+ else if (die ){
583+ kill (child , SIGTERM );
580584 release_devices ();
581585 _exit (WEXITSTATUS (st ));
582586 }
587+
588+ /* first send a watchdog signal, SIGUSR1, child will check if it comes from
589+ * ppid() or not - and use that as an 'ANR' (if it comes from the lua context,
590+ * second time around, it's killing time */
591+ uint64_t ts = arcan_watchdog_ping ? atomic_load (arcan_watchdog_ping ) : 0 ;
592+ if (ts && arcan_timemillis () - ts > WATCHDOG_ANR_TIMEOUT_MS ){
593+
594+ /* only trigger if there is a drm device open */
595+ bool found = false;
596+ for (size_t i = 0 ; i < COUNT_OF (whitelist ); i ++ ){
597+ if (whitelist [i ].fd != -1 && (whitelist [i ].mode & MODE_DRM )){
598+ found = true;
599+ break ;
600+ }
601+ }
602+ if (!found )
603+ return ;
604+
605+ /* the other option here would be to longjmp back into main, we ignore that as
606+ * that would cause more complexity with pledge/unveil, so shutdown and assume
607+ * an outer service manager would relaunch us if possible - we want explicit
608+ * relaunch in order to not act as a fork() oracle for ASLR break */
609+ if (watchdog_anr_sent ){
610+ /* if (arcan_timemillis() - watchdog_anr_sent > WATCHDOG_ANR_TIMEOUT_MS){
611+ kill(child, SIGTERM);
612+ release_devices();
613+ _exit(EXIT_FAILURE);
614+ }*/
615+ }
616+ else {
617+ kill (child , SIGUSR1 );
618+ watchdog_anr_sent = arcan_timemillis ();
619+ }
620+ }
621+ else
622+ watchdog_anr_sent = 0 ;
583623}
584624
585625#if defined(__OpenBSD__ ) || defined(__FreeBSD__ )
@@ -664,7 +704,7 @@ static void parent_loop(pid_t child, int netlink)
664704
665705 int rv = poll (pfd , netlink == -1 ? 1 : 2 , 1000 );
666706 if (-1 == rv && (errno != EAGAIN && errno != EINTR ))
667- check_child (child , true); /* don't to stronger than this */
707+ check_child (child , true); /* don't go stronger than this */
668708
669709 if (rv == 0 )
670710 return ;
@@ -760,6 +800,7 @@ static bool drop_privileges()
760800static int psock = -1 ;
761801void platform_device_init ()
762802{
803+
763804/*
764805 * Signs of these environment variables indicate that we are in a context where
765806 * other display servers exist, drop out immediately so that we don't risk
0 commit comments