systemd: 228のlocal exploit(CVE-2016-10156)めも

systemd 228にlocal exploitがあったようなのでどんなバグだったのかをメモします。脆弱性の説明は、Headsup: systemd v228 local root exploit (CVE-2016-10156)に書かれてました。CVEはCVE-2016-10156です。

ちなみに、fedora 25のsystemdは201701/24時点で231です。

修正patchはbasic: fix touch() creating files with 07777 mode · systemd/systemd@06eeacb · GitHubです。 修正は以下のようになってます。

-        fd = open(path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY, mode > 0 ? mode : 0644);
+        fd = open(path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY,
+                        (mode == 0 || mode == MODE_INVALID) ? 0644 : mode);

修正された関数はbasic/fs-util.cのtouch_file()です。この関数はtouch()から呼ばれます。

int touch(const char *path) {
        return touch_file(path, false, USEC_INFINITY, UID_INVALID, GID_INVALID, MODE_INVALID);

修正前のコードではmode > 0としてmodeの値を比較していますが、この変数は符号なしなのでこの条件は常にtrueになります。

mode_tは/usr/include/sys/types.hでこうなっていて、

#ifndef __mode_t_defined
typedef __mode_t mode_t;
# define __mode_t_defined
#endif

/usr/include/bits/types.hでは__MODE_T_TYPEとなってます。

__STD_TYPE __MODE_T_TYPE __mode_t;      /* Type of file attribute bitmasks.  */

/usr/include/bits/typesize.hでこのようになり、

#define __MODE_T_TYPE           __U32_TYPE

/usr/include/bits/types.hでこのように定義されてます。

#define __U32_TYPE              unsigned int

というわけでmode > 0は常に真になるからmodeがそのまま使われます。

つぎに、modeですが、これはtouch()がMODE_INVALIDを渡しています。MODE_INVALIDはsrc/basic/parse-util.hで以下のように定義されています。

#define MODE_INVALID ((mode_t) -1)

mode_tは符号なしなので、全bitが立ちますね。 なのでこんな感じのファイルが作れるからどのようなファイルを作るかによっては・・・(´・ω・`)

masami@saga:~$ cat mode_test.c
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>

int main(int argc, char **argv)
{
        mode_t mode = (mode_t) -1;
        int fd = open("mode_test", O_CREAT | O_RDWR, mode);

        if (fd < 0) {
                perror("open");
                return -1;
        }
        close(fd);
        return 0;
}
masami@saga:~$ gcc mode_test.c
masami@saga:~$ ./a.out
masami@saga:~$ ls -la mode_test
-rwsrwsr-t. 1 masami masami 0 Jan 25 00:12 mode_test*
masami@saga:~$

バグの内容としては変数の型を間違えたから条件文で正しく処理できてないかったというところですが、そこからこういった脆弱性になるわけですねφ(..)メモメモ

( ´ー`)フゥー...