ループバックデバイスのCRYPT
/dev/loop0にxor crypt/keyをhogeで設定するサンプルです。struct loop_info等は、gccの標準includeファイルで定義されておらず、カーネルソースのroot/include/linux/loop.hで定義され、本来はこれをincludeする事になります。サンプルのloop infoはver3.3のカーネルです。
loop_infoの各メンバーを参照できなく、loop_infoそのものを参照する必要があります。なお、参照にあたって、ループデバイスがdiskにバインドされている必要があります。検証ではlosetupコマンドで行っています。
排他論理和故、0x00/0xffの続くイメージは、サイズ長さ分、繰り返されたlo_encrypt_key/~lo_encrypt_keyとなり、脆弱性なところがあります。keyは最大サイズ32とする文字列とした方がセキュリティ的によさそうです。
loop_infoの各メンバーを参照できなく、loop_infoそのものを参照する必要があります。なお、参照にあたって、ループデバイスがdiskにバインドされている必要があります。検証ではlosetupコマンドで行っています。
#include <stdio.h> #include <fcntl.h> #include <string.h> typedef unsigned short __kernel_old_dev_t; #define LO_NAME_SIZE 64 #define LO_KEY_SIZE 32 struct loop_info { int lo_number; /* ioctl r/o */ __kernel_old_dev_t lo_device; /* ioctl r/o */ unsigned long lo_inode; /* ioctl r/o */ __kernel_old_dev_t lo_rdevice; /* ioctl r/o */ int lo_offset; int lo_encrypt_type; int lo_encrypt_key_size; /* ioctl w/o */ int lo_flags; /* ioctl r/o */ char lo_name[LO_NAME_SIZE]; unsigned char lo_encrypt_key[LO_KEY_SIZE]; /* ioctl w/o */ unsigned long lo_init[2]; char reserved[4]; }; #define LOOP_SET_STATUS 0x4C02 #define LOOP_GET_STATUS 0x4C03 void show_crypt(); void set_crypt(); int get_cmd(char *cmd); void main(int argc, char *argv[]) { switch (get_cmd(argv[1])) { case 0: show_crypt(argv[2]); break; case 1: set_crypt(argv[2]); break; default: printf("cmd err\n"); break; } } void set_crypt() { struct loop_info loopinfo; int fd; fd = open ("/dev/loop0", O_RDONLY)); if (ioctl (fd, LOOP_GET_STATUS, &loopinfo) < 0) { fprintf(stderr, "can't get info\n"); close (fd); return; } loopinfo.lo_encrypt_type = 1; loopinfo.lo_encrypt_key_size = 4; strncpy(loopinfo.lo_encrypt_key, "hoge", 4); if (ioctl (fd, LOOP_SET_STATUS, &loopinfo) < 0) { fprintf(stderr, "can't set info\n"); } close (fd); } void show_crypt() { struct loop_info loopinfo; int fd, i; fd = open ("/dev/loop0", O_RDONLY)); if (ioctl (fd, LOOP_GET_STATUS, &loopinfo) < 0) { fprintf(stderr, "can't get info\n"); close (fd); return; } printf("lo_encrypt_type:%d\n", loopinfo.lo_encrypt_type); printf("lo_encrypt_key:"); for (i = 0; i < loopinfo.lo_encrypt_key_size; i++) { putchar(loopinfo.lo_encrypt_key[i]); } putchar('\n'); close (fd); } int get_cmd(char *cmd) { int ans = -1; if (!strcmp(cmd, "show")) { ans = 0; } if (!strcmp(cmd, "set")) { ans = 1; } return ans; }losetupコマンドでバインドすればcrypy type=0のcrypt無しとなります。
[root@localhost lkm]# dd if=/dev/zero of=disk bs=1M count=1 [root@localhost lkm]# losetup /dev/loop0 disk [root@localhost lkm]# ./a.out show /dev/loop0 lo_encrypt_type:0 lo_encrypt_key: [root@localhost lkm]# echo 1234 > /dev/loop0 [root@localhost lkm]# cat /dev/loop0 | more 1234 : [root@localhost lkm]# cat disk | more 1234 :先のバインドしたdiskをアンバインドして、crypt_type=1(xor)/crypt key=hogeとします。/dev/loop0を介して参照するには問題ないですが、diskそのものはcryptされたデータとなります。
[root@localhost lkm]# losetup -d /dev/loop0 [root@localhost lkm]# dd if=/dev/zero of=disk bs=1M count=1 [root@localhost lkm]# losetup /dev/loop0 disk [root@localhost lkm]# ./a.out set /dev/loop0 [root@localhost lkm]# ./a.out show /dev/loop0 lo_encrypt_type:1 lo_encrypt_key:hoge [root@localhost lkm]# echo 1234 > /dev/loop0 [root@localhost lkm]# od -xa /dev/loop0 0000000 3231 3433 0a0a 6567 6f68 6567 6f68 6567 1 2 3 4 nl nl g e h o g e h o g e 0000020 6f68 6567 6f68 6567 6f68 6567 6f68 6567 h o g e h o g e h o g e h o g e [root@localhost lkm]# od -xa disk 0000000 5d59 5154 6562 0000 0000 0000 0000 0000 Y ] T Q b e nul nul nul nul nul nul nul nul nul nul 0000020 0000 0000 0000 0000 0000 0000 0000 0000 nul nul nul nul nul nul nul nul nul nul nul nul nul nul nul nulxfer_funcs[]はデフォルトで、none_funcs/xor_funcsがcrypt type=LO_CRYPT_NONE/LO_CRYPT_XORで登録されています。他のcrypt typeはlkmをinsmodする必要があります。
#define LO_CRYPT_NONE 0 #define LO_CRYPT_XOR 1 #define LO_CRYPT_DES 2 #define LO_CRYPT_FISH2 3 #define LO_CRYPT_BLOW 4 #define LO_CRYPT_CAST128 5 #define LO_CRYPT_IDEA 6 #define LO_CRYPT_DUMMY 9 #define LO_CRYPT_SKIPJACK 10 #define LO_CRYPT_CRYPTOAPI 18 #define MAX_LO_CRYPT 20 static struct loop_func_table *xfer_funcs[MAX_LO_CRYPT] = { &none_funcs, &xor_funcs }; static struct loop_func_table xor_funcs = { .number = LO_CRYPT_XOR, .transfer = transfer_xor, .init = xor_init };xorのcryptのtransfeコールバックです。cryptは*out++ = *in++ ^ key[(i & 511) % keysize];で、lo->lo_encrypt_key[]の先頭から順(オーバサイクル)に、転送バイト毎にxorします。
static int transfer_xor(struct loop_device *lo, int cmd, struct page *raw_page, unsigned raw_off, struct page *loop_page, unsigned loop_off, int size, sector_t real_block) { char *raw_buf = kmap_atomic(raw_page, KM_USER0) + raw_off; char *loop_buf = kmap_atomic(loop_page, KM_USER1) + loop_off; char *in, *out, *key; int i, keysize; if (cmd == READ) { in = raw_buf; out = loop_buf; } else { in = loop_buf; out = raw_buf; } key = lo->lo_encrypt_key; keysize = lo->lo_encrypt_key_size; for (i = 0; i < size; i++) *out++ = *in++ ^ key[(i & 511) % keysize]; kunmap_atomic(loop_buf, KM_USER1); kunmap_atomic(raw_buf, KM_USER0); cond_resched(); return 0; }
補足
サンプルでのcrypt設定は、losetupコマンドのEオプションで行えます。排他論理和故、0x00/0xffの続くイメージは、サイズ長さ分、繰り返されたlo_encrypt_key/~lo_encrypt_keyとなり、脆弱性なところがあります。keyは最大サイズ32とする文字列とした方がセキュリティ的によさそうです。