diff mbox

[08/12] ima: added parser for RPM data type

Message ID 20170725154423.24845-9-roberto.sassu@huawei.com (mailing list archive)
State New, archived
Headers show

Commit Message

Roberto Sassu July 25, 2017, 3:44 p.m. UTC
This patch introduces a parser for RPM packages. It extracts the digests
from the RPMTAG_FILEDIGESTS header section and converts them to binary data
before adding them to the hash table.

The advantage of this data type is that verifiers can determine who
produced that data, as headers are signed by Linux distributions vendors.
RPM headers signatures can be provided as digest list metadata.

Signed-off-by: Roberto Sassu <roberto.sassu@huawei.com>
---
 security/integrity/ima/ima_digest_list.c | 84 +++++++++++++++++++++++++++++++-
 1 file changed, 83 insertions(+), 1 deletion(-)

Comments

kernel test robot July 27, 2017, 5:03 a.m. UTC | #1
Hi Roberto,

[auto build test WARNING on integrity/next]
[also build test WARNING on v4.13-rc2 next-20170726]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url:    https://github.com/0day-ci/linux/commits/Roberto-Sassu/ima-measure-digest-lists-instead-of-individual-files/20170727-123131
base:   https://git.kernel.org/pub/scm/linux/kernel/git/zohar/linux-integrity.git next
config: xtensa-allyesconfig (attached as .config)
compiler: xtensa-linux-gcc (GCC) 4.9.0
reproduce:
        wget https://raw.githubusercontent.com/01org/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # save the attached .config to linux build tree
        make.cross ARCH=xtensa 

All warnings (new ones prefixed by >>):

   security/integrity/ima/ima_digest_list.c: In function 'ima_parse_rpm':
>> security/integrity/ima/ima_digest_list.c:147:4: warning: ignoring return value of 'hex2bin', declared with attribute warn_unused_result [-Wunused-result]
       hex2bin(digest, datap, digest_len);
       ^

vim +/hex2bin +147 security/integrity/ima/ima_digest_list.c

    98	
    99	static int ima_parse_rpm(loff_t size, void *buf)
   100	{
   101		void *bufp = buf, *bufendp = buf + size;
   102		struct rpm_hdr *hdr = bufp;
   103		u32 tags = be32_to_cpu(hdr->tags);
   104		struct rpm_entryinfo *entry;
   105		void *datap = bufp + sizeof(*hdr) + tags * sizeof(struct rpm_entryinfo);
   106		int digest_len = hash_digest_size[ima_hash_algo];
   107		u8 digest[digest_len];
   108		int ret, i, j;
   109	
   110		const unsigned char rpm_header_magic[8] = {
   111			0x8e, 0xad, 0xe8, 0x01, 0x00, 0x00, 0x00, 0x00
   112		};
   113	
   114		if (size < sizeof(*hdr)) {
   115			pr_err("Missing RPM header\n");
   116			return -EINVAL;
   117		}
   118	
   119		if (memcmp(bufp, rpm_header_magic, sizeof(rpm_header_magic))) {
   120			pr_err("Invalid RPM header\n");
   121			return -EINVAL;
   122		}
   123	
   124		bufp += sizeof(*hdr);
   125	
   126		for (i = 0; i < tags && (bufp + sizeof(*entry)) <= bufendp;
   127		     i++, bufp += sizeof(*entry)) {
   128			entry = bufp;
   129	
   130			if (be32_to_cpu(entry->tag) != RPMTAG_FILEDIGESTS)
   131				continue;
   132	
   133			datap += be32_to_cpu(entry->offset);
   134	
   135			for (j = 0; j < be32_to_cpu(entry->count) &&
   136			     datap < bufendp; j++) {
   137				if (strlen(datap) == 0) {
   138					datap++;
   139					continue;
   140				}
   141	
   142				if (datap + digest_len * 2 + 1 > bufendp) {
   143					pr_err("RPM header read at invalid offset\n");
   144					return -EINVAL;
   145				}
   146	
 > 147				hex2bin(digest, datap, digest_len);
   148	
   149				ret = ima_add_digest_data_entry(digest);
   150				if (ret < 0 && ret != -EEXIST)
   151					return ret;
   152	
   153				datap += digest_len * 2 + 1;
   154			}
   155	
   156			break;
   157		}
   158	
   159		return 0;
   160	}
   161	

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation
diff mbox

