반응형

리눅스 커널 버젼 3.13 이후로는 최초 빌드시에 아래와 같은 오류가 발생합니다.

 

scripts/sign-file.c:25:30: fatal error: openssl/opensslv.h: No such file or directory
compilation terminated.

 

이 문제는 openssl 관련된 라이브러리가 없어서 생기는 에러로서 그 이전에는 자체 커널 소스에 있는 API를 사용하다가 3.13 이후에는 외부의 libssl 라이브러리를 사용하게 됩니다.

 

이는 보안관련된 이슈가 생기면서 발생한 이슈라고 합니다. 특히 4.13 버젼이후로는 TLS도 지원한다고 하니 보다 보안이 강력한 kernel을 사용하고 싶다면 4.13버젼을 사용하는 것도 좋을 거 같습니다.

 

 apt-get install libssl-dev

 

이렇게 사용하게 되면 위에 발생한 오류를 해결할 수 있다는 점 확인해 주시기 바랍니다.

※ 크립토 API (Crypto API)는 리눅스 커널에서 사용하는 암호 프레임워크이며, IPsec과 dm-crypt와 같은 암호화된 데이터를 다루는 부분에서 사용한다. 리눅스 커널 버전 2.5.45에서 최초로 도입되었으며 자주 사용되는 블록 암호와 해시 함수를 포함하기 위해 확장되고 있다

 

반응형
반응형

이번에는 리눅스(우분투)환경에서 리눅스 컴파일 하는 방법에 대해서 알아보고자 합니다.

 

1) 커널 소스코드 다운받기

 

리눅스 커널 소스코드는 http://www.kernel.org 사이트에서 다운로드가 가능합니다.

 

 

현재 가장 최신 stable 버젼은 4.14.4인 만큼 해당 버전을 다운받아서 설치 해보도록 하겠습니다.

 

 root@ubuntu:/work# wget https://www.kernel.org/pub/linux/kernel/v4.x/linux-4.14.tar.xz
--2017-12-10 15:51:23--  https://www.kernel.org/pub/linux/kernel/v4.x/linux-4.14.tar.xz
Resolving www.kernel.org (www.kernel.org)... 147.75.110.187, 2604:1380:3000:3500::3
Connecting to www.kernel.org (www.kernel.org)|147.75.110.187|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 100770500 (96M) [application/x-xz]
Saving to: ‘linux-4.14.tar.xz’

linux-4.14.tar.xz      100%[==========================>]  96.10M   244KB/s    in 7m 3s

2017-12-10 15:58:28 (232 KB/s) - ‘linux-4.14.tar.xz’ saved [100770500/100770500]

 

다음과 같이 wget 명령어를 이용해서 커널 소스코드를 다운 받을 수 있습니다.

wget https://www.kernel.org/pub/linux/kernel/v4.x/linux-4.14.tar.x

명령어를 이용하여 커널소스를 다운을 받고 압축을 해제 합니다.

 

tar xvf linux-4.14.tar.xz

 

2) 리눅스 커널 컴파일을 위한 패키지 설치 

#apt-get install kernel-package
#apt-get install build-essential bin86
#apt-get install libncurses5-dev
 

 

3) 커널 설정파일 가져오기

커널을 컴파일하기 위해서는 관련된 설정파일을 셋팅을 사전에 해야 합니다.

우선 /boot 폴더에 있는 현재 시스템의 config 설정을 가져 옵니다.

물론 처음부터 세팅을 할 수 도 있지만... 그건 너무 무모하고 힘든 작업 일수 있기 때문에 현재 시스템의 설정을 가져와서 목적에 맡게 수정할 것을 권고 해 드립니다.

 

# cp /boot/config-4.4.0-87-generic ./.config

# make menuconfig

 

이렇게 설정을 하게 되면 최종 모든 설정이 끝나게 됩니다.

 

4) 커널 컴파일하기

 

사전에 필수 패키지를 잘 설치했으면 make-kpkg 란 tool이 정상적으로 설치가 되었을 겁니다. make-kpkg는 커널 소스를 컴파일 하고 타겟에 맞게 결과물을 생성합니다.

 

