본문 바로가기
IT 기술/리눅스 커널

sparse : kernel static analysis tool

by 땅뚱 2013. 2. 12.

커널 코드를 보다 보니 이상한 문법의 코드가 있어서 확인해보았다.

    203 static int expand_fdtable(struct files_struct *files, int nr)
    204     __releases(files->file_lock)
    205     __acquires(files->file_lock)
    206 {

expand_fdtable() 함수를 보면, 파라미터 정의 다음 줄에 __releases / __acquires 라는 함수 비슷한 것이 정의되어있다. 이를 찾아보면 include/linux/compiler.h 파일에 다음과 같이 정의되어 있다.

  6 #ifdef __CHECKER__
  7 # define __user     __attribute__((noderef, address_space(1)))
  8 # define __kernel   __attribute__((address_space(0)))
  9 # define __safe     __attribute__((safe))
 10 # define __force    __attribute__((force))
 11 # define __nocast   __attribute__((nocast))
 12 # define __iomem    __attribute__((noderef, address_space(2)))
 13 # define __acquires(x)  __attribute__((context(x,0,1)))
 14 # define __releases(x)  __attribute__((context(x,1,0)))
 15 # define __acquire(x)   __context__(x,1)
 16 # define __release(x)   __context__(x,-1)
 17 # define __cond_lock(x,c)   ((c) ? ({ __acquire(x); 1; }) : 0)
 18 # define __percpu   __attribute__((noderef, address_space(3)))
 19 #ifdef CONFIG_SPARSE_RCU_POINTER
 20 # define __rcu      __attribute__((noderef, address_space(4)))
 21 #else
 22 # define __rcu
 23 #endif
 24 extern void __chk_user_ptr(const volatile void __user *);
 25 extern void __chk_io_ptr(const volatile void __iomem *);
 26 #else
 27 # define __user
 28 # define __kernel
 29 # define __safe
 30 # define __force
 31 # define __nocast
 32 # define __iomem
 33 # define __chk_user_ptr(x) (void)0
 34 # define __chk_io_ptr(x) (void)0
 35 # define __builtin_warning(x, y...) (1)
 36 # define __acquires(x)
 37 # define __releases(x)
 38 # define __acquire(x) (void)0
 39 # define __release(x) (void)0
 40 # define __cond_lock(x,c) (c)
 41 # define __percpu
 42 # define __rcu
 43 #endif

 

__CHEKCER__ 가 정의되어 있는 경우에 추가되는데, 이 것은 gcc 를 위한 것이 아니고, Sparse 라는 툴을 위한 코드이다.

Sparse 에 의해서 수행되는 check 중 일부는 __attribute__ 를 사용하거나, Sparse 고유 specifier 인 __context__ 를 사용한다. Sparse 는 아래와 같은 attribute 를 정의한다.

 

  • address_space(num)
  • bitwise
  • fore
  • context(expression, in_context, out_context)

 

위 정의를 잘 보면 익숙한 키워드가 보인다. __user / __kernel 이 그것이다. 2.6.7 부터 커널 코드에서 사용되기 시작한 지시어로 해당 변수가 속한 위치를 나타내 준다. __user 는 일반적인 커널 컴파일시에는 empty string 으로 빌드되지만, sparse 를 사용하는 경우 해당 포인터는 분리된 address space 가 되고 이 영역이 dereference 가 되지 않도록 한다.

 

Sparse 는 이를 기준으로 user 와 kernel 포인터를 섞어서 사용하는 경우, user 영역에 직접 접근하는 경우를 찾아낸다. 그 외에도 상수값의 최대치를 넘어서는 경우, 내장 어셈블리 코드의 실수, switch 문의 잘못된 사용등 다양한 조건 체크를 수행한다.⑵

 

Sparse 가 설치되어 있다면, make 시에 C=1 옵션을 추가해서 컴파일하면 된다. 외부 모듈도 같은 방식으로 체크할 수 있다.

Sparse 를 찾아보면, 위키피디아에서 잘 정의되어 있다. 상세한 내용은 아래 링크를 참조한다.

 

< Reference >

 

1) : http://en.wikipedia.org/wiki/Sparse

2) : http://lwn.net/Articles/87538/