Linux v6.6 · 개념과 코드 읽기

사용자 포인터를 공통 exec 경로로 넘깁니다

이 코드는 어떤 문제를 푸나요?

execve는 새 프로세스를 하나 더 만드는 호출이 아니라 현재 프로세스가 실행할 프로그램을 바꾸는 요청입니다. 여기서는 native 사용자 인자 포인터를 공통 표현으로 감싸서 execveat 계열과 공통인 경로로 넘기는 작은 진입 함수를 봅니다. ELF 로딩과 주소 공간 교체 전체가 이 여덟 줄에 들어 있는 것은 아닙니다.

읽을 범위: v6.6 · fs/exec.c · do_execve 2032–2039행입니다. 아래에 이 범위의 원문과 각 줄의 설명을 실었습니다. 주제 전체의 흐름과 다른 경로는 기존 분석에서 함께 읽으실 수 있습니다.

먼저 알아둘 개념

user 포인터

사용자 주소 공간을 가리키는 값으로, 일반 커널 포인터처럼 곧바로 역참조할 수 있다고 가정하지 않습니다.

공통 호출 경로

여러 사용자 ABI가 인자 형식을 맞춘 뒤 같은 구현을 재사용하는 방식입니다.

처음 읽을 때

코드를 읽을 때 파일 이름과 argv·envp 사용자 포인터를 받습니다. 그다음 어느 상태가 바뀌는지 각 줄에서 확인하세요.

더 깊이 살펴볼 때

이 경로의 호출 문맥, 잠금·인터럽트 상태, 오류 시 남는 자원을 함께 추적해 보세요. 호출된 함수가 수행하는 작업과 현재 함수가 직접 보장하는 범위를 구분하는 것이 중요합니다.

그림으로 보는 변화

사용자 포인터를 공통 exec 경로로 넘깁니다의 단계별 개념 그림
각 단계에 화살표 의미와 생략 범위를 표시했습니다. 주소·숫자 예제는 실제 장치 값을 뜻하지 않습니다.
1단계 설명

1단계 고정

GIF 원본 열기

1. 입력 구분

파일 이름과 argv·envp 사용자 포인터를 받습니다.

포인터를 받는 것과 문자열 전체를 복사하는 것은 다릅니다.

2. 공통 표현 구성

native 포인터를 user_arg_ptr에 담습니다.

작은 구조체 초기화이지 새 프로세스 생성이 아닙니다.

3. 실행 교체 요청

AT_FDCWD 기준의 공통 exec 구현으로 넘깁니다.

후속 코드가 파일 검증과 프로그램 전환을 수행합니다.

do_execve를 한 줄씩 읽기

줄 번호는 v6.6 원문 기준입니다. 주석·빈 줄을 포함한 함수 전체를 먼저 보고, 그 아래에서 각 줄을 설명합니다.

static int do_execve(struct filename *filename,
	const char __user *const __user *__argv,
	const char __user *const __user *__envp)
{
	struct user_arg_ptr argv = { .ptr.native = __argv };
	struct user_arg_ptr envp = { .ptr.native = __envp };
	return do_execveat_common(AT_FDCWD, filename, argv, envp, 0);
}
static int do_execve(struct filename *filename,

실행 파일을 나타내는 커널 filename과 사용자 argv·envp 주소를 받아 exec 공통 경로에 넘깁니다. 성공 시 현재 태스크의 프로그램이 바뀌며 실패하면 음수 오류가 반환됩니다.

	const char __user *const __user *__argv,

사용자 주소 공간에 있는 argv 포인터 배열을 받습니다. 배열의 각 원소도 사용자 문자열을 가리키며 __user는 이후 안전한 사용자 접근 경로를 따라야 하는 주소임을 표시합니다. 포인터가 보관하는 것은 객체의 주소입니다. 이 선언만으로 대상 구조체나 문자열의 내용이 복사되지는 않습니다.

	const char __user *const __user *__envp)

사용자 환경 문자열 포인터 배열을 받습니다. 여기서 내용을 즉시 역참조하지 않고 아래 user_arg_ptr 형식에 담아 공통 exec 경로로 넘깁니다. 포인터가 보관하는 것은 객체의 주소입니다. 이 선언만으로 대상 구조체나 문자열의 내용이 복사되지는 않습니다.

	struct user_arg_ptr argv = { .ptr.native = __argv };

native 사용자 인자 배열 포인터를 공통 인자 형식에 담습니다. 문자열을 이 자리에서 전부 읽지 않습니다.

	struct user_arg_ptr envp = { .ptr.native = __envp };

환경 문자열 배열의 사용자 포인터도 같은 공통 표현으로 맞춥니다.

	return do_execveat_common(AT_FDCWD, filename, argv, envp, 0);

native 인자를 파일 디스크립터 기준 exec 공통 경로로 넘깁니다. AT_FDCWD는 현재 디렉터리 기준을 뜻합니다.

함께 생각해 볼 질문

이 함수가 argv 문자열을 모두 읽나요?

여기서는 포인터를 감쌉니다. 실제 접근과 복사는 후속 경로에서 확인합니다.

AT_FDCWD는 파일 디스크립터를 새로 여나요?

현재 작업 디렉터리를 기준으로 해석하라는 특별한 값입니다.

성공하면 다른 PID가 생기나요?

exec는 기존 태스크의 프로그램을 교체합니다. 프로세스 생성과 구분합니다.

출처와 읽은 범위

Linux stable v6.6 · fs/exec.c

해당 버전 원본 파일 · 기존 코드 분석 · 설명 원고

맨 위로 ↑