/proc/self/pagemap 과 /dev/mem으로 physical address 접근

andrea0403의 이미지

하려는 것은
메모리에 malloc하여 데이터를 잡고
그것의 physical address를 받아와서 기록하여서,
다른 코드에서 그 주소를 받아와서 읽는 것을 하려고 합니다.

다음과 같이 하고있는데, 2번째 코드를 돌리면 Bad file descriptor 에러가 뜹니다.
가끔 에러가 안뜨는거 같기도 하는데, 컴퓨터가 죽는듯 합니다.

무엇을 고쳐야 할까요?

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>
#include <errno.h>
#include <fcntl.h>
#include <stdint.h>
 
// ORIG_BUFFER will be placed in memory
#define ORIG_BUFFER "Hello, World!"
 
// The page frame shifted left by PAGE_SHIFT will give us the physcial address of the frame
// Note that this number is architecture dependent. For me on x86_64 with 4096 page sizes,
// it is defined as 12. If you're running something different, check the kernel source
// for what it is defined as.
#define PAGE_SHIFT 12
#define PAGEMAP_LENGTH 8
 
void* create_buffer(void);
unsigned long get_page_frame_number_of_address(void *addr);
 
int main(void) {
   // Create a buffer with some data in it
   void *buffer = create_buffer();
 
   // Get the page frame the buffer is on
   unsigned int page_frame_number = get_page_frame_number_of_address(buffer);
   printf("Page frame: 0x%x\n", page_frame_number);
 
   // Find the difference from the buffer to the page boundary
   unsigned int distance_from_page_boundary = (unsigned long)buffer % getpagesize();
 
   // Determine how far to seek into memory to find the buffer
   uint64_t offset = (page_frame_number << PAGE_SHIFT) + distance_from_page_boundary;
   printf("PAGE_SHIFT: %d\n", PAGE_SHIFT);
   printf("physical address: %lx\n", offset);
   printf("distance: %x\n", distance_from_page_boundary);
   FILE *f;
   char s[64];
   char logacalAddress[64];
   sprintf(s, "%lx", offset);
   printf("logical address: %lx\n", buffer);
   f = fopen("log.txt", "w");
   fprintf(f, s);
   fclose(f);
 
   // Clean up
   free(buffer);
   close(mem_fd);
 
   return 0;
}
 
void* create_buffer(void) {
   size_t buf_size = strlen(ORIG_BUFFER) + 1;
 
   // Allocate some memory to manipulate
   void *buffer = malloc(buf_size);
   if(buffer == NULL) {
      fprintf(stderr, "Failed to allocate memory for buffer\n");
      exit(1);
   }
 
   // Lock the page in memory
   // Do this before writing data to the buffer so that any copy-on-write
   // mechanisms will give us our own page locked in memory
   if(mlock(buffer, buf_size) == -1) {
      fprintf(stderr, "Failed to lock page in memory: %s\n", strerror(errno));
      exit(1);
   }
 
   // Add some data to the memory
   strncpy(buffer, ORIG_BUFFER, strlen(ORIG_BUFFER));
 
   return buffer;
}
 
unsigned long get_page_frame_number_of_address(void *addr) {
   // Open the pagemap file for the current process
   FILE *pagemap = fopen("/proc/self/pagemap", "rb");
 
   // Seek to the page that the buffer is on
   unsigned long offset = (unsigned long)addr / getpagesize() * PAGEMAP_LENGTH;
   if(fseek(pagemap, (unsigned long)offset, SEEK_SET) != 0) {
      fprintf(stderr, "Failed to seek pagemap to proper location\n");
      exit(1);
   }
 
   // The page frame number is in bits 0-54 so read the first 7 bytes and clear the 55th bit
   unsigned long page_frame_number = 0;
   fread(&page_frame_number, 1, PAGEMAP_LENGTH-1, pagemap);
 
   page_frame_number &= 0x7FFFFFFFFFFFFF;
 
   fclose(pagemap);
 
   return page_frame_number;
}

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#define ORIG_BUFFER "Hello, World!"
 
int main() {
    int mem_dev = open("/dev/mem", O_RDWR | O_SYNC);
 
    if(mem_dev == -1)
    {
        printf("Error\n"); // Error
    }
 
    char s[64];
    uint64_t mem_address;
    FILE *f = fopen("log.txt", "r");
    //fgets(s, sizeof(s), f);
    //printf("%s\n", s);
    fscanf(f, "%lx", &mem_address);
    //printf("%x\n", mem_addr);
    fclose(f);
 
    printf("%lx\n", mem_address);
 
 
    /*if(mem_addr == 0xa30e9010) {
        printf("true\n");
    }*/
 
    //const uint32_t mem_address = 0x10001234;
    const uint32_t  mem_size = strlen(ORIG_BUFFER) + 1;
 
    uint32_t alloc_mem_size, page_mask, page_size;
    void *mem_pointer, *virt_addr;
 
    page_size = sysconf(_SC_PAGESIZE);
    alloc_mem_size = (((mem_size / page_size) + 1) * page_size);
    page_mask = (page_size - 1);
 
    mem_pointer = mmap(NULL,
                       alloc_mem_size,
                       PROT_READ | PROT_WRITE,
                       MAP_SHARED,
                       mem_dev,
                       (mem_address & ~page_mask)
                       );
 
    if(mem_pointer == MAP_FAILED)
    {
        printf("Error2\n"); // Error
        printf("%s\n", strerror(errno)); // Error
    }
 
    virt_addr = (mem_pointer + (mem_address & page_mask));
 
    printf("%s\n", (const char *)virt_addr);
 
    munmap(mem_pointer, alloc_mem_size);
 
    close(mem_dev);
 
    return 0;
}
라스코니의 이미지

일종의 shared memory와 같은 것을 구현하시려는 것 같습니다.
다른 프로세스와 정보를 공유하려면 유사한 방식이 필요하겠죠.

우선 리눅스 정책상 유저 프로세스에서 physical memory에 접근할 방법이 없습니다. 있더라도 root 권한을 요구하거나 또는 메뉴얼 상에서 권장하지 않습니다. 하시려는 작업과 유사한 작업은 커널 모드에서 수행하시면 됩니다.

또한 커널 모드에서 작업한다고 하더라도 malloc(커널 모드에서는 kalloc가 되겠네요)이 실제 physical memory를 할당하여 돌려주지 않을수도 있습니다. 그것은 커널 & MMU에 의해서 가변적입니다.

만약 정말 physical memory에 대한 엑세스가 필요하시다면 mmu(가상 메모리)를 사용하지 않고 uni memory space를 사용(지원)하는 tiny embedded os를 사용하셔야 합니다. 현대적 데스크탑 OS에서 커널/드라이버 단이 아니고서 물리적 주소에 접근할 수도 없고 접근할 필요도 없습니다.

chocokeki의 이미지

커널 드라이버 제작 가능하고 올릴 수 있는 환경이면 커널 플래그로 메모리 일부 영역 주소를 할당에서 제외 한 다음에 드라이버에서 그 영역 주소를 ioremap으로 물리 -> 커널가상으로 변환 후 ioctl mmap 부분을 구현해서 어플리케이션 간 물리 메모리를 공유하도록 하는건 어떤가요?

chocokeki의 이미지

근데 하시려는거 보니까 물리 메모리를 순수 user space에서 직접 접근해서 어플리케이션간 공유하려는게 맞나요?
이거 그냥 아예 리눅스 커널 정책 위반이라 방법을 찾으면 그 자체가 cve 들어가는거 아닌가요

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.