Commit | Line | Data |
---|---|---|
adf53a77 RS |
1 | /* |
2 | * Copyright (C) 2013 Politecnico di Torino, Italy | |
3 | * TORSEC group -- http://security.polito.it | |
4 | * | |
5 | * Author: Roberto Sassu <roberto.sassu@polito.it> | |
6 | * | |
7 | * This program is free software; you can redistribute it and/or | |
8 | * modify it under the terms of the GNU General Public License as | |
9 | * published by the Free Software Foundation, version 2 of the | |
10 | * License. | |
11 | * | |
12 | * File: ima_template.c | |
13 | * Helpers to manage template descriptors. | |
14 | */ | |
20ee451f JP |
15 | |
16 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | |
17 | ||
adf53a77 | 18 | #include "ima.h" |
3ce1217d | 19 | #include "ima_template_lib.h" |
adf53a77 RS |
20 | |
21 | static struct ima_template_desc defined_templates[] = { | |
4d7aeee7 | 22 | {.name = IMA_TEMPLATE_IMA_NAME, .fmt = IMA_TEMPLATE_IMA_FMT}, |
2bb930ab DK |
23 | {.name = "ima-ng", .fmt = "d-ng|n-ng"}, |
24 | {.name = "ima-sig", .fmt = "d-ng|n-ng|sig"}, | |
c2426d2a | 25 | {.name = "", .fmt = ""}, /* placeholder for a custom format */ |
adf53a77 RS |
26 | }; |
27 | ||
28 | static struct ima_template_field supported_fields[] = { | |
2bb930ab | 29 | {.field_id = "d", .field_init = ima_eventdigest_init, |
3ce1217d | 30 | .field_show = ima_show_template_digest}, |
2bb930ab | 31 | {.field_id = "n", .field_init = ima_eventname_init, |
3ce1217d | 32 | .field_show = ima_show_template_string}, |
2bb930ab | 33 | {.field_id = "d-ng", .field_init = ima_eventdigest_ng_init, |
4d7aeee7 | 34 | .field_show = ima_show_template_digest_ng}, |
2bb930ab | 35 | {.field_id = "n-ng", .field_init = ima_eventname_ng_init, |
4d7aeee7 | 36 | .field_show = ima_show_template_string}, |
2bb930ab | 37 | {.field_id = "sig", .field_init = ima_eventsig_init, |
bcbc9b0c | 38 | .field_show = ima_show_template_sig}, |
adf53a77 RS |
39 | }; |
40 | ||
a71dc65d | 41 | static struct ima_template_desc *ima_template; |
9b9d4ce5 | 42 | static struct ima_template_desc *lookup_template_desc(const char *name); |
c2426d2a RS |
43 | static int template_desc_init_fields(const char *template_fmt, |
44 | struct ima_template_field ***fields, | |
45 | int *num_fields); | |
9b9d4ce5 RS |
46 | |
47 | static int __init ima_template_setup(char *str) | |
48 | { | |
49 | struct ima_template_desc *template_desc; | |
50 | int template_len = strlen(str); | |
51 | ||
c2426d2a RS |
52 | if (ima_template) |
53 | return 1; | |
54 | ||
9b9d4ce5 RS |
55 | /* |
56 | * Verify that a template with the supplied name exists. | |
57 | * If not, use CONFIG_IMA_DEFAULT_TEMPLATE. | |
58 | */ | |
59 | template_desc = lookup_template_desc(str); | |
71fed2ee RS |
60 | if (!template_desc) { |
61 | pr_err("template %s not found, using %s\n", | |
62 | str, CONFIG_IMA_DEFAULT_TEMPLATE); | |
9b9d4ce5 | 63 | return 1; |
71fed2ee | 64 | } |
9b9d4ce5 RS |
65 | |
66 | /* | |
67 | * Verify whether the current hash algorithm is supported | |
68 | * by the 'ima' template. | |
69 | */ | |
70 | if (template_len == 3 && strcmp(str, IMA_TEMPLATE_IMA_NAME) == 0 && | |
71 | ima_hash_algo != HASH_ALGO_SHA1 && ima_hash_algo != HASH_ALGO_MD5) { | |
20ee451f | 72 | pr_err("template does not support hash alg\n"); |
9b9d4ce5 RS |
73 | return 1; |
74 | } | |
75 | ||
76 | ima_template = template_desc; | |
77 | return 1; | |
78 | } | |
79 | __setup("ima_template=", ima_template_setup); | |
a71dc65d | 80 | |
c2426d2a RS |
81 | static int __init ima_template_fmt_setup(char *str) |
82 | { | |
83 | int num_templates = ARRAY_SIZE(defined_templates); | |
84 | ||
85 | if (ima_template) | |
86 | return 1; | |
87 | ||
88 | if (template_desc_init_fields(str, NULL, NULL) < 0) { | |
89 | pr_err("format string '%s' not valid, using template %s\n", | |
90 | str, CONFIG_IMA_DEFAULT_TEMPLATE); | |
91 | return 1; | |
92 | } | |
93 | ||
94 | defined_templates[num_templates - 1].fmt = str; | |
95 | ima_template = defined_templates + num_templates - 1; | |
96 | return 1; | |
97 | } | |
98 | __setup("ima_template_fmt=", ima_template_fmt_setup); | |
99 | ||
a71dc65d RS |
100 | static struct ima_template_desc *lookup_template_desc(const char *name) |
101 | { | |
102 | int i; | |
103 | ||
104 | for (i = 0; i < ARRAY_SIZE(defined_templates); i++) { | |
105 | if (strcmp(defined_templates[i].name, name) == 0) | |
106 | return defined_templates + i; | |
107 | } | |
108 | ||
109 | return NULL; | |
110 | } | |
111 | ||
3ce1217d | 112 | static struct ima_template_field *lookup_template_field(const char *field_id) |
adf53a77 RS |
113 | { |
114 | int i; | |
115 | ||
116 | for (i = 0; i < ARRAY_SIZE(supported_fields); i++) | |
117 | if (strncmp(supported_fields[i].field_id, field_id, | |
118 | IMA_TEMPLATE_FIELD_ID_MAX_LEN) == 0) | |
119 | return &supported_fields[i]; | |
120 | return NULL; | |
121 | } | |
122 | ||
dbc335d2 | 123 | static int template_fmt_size(const char *template_fmt) |
adf53a77 RS |
124 | { |
125 | char c; | |
126 | int template_fmt_len = strlen(template_fmt); | |
127 | int i = 0, j = 0; | |
128 | ||
129 | while (i < template_fmt_len) { | |
130 | c = template_fmt[i]; | |
131 | if (c == '|') | |
132 | j++; | |
133 | i++; | |
134 | } | |
135 | ||
136 | return j + 1; | |
137 | } | |
138 | ||
dbc335d2 | 139 | static int template_desc_init_fields(const char *template_fmt, |
adf53a77 RS |
140 | struct ima_template_field ***fields, |
141 | int *num_fields) | |
142 | { | |
9f3166b8 | 143 | const char *template_fmt_ptr; |
1bd7face | 144 | struct ima_template_field *found_fields[IMA_TEMPLATE_NUM_FIELDS_MAX]; |
3ce1217d | 145 | int template_num_fields = template_fmt_size(template_fmt); |
1bd7face | 146 | int i, len; |
adf53a77 | 147 | |
71fed2ee RS |
148 | if (template_num_fields > IMA_TEMPLATE_NUM_FIELDS_MAX) { |
149 | pr_err("format string '%s' contains too many fields\n", | |
150 | template_fmt); | |
adf53a77 | 151 | return -EINVAL; |
71fed2ee | 152 | } |
adf53a77 | 153 | |
9f3166b8 RS |
154 | for (i = 0, template_fmt_ptr = template_fmt; i < template_num_fields; |
155 | i++, template_fmt_ptr += len + 1) { | |
156 | char tmp_field_id[IMA_TEMPLATE_FIELD_ID_MAX_LEN + 1]; | |
9f3166b8 RS |
157 | |
158 | len = strchrnul(template_fmt_ptr, '|') - template_fmt_ptr; | |
159 | if (len == 0 || len > IMA_TEMPLATE_FIELD_ID_MAX_LEN) { | |
160 | pr_err("Invalid field with length %d\n", len); | |
1bd7face | 161 | return -EINVAL; |
9f3166b8 | 162 | } |
adf53a77 | 163 | |
9f3166b8 RS |
164 | memcpy(tmp_field_id, template_fmt_ptr, len); |
165 | tmp_field_id[len] = '\0'; | |
1bd7face RS |
166 | found_fields[i] = lookup_template_field(tmp_field_id); |
167 | if (!found_fields[i]) { | |
9f3166b8 | 168 | pr_err("field '%s' not found\n", tmp_field_id); |
1bd7face | 169 | return -ENOENT; |
adf53a77 | 170 | } |
adf53a77 | 171 | } |
1bd7face | 172 | |
c2426d2a RS |
173 | if (fields && num_fields) { |
174 | *fields = kmalloc_array(i, sizeof(*fields), GFP_KERNEL); | |
175 | if (*fields == NULL) | |
176 | return -ENOMEM; | |
177 | ||
178 | memcpy(*fields, found_fields, i * sizeof(*fields)); | |
179 | *num_fields = i; | |
180 | } | |
1bd7face | 181 | |
1bd7face | 182 | return 0; |
adf53a77 RS |
183 | } |
184 | ||
a71dc65d RS |
185 | struct ima_template_desc *ima_template_desc_current(void) |
186 | { | |
187 | if (!ima_template) | |
4286587d MZ |
188 | ima_template = |
189 | lookup_template_desc(CONFIG_IMA_DEFAULT_TEMPLATE); | |
a71dc65d RS |
190 | return ima_template; |
191 | } | |
192 | ||
e4a9c519 | 193 | int __init ima_init_template(void) |
adf53a77 | 194 | { |
b4148db5 | 195 | struct ima_template_desc *template = ima_template_desc_current(); |
71fed2ee | 196 | int result; |
adf53a77 | 197 | |
71fed2ee RS |
198 | result = template_desc_init_fields(template->fmt, |
199 | &(template->fields), | |
200 | &(template->num_fields)); | |
201 | if (result < 0) | |
7dbdb420 RS |
202 | pr_err("template %s init failed, result: %d\n", |
203 | (strlen(template->name) ? | |
204 | template->name : template->fmt), result); | |
71fed2ee RS |
205 | |
206 | return result; | |
adf53a77 | 207 | } |