Patch

diff --git a/security/integrity/ima/ima_digest_list.c b/security/integrity/ima/ima_digest_list.c
index c1ef79a..11ee77e 100644
--- a/security/integrity/ima/ima_digest_list.c
+++ b/security/integrity/ima/ima_digest_list.c
@@ -19,11 +19,13 @@ 
 #include "ima.h"
 #include "ima_template_lib.h"
 
+#define RPMTAG_FILEDIGESTS 1035
+
 enum digest_metadata_fields {DATA_ALGO, DATA_DIGEST, DATA_SIGNATURE,
 			     DATA_FILE_PATH, DATA_REF_ID, DATA_TYPE,
 			     DATA__LAST};
 
-enum digest_data_types {DATA_TYPE_COMPACT_LIST};
+enum digest_data_types {DATA_TYPE_COMPACT_LIST, DATA_TYPE_RPM};
 
 enum compact_list_entry_ids {COMPACT_LIST_ID_DIGEST};
 
@@ -33,6 +35,20 @@  struct compact_list_hdr {
 	u32 datalen;
 } __packed;
 
+struct rpm_hdr {
+	u32 magic;
+	u32 reserved;
+	u32 tags;
+	u32 datasize;
+} __packed;
+
+struct rpm_entryinfo {
+	int32_t tag;
+	u32 type;
+	int32_t offset;
+	u32 count;
+} __packed;
+
 static int ima_parse_compact_list(loff_t size, void *buf)
 {
 	void *bufp = buf, *bufendp = buf + size;
@@ -80,6 +96,69 @@  static int ima_parse_compact_list(loff_t size, void *buf)
 	return 0;
 }
 
+static int ima_parse_rpm(loff_t size, void *buf)
+{
+	void *bufp = buf, *bufendp = buf + size;
+	struct rpm_hdr *hdr = bufp;
+	u32 tags = be32_to_cpu(hdr->tags);
+	struct rpm_entryinfo *entry;
+	void *datap = bufp + sizeof(*hdr) + tags * sizeof(struct rpm_entryinfo);
+	int digest_len = hash_digest_size[ima_hash_algo];
+	u8 digest[digest_len];
+	int ret, i, j;
+
+	const unsigned char rpm_header_magic[8] = {
+		0x8e, 0xad, 0xe8, 0x01, 0x00, 0x00, 0x00, 0x00
+	};
+
+	if (size < sizeof(*hdr)) {
+		pr_err("Missing RPM header\n");
+		return -EINVAL;
+	}
+
+	if (memcmp(bufp, rpm_header_magic, sizeof(rpm_header_magic))) {
+		pr_err("Invalid RPM header\n");
+		return -EINVAL;
+	}
+
+	bufp += sizeof(*hdr);
+
+	for (i = 0; i < tags && (bufp + sizeof(*entry)) <= bufendp;
+	     i++, bufp += sizeof(*entry)) {
+		entry = bufp;
+
+		if (be32_to_cpu(entry->tag) != RPMTAG_FILEDIGESTS)
+			continue;
+
+		datap += be32_to_cpu(entry->offset);
+
+		for (j = 0; j < be32_to_cpu(entry->count) &&
+		     datap < bufendp; j++) {
+			if (strlen(datap) == 0) {
+				datap++;
+				continue;
+			}
+
+			if (datap + digest_len * 2 + 1 > bufendp) {
+				pr_err("RPM header read at invalid offset\n");
+				return -EINVAL;
+			}
+
+			hex2bin(digest, datap, digest_len);
+
+			ret = ima_add_digest_data_entry(digest);
+			if (ret < 0 && ret != -EEXIST)
+				return ret;
+
+			datap += digest_len * 2 + 1;
+		}
+
+		break;
+	}
+
+	return 0;
+}
+
 static int ima_parse_digest_list_data(struct ima_field_data *data)
 {
 	void *digest_list;
@@ -107,6 +186,9 @@  static int ima_parse_digest_list_data(struct ima_field_data *data)
 	case DATA_TYPE_COMPACT_LIST:
 		ret = ima_parse_compact_list(digest_list_size, digest_list);
 		break;
+	case DATA_TYPE_RPM:
+		ret = ima_parse_rpm(digest_list_size, digest_list);
+		break;
 	default:
 		pr_err("Parser for data type %d not implemented\n", data_type);
 		ret = -EINVAL;