cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

freefall.c (3176B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/* Disk protection for HP/DELL machines.
      3 *
      4 * Copyright 2008 Eric Piel
      5 * Copyright 2009 Pavel Machek <pavel@ucw.cz>
      6 * Copyright 2012 Sonal Santan
      7 * Copyright 2014 Pali Rohár <pali@kernel.org>
      8 */
      9
     10#include <stdio.h>
     11#include <stdlib.h>
     12#include <unistd.h>
     13#include <fcntl.h>
     14#include <sys/stat.h>
     15#include <sys/types.h>
     16#include <string.h>
     17#include <stdint.h>
     18#include <errno.h>
     19#include <signal.h>
     20#include <sys/mman.h>
     21#include <sched.h>
     22#include <syslog.h>
     23
     24static int noled;
     25static char unload_heads_path[64];
     26static char device_path[32];
     27static const char app_name[] = "FREE FALL";
     28
     29static int set_unload_heads_path(char *device)
     30{
     31	if (strlen(device) <= 5 || strncmp(device, "/dev/", 5) != 0)
     32		return -EINVAL;
     33	strncpy(device_path, device, sizeof(device_path) - 1);
     34
     35	snprintf(unload_heads_path, sizeof(unload_heads_path) - 1,
     36				"/sys/block/%s/device/unload_heads", device+5);
     37	return 0;
     38}
     39
     40static int valid_disk(void)
     41{
     42	int fd = open(unload_heads_path, O_RDONLY);
     43
     44	if (fd < 0) {
     45		perror(unload_heads_path);
     46		return 0;
     47	}
     48
     49	close(fd);
     50	return 1;
     51}
     52
     53static void write_int(char *path, int i)
     54{
     55	char buf[1024];
     56	int fd = open(path, O_RDWR);
     57
     58	if (fd < 0) {
     59		perror("open");
     60		exit(1);
     61	}
     62
     63	sprintf(buf, "%d", i);
     64
     65	if (write(fd, buf, strlen(buf)) != strlen(buf)) {
     66		perror("write");
     67		exit(1);
     68	}
     69
     70	close(fd);
     71}
     72
     73static void set_led(int on)
     74{
     75	if (noled)
     76		return;
     77	write_int("/sys/class/leds/hp::hddprotect/brightness", on);
     78}
     79
     80static void protect(int seconds)
     81{
     82	const char *str = (seconds == 0) ? "Unparked" : "Parked";
     83
     84	write_int(unload_heads_path, seconds*1000);
     85	syslog(LOG_INFO, "%s %s disk head\n", str, device_path);
     86}
     87
     88static int on_ac(void)
     89{
     90	/* /sys/class/power_supply/AC0/online */
     91	return 1;
     92}
     93
     94static int lid_open(void)
     95{
     96	/* /proc/acpi/button/lid/LID/state */
     97	return 1;
     98}
     99
    100static void ignore_me(int signum)
    101{
    102	protect(0);
    103	set_led(0);
    104}
    105
    106int main(int argc, char **argv)
    107{
    108	int fd, ret;
    109	struct stat st;
    110	struct sched_param param;
    111
    112	if (argc == 1)
    113		ret = set_unload_heads_path("/dev/sda");
    114	else if (argc == 2)
    115		ret = set_unload_heads_path(argv[1]);
    116	else
    117		ret = -EINVAL;
    118
    119	if (ret || !valid_disk()) {
    120		fprintf(stderr, "usage: %s <device> (default: /dev/sda)\n",
    121				argv[0]);
    122		exit(1);
    123	}
    124
    125	fd = open("/dev/freefall", O_RDONLY);
    126	if (fd < 0) {
    127		perror("/dev/freefall");
    128		return EXIT_FAILURE;
    129	}
    130
    131	if (stat("/sys/class/leds/hp::hddprotect/brightness", &st))
    132		noled = 1;
    133
    134	if (daemon(0, 0) != 0) {
    135		perror("daemon");
    136		return EXIT_FAILURE;
    137	}
    138
    139	openlog(app_name, LOG_CONS | LOG_PID | LOG_NDELAY, LOG_LOCAL1);
    140
    141	param.sched_priority = sched_get_priority_max(SCHED_FIFO);
    142	sched_setscheduler(0, SCHED_FIFO, &param);
    143	mlockall(MCL_CURRENT|MCL_FUTURE);
    144
    145	signal(SIGALRM, ignore_me);
    146
    147	for (;;) {
    148		unsigned char count;
    149
    150		ret = read(fd, &count, sizeof(count));
    151		alarm(0);
    152		if ((ret == -1) && (errno == EINTR)) {
    153			/* Alarm expired, time to unpark the heads */
    154			continue;
    155		}
    156
    157		if (ret != sizeof(count)) {
    158			perror("read");
    159			break;
    160		}
    161
    162		protect(21);
    163		set_led(1);
    164		if (1 || on_ac() || lid_open())
    165			alarm(2);
    166		else
    167			alarm(20);
    168	}
    169
    170	closelog();
    171	close(fd);
    172	return EXIT_SUCCESS;
    173}