답변:
실제로 대부분의 플랫폼에서 오류와 함께 실패하지만 하드웨어 아키텍처에 따라 다릅니다. 권한이없는 사용자로 명령을 실행하지 않는 한 이것이 무해하다는 보장은 없습니다. 권한이없는 사용자는 명령을 열 수 없기 때문에 완벽하게 무해합니다 /dev/mem
.
루트로 명령을 실행하면 수행중인 작업을 알아야합니다. 커널은 때때로 위험한 일을 막을 수 있지만 항상 그런 것은 아닙니다. /dev/mem
당신이하고있는 일을 정말로 알고 있어야하는 잠재적으로 위험한 것들 중 하나입니다.
/dev/mem
Linux 에서 쓰기 작업 을 수행하는 방법을 살펴 보겠습니다 . 일반적인 원리는 다른 Unices에서도 동일하지만 커널 옵션과는 완전히 다릅니다.
프로세스가 장치 파일을 읽거나 쓸 때 발생하는 일은 커널에 달려 있습니다. 장치 파일에 대한 액세스는이 장치 파일을 처리하는 드라이버에서 일부 코드를 실행합니다. 예를 들어, 서면 /dev/mem
함수 호출 write_mem
에를drivers/char/mem.c
. 이 함수는 열린 파일을 나타내는 데이터 구조, 쓸 데이터에 대한 포인터, 쓸 바이트 수 및 파일의 현재 위치 등 4 개의 인수를 사용합니다.
호출자가 처음에 파일을 열 수있는 권한이있는 경우에만 해당 정보를 얻을 수 있습니다. 장치 파일은 일반적으로 파일 권한을 따릅니다. 의 일반 권한 /dev/mem
은의 crw-r-----
소유 root:kmem
이므로 루트 권한없이 쓰기 위해 열려고하면 "권한이 거부되었습니다"(EACCESS)됩니다. 그러나 루트 인 경우 (또는 루트가이 파일의 권한을 변경 한 경우) 열기가 진행된 후 쓰기를 시도 할 수 있습니다.
write_mem
함수 의 코드는 온전한 검사를 수행하지만 이러한 검사로는 모든 것을 방지하기에 충분하지 않습니다. 가장 먼저하는 일은 현재 파일 위치 *ppos
를 실제 주소 로 변환하는 것 입니다. (실제로 32 비트 실제 주소는 있지만 64 비트 파일 오프셋이 있고 파일 오프셋이 2 ^ 32보다 큰 플랫폼에 있기 때문에) 쓰기가 실패하면 EFBIG (파일이 너무 큼)로 쓰기에 실패합니다. 다음 점검은 쓰기 할 물리적 주소 범위가이 특정 프로세서 아키텍처에서 유효한지 여부이며 실패하면 EFAULT (잘못된 주소)가 발생합니다.
다음으로 Sparc 및 m68k에서 첫 번째 실제 페이지의 쓰기 부분은 자동으로 건너 뜁니다.
이제 하나의 MMU 페이지에 들어갈 수있는 블록 단위로 데이터를 반복 하는 기본 루프에 도달했습니다 .
가상 메모리가 아닌 물리적 메모리에 액세스하지만 메모리에 데이터를로드하고 저장하는 프로세서 명령은 가상 주소를 사용하므로 코드는 물리적 메모리를 일부 가상 주소에 매핑하도록 정렬해야합니다. Linux에서는 프로세서 아키텍처 및 커널 구성에 따라이 맵핑이 영구적으로 존재하거나 즉시 작성되어야합니다. 그것은 그 일입니다 (그리고 무엇이든 취소합니다 ). 그런 다음 함수 는 버퍼로 전달 된 버퍼에서 읽습니다./dev/mem
xlate_dev_mem_ptr
unxlate_dev_mem_ptr
xlate_dev_mem_ptr
copy_from_user
write
시스템 호출을하고 실제 메모리가 현재 매핑 된 가상 주소에 씁니다. 이 코드는 일반적인 메모리 저장 명령어를 내며 이는 하드웨어에 달려 있습니다.
실제 주소에 대한 쓰기에 대해 논의하기 전에이 쓰기 전에 수행되는 검사에 대해 설명하겠습니다. 루프 내에서이 기능 page_is_allowed
은 커널 구성 옵션 CONFIG_STRICT_DEVMEM
이 활성화 된 경우 특정 주소에 대한 액세스를 차단합니다 (기본적으로 허용됨). 허용되는 주소 만에 devmem_is_allowed
도달 할 수 있습니다. /dev/mem
다른 경우에는 EPERM으로 쓰기에 실패합니다 (작업이 허용되지 않음). 이 옵션에 대한 설명은 다음과 같습니다.
이 옵션이 켜져 있고 IO_STRICT_DEVMEM = n 인 경우 / dev / mem 파일은 PCI 공간 및 BIOS 코드 및 데이터 영역에 대한 사용자 공간 액세스 만 허용합니다. 이것은 dosemu 및 X와 / dev / mem의 모든 일반 사용자에게 충분합니다.
이것은 매우 x86 중심의 설명입니다. 실제로보다 일반적으로 CONFIG_STRICT_DEVMEM
RAM에 매핑되는 물리적 메모리 주소에 대한 액세스는 차단하지만 RAM에 매핑되지 않는 주소에 대한 액세스는 허용합니다. 허용되는 물리적 주소 범위에 대한 자세한 내용은 프로세서 아키텍처에 따라 다르지만 커널 및 사용자 랜드 프로세스의 데이터가 저장되는 RAM은 제외합니다. 추가 옵션 CONFIG_IO_STRICT_DEVMEM
(Ubuntu 18.04부터 비활성화 됨)은 드라이버가 요청한 물리적 주소에 대한 액세스를 차단합니다.
RAM에 매핑되는 실제 메모리 주소 . RAM에 매핑되지 않은 물리적 메모리 주소가 있습니까? 예. 그것이 주소에 쓰는 것이 무엇을 의미하는지에 대해 위에서 약속 한 것입니다.
메모리 저장 명령어는 반드시 RAM에 쓸 필요는 없습니다. 프로세서는 주소를 분해하고 상점을 발송할 주변 장치를 결정합니다. (“프로세서”라고 말하면 동일한 제조업체에서 제공하지 않은 주변 장치 컨트롤러를 포함합니다.) RAM은 이러한 주변 장치 중 하나 일뿐입니다. 디스패치가 수행되는 방법은 프로세서 아키텍처에 따라 크게 다르지만 기본은 모든 아키텍처에서 거의 동일합니다. 프로세서는 기본적으로 주소의 상위 비트를 분해하여 하드 코드 된 정보, 일부 버스를 조사하여 얻은 정보 및 소프트웨어가 구성한 정보를 기반으로 채워지는 일부 테이블에서 찾아냅니다. 많은 캐싱 및 버퍼링이 수반 될 수 있지만 간단히 말해서이 분해 후버스 는 주변 장치에 달려 있습니다. (또는 테이블 조회의 결과로이 주소에 주변 장치가 없을 수 있습니다.이 경우 프로세서는 트랩 상태 가되어 커널에서 일부 코드를 실행 하여 호출 프로세스 에 대해 SIGBUS 를 발생시킵니다.
RAM에 매핑되는 주소에 대한 저장소는 이전에이 주소에 저장된 값을 덮어 쓰는 것 외에 다른 어떤 것도하지 않습니다. 같은 주소에 나중에로드하면 마지막에 저장된 값이 다시 나옵니다. 그러나 심지어 RAM이 방식으로 작동하지 않는 몇 가지 주소가 있습니다 : 그것은 몇 가지가 등록 새로 고침 속도 및 전압 등을 제어 할 수 있습니다.
일반적으로 하드웨어 레지스터에 대한 읽기 또는 쓰기는 하드웨어가 프로그래밍 한 모든 작업을 수행합니다. 대부분의 하드웨어 액세스는 다음과 같은 방식으로 작동합니다. 소프트웨어 (일반적으로 커널 코드)는 특정 물리적 주소에 액세스하고, 프로세서를 주변 장치에 연결하는 버스에 도달하면 주변 장치가 작동합니다. 일부 프로세서 (특히 x86)에는 메모리로드 및 저장과는 다른 주변 장치에 대한 읽기 / 쓰기를 유발하는 별도의 CPU 명령도 있지만 x86에서도로드 / 저장을 통해 많은 주변 장치에 도달합니다.
이 명령 dd if=/dev/urandom of=/dev/mem
은 주소 0 (및 쓰기가 성공하는 한 후속 주소)에 매핑 된 주변 장치에 임의의 데이터를 씁니다. 실제로 많은 아키텍처에서 물리적 주소 0에는 주변 장치가 매핑되지 않았거나 RAM이 없으므로 첫 번째 쓰기 시도가 실패합니다. 그러나 주소 0에 매핑 된 주변 장치가 있거나 다른 주소에 쓰도록 명령을 변경하면 주변 장치에서 예측할 수없는 무언가가 트리거됩니다. 증가하는 주소에 임의의 데이터가 있으면 흥미로운 일을 할 가능성은 없지만 원칙적으로 컴퓨터를 끄거나 (실제로이 작업을 수행하는 주소가있을 수 있음) 일부 BIOS 설정을 덮어 쓰거나 부팅 할 수없는 경우도 있습니다. 버그가있는 주변 장치를 손상시킵니다.
alias Russian_roulette='dd if=/dev/urandom of=/dev/mem seek=$((4096*RANDOM+4096*32768*RANDOM))'
CONFIG_STRICT_DEVMEM
활성화되어 있으면 커널을 손상시킬 수 없습니다 .
매뉴얼 페이지 당 mem (4) :
/ dev / mem은 컴퓨터의 기본 메모리 이미지 인 문자 장치 파일입니다. 예를 들어 시스템을 검사 (및 패치)하는 데 사용될 수 있습니다.
그래서 이론적으로 dd if=/dev/urandom of=/dev/mem
설치 한 물리적 메모리의 전체 주소 공간을 덮어 쓰기해야하고, 커널과 다른 프로그램이 메모리에서 실행하기 때문에이 해야 효율적으로 시스템을 충돌. 실제로는 한계가 있습니다. 같은 매뉴얼 페이지에서 :
Linux 2.6.26부터 아키텍처에 따라 CONFIG_STRICT_DEVMEM 커널 구성 옵션은이 파일을 통해 액세스 할 수있는 영역을 제한합니다.
가상 머신 Ubuntu 18.04에서 이것을 시도하면 root 권한에 dd: writing to '/dev/mem': Operation not permitted
관계없이 오류를 반환합니다 . 에서 우분투 위키 :sudo
crw-r-----
/ dev / mem 보호
일부 응용 프로그램 (Xorg)은 사용자 공간에서 실제 메모리에 직접 액세스해야합니다. 이 액세스를 제공하기 위해 특수 파일 / dev / mem이 존재합니다. 과거에는 공격자가 루트 액세스 권한을 가진 경우이 파일에서 커널 메모리를보고 변경할 수있었습니다. CONFIG_STRICT_DEVMEM 커널 옵션은 비 장치 메모리 액세스를 차단하기 위해 도입되었습니다 (원래 이름은 CONFIG_NONPROMISC_DEVMEM).
따라서 기술적으로는 안전하지 않습니다 (시스템이 충돌하기 때문에). 커널 옵션 CONFIG_STRICT_DEVMEM
이 비활성화 되어 있으면 보안상의 허점이되지만 지금까지 내가 본 것에서 해당 옵션이 활성화되어 있으면 명령이 실행되지 않습니다. 사이트 간 복제 에 따르면 재부팅하면 문제가 해결되지만 물론 RAM의 데이터는 손실되고 디스크로 플러시되지 않습니다 (필요한 경우).
이전에 사용했던 복제본에 제안 된 방법이 busybox devmem
있으므로 RAM을 사용 하기로 결정한 경우 결국 방법이있을 수 있습니다.
CONFIG_STRICT_DEVMEM
주변 장치가 매핑 된 메모리 영역에 액세스 할 수 있습니다 /dev/mem
. 주변 장치에 임의의 내용을 쓰면 어떤 일이 발생할 수 있습니다. 매핑되지 않은 주소에 액세스하려고하면 명령이 주소 0에서 시작하면 "작업이 허용되지 않습니다"라는 메시지가 나타납니다. 주소 0이 잘못된 것으로 매핑되는지 여부는 하드웨어 아키텍처에 따라 다릅니다. 내가 아는 한, 그것은 PC의 어떤 것에도 매핑되지 않을 수도 있지만 일반적으로 안전하지는 않습니다.
head -c 1024 </dev/mem | od -tx1
있지만 ( ) 프로세서가 실제 모드 (8088 모드)가 아닐 때 이것이 사용되는지 모르겠습니다. 64 비트 모드에서 사용할 수 있다고 생각하지 않습니다. 결국 8088 인터럽트 벡터에는 주소에 32 비트 만 있습니다. 그리고 이것은 CONFIG_STRICT_DEVMEM
세트 로 액세스 할 수 있으므로 Linux는 그것을 사용하지 않는 것 같습니다.