数据字段解析

首先贴出一个 IMA 度量文件的实例:

binary_runtime_measurement:
00000000  00 0a 00 00 9d 4c 81 b9 db f2 b4 c5 27 17 7f 49  |.....L......'..I|
00000010  75 9d e9 8f dc 50 a2 f6 00 06 00 00 6d 69 2d 61  |u....P......mi-a|
00000020  67 6e 00 31 00 00 00 1a 00 00 68 73 31 61 00 3a  |gn.1......hs1a.:|
00000030  99 92 05 e7 2f 9f 3c 26 9a c8 61 55 cf e2 87 58  |..../.<&..aU...X|
00000040  98 cc 9b 30 00 0f 00 00 6f 62 74 6f 61 5f 67 67  |...0....obtoa_gg|
00000050  65 72 61 67 65 74 0a 00 00 00 97 00 62 2d 5b ff  |eraget......b-[.|
00000060  74 3a 99 e8 e0 52 0b 98 99 20 d4 ee f8 9b 06 f0  |t:...R... ......|
00000070  00 00 69 00 61 6d 6e 2d 28 67 00 00 1a 00 00 00  |..i.amn-(g......|

对应的ascii_runtime_measurement:
10 4c9db981f2dbc5b41727497f9d758fe950dcf6a2 ima-ng sha1:9299e7059f2f263cc89a5561e2cf5887cc98309b boot_aggregate
10 972d62ff5b3a74e89952e0980b2099eed49bf8f0 ima-ng sha1:e9002ba6c5a98f5b7a33dc6bbf9ac1863873b713 /init
10 db389c4b5590a7450cb7b20d6fa4a97bc901420d ima-ng sha1:3cdd378dde62d830349e4221591655229a757ae5 /usr/bin/sh

相应代码中【2】对应读取的结构体如下:

struct event {
    struct {
        u_int32_t pcr;
        u_int8_t digest[SHA_DIGEST_LENGTH];
        u_int32_t name_len;
    } header;
    char name[TCG_EVENT_NAME_LEN_MAX + 1];
    // struct ima_template_desc *template_desc; /* template descriptor */
    u_int32_t template_data_len;
    u_int8_t *template_data; /* template related data */
};

下面会根据数据排列顺序,以第一行 boot_aggregate 为例说明数据内容结构。

  1. header

    读取时,首先填充 event 结构体中 header 结构体的内容,这部分长度是固定的。首先是4字节 PCR 索引,然后是哈希值,这里采用的是 SHA1,因此是20字节,接着是4字节的 IMA 模板名称长度。该部分对应下面的二进制内容:

    00000000  00 0a 00 00 9d 4c 81 b9 db f2 b4 c5 27 17 7f 49  |.....L......'..I|
    00000010  75 9d e9 8f dc 50 a2 f6 00 06 00 00              |u....P......    |
    
  2. name

    根据上一步读取的 IMA 模板名称长度读取模板名称,本处读取的名称为ima-ng,共6字节:

    00000000  00 0a 00 00 9d 4c 81 b9 db f2 b4 c5 27 17 7f 49  |.....L......'..I|
    00000010  75 9d e9 8f dc 50 a2 f6 00 06 00 00 6d 69 2d 61  |u....P......mi-a|
    00000020  67 6e                                            |gn              |
    
  3. 接下来会根据模板的不同采用不同的方案读取数据

    1. 对于模板名称为ima的类型,将首先读取模板哈希值,如果采用 SHA1 算法,将读取20字节的哈希值。然后读取4字节的field_len(?)和该数值相对应长度的数据。

    2. 对于非ima的其他类型模板,将首先读取4字节的模板数据长度值,对于本示例,读取的长度为49字节(0x31)。至此读取过的全部内容为:

      00000000  00 0a 00 00 9d 4c 81 b9 db f2 b4 c5 27 17 7f 49  |.....L......'..I|
      00000010  75 9d e9 8f dc 50 a2 f6 00 06 00 00 6d 69 2d 61  |u....P......mi-a|
      00000020  67 6e 00 31 00 00                                |gn.1..          |
      

      进一步,将根据该长度读取模板特定数据。至此读取完后的全部内容为:

      00000000  00 0a 00 00 9d 4c 81 b9 db f2 b4 c5 27 17 7f 49  |.....L......'..I|
      00000010  75 9d e9 8f dc 50 a2 f6 00 06 00 00 6d 69 2d 61  |u....P......mi-a|
      00000020  67 6e 00 31 00 00 00 1a 00 00 68 73 31 61 00 3a  |gn.1......hs1a.:|
      00000030  99 92 05 e7 2f 9f 3c 26 9a c8 61 55 cf e2 87 58  |..../.<&..aU...X|
      00000040  98 cc 9b 30 00 0f 00 00 6f 62 74 6f 61 5f 67 67  |...0....obtoa_gg|
      00000050  65 72 61 67 65 74 0a                             |eraget.         |
      

      该步骤读取的模板特定数据中,前四字节的 INT 值内容含义未知(00 1a 00 00),在实际解析时也未使用。而后面的内容可以对照本文章开头的ascii_runtime_measurement部分内容对照查看,分别为:

      • "sha1" || 0x00 || ":" || 模板哈希值 || 文件路径名称长度(包含1字节换行符) || 文件路径

参考资料

  1. Integrity Measurement Architecture (IMA) Wiki,https://sourceforge.net/p/linux-ima/wiki/Home/#verifying-ima-measurements
  2. ima解析源码,http://downloads.sf.net/project/linux-ima