우려하던대로, 답글이 없네요. ㅜ.ㅜ;;
먼저, 제가 전에 문의드린 내용에 부족한 점이 많은 것 같아 죄송하다는 말씀을 드리고 싶네요.
방향을 조금 바꿔보았습니다. 바로 Callgate가 아닌 IDT를 이용하는 것으로요.
새로운 세그먼트는 arch/x86/kernel/cpu/common.c 라는 파일에 [GDT_ENTRY_SECURE_CS] = {....DPL:1, read+execute, 나머지는 커널과 거의 같음....}와 [GDT_ENTRY_SECURE_DS] = {....DPL:1, read+write+confirm, 나머지는 커널과 거의 같음....}로 정의하였습니다. 물론, include/asm-x86/segment_32.h 파일에 unused라고 되어 있는 28~29번을 사용하였습니다.
-------------segment_32.h에 정의한 내용 ---------------------
#define GDT_ENTRY_SECURE_BASE 28
#define GDT_ENTRY_SECURE_CS (GDT_ENTRY_SECURE_BASE + 0)
#define __SECURE_CS (GDT_ENTRY_SECURE_CS * 8 + 1)
#define GDT_ENTRY_SECURE_DS (GDT_ENTRY_SECURE_BASE + 1)
#define __SECURE_DS (GDT_ENTRY_SECURE_DS * 8 + 1)
---------------------------------------------------------------------
위와 같이 세그먼트 셀렉터는 __SECURE_CS와 __SECURE_DS가 되는데, 각각 0xE1과 0xE9가 되죠.
하지만, 아직까지 User(CPL:3) 입장에서 lcall 0xE1:0x0000으로 접근이 불가능한 상황입니다. 그래서 Callgate를 새로 선언해서 사용해보려고 했지만, TSS 레지스터를 사용해야된다는 의견이 있어서 그만 두고, 바로 IDT를 이용해보았습니다.
-------------------arch/x86/kernel/entry_32.S---------------------
/* Add my code (wbhacker) */
ENTRY(secure_test)
RING0_INT_FRAME
SAVE_ALL
pushl $context_msg
call printk
addl $4, %esp
RESTORE_REGS
INTERRUPT_RETURN
CFI_ENDPROC
context_msg:
.ascii
"EBX : 0x%08xnECX : 0x%08xnEDX : 0x%08xnESI : 0x%08xn"
"EDI : 0x%08xnEBP : 0x%08xnEAX : 0x%08xn"
"DS : 0x%08xnES : 0x%08xnFS : 0x%08xnx0"
ENDPROC(secure_test)
---------------------------------------------------------------------------
위와 같이 엔트리에 어셈블리어로 추가하고,
-------------------arch/x86/kernel/traps_32.c----------------------
/* add my code */
set_system_gate(0xef, &secure_test);
----------------------------------------------------------------------------
위와 같이 trap에 새로 정의하여 사용자가 int 0xef를 통해 연결되도록 하였습니다.
소스가 잘 적용되어 수행이 되었습니다. printk 함수를 잘 수행되었습니다.
-----------------------------------------------------------------------------
// traps_32.c에 정의되어 있는 set_system_gate 함수 내용
static void __init set_system_gate(unsigned int n, void *addr)
{
_set_gate(n, DESCTYPE_TRAP | DESCTYPE_DPL3, addr, __KERNEL_CS);
}
// 제가 새로 정의한 함수로, __SECURE_CS로 IDT의 DPL이 1임을 알 수 있죠.
static void __init set_system_gate_secure(unsigned int n, void *addr)
{
_set_gate(n, DESCTYPE_TRAP | DESCTYPE_DPL3, addr, __SECURE_CS);
}
-----------------------------------------------------------------------------
하지만, 위와 같이 __SECURE_CS로 접근하려고 하면, 접근은 불가능하게 되었습니다.
__KERNEL_CS로 하면 접근이 잘되고 코드 수행도 잘 되었죠. 그런데, 제가 하고자 하는 DPL:1 권한으로는 안되는 겁니다.
----------------int 0xef일 때 나오는 메시지(KERNEL_CS일 때)-------
EBX : 0x40149ff0
[ 566.213324] ECX : 0x00000000
[ 566.213328] EDX : 0x08049440
[ 566.213331] ESI : 0x4014c41c
[ 566.213333] EDI : 0x00000000
[ 566.213335] EBP : 0xbfe4f018
[ 566.213337] EAX : 0x00000010
[ 566.213339] DS : 0x0000007b
[ 566.213340] ES : 0x0000007b
[ 566.213342] FS : 0xffff0000
----------------int 0xef일 때 나오는 메시지(SECURE_CS일 때)-------
trap[3052]: segfault at c010413c eip c010413c esp bf9fc3c4 error 5
-----------------------------------------------------------------------------
저와 같이 진행중인 후배가 생각하기엔 메모리 접근쪽 문제일 가능성이 큰데요.
책을 살펴보니, 리눅스에서의 메모리 접근 권한 체크는 0xC0000000 영역부터 커널이라고 하는데, 그 영역의 접근 권한으로 Page의 User/Supervisor로 한다고 합니다.
즉 0x00000000~0xBFFFFFFF는 Page가 User권한이며, 0xC0000000~0xFFFFFFFF는 Page가 Supervisor권한이라는 겁니다. 세그먼트 정책으로는 KERNEL_CS와 USER_CS가 모두 BaseAddress는 0x0이고, Limit는 4G이기 때문에, 접근 제한 체크가 없을 것 같고요.
제가 원하는 것은 User 영역을 0x00000000~0xAFFFFFFF 정도로 하고, Secure 영역으로 0xB0000000~0xBFFFFFFF를 잡고 싶은 겁니다. -_-; 제가 접근해야 될 것이 어떤 방법이 있을까요?
모든 프로세스가 생성될 때마다 수행이 되는 쪽으로 해야할 것 같아 do_fork나 do_execv를 분석해야 된다는 생각은 있고, 조금 분석해보긴 했는데, 너무 어렵더군요. 이렇게 접근하면 되는지요? 관련 서적도 알려주시면 감사하겠습니다. 현재는 "리눅스 커널의 이해 - 한빛미디어", "리눅스 커널 프로그래밍 - 교학사", "박장수의 리눅스 커널 분석 2.4 - 가메출판사", "만들면서 배우는 OS 커널의 구조와 원리 - 한빛미디어", "IA-32 Intel(R) Architecture Software Developer's Manual(3)"을 보고 있습니다.
뭐라도 좋으니, 조언 해주시면 감사하겠습니다. -- 2008-06-18 19:23 wbhacker
먼저, 제가 전에 문의드린 내용에 부족한 점이 많은 것 같아 죄송하다는 말씀을 드리고 싶네요.
방향을 조금 바꿔보았습니다. 바로 Callgate가 아닌 IDT를 이용하는 것으로요.
새로운 세그먼트는 arch/x86/kernel/cpu/common.c 라는 파일에 [GDT_ENTRY_SECURE_CS] = {....DPL:1, read+execute, 나머지는 커널과 거의 같음....}와 [GDT_ENTRY_SECURE_DS] = {....DPL:1, read+write+confirm, 나머지는 커널과 거의 같음....}로 정의하였습니다. 물론, include/asm-x86/segment_32.h 파일에 unused라고 되어 있는 28~29번을 사용하였습니다.
-------------segment_32.h에 정의한 내용 ---------------------
#define GDT_ENTRY_SECURE_BASE 28
#define GDT_ENTRY_SECURE_CS (GDT_ENTRY_SECURE_BASE + 0)
#define __SECURE_CS (GDT_ENTRY_SECURE_CS * 8 + 1)
#define GDT_ENTRY_SECURE_DS (GDT_ENTRY_SECURE_BASE + 1)
#define __SECURE_DS (GDT_ENTRY_SECURE_DS * 8 + 1)
---------------------------------------------------------------------
위와 같이 세그먼트 셀렉터는 __SECURE_CS와 __SECURE_DS가 되는데, 각각 0xE1과 0xE9가 되죠.
하지만, 아직까지 User(CPL:3) 입장에서 lcall 0xE1:0x0000으로 접근이 불가능한 상황입니다. 그래서 Callgate를 새로 선언해서 사용해보려고 했지만, TSS 레지스터를 사용해야된다는 의견이 있어서 그만 두고, 바로 IDT를 이용해보았습니다.
-------------------arch/x86/kernel/entry_32.S---------------------
/* Add my code (wbhacker) */
ENTRY(secure_test)
RING0_INT_FRAME
SAVE_ALL
pushl $context_msg
call printk
addl $4, %esp
RESTORE_REGS
INTERRUPT_RETURN
CFI_ENDPROC
context_msg:
.ascii
"EBX : 0x%08xnECX : 0x%08xnEDX : 0x%08xnESI : 0x%08xn"
"EDI : 0x%08xnEBP : 0x%08xnEAX : 0x%08xn"
"DS : 0x%08xnES : 0x%08xnFS : 0x%08xnx0"
ENDPROC(secure_test)
---------------------------------------------------------------------------
위와 같이 엔트리에 어셈블리어로 추가하고,
-------------------arch/x86/kernel/traps_32.c----------------------
/* add my code */
set_system_gate(0xef, &secure_test);
----------------------------------------------------------------------------
위와 같이 trap에 새로 정의하여 사용자가 int 0xef를 통해 연결되도록 하였습니다.
소스가 잘 적용되어 수행이 되었습니다. printk 함수를 잘 수행되었습니다.
-----------------------------------------------------------------------------
// traps_32.c에 정의되어 있는 set_system_gate 함수 내용
static void __init set_system_gate(unsigned int n, void *addr)
{
_set_gate(n, DESCTYPE_TRAP | DESCTYPE_DPL3, addr, __KERNEL_CS);
}
// 제가 새로 정의한 함수로, __SECURE_CS로 IDT의 DPL이 1임을 알 수 있죠.
static void __init set_system_gate_secure(unsigned int n, void *addr)
{
_set_gate(n, DESCTYPE_TRAP | DESCTYPE_DPL3, addr, __SECURE_CS);
}
-----------------------------------------------------------------------------
하지만, 위와 같이 __SECURE_CS로 접근하려고 하면, 접근은 불가능하게 되었습니다.
__KERNEL_CS로 하면 접근이 잘되고 코드 수행도 잘 되었죠. 그런데, 제가 하고자 하는 DPL:1 권한으로는 안되는 겁니다.
----------------int 0xef일 때 나오는 메시지(KERNEL_CS일 때)-------
EBX : 0x40149ff0
[ 566.213324] ECX : 0x00000000
[ 566.213328] EDX : 0x08049440
[ 566.213331] ESI : 0x4014c41c
[ 566.213333] EDI : 0x00000000
[ 566.213335] EBP : 0xbfe4f018
[ 566.213337] EAX : 0x00000010
[ 566.213339] DS : 0x0000007b
[ 566.213340] ES : 0x0000007b
[ 566.213342] FS : 0xffff0000
----------------int 0xef일 때 나오는 메시지(SECURE_CS일 때)-------
trap[3052]: segfault at c010413c eip c010413c esp bf9fc3c4 error 5
-----------------------------------------------------------------------------
저와 같이 진행중인 후배가 생각하기엔 메모리 접근쪽 문제일 가능성이 큰데요.
책을 살펴보니, 리눅스에서의 메모리 접근 권한 체크는 0xC0000000 영역부터 커널이라고 하는데, 그 영역의 접근 권한으로 Page의 User/Supervisor로 한다고 합니다.
즉 0x00000000~0xBFFFFFFF는 Page가 User권한이며, 0xC0000000~0xFFFFFFFF는 Page가 Supervisor권한이라는 겁니다. 세그먼트 정책으로는 KERNEL_CS와 USER_CS가 모두 BaseAddress는 0x0이고, Limit는 4G이기 때문에, 접근 제한 체크가 없을 것 같고요.
제가 원하는 것은 User 영역을 0x00000000~0xAFFFFFFF 정도로 하고, Secure 영역으로 0xB0000000~0xBFFFFFFF를 잡고 싶은 겁니다. -_-; 제가 접근해야 될 것이 어떤 방법이 있을까요?
모든 프로세스가 생성될 때마다 수행이 되는 쪽으로 해야할 것 같아 do_fork나 do_execv를 분석해야 된다는 생각은 있고, 조금 분석해보긴 했는데, 너무 어렵더군요. 이렇게 접근하면 되는지요? 관련 서적도 알려주시면 감사하겠습니다. 현재는 "리눅스 커널의 이해 - 한빛미디어", "리눅스 커널 프로그래밍 - 교학사", "박장수의 리눅스 커널 분석 2.4 - 가메출판사", "만들면서 배우는 OS 커널의 구조와 원리 - 한빛미디어", "IA-32 Intel(R) Architecture Software Developer's Manual(3)"을 보고 있습니다.
뭐라도 좋으니, 조언 해주시면 감사하겠습니다. -- 2008-06-18 19:23 wbhacker
.
그동안 잠수 타고 있어서 글을 못보았을 뿐더러 나중에 글을 보았을때는
저를 콕 찝어서 말씀하신것 같아 부담스러워서 제대로 읽어보지 않았습니다.
더 이상 아무 응답이 없으면 실례일것 같아 몇자 적습니다.
생각 나는걸 대충 추려서 적어보겠습니다.
1. GDT 설정은 제대로 하셨는지 궁금하네요.
- 각각의 필드의 값은 제대로 설정되어 있나요?
2. 0xc010413c 코드에서 세그먼트 폴트가 발생했는데 어떤 코드인지 궁금하네요.
3. 0xC0000000 영역 이하로는 프로세스의 stack 영역인데 이에 대한 고려가 되어 있는지 궁금하네요.
대략 이정도일것 같습니다.
이미 오랜 시간이 지난 관계로 다시 보실지 모르겠네요.
그리고 질문 내용이 일일이 따져보고 포괄적으로 고민해봐야 되는 내용이기 때문에 아마 호응이 없었던것 같습니다. 간단한 단답형 형식의 질문을 주시면 더 많은 분들이 답변해줄실것 같습니다.
그럼 수고하십시요.