ループバックデバイスの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コマンドで行っています。
#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 nul
xfer_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とする文字列とした方がセキュリティ的によさそうです。

最終更新 2014/12/15 23:41:01 - north
(2014/12/15 19:04:26 作成)


検索

アクセス数
3682568
最近のコメント
コアダンプファイル - sakaia
list_head構造体 - yocto_no_yomikata
勧告ロックと強制ロック - wataash
LKMからのファイル出力 - 重松 宏昌
kprobe - ななし
ksetの実装 - スーパーコピー
カーネルスレッドとは - ノース
カーネルスレッドとは - nbyst
asmlinkageってなに? - ノース
asmlinkageってなに? - よろしく
Adsense
広告情報が設定されていません。