[TIL/크래프톤 정글] DAY 79

배재준·2025년 5월 27일

크래프톤 정글 - TIL

목록 보기
71/93
post-thumbnail

2025.05.27

TIL(TODAY I LEARN)


  • 오늘한 내용 : PintOS - Project2: UserProgram - System calls
    파일 디스크립터 구현 및 자잘한 예외처리 구현 완료
  • WEEK 11 : 정글 끝까지(PintOS) - UserProgram

여러가지 예외?

rox : Read-Only Executable → Deny Write on Executables 처리

bad : page fault가 발생 → exit(-1)로 종료되도록

syn : synchronization 구현 → filesys_lock 사용

bad test

static void
page_fault(struct intr_frame *f)
{
	.....
	/* Determine cause. */
	not_present = (f->error_code & PF_P) == 0;
	write = (f->error_code & PF_W) != 0;
	user = (f->error_code & PF_U) != 0;
	
---------------------------------------------------------------------
	/* 유저 모드에서의 페이지 폴트라면, 즉시 종료 */
	if (user)
	{
		/* sys_exit()는 프로세스를 exit(-1)하고 thread_exit까지 해 줌 */
		sys_exit(-1);
		NOT_REACHED();
	}
------------------------------------------------------------------------
....
}
  • page fault가 유저모드에서 발생했다면 종료 시키고, 이후 print가 찍히지 않도록 함.
  • 디버그 메시지와 kill(f) 호출은 커널 모드 폴트에만 실행

rox test

thread 구조체

struct thread{
	...
	/* rox를 위한 자신이 실행한 프로그램을 가짐 */
	struct file *exec_prog;
}
  • 로딩 시에만 지역 변수에 있던 파일 핸들을, 프로세스가 끝날 때까지 남아 있게 하려면 컨텍스트(스레드) 구조체에 저장해야 함

load() 함수 내부 deny 추가

load()
{
...
	file = filesys_open(argv[0]);
		if (file == NULL)
		{
			printf("load: %s: open failed\n", argv[0]);
			goto done;
		}
		
		/* rox를 위한 deny 추가*/
		file_deny_write(file);
		t->exec_prog = file;
		
...
	
	done:
	// load 이후에 file_close 해버리면 안되고, exit()가 되었을 때 파일을 닫아야 함
	/* We arrive here whether the load is successful or not. */
	// if (file != NULL)
	// {
	// 	file_close(file);
	// }
	return success;
}
  • filesys_open 이후 file_deny_wirte 호출
  • filesys_open()이 반환한 struct file *file은, 곧바로 file_deny_write(file) 호출로 inode->deny_write_cnt++ 를 당함.
  • 이 순간부터, 이 프로세스가 파일 디스크 블록에 쓰기를 시도하면(= write(fd, …)), file_write() 내부의 때문에 “0바이트 써지고 실패”가 보장됨.
    if (file->deny_write)
        return 0;

exit() 시 쓰기 금지 해제·파일 닫기

case SYS_EXIT:
  sys_exit(status);
  
-----------------------
void sys_exit(int status)
{
	struct thread *curr = thread_current();
	
	/* 추가한 부분 
	*/
	if (curr->exec_prog!= NULL)
	{
		file_allow_write(curr->exec_prog);
		file_close(curr->exec_prog);
	}
	
	curr->exit_status = status;
	thread_exit(); // curr->status -> THREAD_DYING
}
  • file_allow_write() 호출로 inode->deny_write_cnt-- 되어 쓰기 카운터가 원래대로 돌아가고,
  • file_close() 는 내부에서 inode_close() 까지 해 주므로,
  • 다른 프로세스나 테스트가 이 파일을 나중에 정상 생성·삭제·수정할 때 아무 문제가 없음.

rox 정리

  1. 로드(load) 단계에서
    • filesys_open()file_deny_write() 를 호출해서
    • 실행 중인 프로세스가 사용하는 바이너리 파일에 대해 쓰기 금지를 걸어둠.
  2. 프로세스 실행 중에는
    • 그 파일이 여전히 열려 있고, deny_write_cnt > 0 이므로
    • 다른 어떤 프로세스나 스레드도 그 파일에 write() 시스템콜을 통해 수정할 수 없음.
    • 즉, 실행 중인 코드가 “뒤에서 누가 파일을 덮어쓰는” 상황을 방지.
  3. 즉시 file_close() 를 해 버리면
    • file_close() 내부에서 자동으로 inode_allow_write() 가 호출되어
    • deny_write_cnt 가 0이 되고,
    • 다른 프로세스가 그 순간부터 파일을 수정할 수 있게 됨. → 따라서 “로드 직후”에 닫아 버리면 보호가 무력화.
  4. 프로세스가 종료(exit)될 때까지 파일을 열어 두었다가
    • exit() 핸들러에서 file_allow_write()deny_write_cnt--
    • file_close() → 실제 핸들 해제 로 순서대로 처리해야,
    • 실행 중에는 계속 보호가 유지되고,
    • 종료되면 정상적으로 다시 쓰기·삭제가 가능해짐.

따라서 “로드 시 바로 닫지 않고, 프로세스가 끝날 때까지 열어 두어야 한다”는 설계가 반드시 필요함.

syn test

  • filesys.c, file.c 에 있는 모든 파일 관련 함수에도
  • create, remove, open, read, wirte함수에 lock 걸어주기
lock_acquire(&filesys_lock);;
lock_release(&filesys_lock);
  • 시스템 콜 구현부에 lock을 걸어주는게 아닌 파일 함수에 직접 lock을 걸어야함
    • 시스템 콜 레이어 뿐 아니라 다른 경로에서도 파일시스템 관련 함수가 호출 될 수 있기 때문

ALL PASSED


dup까지 해보자 화이팅

0개의 댓글