root@ubuntu:/work/linux-4.14# make-kpkg --initrd --revision=1.0 kernel_image kernel_headers
exec make kpkg_version=13.018 -f /usr/share/kernel-package/ruleset/minimal.mk debian DEBIAN_REVISION=1.0  INITRD=YES
====== making target debian/stamp/conf/minimal_debian [new prereqs: ]======
This is kernel package version 13.018.
test -d debian             || mkdir debian
test ! -e stamp-building || rm -f stamp-building
install -p -m 755 /usr/share/kernel-package/rules debian/rules
for file in ChangeLog  Control  Control.bin86 config templates.in rules; do                                      \
            cp -f  /usr/share/kernel-package/$file ./debian/;                               \
        done
cp: cannot stat '/usr/share/kernel-package/ChangeLog': No such file or directory
for dir  in Config docs examples ruleset scripts pkg po;  do                                      \
          cp -af /usr/share/kernel-package/$dir  ./debian/;        

 

5) 커널 설치하기

 

마지막으로

 

dpkg -i *.deb 를 수행 하게 되면 해당 커널이 마치게 됩니다.

반응형
반응형

시스템 호출 구현

 

<목적 정의 >

→ 이 시스템 콜의 중요 목적을 정의해야 한다. 가장 안좋은 예로는 ioctl() 함수를 들수있다 (이와 관련된 추가 설명은... 나중에)

<가능한 적은 개수의 인자사용, 깔끔하고 간단한 인터페이스>

<시간이 흐름에 따라 함수가 어떻게 바뀔지 예상하는 일...>

<방법을 제공해야지 정책을 제공하면 안된다>

 

매개변수 검사

시스템 호출은 모든 매개변수가 유효하고 적당한지 주의깊게 확인해야 한다.

가장 중요한 확인작업중 하나는 사용자가 제공한 포인터의 유효성을 확인하는 것이다.

  • 포인터는 사용자 공간의 메모리영역을 가르키고 있어야한다.
    →프로세스는 커널을 속이고 직접 커널 공간의 데이터를 읽어서는 안된다.
  • 포인터는 프로세스 주소공간의 메모리 영역을 가르키고 있어야 한다
  • 읽는 경우라면 해당 메모리가 읽기 가능상태, 쓰는 경우라면 메모리가 쓰기 가능상태 실행하는 경우면 실행 가능상태
    → 프로세스가 메모리 접근 제한을 우회하면 안된다.

커널은 필요한 확인 작업을 수행하고 원하는 내용을 사용자 공간으로 가져오는 방법을 2가지 제공한다.

 

1. copy_to_user() : 사용자 주소 공간의 src에 있는 데이터를 복사

→ 매개변수 : 1 - 프로세스 주소공간의 목적지 메모리 주소, 2 - 커널공간의 원본 포인터, 3- 복사할 데이터의 바이트 크기

2. copy_to from() : 커널 공간에 있는 데이터를 사용자 주소 공간으로 복사

 

시스템 호출 컨텍스트

: 시스템 호출을 실행하는 동안 커널은 프로세스 컨텍스트 상태에 있다.

current 포인터는 시스콜을 호출한 프로세스인 현재 태스크릴 지칭

 

프로세스 컨택스트에서 커널은,

 1. 휴면 상태가 될 수 있으며

 2. 완전히 선점이 가능하다.

 

1. 휴면상태가 될 수 있다는 것은 시스템 호출이 커널의 대다수 기능을 사용할 수 있다는 의미

2. 프로세스 컨텍스트가 선점 가능하다는 사실은 사용자 공간고 마찬가지로 다른 작업에 선점 될 수 있다는 의미

 

→ 새로운 작업이 같은 시스템 호출을 실행할 수 있기 때문에 시스템 호출은 재진입이 가능해야 한다.

 

시스템 호출이 끝나고 반환되면 제어 권한은 system_call() 함수로 넘어가고 이 함수는 결국 사용자 공간으로 전환시켜 사용자 프로세스의 실행이 재개된다.

 

시스템 호출 등록의 마지막 단계

  1. 시스템 호출 테이즐의 마지막에 항목을 추가, 시스템 호출을 지원하는 모든 아키텍처에 대해 이 작업을 수행
  2. 지원하는 모든 아키텍처의 시스콜 번호를 <asm/unistd.h> 파일에 정의
  3. 시스콜을 커널 이미지로 컴파일 한다. (Full compile)

시스템 호출의 장/단점 그리고 대안

 

장점

  • 구현이 간단하고 사용이 쉽다
  • 성능이 빠르다

단점

  • 공식적으로 할당된 시스콜 번호가 필요
  • 유연성이 떨어진다. 사용자 프로그램에 영향이 발생
  • 아키텍처별로 별도로 관리해야 한다.
  • 파일시스템에서 접근이 힘들다
  • 주 커널 트리 외부에서 시스템 호출을 관리하기 어렵다

