今回は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に設定していき、最後に関数自体の返り値としています。