기술이 프로그램에 미치는 영향 (중요한 개념 포함) in C언어 기반
Objectives
- 운영체제가 자원을 관리하는 방법을 학습한다.
- 버퍼 오버플로우를 실험한다.
- 동시성 및 비동기 동작을 탐구한다.
- 기본 운영체제 용어를 사용한다.
- 잘못된 코드의 심각한 영향을 이해한다.
Fundamental changes in commercial software (상업용 소프트웨어의 근본적인 변화)
- 대형 데이터베이스(DB)와 비즈니스 애플리케이션들이 메인프레임에서 작은 값싼 분산된 기계들로 발전하며 GUI와 멀티미디어를 사용하는 터미널 환경으로 변하게 됨
- CSCW : 컴퓨터 지원 협업 작업을 의미하며 네트워크 통신을 지원하는 독립 애플리케이션으로 발전
- 기술의 발전은 통신, 동시성, 비동기적 운영에 의존됨 (퍼포먼스를 향상 시킬 수 있는 중요 키워드 3가지가 됨)
Asynchronous operation (비동기식 운영)
- 많은 이벤트가 예측 불가능한 순서와 시간에 발생함 ex) 사용자 키 입력, 프린터 요청
Concurrency (동시성, 병행성) < ㅡ > parallel (병렬)
- 동일한 시간 프레임에서 자원을 공유하는 것 (동시성 : 동시에 실행되는 것처럼 보이지만 실제로 하나만 수행 vs 병렬은 실제로 동시에 수행됨) ex) CPU,데이터, 코드,장치
Communication (통신)
- 1개의 엔티티가 다른 엔티티로 정보를 전달하는 것
Time and Speed (시간과 속도) - 시스템의 성능의 측정 기준
- OS가 시스템 자원(소프트웨어 & 하드웨어)을 관리
- Disk drives (하드 디스크 - 대표적 하드웨어)
- 성능은 향상 되었으나 회전하는 기계적 특성 때문에 성능에 제약이 있고 접근 시간(Access time)이 크게 단축되지 않았음, CPU에 비해 빠르게 발전되지 않음!
- Processor (CPU, 제약사항이 없어 빠르게 발전함)
- 속도가 기하급수적으로 증가함
다중 프로그래밍 (Multi Programming)
- 2개 이상의 프로세스가 실행 준비 상태 (레디 큐 내부에서 대기)일 때를 말하며 운영체제가 준비된 프로세스 중 1개를 선택
- 자원 요청(읽기 및 쓰기)이 운영체제 요청으로 이어짐 즉, 시스템 호출(운영체제에 서비스를 요청하는 것으로 정상적인 CPU주기를 중단하고 운영체제로 제어권을 넘기는 것)을 말함
시간 공유 (Time Sharing)
- 하나의 물리적 CPU에서 여러 프로세스가 동시에 실행되는 것처럼 보이는 착각을 말하며 운영체제가 여러 프로세스 간을 빠르게 전환하여 동시에 여러 프로세스가 실행되는 것처럼 보이는 환상을 줆
- 다중 프로그래밍과 시간 공유의 차이 : 시간 공유에서의 Time Quantum (타임 퀀텀)을 말함
다중 프로그래밍은 여러 프로세스가 대기 상태에 있고 시간 공유는 여러 프로세스가 빠르게 스위치되어 CPU에서 실행되며 타임 퀀텀을 적절히 부여하여 각 프로세스가 조금씩 실행되어 사용자에게 동시에 실행되는 것처럼 보이게 함
인터럽트 (Interrupts)
- 인터럽트가 발생하면 프로세서는 현재 프로그램 카운터 값을 저장하고 인터럽트 서비스 루틴의 주소를 로드하고, 인터럽트 서비스 루틴이 끝나면 프로세서는 이전 명령의 실행을 다시 시작함
- 인터럽트가 발생하면, CPU는 실행 중인 프로세스를 잠시 멈추고(실행했던 프로세스 지점을 기록한 후) 제어권을 넘겨줌
인터럽트 요약:
- 인터럽트 발생: 주변 장치가 프로세서에 하드웨어 플래그를 설정해 인터럽트를 발생시킴.
- 플래그 확인: 프로세서는 명령 주기마다 하드웨어 플래그를 확인함.
- 프로그램 중단: 인터럽트가 발생하면 프로세서는 현재 작업을 멈추고 프로그램 카운터 값을 저장한 후, 인터럽트 서비스 루틴을 실행함.
- 이전 작업 재개: 인터럽트 처리 후, 프로세서는 이전에 중단된 명령을 다시 실행함.
이를 통해 CPU는 비동기 이벤트를 효율적으로 처리할 수 있습니다.
시그널 (Signals)
- 이벤트가 발생했음을 알리는 소프트웨어 알림으로 종종 인터럽트에 대한 운영체제의 응답으로 발생함
- 시그널은 동기적 or 비동기적일 수 있음
예) Ctrl+C(인터럽트 시그널 발생) -> 디바이스 드라이버가 인터럽트를 발생 -> OS가 프로세스에 시그널을 보냄
- Synchronous: 불법 명령 또는 0으로 나누기와 같은 실행 중 오류 상황
- Asynchronous: Ctrl+C (예측할 수 없는 상황에서 발생)
프로세스와 스레드 (Processes, threads)
- 프로세스 생성:
유닉스 환경에서 fork 함수를 사용하여 여러 프로세스를 생성할 수 있습니다. 이 함수는 부모 프로세스가 자식 프로세스를 만들고, 각 자식 프로세스는 독립적으로 실행됩니다. - 프로세스 간 통신:
- 공통 조상을 가진 프로세스들은 파이프(pipe)를 통해 통신할 수 있습니다. 파이프는 부모-자식 관계의 프로세스들 간에 데이터를 주고받을 수 있는 통신 경로입니다.
- 공통 조상이 없는 프로세스들은 파이프 대신 시그널, FIFO, 세마포어, 공유 메모리 등의 방법을 사용하여 통신합니다. 이는 프로세스 간의 직접적인 메모리 공유가 불가능하기 때문입니다.
- 프로세스 내 동시성 (Concurrency):
하나의 프로세스 내부에서 스레드(thread)를 사용하여 동시에 여러 작업을 실행할 수 있습니다.- 스레드는 프로세스 내에서 공유 메모리를 사용하여 빠르게 데이터를 주고받을 수 있기 때문에, 스레드 간 통신은 CPU 자원을 많이 소모하지 않고 효율적으로 이루어집니다.
- 스레드의 역할:
스레드는 각기 독립된 실행 흐름을 가지면서, 같은 프로세스 내에서 메모리를 공유합니다. 이를 통해 하나의 프로세스에서 여러 작업이 병렬적으로 처리될 수 있습니다.
컴퓨터 내부의 네트워크 (The network as the computer)
- 동시성 및 통신이 결합하여 새로운 애플리케이션을 형성
- 클라이언트 - 서비스를 요청 / 서버 - 서비스를 제공 (서로 다른 위치에서 제공가능해야 함)
- 일반적인 모델은 클라이언트-서버 모델이며 서버 프로세스는 자원을 관리하고 클라이언트 프로세스는 서버에 요청을 보내 자원에 접근하고 서버는 요청을 처리하여 응답을 클라이언트에게 보냄
동적 메모리 할당 기법
- malloc(), alloc(), calloc() 함수 사용 가능
- 스택(stack): 함수가 실행되는 동안에만 유지되는 공간, 함수가 종료되면 자동으로 사라짐
- 힙(heap): 동적 메모리가 할당되는 공간, 사용자가 수동으로 해제해야 하며 그렇지 않으면 계속 남아 있음
결함 허용 (Fault tolerance)
- 자원 해제 문제:
프로그래머가 명확한 위치에서 버퍼와 같은 자원을 해제하더라도, 예기치 않은 오류 발생 시 자원을 해제하지 않고 잊어버리는 경우가 발생할 수 있습니다. 이러한 실수는 메모리 누수와 같은 문제가 발생할 가능성을 높입니다. - C 언어의 문제점:
- 반환값 확인 요구 없음: C 언어에서는 함수의 반환값을 꼭 확인해야 할 의무가 없기 때문에, 잘못된 반환값이나 에러를 놓칠 수 있습니다. 예를 들어, 메모리 할당 함수가 실패해도 이를 확인하지 않으면 프로그램이 비정상적으로 작동할 수 있습니다.
- 배열 범위 초과 허용: C 언어는 배열의 크기를 초과하는 인덱스로 접근하는 것을 막지 않습니다. 예를 들어, 배열의 크기를 10으로 선언했음에도 불구하고 11번째 요소에 접근할 수 있으며, 이는 메모리 손상을 초래할 수 있습니다.
- 현대 프로그래밍 언어(Java)의 개선:
Java와 같은 현대 프로그래밍 언어는 배열 범위 초과와 같은 문제를 런타임 검사를 통해 자동으로 감지하고 오류를 발생시킵니다. 이를 통해 배열의 범위를 넘는 접근을 방지하며, 안전한 메모리 관리가 가능합니다.
버퍼 오버플로우 (Buffer Overflows)
- 사용자가 지정된 버퍼보다 더 많은 데이터를 입력하면 버퍼 오버플로우가 발생합니다.
Possibility of buffer overflow (버퍼 오버플로우의 가능성)
char buf[80];
printf("Enter your first name: ");
scanf("%s", buf);
If the user enters more than 79 bytes, the resulting string and string terminator do not fit in the allocated variable.
(사용자가 79바이트 이상을 입력하면, 결과 문자열과 문자열 종료 문자가 할당된 변수에 맞지 않게 됩니다.)
Consequences of buffer overflows (버퍼 오버플로우의 결과)
- 프로그램의 자동 변수 할당:
프로그램은 일반적으로 자동 변수를 스택에 할당합니다. 스택은 함수 호출 시마다 새 변수를 저장하는 공간으로, 버퍼도 여기에 저장됩니다. - 스택의 확장 방향:
스택은 메모리 공간에서 높은 주소에서 낮은 주소로 확장됩니다. 즉, 새로운 변수가 스택에 추가될 때 메모리 상에서 상위 주소에서 하위 주소로 내려가면서 할당됩니다. - 버퍼 오버플로우 발생 시 영향:
버퍼에 예상보다 많은 데이터가 입력되면, 이 데이터가 스택에서 다른 공간을 덮어쓸 수 있습니다.- 사용되지 않은 메모리 공간을 덮어쓸 수 있고,
- 다른 변수의 값을 덮어쓸 수도 있으며,
- 특히 **반환 주소(return address)**나 허용되지 않은 메모리 공간을 침범할 수도 있습니다.
이로 인해 프로그램이 예기치 않은 값을 참조하거나, 다른 메모리 영역을 침범하게 되어 치명적인 오류가 발생할 수 있습니다.
- 버퍼 오버플로우의 결과:
- 영향이 없을 수 있음: 오버플로우가 발생했지만 그 결과가 나타나지 않을 수도 있습니다.
- 프로그램 충돌: 잘못된 메모리 접근으로 인해 프로그램이 비정상 종료되거나 코어 덤프가 발생할 수 있습니다.
- 예측 불가능한 동작: 가장 위험한 결과로, 프로그램이 예측할 수 없는 방식으로 동작하거나, 악의적인 사용자가 이를 악용해 시스템을 장악할 수도 있습니다.
결론: 버퍼 오버플로우는 단순한 실수로 프로그램에 치명적인 영향을 미칠 수 있으며, 이로 인해 프로그램 충돌이나 심지어 시스템 보안 위협까지 발생할 수 있습니다. 침범영역에 따라 결과가 달라질 수 있기에 결과를 알 수 없음
Example of buffer overflows (버퍼 오버플로우의 예시)
- Program 1.1
- 사용자가 입력한 문자열이 "mypass"와 일치하는지 확인하고, 일치하면 1을 반환하고, 그렇지 않으면 0을 반환하는 함수입니다.
- checkpasstest.c
- 만약 13자의 문자열이 입력되면, 변수 x는 0이 아닌 값으로 변경되며, 함수는 이 값을 반환합니다.
Security of buffer overflows (버퍼 오버플로우의 보안 문제)
- 첫 번째 웜 (1988년, Robert Morris):
1988년 11월 2일에 Robert Morris가 개발한 최초의 컴퓨터 웜은 finger 데몬에서 발견된 버퍼 오버플로우 취약점을 이용했습니다. 웜이 시스템에 침투하여 네트워크를 통해 확산되어 버퍼 오버플로우를 이용한 공격의 초기 사례로, 시스템 보안에 큰 영향을 미쳤습니다. - Telnet 데몬 취약점:
Telnet 데몬에서 비밀번호를 확인하는 함수가 있습니다. 이 함수는- 비밀번호가 맞으면 1을 반환하고,
- 틀리면 0을 반환합니다.
그러나, 버퍼 오버플로우를 이용하여 반환값(return value)을 덮어쓰는 공격을 감행할 수 있다면, 비밀번호가 틀렸어도 공격자가 루트 셸을 생성할 수 있는 위험이 발생합니다. 즉, 공격자가 의도적으로 잘못된 비밀번호를 입력하고도 시스템에 침투할 수 있는 가능성을 열어둡니다.
- 루트 권한을 가진 프로그램의 위험성:
루트 권한으로 실행되는 애플리케이션이 버퍼 오버플로우에 취약한 경우, 공격자는 이 취약점을 악용해 루트 권한을 가진 셸을 생성할 수 있습니다.- 이는 시스템을 완전히 제어할 수 있는 권한을 공격자에게 넘겨주는 셈이 됩니다.
- 루트 권한의 프로그램이 버퍼 오버플로우에 노출되면, 해당 시스템 전체가 해킹될 위험이 커집니다.
'Computer Science > 시스템 프로그래밍' 카테고리의 다른 글
시스템 프로그래밍 chapter 05. (파일과 디렉토리) (1) | 2024.10.29 |
---|---|
시스템 프로그래밍 chapter 04. (4) | 2024.10.09 |
시스템 프로그래밍 chapter 03. (1) | 2024.10.08 |
시스템 프로그래밍 chapter 02. (0) | 2024.10.08 |
시스템 프로그래밍 Linux Tutorial (0) | 2024.10.07 |