LINUX.ORG.RU

«God-mode» для чтения физ. памяти BAR регистров PCIe из userland

 


0

3

Есть ли такое? Понятно, что если бы было, то Linux превратился бы в помойку для вирусов. Но вот для разработки надо. Припоминаю, была возможность увидеть память как файл.

Понятно, что если бы было, то Linux превратился бы в помойку для вирусов.

С чего бы это? Главное чтобы права доступа были правильно ограничены.

Припоминаю, была возможность увидеть память как файл.

/dev/mem ?

firkax ★★★★★
()
Последнее исправление: firkax (всего исправлений: 1)

Если есть возможность воткнуть свой драйвер - то для таких вещей специально есть UIO (Userspace I/O) https://www.kernel.org/doc/html/v5.9/driver-api/uio-howto.html

Простой драйвер мапит PCI bar’ы, а из юзерспейса их можно читать/писать как файлы. Фактически позволяет написать драйвер устройства в userspace.

UPD: Оказывается даже драйвер писать не нужно, уже есть универсальный драйвер uio_pci_generic который всё сам мапит.

tim239 ★★
()
Последнее исправление: tim239 (всего исправлений: 1)
Ответ на: комментарий от I-Love-Microsoft

Ну вот, сделал утилиту по мотивам https://russianblogs.com/article/2115558794/ Не знаю, можно ли ей верить. Билдите «gcc md.c -o md», и можно изучать память. Не все мапится, что выдает «cat /proc/iomem».

#include <stdio.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <fcntl.h>

unsigned long htoi(char *s)
{
    unsigned long	n = 0;

    for( ; s; s++)
    {
	n <<= 4;
	if(*s>='0' && *s<='9')
	    n |= *s - '0';
	else if(*s>='a' && *s<='f')
	    n |= *s - 'a' + 10;
	else if(*s>='A' && *s<='F')
	    n |= *s - 'A' + 10;
	else
	{
	    n >>= 4;
	    break;
	}
    }

    return n;
}

void dump(unsigned long start, unsigned char *addr, unsigned long len)
{
    int i, j;
    unsigned char c;

    for(i=0; i<len; i+=16)
    {
	printf("%8.8X:", start+i);
	for(j=0; j<16; j++)
	{
	    printf(" %2.2X", *(addr + (i+j)) );
	}
	printf("  |");
	for(j=0; j<16; j++)
	{
	    c = *(addr + (i+j));
	    if(c<' ' || c==0x7F) c = '`';
	    printf( "%c", c );
	}
	printf("|\n");
    }
}

int main(int argc, char **argv)	
{	
    int fd;
    unsigned char *addr;
    unsigned long start, size;

    if(argc<3)
    {
	printf("Use\n\tmd start_adr length\n");
	return -1;
    }

    start = htoi(argv[1]);
    size = htoi(argv[2]);

    //fd = open("/dev/mem", O_RDWR);
    fd = open("/dev/mem", O_RDONLY);

    // 0x34000000 - это смещение / dev / mem, которое является смещением зарезервированной памяти в физическом адресном пространстве. Мой пример 0x34000000	
    //addr = mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0x34000000);
    //addr = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, start);
    addr = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, start);

    // ... использовать зарезервированную память по желанию
    printf("addr = 0x%X\n",addr);
    dump( start, addr, size );

    close(fd);
    munmap(addr, 4096);
    return 1;
}
bugs-bunny
() автор топика

Делал такое - самый простой вариант за-mmapить желаемый /sys/bus/pci/devices/0000:0?:00.0/resource? с правильными флагами

https://github.com/galkinvv/pcie_mem_test/blob/main/src/main.rs

Из нюансов - если на устройстве сидит драйвер, то без параметра ядра iomem=relaxed - доступа к bar устройства занятого драйвером - не будет

GPFault ★★
()
Ответ на: комментарий от GPFault

Ещё из нюансов - важно какой инструкцией читать оттуда байты.

Считывание меньше чем по 32бита у меня давало ерунду на многих устроствах. Так что не факт что char хороший вариант.

Также там рядом лежит /sys/bus/pci/devices/0000:0?:00.0/config - PCI Configuration Space

И если в нём выключены биты в регистреи COMMAND - то доступа к BAR не будет

Включить можно например sudo setpci -s 01:00.0 ROM_ADDRESS=00000001:00000001 COMMAND=0407:0407

GPFault ★★
()