범위를 벗어난 배열에 액세스하는 것이 얼마나 위험합니까?
범위를 벗어난 어레이에 액세스하는 것이 얼마나 위험합니까 (C)? 때로는 배열 외부에서 읽거나 (이제 프로그램의 다른 부분이나 그 이상으로 사용되는 메모리에 액세스한다는 것을 이해합니다) 또는 배열 외부의 인덱스로 값을 설정하려고합니다. 프로그램이 때때로 충돌하지만 때로는 실행되어 예기치 않은 결과 만 나타납니다.
이제 제가 알고 싶은 것은 이것이 얼마나 위험합니까? 프로그램이 손상되면 그렇게 나쁘지 않습니다. 반면에 프로그램과 관련이없는 것이 있다면 완전히 관련이없는 메모리에 액세스 할 수 있기 때문에 매우 나쁩니다. 나는 '어떤 일이 일어날 수 있는가', '세그먼테이션이 가장 나쁜 문제일지도 모른다' , '하드 디스크가 분홍색으로 변하고 유니콘이 당신의 창 아래에서 노래를 부를지도 모른다 '를 많이 읽었습니다 .
내 질문 :
- 배열 외부에서 값을 읽으면 프로그램 이외의 것이 손상 될 수 있습니까? 나는 물건을 보는 것이 아무것도 변하지 않는다고 상상할 것입니다. 예를 들어 도달 한 파일의 '마지막으로 열린 시간'속성을 변경합니까?
- 설정 값이 배열 외부로 빠져 나갈 수 있습니까? 이 스택 오버플로 질문에서 메모리 위치에 액세스 할 수 있으며 안전 보장이 없다는 것을 수집합니다.
- 이제 XCode 내에서 작은 프로그램을 실행합니다. 자체 메모리 외부에 도달 할 수없는 프로그램에 대해 추가적인 보호 기능을 제공합니까? XCode를 해칠 수 있습니까?
- 본질적으로 버그가있는 코드를 안전하게 실행하는 방법에 대한 권장 사항이 있습니까?
OSX 10.7, Xcode 4.6을 사용합니다.
ISO C 표준 (언어의 공식 정의)에 관한 한, 범위를 벗어난 배열에 액세스하는 경우 " 정의되지 않은 동작 "이 있습니다. 문자 그대로의 의미는 다음과 같습니다.
휴대 할 수 없거나 잘못된 프로그램 구조 또는 잘못된 데이터를 사용하는 경우,이 표준에 요구 사항이없는 행동
비표준 메모는 다음과 같이 확장됩니다.
정의되지 않은 동작은 예측할 수없는 결과로 상황을 완전히 무시하는 것, 환경의 특징적인 문서화 된 방식으로 진단 또는 프로그램 실행 중 (진단 메시지 발행 여부에 관계없이), 번역 또는 실행 종료 (발급 포함)에 이르기까지 다양합니다. 진단 메시지).
이것이 이론입니다. 현실은 무엇입니까?
"최상의"경우 현재 실행중인 프로그램이 소유하고 있거나 (프로그램이 오작동 할 수 있음) 현재 실행중인 프로그램이 소유 하지 않은 메모리에 액세스 할 수 있습니다 (아마도 프로그램이 세그먼테이션 오류와 같은 것으로 충돌). 또는 프로그램이 소유 한 메모리에 쓰려고 시도하지만 읽기 전용으로 표시되어 있습니다. 이로 인해 프로그램이 중단 될 수도 있습니다.
그것은 프로그램이 서로 동시에 실행중인 프로세스를 보호하려고 시도하는 운영 체제에서 실행되고 있다고 가정합니다. 코드가 "베어 메탈 (bare metal)"에서 실행중인 경우, OS 커널 또는 임베디드 시스템의 일부인 경우에는 그러한 보호 기능이 없습니다. 오작동하는 코드는 그러한 보호 기능을 제공하는 것입니다. 이 경우 하드웨어 (또는 주변 사물 또는 사람)에 대한 물리적 손상을 포함하여 손상 가능성이 훨씬 더 큽니다.
보호 된 OS 환경에서도 항상 100 % 보호되는 것은 아닙니다. 예를 들어 권한이없는 프로그램이 루트 (관리) 액세스를 얻을 수있게하는 운영 체제 버그가 있습니다. 일반 사용자 권한이 있어도 오작동하는 프로그램은 과도한 리소스 (CPU, 메모리, 디스크)를 소비하여 전체 시스템을 중단시킬 수 있습니다. 많은 맬웨어 (바이러스 등)가 버퍼 오버런을 악용하여 시스템에 대한 무단 액세스를 얻습니다.
(역사적 예 : 코어 메모리 가있는 일부 구형 시스템 에서 타이트한 루프로 단일 메모리 위치에 반복적으로 액세스하면 문자 그대로 해당 메모리 덩어리가 녹을 수 있습니다. 다른 방법으로는 CRT 디스플레이 파괴 및 읽기 이동 등이 있습니다 / 드라이브 캐비닛의 고조파 주파수로 디스크 드라이브의 헤드를 쓰면 테이블을 가로 질러 걸어서 바닥에 떨어집니다.)
그리고 항상 걱정할 Skynet 이 있습니다.
결론은 이것입니다. 의도적으로 나쁜 일을하는 프로그램을 작성할 수 있다면 , 적어도 이론적으로는 버그가있는 프로그램이 우연히 같은 일을 할 수 있다는 것 입니다.
실제로, 그건 매우 맥 OS X 시스템에서 실행되는 버그 프로그램이 충돌보다 더 심각한 아무것도 할 것입니다 가능성. 그러나 버그가있는 코드가 실제로 나쁜 일을하는 것을 완전히 막을 수는 없습니다 .
일반적으로 오늘날 운영 체제 (일반적으로 인기있는 운영 체제)는 가상 메모리 관리자를 사용하여 보호 된 메모리 영역의 모든 응용 프로그램을 실행합니다. 프로세스에 할당 / 할당 된 영역 외부의 REAL 공간에있는 위치를 단순히 읽거나 쓰는 것이 그리 쉬운 일이 아님이 밝혀졌습니다.
직접 답변 :
1) 읽기는 다른 프로세스를 거의 직접 손상시키지 않지만 프로그램 / 프로세스를 암호화, 암호 해독 또는 유효성 검사하는 데 사용되는 KEY 값을 읽으면 프로세스를 간접적으로 손상시킬 수 있습니다. 경계를 벗어나면 읽고있는 데이터를 기반으로 결정을 내리면 코드에 다소 악영향을 줄 수 있습니다.
2) 메모리 주소로 액세스 할 수있는 로션에 쓰면 실제로 무언가를 손상시킬 수있는 유일한 방법은 쓰려는 메모리 주소가 실제로 하드웨어 레지스터 (실제로는 데이터 저장이 아니라 일부 부분을 제어하기위한 위치) 인 경우입니다. RAM 위치가 아님). 사실, 다시 쓸 수없는 (또는 그 성격의) 프로그래밍 가능한 위치를 한 번 작성하지 않는 한 여전히 정상적으로 무언가를 손상시키지 않습니다.
3) 일반적으로 디버거 내에서 실행하면 코드가 디버그 모드로 실행됩니다. 디버그 모드에서 실행하면 실습 또는 불법으로 간주되는 작업을 수행했을 때 코드를 더 빨리 중지하지 않습니다.
4) 매크로를 사용하지 말고 이미 내장 된 배열 인덱스 바운드 검사가있는 데이터 구조 등을 사용하십시오.
추가 위의 정보는 실제로 메모리 보호 창이있는 운영 체제를 사용하는 시스템에만 해당됩니다. 내장 시스템 또는 메모리 보호 창 (또는 가상 주소 지정 창)이없는 운영 체제 (실시간 또는 기타)를 사용하는 시스템의 코드를 작성하는 경우 메모리를 읽고 쓰는 데 훨씬 더주의를 기울여야합니다. 또한 이러한 경우에는 보안 문제를 피하기 위해 항상 SAFE 및 SECURE 코딩 방법을 사용해야합니다.
경계를 확인하지 않으면 보안 허점을 포함하여 추악한 부작용이 발생할 수 있습니다. 못생긴 것 중 하나는 임의의 코드 실행 입니다. 전형적인 예 : 고정 크기 배열 strcpy()
이 있고 사용자가 제공 한 문자열을 거기에 넣는 데 사용 하는 경우 사용자는 버퍼를 오버플로하고 함수가있을 때 CPU가 반환 해야하는 코드 주소를 포함하여 다른 메모리 위치를 덮어 쓰는 문자열을 제공 할 수 있습니다 마무리합니다.
즉, 사용자가 프로그램을 본질적으로 호출하게하는 문자열을 보낼 수 있습니다.이 경우 프로그램이 exec("/bin/sh")
셸로 전환되어 모든 데이터 수집 및 머신을 봇넷 노드로 전환하는 등 시스템에서 원하는 모든 것을 실행합니다.
이 작업을 수행하는 방법에 대한 자세한 내용은 재미와 이익을 위해 스택 스매싱을 참조하십시오 .
당신은 쓰기:
나는 '무엇이 일어날 수 있는가', '세그먼트가 가장 나쁜 문제일지도 모른다', '하드 디스크가 분홍색으로 변하고 유니콘이 당신의 창 아래에서 노래를 부르고있을 수 있습니다'를 많이 읽었습니다.
총을 넣으십시오. 특정 조준 및 발사없이 창 밖으로 지적하십시오. 위험은 무엇입니까?
문제는 당신이 모른다는 것입니다. 코드가 프로그램과 충돌하는 것을 덮어 쓰면 정의 된 상태로 중지되기 때문에 괜찮습니다. 그러나 충돌하지 않으면 문제가 발생하기 시작합니다. 프로그램을 관리하는 리소스는 무엇이며 어떻게 할 수 있습니까? 프로그램을 제어 할 수있는 리소스는 무엇이며 어떻게 할 수 있습니까? 이러한 오버플로로 인해 발생한 적어도 하나의 주요 문제를 알고 있습니다. 이 문제는 프로덕션 데이터베이스에 대한 관련이없는 변환 표를 엉망으로 만드는 의미없는 통계 함수에있었습니다. 그 결과 결과적으로 매우 비싼 정리가 이루어졌습니다. 실제로이 문제가 하드 디스크를 포맷했을 경우 훨씬 저렴하고 다루기가 쉬웠을 것입니다. 즉, 핑크 유니콘이 가장 적은 문제 일 수 있습니다.
운영 체제가 사용자를 보호한다는 아이디어는 낙관적입니다. 가능하면 범위를 쓰지 않도록하십시오.
루트 또는 다른 권한있는 사용자로 프로그램을 실행하지 않으면 시스템에 아무런 영향을 미치지 않으므로 일반적으로 이것이 좋습니다.
임의의 메모리 위치에 데이터를 쓰면 각 프로세스가 자체 메모리 공간에서 실행될 때 컴퓨터에서 실행중인 다른 프로그램을 직접 "손상"시키지 않습니다.
프로세스에 할당되지 않은 메모리에 액세스하려고하면 운영 체제에서 세그먼트 오류로 인해 프로그램 실행이 중지됩니다.
따라서 루트로 실행하지 않고 / dev / mem과 같은 파일에 직접 액세스하지 않고도 프로그램이 운영 체제에서 실행중인 다른 프로그램을 방해 할 위험이 없습니다.
그럼에도 불구하고 우연히 임의의 데이터를 임의의 메모리 위치에 맹목적으로 쓰면 손상 될 수있는 모든 것을 손상시킬 수 있습니다.
예를 들어, 프로그램은 프로그램 어딘가에 저장된 파일 이름으로 지정된 특정 파일을 삭제하려고 할 수 있습니다. 실수로 파일 이름이 저장된 위치를 덮어 쓰면 대신 다른 파일을 삭제할 수 있습니다.
코드를 테스트 할 때 Valgrind에서이memcheck
도구 를 사용해보십시오 . 스택 프레임 내에서 개별 배열 경계 위반을 포착하지는 않지만 미묘하고 넓게 만드는 것을 포함하여 많은 다른 종류의 메모리 문제를 포착해야합니다. 단일 기능의 범위를 벗어난 문제.
매뉴얼에서 :
Memcheck는 메모리 오류 감지기입니다. C 및 C ++ 프로그램에서 일반적으로 발생하는 다음 문제를 감지 할 수 있습니다.
- 메모리에 액세스하면 (예 : 힙 블록 오버런 및 언더런 실행, 스택의 상단 오버런 및 메모리가 해제 된 후의 메모리 액세스)해서는 안됩니다.
- 정의되지 않은 값, 즉 초기화되지 않았거나 다른 정의되지 않은 값에서 파생 된 값 사용
- 이중 해제 힙 블록과 같은 힙 메모리 해제 또는 malloc / new / new [] 대 사용 가능 / 삭제 / 삭제 []와 일치하지 않는 사용
- memcpy 및 관련 함수에서 src 및 dst 포인터가 겹칩니다.
- 메모리 누수가 발생합니다.
ETA : Kaz의 답변에서 알 수 있듯이, 만병 통치약은 아니며 특히 흥미로운 액세스 패턴을 사용할 때 항상 가장 유용한 결과를 제공하지는 않습니다 .
NSArray
Objective-C의 s에는 특정 메모리 블록이 지정됩니다. 배열의 경계를 초과하면 배열에 할당되지 않은 메모리에 액세스하게됩니다. 이것은 다음을 의미합니다.
- 이 메모리는 어떤 값이든 가질 수 있습니다. 데이터 유형에 따라 데이터가 유효한지 알 수있는 방법이 없습니다.
- 이 메모리에는 개인 키 또는 다른 사용자 자격 증명과 같은 민감한 정보가 포함될 수 있습니다.
- 메모리 주소가 유효하지 않거나 보호되어있을 수 있습니다.
- 메모리는 다른 프로그램이나 스레드가 액세스하기 때문에 값을 변경할 수 있습니다.
- 다른 것들은 메모리 매핑 된 포트와 같은 메모리 주소 공간을 사용합니다.
- 알 수없는 메모리 주소에 데이터를 쓰면 프로그램이 중단되고 OS 메모리 공간을 덮어 쓰며 일반적으로 태양이 the 수 있습니다.
프로그램의 측면에서 코드가 언제 배열의 범위를 초과하는지 알고 싶을 것입니다. 이로 인해 알 수없는 값이 반환되어 응용 프로그램이 중단되거나 유효하지 않은 데이터가 제공 될 수 있습니다.
시스템 레벨 프로그래밍 또는 임베디드 시스템 프로그래밍을 수행하는 경우 임의의 메모리 위치에 쓰면 매우 나쁜 일이 발생할 수 있습니다. 구형 시스템과 많은 마이크로 컨트롤러는 메모리 매핑 된 IO를 사용하므로 주변 장치 레지스터에 매핑되는 메모리 위치에 쓰는 것이 특히 비동기식으로 수행되는 경우 혼란을 초래할 수 있습니다.
플래시 메모리 프로그래밍이 그 예입니다. 메모리 칩의 프로그래밍 모드는 칩의 주소 범위 내의 특정 위치에 특정 값 시퀀스를 기록하여 활성화됩니다. 다른 프로세스가 진행되는 동안 칩의 다른 위치에 쓰려고하면 프로그래밍주기가 실패합니다.
어떤 경우에는 하드웨어가 주소를 둘러싸고 (가장 중요한 비트 / 바이트 주소는 무시 됨) 실제 주소 공간 끝을 넘어 주소에 쓰면 실제로 데이터가 바로 기록됩니다.
마지막으로, MC68000과 같은 구형 CPU는 하드웨어 재설정만으로 다시 갈 수있는 수준까지 고정 될 수 있습니다. 수십 년 동안 그들에 대해 작업하지 않았지만 예외를 처리하려고 할 때 버스 오류 (존재하지 않는 메모리)가 발생했을 때 하드웨어 재설정이 주장 될 때까지 중단 될 것이라고 생각합니다.
가장 큰 권장 사항은 제품에 대한 명백한 플러그이지만 개인적 관심은 없으며 어떤 방식으로도 관련이 없습니다. 그러나 수십 년의 C 프로그래밍 및 신뢰성이 중요한 임베디드 시스템을 기반으로 Gimpel의 PC Lint는 이러한 종류의 오류를 감지 할뿐만 아니라 나쁜 습관에 대해 끊임없이 당신을 괴롭힘 으로써 더 나은 C / C ++ 프로그래머를 만들 것입니다 .
또한 누군가의 사본을 걸 수있는 경우 MISRA C 코딩 표준을 읽는 것이 좋습니다. 나는 최근의 것들을 보지 못했지만 예전에는 그들이 당신이 그들이 다루는 것들을 수행하지 말아야 할 이유에 대해 잘 설명했습니다.
당신에 대해 Dunno,하지만 두 번째 또는 세 번째 시간에 나는 모든 응용 프로그램에서 코어 덤프 또는 끊기를 얻습니다. 어떤 회사가 생산했는지에 대한 내 의견은 절반으로 줄어 듭니다. 네 번째 또는 다섯 번째 시간과 패키지가 선반웨어가되면 패키지 / 디스크의 중심을 통해 나무 말뚝을 운전하여 결코 나를 괴롭히지 않도록합니다.
저는 DSP 칩용 컴파일러를 사용하여 의도적으로 배열의 끝을지나 C 코드 중 하나에 액세스하는 코드를 생성합니다.
반복의 끝이 다음 반복을 위해 일부 데이터를 프리 페치하도록 루프가 구성되어 있기 때문입니다. 따라서 마지막 반복이 끝날 때 프리 페치 된 데이텀은 실제로 사용되지 않습니다.
이와 같이 C 코드를 작성하면 정의되지 않은 동작이 발생하지만 이는 최대 이식성과 관련된 표준 문서의 형식 일뿐입니다.
더 자주, 그렇지 않은 경우, 범위를 벗어나는 프로그램은 영리하게 최적화되지 않습니다. 그것은 단순히 버그입니다. 이 코드는 일부 가비지 값을 가져오고 앞에서 언급 한 컴파일러의 최적화 된 루프와 달리 이후 계산에서 값 을 사용 하여 결과를 손상시킵니다.
이와 같은 버그를 잡는 것이 가치가 있으며, 그 이유만으로도 동작을 정의하지 않아도됩니다. 즉, 런타임이 "main.c의 42 행에서 배열 오버런"과 같은 진단 메시지를 생성 할 수 있습니다.
가상 메모리가있는 시스템에서는 다음에 오는 주소가 매핑되지 않은 가상 메모리 영역에 있도록 배열이 할당 될 수 있습니다. 그러면 액세스가 프로그램을 폭격합니다.
따로, C에서는 배열 끝을 지나는 포인터를 만들 수 있습니다. 그리고이 포인터는 배열의 내부에 대한 포인터보다 크게 비교해야합니다. 이것은 C 구현이 메모리의 끝에 배열을 배치 할 수 없다는 것을 의미합니다. 여기서 하나의 더하기 주소는 배열의 다른 주소보다 줄어든 것처럼 보입니다.
그럼에도 불구하고, 초기화되지 않았거나 범위를 벗어난 값에 액세스하는 것은 최대로 이식 가능하지 않더라도 때때로 유효한 최적화 기술입니다. 예를 들어 Valgrind 도구는 액세스가 발생할 때 초기화되지 않은 데이터에 대한 액세스를보고하지 않고 나중에 프로그램의 결과에 영향을 줄 수있는 방식으로 값을 사용하는 경우에만보고합니다. "xxx : nnn의 조건부 분기는 초기화되지 않은 값에 따라 다릅니다"와 같은 진단이 표시되며 원래 위치를 추적하기가 어려운 경우가 있습니다. 이러한 모든 액세스가 즉시 갇히게되면 컴파일러 최적화 코드와 올바르게 수동 최적화 된 코드에서 발생하는 많은 오 탐지가 발생합니다.
말하자면, Linux로 포팅하고 Valgrind에서 실행할 때 이러한 오류를 발생시키는 공급 업체의 일부 코덱으로 작업하고있었습니다. 그러나 공급 업체는 몇 비트 만실제로 사용되는 값 중 하나는 초기화되지 않은 메모리에서 왔으며 해당 비트는 논리에 의해 신중하게 피했습니다. 값의 올바른 비트 만 사용되었으며 Valgrind는 개별 비트를 추적 할 수 없습니다. 초기화되지 않은 자료는 인코딩 된 데이터의 비트 스트림 끝을지나 단어를 읽는 데서 나왔지만 코드는 스트림에 몇 비트가 있는지 알고 실제로 실제보다 많은 비트를 사용하지 않습니다. 비트 스트림 배열의 끝을 넘어서 액세스해도 DSP 아키텍처에 아무런 해를 끼치 지 않기 때문에 (어레이 다음에는 가상 메모리가없고, 메모리 매핑 된 포트가없고, 주소가 랩핑되지 않습니다) 유효한 최적화 기술입니다.
ISO C에 따르면 단순히 C 표준에 정의되지 않은 헤더를 포함하거나 프로그램 자체 또는 C 표준에 정의되지 않은 함수를 호출하는 것은 정의되지 않은 예이므로 "정의되지 않은 동작"은 실제로 의미가 없습니다. 행동. 정의되지 않은 동작은 "지구상의 누군가가 정의하지 않음", "ISO C 표준에 의해 정의되지 않음"을 의미하지 않습니다. 그러나 물론, 때로는 정의되지 않은 동작이 정말 됩니다 절대적으로 누군가에 의해 정의되어 있지 않습니다.
자신의 프로그램 외에도, 나는 당신이 아무것도 깨뜨릴 것이라고 생각하지 않습니다. 최악의 경우 커널이 당신의 프로세스에 할당하지 않은 페이지에 해당하는 메모리 주소를 읽거나 쓰려고 시도하여 적절한 예외를 생성합니다 그리고 살해당하는 것입니다.
참고 URL : https://stackoverflow.com/questions/15646973/how-dangerous-is-it-to-access-an-array-out-of-bounds
'Programing' 카테고리의 다른 글
"if x : return x"문을 피하는 파이썬 방식 (0) | 2020.04.25 |
---|---|
SQL Server에서 왼쪽 조인과 오른쪽 조인의 차이점 (0) | 2020.04.25 |
Express 4.0으로 파일 업로드 : req.files undefined (0) | 2020.04.25 |
힘내 빨리 감기 VS 빨리 감기 병합 (0) | 2020.04.25 |
TortoiseHG로 분기하는 방법 (0) | 2020.04.25 |