대안

  • 장치노드를 구현하고 read(), write() 함수를 해당 장치에 호출, ioctl() 사용
  • 세마포어 같은 일부 인터페이스는 파일 서술자 형태로 표현 가능
  • sysfs, proc상의 적당한 위치에 파일로 정보를 남긴다.

 

반응형
반응형

시스템 호출 핸들러

 

사용자 공간의 애플리케이션은 직접 커널 코드를 호출할 수 없다

대신 사용자 공간 애플리케이션은 어떻게든 실행하고 싶은 시스템 호출이 있다는 것을 커널에 알려서 시스템을 커널모드로 전환해야 애플리케이션을 대신해 커널공간에서 시스템 호출을 실행할 수 있다.

 

커널에 신호를 보내는 방법으로 소프트웽어 인터럽트라는 방법을 사용한다

→ 예외(exception)가 발생하면 시스템은 커널 모드로 전환 되고 예외 처리기 (exception handler)가 실행된다. 소프트웨어 인터럽트의  경우 시스템 호출 핸들러가 예외 처리기가 된다

 

시스템 호출 핸들러는 그 역할에 걸맞은 이름을 가진 system_call() 한수로 구현되어 있으며 아키텍처별로 따로 구현이되고 x86-64는 entry_64.S 파일에 어셈블리어로 구현되어 있다. 시스템 호출 핸들러가 어떤 방식으로 호출되든, 중요한 사실은 사용자 공간에서 커널로 진입하려면 어떤 방법으로든 예외를 방생 시켜야 한다.

 

매개변수 전달

 

대부분의 시스콜은 시스템 호출 번호와 함께 하나 이상의 매개변수(Parameter)가 필요하다. 어떻게 해서든 예외 발생과정에서 매개변수를 사용자 공간에서 커널로 전달 해야 한다. 가장 쉬운 방법은 시스콜 번호를 전달 하는 것과 같은 방법으로 매개변수를 레지스터에 저장하는 것이다

총 5개의 매게변수를 레지스터에 저장가능하며 여섯개 이상의 인자를 사용하는 경우에는 모든 매개변수가 저장된 사용자 공간의 주소를 가르키는 포인터 값을 하나의 레지스터에 저장한다.

 

 

 

 

반응형
반응형

커널과 통신

  1. 시스템 호출은 하드웨어와 사용자 공간 프로세스 사이에 있는 계층
  2. 이 계층은 세가지 역할을 수행
  • 사용자 공간에 하드웨어 인터페이스를 추상화된 형태를 제공
  • 시스템 호출은 시스템보안 및 안정성을 제공
  • 사용자 공간과 기타 시스템 사이에 계층을 둠으로써 프로세스 별 가상 시스펨 환경을 제공

 

API, POSIX, C 라이브러리

  • 애플리캐이션으 일반적으로 시스템 호출을 직접 사용하지 않고 사용하지 않고, 사용자 공간에 구현된 애플리케이션 프로그래밍 인터페이스(API)를 이용
  • API는 애플리케이션이 사용하는 프로그래밍 인터페이스
  • API는 하나 또는 이상의 시스템 호출을 사용해 구현되며 경우에 따라 시스템 호출을 사용하지 않을 수 있다.

  < printf() 호출 시 애플리케이션, C 라이브러리, 커널사이의 관계>

 

 

  • 유닉스에서 가장 유명한 API는 POSIX 표준이다.
  • POSIX는 API와 시스템 호출간의 관계를 보여주는 예
  • 리눅스의 시스템 호출 인터페이스는 다른 유닉스 시스템과 마찬가지로 C라이브러리 형태로 제공
  • C라이브러리는 표준 C라이브러리와 시스템 호출 인터페이스 등 유닉스 시스템의 주요 API가 구현
  • C라이브러리는 모든 C프로그램이 사용하며, 대다수의 POSIX API를 추가로 제공
  • 유닉스 인터페이스의 공통적인 모토는 "정책이 아닌 방식을 제공하라" → 유닉스 시스템 호출은 특정 기능을 아주 일반적인 형태로 제공

 

