2014-08-20 6 views
15

64 비트 커널을 만들 때 (x86_64 플랫폼 용) 컴파일러에서 사용자 공간 ABI가 수행하는 128 바이트 Red Zone을 사용하지 않도록하는 것이 좋습니다 . GCC의 경우 컴파일러 플래그는 -mno-red-zone입니다.커널 코드에서 Red Zone을 사용할 수없는 이유

커널을 사용할 수 있으면 인터럽트 방지가되지 않습니다.

하지만 그 이유는 무엇입니까?

+1

관련 항목 : http://stackoverflow.com/questions/38042188/where-exactly-is-the-red-zone-on-x86-64 및 http://stackoverflow.com/questions/37941779/why-do 우리가 필요로하는 스택 할당 (stack-allocation-when-we-have-a-red-zone)은 레드 존이 그것을 사용할 수있는 코드에 대해 무엇을 설명하는지에 대한 해답을 가지고있다. –

답변

11

는 AMD64 ABI 인용 : 위치 이후

128 바이트 영역 %의 RSP이 예약 된 것으로 간주되고, 신호 또는 인터럽트 핸들러를 수정할 수 없다 가리키는. 따라서 함수는 함수 호출을 통해 필요하지 않은 임시 데이터에이 영역을 사용할 수 있습니다. 특히 리프 함수는 프롤로그 및 에필로그에서 스택 포인터를 조정하는 대신 전체 스택 프레임에이 영역을 사용할 수 있습니다. 이 영역을 적색 영역이라고합니다.

본질적으로, 그것은 최적화입니다 - 유저 랜드 컴파일러 (간단한 구현, 지역 변수의 전체 크기) 주어진 시간에 사용되며 호출하기 전에 그에 따라 %rsp를 조정할 수있는 방법을 레드 존의 많은 정확히 알고 하위 기능.

특히 잎 기능에서는 기능 중에 익숙하지 않은 코드가 실행되지 않을 수도 있으므로 %rsp을 조정하지 않아도 성능이 향상 될 수 있습니다. (POSIX 시그널 핸들러는 코 루틴의 형태로 볼 수 있지만, 시그널 핸들러에서 스택 변수를 사용하기 전에 레지스터를 조정하도록 컴파일러에 지시 할 수 있습니다).

커널 공간에서 인터럽트에 대해 생각하기 시작하면 해당 인터럽트가 %rsp에 대한 가정을하면 Red Zone의 사용과 관련하여 확실치 않습니다. 따라서 모든 것이 더럽고 불필요하게 스택 공간을 낭비한다고 가정합니다 (모든 함수에서 128 바이트의 보장 된 로컬 변수로 효과적으로 실행 됨). 또는 인터럽트가 %rsp에 대한 가정을하지 않는다는 것을 보장합니다. 이는 까다 롭습니다.

사용자 공간에서 컨텍스트 스위치 + 128 바이트 스택의 할당이 처리합니다.

+5

공간 절약 만이 아닙니다. 인터럽트 핸들러의 코드가 실행되기도 전에 인터럽트가 항상 '% rsp'아래의 16 바이트를 clobber 때문에 정상적으로 128 바이트 레드 존을 안전하게 구현하는 것은 실제로 불가능합니다. –

+0

@qdot, 128 바이트 오버로딩의 의미를 설명해 주시겠습니까? 즉, amd64 ABI에 "red zone"개념이 없으면 가장 낮은 주소 스택이 128 바이트 더 커질 수 있습니다. –

8

커널 공간에서 사용하는 인터럽트와 동일한 스택을 사용하고 있습니다. 인터럽트가 발생하면 the CPU pushes a return address and RFLAGS. 이것은 rsp 아래 16 바이트를 clobbers. 적색 영역의 전체 128 바이트가 가치 있다고 가정하는 인터럽트 처리기를 작성하려는 경우에도 불가능합니다.


당신은 아마 rsp-16에서 rsp-48 또는 뭔가 작은 빨간 존을 가진 커널 내부 ABI있을 수 있습니다. (커널 스택이 중요하기 때문에 작습니다. 대부분의 기능에는 적색 영역이별로 필요하지 않습니다.) 레지스터를 푸시하기 전에 인터럽트 핸들러를 sub rsp, 32으로 설정해야합니다. (iret 전에 복원하십시오). 인터럽트 핸들러 자체가 중단 될 수있는 경우가 sub rsp, 32을 실행하거나이 iret 전에 rsp을 복원 한 후 이전

이 아이디어는 작동하지 않습니다. 귀중한 데이터가 rsp .. rsp-16 인 취약성 창이 있습니다.


이 스키마의 또 다른 실질적인 문제점은 AFAIK gcc에는 구성 가능한 적색 영역 매개 변수가 없다는 것입니다. 켜거나 끕니다. 그러므로 gcc/clang에 red-zone의 커널 플레이버에 대한 지원을 추가해야 할 것입니다.

중첩 된 인터럽트로부터 안전하다고해도 이점은 매우 적습니다. 커널에서 안전하다는 것을 증명하는 것이 어렵다는 것은 가치가 없을 수도 있습니다. (그리고 난 내가 중첩 된 인터럽트가 가능하다고 생각하기 때문에이 안전하게 구현 될 수 전혀 모르겠어요, 말했듯이.)

BTW

(즉, ABI에 대한 링크는 태그 위키를 참조 red-zone을 문서화하는 것 등).

1

커널 유형의 컨텍스트에서는 red-zone을 사용할 수 있습니다. IDTentry는 0..7의 스택 인덱스 (ist)를 지정할 수 있습니다. 여기서 0은 조금 특별합니다. TSS는 이러한 스택의 테이블을 포함합니다. 1..7이로드되고 예외/인터럽트에 의해 저장된 초기 레지스터에 사용되며 중첩되지 않습니다. 우선 순위 (예 : NMI가 가장 높고 언제든지 발생할 수 있음)별로 여러 예외 항목을 분할하고 이러한 스택을 트램폴린으로 처리하면 커널 유형 컨텍스트에서 빨간색 영역을 안전하게 처리 할 수 ​​있습니다. 즉, 예외를 유발할 수있는 인터럽트 또는 코드를 사용 가능하게하기 전에 저장된 스택 포인터에서 128을 빼서 사용 가능한 커널 스택을 얻을 수 있습니다.

제로 인덱스 스택은 특권 전환이 없을 때 기존 스택에서 스택, 플래그, pc, 오류를 푸시하는보다 일반적인 방식으로 작동합니다.

트램펄린의 코드는 기계 상태를 위생하면서 다른 예외를 생성하지 않도록 조심해야하지만 (병적으로 커널입니다), 병적 인 커널 중첩, 스택 손상 등을 감지 할 수있는 안전하고 안전한 지점을 제공합니다. ... [너무 늦게 대답하여 죄송합니다. 다른 항목을 검색하는 동안이 사실을 알게되었습니다.]