今回はLinuxカーネルのソースコードに注目してセキュリティコードレビューを行いたいと思います。Linuxのカーネルはネタの宝庫!といってもよいほど数多くの脆弱性が発見・修正されており、NIST(米国国立標準技術研究所)のNational Vulnerability Databaseで「Linux kernel」をキーワードに単純に検索するだけでも過去に624件の脆弱性が見つかっていることが分かります(執筆時点)。また、2010年は既に42件の脆弱性が登録されています。
サンプルコード
以下のコードはLinuxカーネル2.6.30のdrivers/net/tun.cから抜粋したものです。それでは、このコードのどこに問題があるか考えてみましょう。
/* Poll */
static unsigned int tun_chr_poll(struct file *file, poll_table * wait)
{
struct tun_file *tfile = file->private_data;
struct tun_struct *tun = __tun_get(tfile);
struct sock *sk = tun->sk;
unsigned int mask = 0;
if (!tun)
return POLLERR;
DBG(KERN_INFO "%s: tun_chr_poll\n", tun->dev->name);
poll_wait(file, &tun->socket.wait, wait);
if (!skb_queue_empty(&tun->readq))
mask |= POLLIN | POLLRDNORM;
if (sock_writeable(sk) ||
(!test_and_set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags) &&
sock_writeable(sk)))
mask |= POLLOUT | POLLWRNORM;
if (tun->dev->reg_state != NETREG_REGISTERED)
mask = POLLERR;
tun_put(tun);
return mask;
}
Linuxのtunデバイスはソフトウェア的にネットワークインターフェイスを実現するもので、VPNの実装などに使われています。上に挙げた関数tun_chr_poll()はtunデバイスに対してpoll()システムコールをかけたときに呼び出される関数です。tunデバイスが生きていることを確認した後(if(!tun)という行)、tunデバイスの状態に応じてPOLLINやPOLLOUTなどのビットマスクをローカル変数maskに設定していき、最後に関数自体の返り値としています。
