Есть ли способ сделать кеш sh ARM-кэша от EL0? - PullRequest
1 голос
/ 05 апреля 2020

Я пытался реализовать код Po C для Spectre Attack на ARMV8 (я понимаю, что большинство процессоров ARMV8 не уязвимы для атаки, но все равно пытаюсь реализовать его). Я использую инструкцию asm volatile ("DC CIVAC, %[ad]" : : [ad] "r" (addr)); для очистки кэша sh, а затем пытаюсь измерить время, чтобы снова прочитать очищенный адрес. Но я не вижу разницы в чтении адреса до и после очистки кэша. Это заставило меня понять, что инструкция, которую я использую для гриппа sh, не работает.

При чтении справочного руководства ARMV8 (https://static.docs.arm.com/ddi0487/b/DDI0487B_a_armv8_arm.pdf) я понял, что для DC CIVAC инструкция для работы SCTLR_EL1.UCI должна быть установлена ​​на 1. Я не уверен, как я могу проверить значение регистра SCTLR_EL1 и изменить его на 1, не требуя sudo привилегий.

1 Ответ

2 голосов
/ 07 апреля 2020

Далее описывается процедура чтения / записи SCTLR_EL1 из Linux пользовательского режима. Возможно или недостаточно чтение / запись SCTLR_EL1 в работающей Linux системе для возможности очистки sh кеша не получен ответ.

Это, очевидно, небезопасная практика, поскольку она, очевидно, делает нарушить Armv8-a схему безопасности - не пытайтесь делать это дома , но для целей обучения.

Процедура была выполнена на OrangePi PC2 работающем Armbian Buster (версия ядра была Linux orangepipc2 5.4.28-sunxi64 #20.02.7 SMP Sat Mar 28 17:25:10 CET 2020 aarch64 GNU/Linux.

Установка последнего ядра / linux заголовки:

sudo apt-get update
sudo apt-get upgrade
sudo apt-get install linux-headers-current-sunxi64
sudo shutdown -r now

Компиляция минимально загружаемого модуля ядра с поддержкой procfs:

Makefile:

obj-m+=/sctlr_el1.o
KBUILD_DIR=/usr/src/linux-headers-5.4.28-sunxi64
all:
        make -C $(KBUILD_DIR) M=$(PWD) modules
# Kernel module clean dependency
clean:
        make -C $(KBUILD_DIR) M=$(PWD) clean

install:
        insmod sctlr_el1.ko
remove:
        rmmod sctlr_el1

sctlr_el1.c:

// Credits:
//
// minimal kernel module:    https://docs.legato.io/17_07/yoctoOutofTreeKernelModule.html
// procfs example:           https://gist.github.com/BrotherJing/c9c5ffdc9954d998d1336711fa3a6480

#include<linux/module.h>
#include<linux/init.h>
#include<linux/proc_fs.h>
#include<linux/sched.h>
#include<linux/uaccess.h>
#include<linux/fs.h>
#include<linux/seq_file.h>
#include<linux/slab.h>

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Frant");
MODULE_DESCRIPTION("Minimal kernel module suitable for reading/writing SCTLR_EL1");
MODULE_VERSION("0.0.1");

// write system register  SCTLR_EL1 (s3_0_c1_c0_0) with specified value.
static inline void system_write_SCTLR_EL1(uint64_t val)
{
    asm volatile("msr s3_0_c1_c0_0 , %0" : : "r" (val));
    asm volatile("isb" : : : "memory"); 
}

// read system register value SCTLR_EL1 (s3_0_c1_c0_0).
static inline uint64_t system_read_SCTLR_EL1(void)
{
    uint64_t val;
    asm volatile("mrs %0, s3_0_c1_c0_0" : "=r" (val));
    return val;
}

static int my_proc_show(struct seq_file *m,void *v) {
    uint64_t value = system_read_SCTLR_EL1();
    printk(KERN_INFO "Read value <0x%016llx> from SCTLR_EL1.", value);
    seq_printf(m,"0x%016llx\n",value);
    return 0;
}

static ssize_t my_proc_write(struct file* file,const char __user *buffer,size_t count,loff_t *f_pos){
    int rc = -1;
    uint64_t value = 0;

    char *tmp = kzalloc((count+1),GFP_KERNEL);
    if(!tmp)return -ENOMEM;
    if(copy_from_user(tmp,buffer,count)){
        kfree(tmp);
        return EFAULT;
    }

    rc = kstrtoul (tmp, 0, (unsigned long*) &value);
    if (rc != 0) {
       printk(KERN_ERR "Value <%s> is invalid.", tmp);
       kfree(tmp);
       return EFAULT;
    }

    kfree(tmp);
    system_write_SCTLR_EL1(value);
    printk(KERN_INFO "Wrote value <0x%016llx> to SCTLR_EL1.", value);

    return count;
}

static int my_proc_open(struct inode *inode,struct file *file){
    return single_open(file,my_proc_show,NULL);
}

static struct file_operations my_fops={
    .owner = THIS_MODULE,
    .open = my_proc_open,
    .release = single_release,
    .read = seq_read,
    .llseek = seq_lseek,
    .write = my_proc_write
};

static int __init sctlr_el1_init(void) {
    struct proc_dir_entry *entry;
    entry = proc_create("SCTLR_EL1",0777,NULL,&my_fops);
    if(!entry){
        return -1;  
    } else {
        printk(KERN_INFO "Entering sctlr_el1\n");
    }

 return 0;
}

static void __exit sctlr_el1_exit(void) {
    remove_proc_entry("SCTLR_EL1",NULL);
    printk(KERN_INFO "Exiting sctlr_el1\n");
}

module_init(sctlr_el1_init);
module_exit(sctlr_el1_exit);

Установка:

make install
insmod sctlr_el1.ko

dmesg
[  927.217571] sctlr_el1: loading out-of-tree module taints kernel.
[  927.218556] Entering sctlr_el1

Чтение SCTLR_EL1

cat /proc/SCTLR_EL1
0x0000000034d4d91d

SCTLR_EL1.UCI в моей системе, похоже, установлено .

Переписываете то же значение:

echo 0x0000000034d4d91d > /proc/SCTLR_EL1
dmesg
[ 1130.967798] Wrote value <0x0000000034d4d91d> to SCTLR_EL1.

Нет эффекта. Запись 0x0 приводит к зависанию система, что означает, что SCTLR_EL1, вероятно, было обновлено, но это обновление, очевидно, вызвало (ожидаемую) систему cra sh:

echo 0x0 > /proc/SCTLR_EL1
...