시스콜

  • 시스템 호출 (리눅스에서는 syscall)은 보통 C 라이브러리에 정의된 함수를 호출하는 방식으로 사용
  • 이 함수는 0개 혹은 하나 이상의 인자를 받고 하나 이상 부수효과를 발생 가능
  • 시스템 호출에서 오류가 발생할 경우 C라이브러리는 전역 변수인 errno에 특정 오류 코드를 기록
  • 라이브러리 함수인 perror() 를 사용하여 이 변수를 사람이 보기 편한 문자열 형태로 변환 가능
  • 시스템 호출은 정의된 특정 동작을 수행, 그렇지만 함수 정의로는 구현 내용에 대해 아무것도 알 수없음에 주의
  • 시스템 호출 정의 방법 : 함수 정의 부분에 asmlinkage 지시자가 있으며 이 자시자는 해당 함수의 인자를 스택에서만 찾으라고 컴파일러에게 알려준다 → 이는 리눅스의 모든 시스템 호출이 사용하는 명명규칙

 

 

 

시스템 호출 번호

  • 리눅스의 모든 시스템 호출에는 시스콜 번호가 할당
  • 이 번호는 특정 시스템 호출을 참조하는데 사용하는 고유번호
  • 사용자 공간 프로세스가 시스템 호출을 실행 할 때 시스콜 번호를 통해 실행 할 시스템 호출을 확인
  • 프로세스는 이름을 사용해 시스콜을 참조하지 않는다
  • 시스콜 번호는 한번 할당 하면 변경할 수 없으므로 매우 중요
  • 커널은 등록된 모든 시스템 호출의 목록을 sys_call_table이라는 시스템 호출 테이블에 저장

 

시스템 호출 성능

  • 리눅스 시스템 호출은 다른 운영체제 보다 빠르다.
  • 첫번째, 리눅스의 빠른 Context switch 시간이며
  • 다음은 시스템 호출 핸드러의 구현이 간단하게 되어 있다.

 

반응형
반응형

이번에는 리눅스 커널에서 중요한 부분인 I/O (Storage) Stack에 대해 알아보고자 합니다. I/O (Storage) Stack은 리눅스 커널 시스템에서 가장 중요한 부분중에 하나이며 현재 리눅스 커널 소스 코드에서 다양하게 업데이트 되고 있는 부분입니다.

 

이유는, 메모리 관리 / 스케줄러 / 프로세스 등 리눅스&유닉스의 핵심이자 가장 전통적인 기능들은 수십년을 거쳐오면서 거의 안정화 되어가고 있으며 현재는 최적화에 초점이 맞춰 있습니다.

 

그렇지만 스토리지는 지금도 새로운 디바이스가 출시되고 있으며 특히 SSD의 보급화로 통해 기존의 HDD와는 전혀 다른 메커니즘을 갖고 있기때문에 지금도 I/O (Storage) Stack 부분은 많이 수정이 되고 있습니다.

 

현재 리눅스 커널은 현재까지 4.14 버젼까지 출시된 상태이고 stable version : 4.9, 로 되어 있습니다.

 

간단하게 I/O (Storage) Stack의 구조를 보게 되면

크게 보게 되면

Application → VFS(Virtual File System) → Block I/O Layer → I/O Scheduler → SCSI Layer → Block Device

 

각각의 기능을 보게 되면

 

Application은 read / write / open ... 통해 I/O Stack을 호출하게 됩니다.

 

VFS(Virtual File System) : 가장 파일시스템으로서 block F/S, Network F/S, Special Purpose F/S 등 다양종류의 파일 시스템을 지원을 하고 이들의 구동 방식은 Direct I/O 나 Page cache(MMAP)을 사용하여 I/O를 수행하게 됩니다. 또한 부가적으로 LVM, SW Raid 등의 기능을 지원하게 됩니다.

 

Block I/O Layer는 QUEUE를 이용해서 상위 레이어에서 받은 데이터를 저장하게 되고 이를 통해 구동을 하게 됩니다. 또한 다양한 Storage Device에 대한 추상화 작업을 1차적으로 진행하게 됩니다. 예전에는 이부분에서 추상화 작업은 진행하지 않았지만 nvme를 비롯한 SCSI 계열이 아닌 Storage 디바이스가 나오게 되면서 이부분의 기능이 추가 되었습니다.

 

I/O Scheduler는 noop, cfq, deadline의 기능을 지원하게 됩니다.

 

앞으로 storage stack에 대해서는 추가적으로 연재를 하도록 하겠습니다

 

끝으로 storage stack full diagram입니다.

 

 

 

출처 : https://www.thomas-krenn.com/en/wiki/Linux_Storage_Stack_Diagram#License

반응형

+ Recent posts