/src/selinux/libsepol/src/write.c
Line | Count | Source |
1 | | |
2 | | /* Author : Stephen Smalley, <stephen.smalley.work@gmail.com> */ |
3 | | |
4 | | /* |
5 | | * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com> |
6 | | * |
7 | | * Support for enhanced MLS infrastructure. |
8 | | * |
9 | | * Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com> |
10 | | * |
11 | | * Added conditional policy language extensions |
12 | | * |
13 | | * Updated: Joshua Brindle <jbrindle@tresys.com> and Jason Tang <jtang@tresys.org> |
14 | | * |
15 | | * Module writing support |
16 | | * |
17 | | * Copyright (C) 2004-2005 Trusted Computer Solutions, Inc. |
18 | | * Copyright (C) 2003-2005 Tresys Technology, LLC |
19 | | * Copyright (C) 2017 Mellanox Technologies Inc. |
20 | | * |
21 | | * This library is free software; you can redistribute it and/or |
22 | | * modify it under the terms of the GNU Lesser General Public |
23 | | * License as published by the Free Software Foundation; either |
24 | | * version 2.1 of the License, or (at your option) any later version. |
25 | | * |
26 | | * This library is distributed in the hope that it will be useful, |
27 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
28 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
29 | | * Lesser General Public License for more details. |
30 | | * |
31 | | * You should have received a copy of the GNU Lesser General Public |
32 | | * License along with this library; if not, write to the Free Software |
33 | | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
34 | | */ |
35 | | #include <assert.h> |
36 | | #include <stdlib.h> |
37 | | |
38 | | #include <sepol/policydb/ebitmap.h> |
39 | | #include <sepol/policydb/avtab.h> |
40 | | #include <sepol/policydb/policydb.h> |
41 | | #include <sepol/policydb/conditional.h> |
42 | | #include <sepol/policydb/expand.h> |
43 | | |
44 | | #include "debug.h" |
45 | | #include "private.h" |
46 | | #include "mls.h" |
47 | | |
48 | | #define glblub_version \ |
49 | 5.93k | ((p->policy_type == POLICY_KERN && \ |
50 | 2.96k | p->policyvers >= POLICYDB_VERSION_GLBLUB) || \ |
51 | 5.93k | (p->policy_type == POLICY_BASE && \ |
52 | 1.19k | p->policyvers >= MOD_POLICYDB_VERSION_GLBLUB)) |
53 | | |
54 | | struct policy_data { |
55 | | struct policy_file *fp; |
56 | | struct policydb *p; |
57 | | }; |
58 | | |
59 | | static int avrule_write_list(policydb_t *p, avrule_t *avrules, |
60 | | struct policy_file *fp, unsigned conditional); |
61 | | |
62 | | static int ebitmap_write(ebitmap_t *e, struct policy_file *fp) |
63 | 27.9k | { |
64 | 27.9k | ebitmap_node_t *n; |
65 | 27.9k | uint32_t buf[32], bit, count; |
66 | 27.9k | uint64_t map; |
67 | 27.9k | size_t items; |
68 | | |
69 | 27.9k | buf[0] = cpu_to_le32(MAPSIZE); |
70 | 27.9k | buf[1] = cpu_to_le32(e->highbit); |
71 | | |
72 | 27.9k | count = 0; |
73 | 37.9k | for (n = e->node; n; n = n->next) |
74 | 9.96k | count++; |
75 | 27.9k | buf[2] = cpu_to_le32(count); |
76 | | |
77 | 27.9k | items = put_entry(buf, sizeof(uint32_t), 3, fp); |
78 | 27.9k | if (items != 3) |
79 | 0 | return POLICYDB_ERROR; |
80 | | |
81 | 37.9k | for (n = e->node; n; n = n->next) { |
82 | 9.96k | bit = cpu_to_le32(n->startbit); |
83 | 9.96k | items = put_entry(&bit, sizeof(uint32_t), 1, fp); |
84 | 9.96k | if (items != 1) |
85 | 0 | return POLICYDB_ERROR; |
86 | 9.96k | map = cpu_to_le64(n->map); |
87 | 9.96k | items = put_entry(&map, sizeof(uint64_t), 1, fp); |
88 | 9.96k | if (items != 1) |
89 | 0 | return POLICYDB_ERROR; |
90 | 9.96k | } |
91 | | |
92 | 27.9k | return POLICYDB_SUCCESS; |
93 | 27.9k | } |
94 | | |
95 | | static int avtab_write_item(policydb_t *p, avtab_ptr_t cur, |
96 | | struct policy_file *fp, unsigned conditional) |
97 | 3.70k | { |
98 | 3.70k | uint8_t buf8; |
99 | 3.70k | uint16_t buf16[4]; |
100 | 3.70k | uint32_t buf32[10]; |
101 | 3.70k | size_t items; |
102 | 3.70k | unsigned int i; |
103 | | |
104 | | /* Generate the new avtab format. */ |
105 | 3.70k | buf16[0] = cpu_to_le16(cur->key.source_type); |
106 | 3.70k | buf16[1] = cpu_to_le16(cur->key.target_type); |
107 | 3.70k | buf16[2] = cpu_to_le16(cur->key.target_class); |
108 | 3.70k | buf16[3] = cpu_to_le16(cur->key.specified); |
109 | 3.70k | items = put_entry(buf16, sizeof(uint16_t), 4, fp); |
110 | 3.70k | if (items != 4) |
111 | 0 | return POLICYDB_ERROR; |
112 | 3.70k | if ((p->policyvers < POLICYDB_VERSION_XPERMS_IOCTL) && |
113 | 22 | (cur->key.specified & AVTAB_XPERMS)) { |
114 | 0 | ERR(fp->handle, |
115 | 0 | "policy version %u does not support extended " |
116 | 0 | "permissions rules and one was specified", |
117 | 0 | p->policyvers); |
118 | 0 | return POLICYDB_ERROR; |
119 | 0 | } |
120 | | |
121 | 3.70k | if (!policydb_has_cond_xperms_feature(p) && |
122 | 812 | (cur->key.specified & AVTAB_XPERMS) && conditional) { |
123 | 0 | ERR(fp->handle, |
124 | 0 | "policy version %u does not support extended " |
125 | 0 | "permissions rules in conditional policies and one was specified", |
126 | 0 | p->policyvers); |
127 | 0 | return POLICYDB_ERROR; |
128 | 0 | } |
129 | | |
130 | 3.70k | if (p->target_platform != SEPOL_TARGET_SELINUX && |
131 | 216 | (cur->key.specified & AVTAB_XPERMS)) { |
132 | 0 | ERR(fp->handle, |
133 | 0 | "Target platform %s does not support " |
134 | 0 | "extended permissions rules and one was specified", |
135 | 0 | policydb_target_strings[p->target_platform]); |
136 | 0 | return POLICYDB_ERROR; |
137 | 0 | } |
138 | | |
139 | 3.70k | if (cur->key.specified & AVTAB_XPERMS) { |
140 | 3.07k | buf8 = cur->datum.xperms->specified; |
141 | 3.07k | items = put_entry(&buf8, sizeof(uint8_t), 1, fp); |
142 | 3.07k | if (items != 1) |
143 | 0 | return POLICYDB_ERROR; |
144 | 3.07k | buf8 = cur->datum.xperms->driver; |
145 | 3.07k | items = put_entry(&buf8, sizeof(uint8_t), 1, fp); |
146 | 3.07k | if (items != 1) |
147 | 0 | return POLICYDB_ERROR; |
148 | 27.6k | for (i = 0; i < ARRAY_SIZE(cur->datum.xperms->perms); i++) |
149 | 24.5k | buf32[i] = cpu_to_le32(cur->datum.xperms->perms[i]); |
150 | 3.07k | items = put_entry(buf32, sizeof(uint32_t), 8, fp); |
151 | 3.07k | if (items != 8) |
152 | 0 | return POLICYDB_ERROR; |
153 | 3.07k | } else { |
154 | 636 | buf32[0] = cpu_to_le32(cur->datum.data); |
155 | 636 | items = put_entry(buf32, sizeof(uint32_t), 1, fp); |
156 | 636 | if (items != 1) |
157 | 0 | return POLICYDB_ERROR; |
158 | 636 | } |
159 | | |
160 | 3.70k | return POLICYDB_SUCCESS; |
161 | 3.70k | } |
162 | | |
163 | | static int avtab_write(struct policydb *p, avtab_t *a, struct policy_file *fp) |
164 | 1.25k | { |
165 | 1.25k | unsigned int i; |
166 | 1.25k | int rc; |
167 | 1.25k | avtab_ptr_t cur; |
168 | 1.25k | uint32_t nel; |
169 | 1.25k | size_t items; |
170 | | |
171 | 1.25k | nel = cpu_to_le32(a->nel); |
172 | 1.25k | items = put_entry(&nel, sizeof(uint32_t), 1, fp); |
173 | 1.25k | if (items != 1) |
174 | 0 | return POLICYDB_ERROR; |
175 | | |
176 | 419M | for (i = 0; i < a->nslot; i++) { |
177 | 419M | for (cur = a->htable[i]; cur; cur = cur->next) { |
178 | 1.71k | if (avtab_write_item(p, cur, fp, 0)) { |
179 | 0 | rc = -1; |
180 | 0 | goto out; |
181 | 0 | } |
182 | 1.71k | } |
183 | 419M | } |
184 | | |
185 | 1.25k | rc = 0; |
186 | 1.25k | out: |
187 | 1.25k | return rc; |
188 | 1.25k | } |
189 | | |
190 | | /* |
191 | | * Write a semantic MLS level structure to a policydb binary |
192 | | * representation file. |
193 | | */ |
194 | | static int mls_write_semantic_level_helper(mls_semantic_level_t *l, |
195 | | struct policy_file *fp) |
196 | 177 | { |
197 | 177 | uint32_t buf[2], ncat = 0; |
198 | 177 | size_t items; |
199 | 177 | mls_semantic_cat_t *cat; |
200 | | |
201 | 808 | for (cat = l->cat; cat; cat = cat->next) |
202 | 631 | ncat++; |
203 | | |
204 | 177 | buf[0] = cpu_to_le32(l->sens); |
205 | 177 | buf[1] = cpu_to_le32(ncat); |
206 | 177 | items = put_entry(buf, sizeof(uint32_t), 2, fp); |
207 | 177 | if (items != 2) |
208 | 0 | return POLICYDB_ERROR; |
209 | | |
210 | 808 | for (cat = l->cat; cat; cat = cat->next) { |
211 | 631 | buf[0] = cpu_to_le32(cat->low); |
212 | 631 | buf[1] = cpu_to_le32(cat->high); |
213 | 631 | items = put_entry(buf, sizeof(uint32_t), 2, fp); |
214 | 631 | if (items != 2) |
215 | 0 | return POLICYDB_ERROR; |
216 | 631 | } |
217 | | |
218 | 177 | return POLICYDB_SUCCESS; |
219 | 177 | } |
220 | | |
221 | | /* |
222 | | * Read a semantic MLS range structure to a policydb binary |
223 | | * representation file. |
224 | | */ |
225 | | static int mls_write_semantic_range_helper(mls_semantic_range_t *r, |
226 | | struct policy_file *fp) |
227 | 59 | { |
228 | 59 | int rc; |
229 | | |
230 | 59 | rc = mls_write_semantic_level_helper(&r->level[0], fp); |
231 | 59 | if (rc) |
232 | 0 | return rc; |
233 | | |
234 | 59 | rc = mls_write_semantic_level_helper(&r->level[1], fp); |
235 | | |
236 | 59 | return rc; |
237 | 59 | } |
238 | | |
239 | | /* |
240 | | * Write a MLS level structure to a policydb binary |
241 | | * representation file. |
242 | | */ |
243 | | static int mls_write_level(mls_level_t *l, struct policy_file *fp) |
244 | 1.06k | { |
245 | 1.06k | uint32_t sens; |
246 | 1.06k | size_t items; |
247 | | |
248 | 1.06k | sens = cpu_to_le32(l->sens); |
249 | 1.06k | items = put_entry(&sens, sizeof(uint32_t), 1, fp); |
250 | 1.06k | if (items != 1) |
251 | 0 | return POLICYDB_ERROR; |
252 | | |
253 | 1.06k | if (ebitmap_write(&l->cat, fp)) |
254 | 0 | return POLICYDB_ERROR; |
255 | | |
256 | 1.06k | return POLICYDB_SUCCESS; |
257 | 1.06k | } |
258 | | |
259 | | /* |
260 | | * Write a MLS range structure to a policydb binary |
261 | | * representation file. |
262 | | */ |
263 | | static int mls_write_range_helper(mls_range_t *r, struct policy_file *fp) |
264 | 1.24k | { |
265 | 1.24k | uint32_t buf[3]; |
266 | 1.24k | size_t items, items2; |
267 | 1.24k | int eq; |
268 | | |
269 | 1.24k | eq = mls_level_eq(&r->level[1], &r->level[0]); |
270 | | |
271 | 1.24k | items = 1; /* item 0 is used for the item count */ |
272 | 1.24k | buf[items++] = cpu_to_le32(r->level[0].sens); |
273 | 1.24k | if (!eq) |
274 | 513 | buf[items++] = cpu_to_le32(r->level[1].sens); |
275 | 1.24k | buf[0] = cpu_to_le32(items - 1); |
276 | | |
277 | 1.24k | items2 = put_entry(buf, sizeof(uint32_t), items, fp); |
278 | 1.24k | if (items2 != items) |
279 | 0 | return POLICYDB_ERROR; |
280 | | |
281 | 1.24k | if (ebitmap_write(&r->level[0].cat, fp)) |
282 | 0 | return POLICYDB_ERROR; |
283 | 1.24k | if (!eq) |
284 | 513 | if (ebitmap_write(&r->level[1].cat, fp)) |
285 | 0 | return POLICYDB_ERROR; |
286 | | |
287 | 1.24k | return POLICYDB_SUCCESS; |
288 | 1.24k | } |
289 | | |
290 | | static int sens_write(hashtab_key_t key, hashtab_datum_t datum, void *ptr) |
291 | 491 | { |
292 | 491 | level_datum_t *levdatum; |
293 | 491 | uint32_t buf[32]; |
294 | 491 | size_t items, items2, len; |
295 | 491 | struct policy_data *pd = ptr; |
296 | 491 | struct policy_file *fp = pd->fp; |
297 | | |
298 | 491 | levdatum = (level_datum_t *)datum; |
299 | | |
300 | 491 | len = strlen(key); |
301 | 491 | items = 0; |
302 | 491 | buf[items++] = cpu_to_le32(len); |
303 | 491 | buf[items++] = cpu_to_le32(levdatum->isalias); |
304 | 491 | items2 = put_entry(buf, sizeof(uint32_t), items, fp); |
305 | 491 | if (items != items2) |
306 | 0 | return POLICYDB_ERROR; |
307 | | |
308 | 491 | items = put_entry(key, 1, len, fp); |
309 | 491 | if (items != len) |
310 | 0 | return POLICYDB_ERROR; |
311 | | |
312 | 491 | if (mls_write_level(levdatum->level, fp)) |
313 | 0 | return POLICYDB_ERROR; |
314 | | |
315 | 491 | return POLICYDB_SUCCESS; |
316 | 491 | } |
317 | | |
318 | | static int cat_write(hashtab_key_t key, hashtab_datum_t datum, void *ptr) |
319 | 544 | { |
320 | 544 | cat_datum_t *catdatum; |
321 | 544 | uint32_t buf[32]; |
322 | 544 | size_t items, items2, len; |
323 | 544 | struct policy_data *pd = ptr; |
324 | 544 | struct policy_file *fp = pd->fp; |
325 | | |
326 | 544 | catdatum = (cat_datum_t *)datum; |
327 | | |
328 | 544 | len = strlen(key); |
329 | 544 | items = 0; |
330 | 544 | buf[items++] = cpu_to_le32(len); |
331 | 544 | buf[items++] = cpu_to_le32(catdatum->s.value); |
332 | 544 | buf[items++] = cpu_to_le32(catdatum->isalias); |
333 | 544 | items2 = put_entry(buf, sizeof(uint32_t), items, fp); |
334 | 544 | if (items != items2) |
335 | 0 | return POLICYDB_ERROR; |
336 | | |
337 | 544 | items = put_entry(key, 1, len, fp); |
338 | 544 | if (items != len) |
339 | 0 | return POLICYDB_ERROR; |
340 | | |
341 | 544 | return POLICYDB_SUCCESS; |
342 | 544 | } |
343 | | |
344 | | static int role_trans_write(policydb_t *p, struct policy_file *fp) |
345 | 1.25k | { |
346 | 1.25k | role_trans_t *r = p->role_tr; |
347 | 1.25k | role_trans_t *tr; |
348 | 1.25k | uint32_t buf[3]; |
349 | 1.25k | size_t nel, items; |
350 | 1.25k | int new_roletr = (p->policy_type == POLICY_KERN && |
351 | 1.25k | p->policyvers >= POLICYDB_VERSION_ROLETRANS); |
352 | 1.25k | int warning_issued = 0; |
353 | | |
354 | 1.25k | nel = 0; |
355 | 1.29k | for (tr = r; tr; tr = tr->next) |
356 | 37 | if (new_roletr || tr->tclass == p->process_class) |
357 | 37 | nel++; |
358 | | |
359 | 1.25k | buf[0] = cpu_to_le32(nel); |
360 | 1.25k | items = put_entry(buf, sizeof(uint32_t), 1, fp); |
361 | 1.25k | if (items != 1) |
362 | 0 | return POLICYDB_ERROR; |
363 | 1.29k | for (tr = r; tr; tr = tr->next) { |
364 | 37 | if (!new_roletr && tr->tclass != p->process_class) { |
365 | 0 | if (!warning_issued) |
366 | 0 | WARN(fp->handle, |
367 | 0 | "Discarding role_transition " |
368 | 0 | "rules for security classes other than " |
369 | 0 | "\"process\""); |
370 | 0 | warning_issued = 1; |
371 | 0 | continue; |
372 | 0 | } |
373 | 37 | buf[0] = cpu_to_le32(tr->role); |
374 | 37 | buf[1] = cpu_to_le32(tr->type); |
375 | 37 | buf[2] = cpu_to_le32(tr->new_role); |
376 | 37 | items = put_entry(buf, sizeof(uint32_t), 3, fp); |
377 | 37 | if (items != 3) |
378 | 0 | return POLICYDB_ERROR; |
379 | 37 | if (new_roletr) { |
380 | 37 | buf[0] = cpu_to_le32(tr->tclass); |
381 | 37 | items = put_entry(buf, sizeof(uint32_t), 1, fp); |
382 | 37 | if (items != 1) |
383 | 0 | return POLICYDB_ERROR; |
384 | 37 | } |
385 | 37 | } |
386 | | |
387 | 1.25k | return POLICYDB_SUCCESS; |
388 | 1.25k | } |
389 | | |
390 | | static int role_allow_write(role_allow_t *r, struct policy_file *fp) |
391 | 1.25k | { |
392 | 1.25k | role_allow_t *ra; |
393 | 1.25k | uint32_t buf[2]; |
394 | 1.25k | size_t nel, items; |
395 | | |
396 | 1.25k | nel = 0; |
397 | 23.2k | for (ra = r; ra; ra = ra->next) |
398 | 22.0k | nel++; |
399 | 1.25k | buf[0] = cpu_to_le32(nel); |
400 | 1.25k | items = put_entry(buf, sizeof(uint32_t), 1, fp); |
401 | 1.25k | if (items != 1) |
402 | 0 | return POLICYDB_ERROR; |
403 | 23.2k | for (ra = r; ra; ra = ra->next) { |
404 | 22.0k | buf[0] = cpu_to_le32(ra->role); |
405 | 22.0k | buf[1] = cpu_to_le32(ra->new_role); |
406 | 22.0k | items = put_entry(buf, sizeof(uint32_t), 2, fp); |
407 | 22.0k | if (items != 2) |
408 | 0 | return POLICYDB_ERROR; |
409 | 22.0k | } |
410 | 1.25k | return POLICYDB_SUCCESS; |
411 | 1.25k | } |
412 | | |
413 | | static int filename_write_one_compat(hashtab_key_t key, void *data, void *ptr) |
414 | 1 | { |
415 | 1 | uint32_t bit, buf[4]; |
416 | 1 | size_t items, len; |
417 | 1 | filename_trans_key_t *ft = (filename_trans_key_t *)key; |
418 | 1 | filename_trans_datum_t *datum = data; |
419 | 1 | ebitmap_node_t *node; |
420 | 1 | void *fp = ptr; |
421 | | |
422 | 1 | len = strlen(ft->name); |
423 | 1 | do { |
424 | 64 | ebitmap_for_each_positive_bit(&datum->stypes, node, bit) { |
425 | 1 | buf[0] = cpu_to_le32(len); |
426 | 1 | items = put_entry(buf, sizeof(uint32_t), 1, fp); |
427 | 1 | if (items != 1) |
428 | 0 | return POLICYDB_ERROR; |
429 | | |
430 | 1 | items = put_entry(ft->name, sizeof(char), len, fp); |
431 | 1 | if (items != len) |
432 | 0 | return POLICYDB_ERROR; |
433 | | |
434 | 1 | buf[0] = cpu_to_le32(bit + 1); |
435 | 1 | buf[1] = cpu_to_le32(ft->ttype); |
436 | 1 | buf[2] = cpu_to_le32(ft->tclass); |
437 | 1 | buf[3] = cpu_to_le32(datum->otype); |
438 | 1 | items = put_entry(buf, sizeof(uint32_t), 4, fp); |
439 | 1 | if (items != 4) |
440 | 0 | return POLICYDB_ERROR; |
441 | 1 | } |
442 | | |
443 | 1 | datum = datum->next; |
444 | 1 | } while (datum); |
445 | | |
446 | 1 | return 0; |
447 | 1 | } |
448 | | |
449 | | static int filename_write_one(hashtab_key_t key, void *data, void *ptr) |
450 | 0 | { |
451 | 0 | uint32_t buf[3]; |
452 | 0 | size_t items, len, ndatum; |
453 | 0 | filename_trans_key_t *ft = (filename_trans_key_t *)key; |
454 | 0 | filename_trans_datum_t *datum; |
455 | 0 | void *fp = ptr; |
456 | |
|
457 | 0 | len = strlen(ft->name); |
458 | 0 | buf[0] = cpu_to_le32(len); |
459 | 0 | items = put_entry(buf, sizeof(uint32_t), 1, fp); |
460 | 0 | if (items != 1) |
461 | 0 | return POLICYDB_ERROR; |
462 | | |
463 | 0 | items = put_entry(ft->name, sizeof(char), len, fp); |
464 | 0 | if (items != len) |
465 | 0 | return POLICYDB_ERROR; |
466 | | |
467 | 0 | ndatum = 0; |
468 | 0 | datum = data; |
469 | 0 | do { |
470 | 0 | ndatum++; |
471 | 0 | datum = datum->next; |
472 | 0 | } while (datum); |
473 | |
|
474 | 0 | buf[0] = cpu_to_le32(ft->ttype); |
475 | 0 | buf[1] = cpu_to_le32(ft->tclass); |
476 | 0 | buf[2] = cpu_to_le32(ndatum); |
477 | 0 | items = put_entry(buf, sizeof(uint32_t), 3, fp); |
478 | 0 | if (items != 3) |
479 | 0 | return POLICYDB_ERROR; |
480 | | |
481 | 0 | datum = data; |
482 | 0 | do { |
483 | 0 | if (ebitmap_write(&datum->stypes, fp)) |
484 | 0 | return POLICYDB_ERROR; |
485 | | |
486 | 0 | buf[0] = cpu_to_le32(datum->otype); |
487 | 0 | items = put_entry(buf, sizeof(uint32_t), 1, fp); |
488 | 0 | if (items != 1) |
489 | 0 | return POLICYDB_ERROR; |
490 | | |
491 | 0 | datum = datum->next; |
492 | 0 | } while (datum); |
493 | | |
494 | 0 | return 0; |
495 | 0 | } |
496 | | |
497 | | static int filename_trans_write(struct policydb *p, void *fp) |
498 | 1.24k | { |
499 | 1.24k | size_t items; |
500 | 1.24k | uint32_t buf[1]; |
501 | 1.24k | int rc; |
502 | | |
503 | 1.24k | if (p->policyvers < POLICYDB_VERSION_FILENAME_TRANS) |
504 | 0 | return 0; |
505 | | |
506 | 1.24k | if (p->policyvers < POLICYDB_VERSION_COMP_FTRANS) { |
507 | 568 | buf[0] = cpu_to_le32(p->filename_trans_count); |
508 | 568 | items = put_entry(buf, sizeof(uint32_t), 1, fp); |
509 | 568 | if (items != 1) |
510 | 0 | return POLICYDB_ERROR; |
511 | | |
512 | 568 | rc = hashtab_map(p->filename_trans, filename_write_one_compat, |
513 | 568 | fp); |
514 | 681 | } else { |
515 | 681 | buf[0] = cpu_to_le32(p->filename_trans->nel); |
516 | 681 | items = put_entry(buf, sizeof(uint32_t), 1, fp); |
517 | 681 | if (items != 1) |
518 | 0 | return POLICYDB_ERROR; |
519 | | |
520 | 681 | rc = hashtab_map(p->filename_trans, filename_write_one, fp); |
521 | 681 | } |
522 | 1.24k | return rc; |
523 | 1.24k | } |
524 | | |
525 | | static int role_set_write(role_set_t *x, struct policy_file *fp) |
526 | 187 | { |
527 | 187 | size_t items; |
528 | 187 | uint32_t buf[1]; |
529 | | |
530 | 187 | if (ebitmap_write(&x->roles, fp)) |
531 | 0 | return POLICYDB_ERROR; |
532 | | |
533 | 187 | buf[0] = cpu_to_le32(x->flags); |
534 | 187 | items = put_entry(buf, sizeof(uint32_t), 1, fp); |
535 | 187 | if (items != 1) |
536 | 0 | return POLICYDB_ERROR; |
537 | | |
538 | 187 | return POLICYDB_SUCCESS; |
539 | 187 | } |
540 | | |
541 | | static int type_set_write(type_set_t *x, struct policy_file *fp) |
542 | 253 | { |
543 | 253 | size_t items; |
544 | 253 | uint32_t buf[1]; |
545 | | |
546 | 253 | if (ebitmap_write(&x->types, fp)) |
547 | 0 | return POLICYDB_ERROR; |
548 | 253 | if (ebitmap_write(&x->negset, fp)) |
549 | 0 | return POLICYDB_ERROR; |
550 | | |
551 | 253 | buf[0] = cpu_to_le32(x->flags); |
552 | 253 | items = put_entry(buf, sizeof(uint32_t), 1, fp); |
553 | 253 | if (items != 1) |
554 | 0 | return POLICYDB_ERROR; |
555 | | |
556 | 253 | return POLICYDB_SUCCESS; |
557 | 253 | } |
558 | | |
559 | | static int cond_write_bool(hashtab_key_t key, hashtab_datum_t datum, void *ptr) |
560 | 400 | { |
561 | 400 | cond_bool_datum_t *booldatum; |
562 | 400 | uint32_t buf[3], len; |
563 | 400 | unsigned int items, items2; |
564 | 400 | struct policy_data *pd = ptr; |
565 | 400 | struct policy_file *fp = pd->fp; |
566 | 400 | struct policydb *p = pd->p; |
567 | | |
568 | 400 | booldatum = (cond_bool_datum_t *)datum; |
569 | | |
570 | 400 | len = strlen(key); |
571 | 400 | items = 0; |
572 | 400 | buf[items++] = cpu_to_le32(booldatum->s.value); |
573 | 400 | buf[items++] = cpu_to_le32(booldatum->state); |
574 | 400 | buf[items++] = cpu_to_le32(len); |
575 | 400 | items2 = put_entry(buf, sizeof(uint32_t), items, fp); |
576 | 400 | if (items != items2) |
577 | 0 | return POLICYDB_ERROR; |
578 | 400 | items = put_entry(key, 1, len, fp); |
579 | 400 | if (items != len) |
580 | 0 | return POLICYDB_ERROR; |
581 | | |
582 | 400 | if (p->policy_type != POLICY_KERN && |
583 | 18 | p->policyvers >= MOD_POLICYDB_VERSION_TUNABLE_SEP) { |
584 | 14 | buf[0] = cpu_to_le32(booldatum->flags); |
585 | 14 | items = put_entry(buf, sizeof(uint32_t), 1, fp); |
586 | 14 | if (items != 1) |
587 | 0 | return POLICYDB_ERROR; |
588 | 14 | } |
589 | | |
590 | 400 | return POLICYDB_SUCCESS; |
591 | 400 | } |
592 | | |
593 | | /* |
594 | | * cond_write_cond_av_list doesn't write out the av_list nodes. |
595 | | * Instead it writes out the key/value pairs from the avtab. This |
596 | | * is necessary because there is no way to uniquely identifying rules |
597 | | * in the avtab so it is not possible to associate individual rules |
598 | | * in the avtab with a conditional without saving them as part of |
599 | | * the conditional. This means that the avtab with the conditional |
600 | | * rules will not be saved but will be rebuilt on policy load. |
601 | | */ |
602 | | static int cond_write_av_list(policydb_t *p, cond_av_list_t *list, |
603 | | struct policy_file *fp) |
604 | 650 | { |
605 | 650 | uint32_t buf[4]; |
606 | 650 | cond_av_list_t *cur_list; |
607 | 650 | uint32_t len, items; |
608 | 650 | int rc = -1; |
609 | | |
610 | 650 | len = 0; |
611 | 2.64k | for (cur_list = list; cur_list != NULL; cur_list = cur_list->next) { |
612 | 1.99k | if (cur_list->node->parse_context) |
613 | 1.99k | len++; |
614 | 1.99k | } |
615 | | |
616 | 650 | buf[0] = cpu_to_le32(len); |
617 | 650 | items = put_entry(buf, sizeof(uint32_t), 1, fp); |
618 | 650 | if (items != 1) |
619 | 0 | goto out; |
620 | | |
621 | 650 | if (len == 0) { |
622 | 263 | rc = 0; |
623 | 263 | goto out; |
624 | 263 | } |
625 | | |
626 | 2.37k | for (cur_list = list; cur_list != NULL; cur_list = cur_list->next) { |
627 | 1.99k | if (cur_list->node->parse_context) |
628 | 1.99k | if (avtab_write_item(p, cur_list->node, fp, 1)) |
629 | 0 | goto out; |
630 | 1.99k | } |
631 | | |
632 | 387 | rc = 0; |
633 | 650 | out: |
634 | 650 | return rc; |
635 | 387 | } |
636 | | |
637 | | static int cond_write_node(policydb_t *p, cond_node_t *node, |
638 | | struct policy_file *fp) |
639 | 325 | { |
640 | 325 | cond_expr_t *cur_expr; |
641 | 325 | uint32_t buf[2]; |
642 | 325 | uint32_t items, items2, len; |
643 | | |
644 | 325 | buf[0] = cpu_to_le32(node->cur_state); |
645 | 325 | items = put_entry(buf, sizeof(uint32_t), 1, fp); |
646 | 325 | if (items != 1) |
647 | 0 | return POLICYDB_ERROR; |
648 | | |
649 | | /* expr */ |
650 | 325 | len = 0; |
651 | 662 | for (cur_expr = node->expr; cur_expr != NULL; cur_expr = cur_expr->next) |
652 | 337 | len++; |
653 | | |
654 | 325 | buf[0] = cpu_to_le32(len); |
655 | 325 | items = put_entry(buf, sizeof(uint32_t), 1, fp); |
656 | 325 | if (items != 1) |
657 | 0 | return POLICYDB_ERROR; |
658 | | |
659 | 662 | for (cur_expr = node->expr; cur_expr != NULL; |
660 | 337 | cur_expr = cur_expr->next) { |
661 | 337 | items = 0; |
662 | 337 | buf[items++] = cpu_to_le32(cur_expr->expr_type); |
663 | 337 | buf[items++] = cpu_to_le32(cur_expr->boolean); |
664 | 337 | items2 = put_entry(buf, sizeof(uint32_t), items, fp); |
665 | 337 | if (items2 != items) |
666 | 0 | return POLICYDB_ERROR; |
667 | 337 | } |
668 | | |
669 | 325 | if (p->policy_type == POLICY_KERN) { |
670 | 325 | if (cond_write_av_list(p, node->true_list, fp) != 0) |
671 | 0 | return POLICYDB_ERROR; |
672 | 325 | if (cond_write_av_list(p, node->false_list, fp) != 0) |
673 | 0 | return POLICYDB_ERROR; |
674 | 325 | } else { |
675 | 0 | if (avrule_write_list(p, node->avtrue_list, fp, 1)) |
676 | 0 | return POLICYDB_ERROR; |
677 | 0 | if (avrule_write_list(p, node->avfalse_list, fp, 1)) |
678 | 0 | return POLICYDB_ERROR; |
679 | 0 | } |
680 | | |
681 | 325 | if (p->policy_type != POLICY_KERN && |
682 | 0 | p->policyvers >= MOD_POLICYDB_VERSION_TUNABLE_SEP) { |
683 | 0 | buf[0] = cpu_to_le32(node->flags); |
684 | 0 | items = put_entry(buf, sizeof(uint32_t), 1, fp); |
685 | 0 | if (items != 1) |
686 | 0 | return POLICYDB_ERROR; |
687 | 0 | } |
688 | | |
689 | 325 | return POLICYDB_SUCCESS; |
690 | 325 | } |
691 | | |
692 | | static int cond_write_list(policydb_t *p, cond_list_t *list, |
693 | | struct policy_file *fp) |
694 | 1.49k | { |
695 | 1.49k | cond_node_t *cur; |
696 | 1.49k | uint32_t len, items; |
697 | 1.49k | uint32_t buf[1]; |
698 | | |
699 | 1.49k | len = 0; |
700 | 1.82k | for (cur = list; cur != NULL; cur = cur->next) |
701 | 325 | len++; |
702 | 1.49k | buf[0] = cpu_to_le32(len); |
703 | 1.49k | items = put_entry(buf, sizeof(uint32_t), 1, fp); |
704 | 1.49k | if (items != 1) |
705 | 0 | return POLICYDB_ERROR; |
706 | | |
707 | 1.82k | for (cur = list; cur != NULL; cur = cur->next) { |
708 | 325 | if (cond_write_node(p, cur, fp) != 0) |
709 | 0 | return POLICYDB_ERROR; |
710 | 325 | } |
711 | 1.49k | return POLICYDB_SUCCESS; |
712 | 1.49k | } |
713 | | |
714 | | /* |
715 | | * Write a security context structure |
716 | | * to a policydb binary representation file. |
717 | | */ |
718 | | static int context_write(struct policydb *p, context_struct_t *c, |
719 | | struct policy_file *fp) |
720 | 673 | { |
721 | 673 | uint32_t buf[32]; |
722 | 673 | size_t items, items2; |
723 | | |
724 | 673 | items = 0; |
725 | 673 | buf[items++] = cpu_to_le32(c->user); |
726 | 673 | buf[items++] = cpu_to_le32(c->role); |
727 | 673 | buf[items++] = cpu_to_le32(c->type); |
728 | 673 | items2 = put_entry(buf, sizeof(uint32_t), items, fp); |
729 | 673 | if (items2 != items) |
730 | 0 | return POLICYDB_ERROR; |
731 | 673 | if ((p->policy_type == POLICY_KERN) || (p->policy_type == POLICY_BASE)) |
732 | 673 | if (mls_write_range_helper(&c->range, fp)) |
733 | 0 | return POLICYDB_ERROR; |
734 | | |
735 | 673 | return POLICYDB_SUCCESS; |
736 | 673 | } |
737 | | |
738 | | /* |
739 | | * The following *_write functions are used to |
740 | | * write the symbol data to a policy database |
741 | | * binary representation file. |
742 | | */ |
743 | | |
744 | | static int perm_write(hashtab_key_t key, hashtab_datum_t datum, void *ptr) |
745 | 1.54k | { |
746 | 1.54k | perm_datum_t *perdatum; |
747 | 1.54k | uint32_t buf[32]; |
748 | 1.54k | size_t items, items2, len; |
749 | 1.54k | struct policy_data *pd = ptr; |
750 | 1.54k | struct policy_file *fp = pd->fp; |
751 | | |
752 | 1.54k | perdatum = (perm_datum_t *)datum; |
753 | | |
754 | 1.54k | len = strlen(key); |
755 | 1.54k | items = 0; |
756 | 1.54k | buf[items++] = cpu_to_le32(len); |
757 | 1.54k | buf[items++] = cpu_to_le32(perdatum->s.value); |
758 | 1.54k | items2 = put_entry(buf, sizeof(uint32_t), items, fp); |
759 | 1.54k | if (items != items2) |
760 | 0 | return POLICYDB_ERROR; |
761 | | |
762 | 1.54k | items = put_entry(key, 1, len, fp); |
763 | 1.54k | if (items != len) |
764 | 0 | return POLICYDB_ERROR; |
765 | | |
766 | 1.54k | return POLICYDB_SUCCESS; |
767 | 1.54k | } |
768 | | |
769 | | static int common_write(hashtab_key_t key, hashtab_datum_t datum, void *ptr) |
770 | 0 | { |
771 | 0 | common_datum_t *comdatum; |
772 | 0 | uint32_t buf[32]; |
773 | 0 | size_t items, items2, len; |
774 | 0 | struct policy_data *pd = ptr; |
775 | 0 | struct policy_file *fp = pd->fp; |
776 | |
|
777 | 0 | comdatum = (common_datum_t *)datum; |
778 | |
|
779 | 0 | len = strlen(key); |
780 | 0 | items = 0; |
781 | 0 | buf[items++] = cpu_to_le32(len); |
782 | 0 | buf[items++] = cpu_to_le32(comdatum->s.value); |
783 | 0 | buf[items++] = cpu_to_le32(comdatum->permissions.nprim); |
784 | 0 | buf[items++] = cpu_to_le32(comdatum->permissions.table->nel); |
785 | 0 | items2 = put_entry(buf, sizeof(uint32_t), items, fp); |
786 | 0 | if (items != items2) |
787 | 0 | return POLICYDB_ERROR; |
788 | | |
789 | 0 | items = put_entry(key, 1, len, fp); |
790 | 0 | if (items != len) |
791 | 0 | return POLICYDB_ERROR; |
792 | | |
793 | 0 | if (hashtab_map(comdatum->permissions.table, perm_write, pd)) |
794 | 0 | return POLICYDB_ERROR; |
795 | | |
796 | 0 | return POLICYDB_SUCCESS; |
797 | 0 | } |
798 | | |
799 | | static int write_cons_helper(policydb_t *p, constraint_node_t *node, |
800 | | int allowxtarget, struct policy_file *fp) |
801 | 6.02k | { |
802 | 6.02k | constraint_node_t *c; |
803 | 6.02k | constraint_expr_t *e; |
804 | 6.02k | uint32_t buf[3], nexpr; |
805 | 6.02k | int items; |
806 | | |
807 | 7.08k | for (c = node; c; c = c->next) { |
808 | 1.06k | nexpr = 0; |
809 | 4.75k | for (e = c->expr; e; e = e->next) { |
810 | 3.69k | nexpr++; |
811 | 3.69k | } |
812 | 1.06k | buf[0] = cpu_to_le32(c->permissions); |
813 | 1.06k | buf[1] = cpu_to_le32(nexpr); |
814 | 1.06k | items = put_entry(buf, sizeof(uint32_t), 2, fp); |
815 | 1.06k | if (items != 2) |
816 | 0 | return POLICYDB_ERROR; |
817 | 4.75k | for (e = c->expr; e; e = e->next) { |
818 | 3.69k | buf[0] = cpu_to_le32(e->expr_type); |
819 | 3.69k | buf[1] = cpu_to_le32(e->attr); |
820 | 3.69k | buf[2] = cpu_to_le32(e->op); |
821 | 3.69k | items = put_entry(buf, sizeof(uint32_t), 3, fp); |
822 | 3.69k | if (items != 3) |
823 | 0 | return POLICYDB_ERROR; |
824 | | |
825 | 3.69k | switch (e->expr_type) { |
826 | 3 | case CEXPR_NAMES: |
827 | 3 | if (!allowxtarget && (e->attr & CEXPR_XTARGET)) |
828 | 0 | return POLICYDB_ERROR; |
829 | 3 | if (ebitmap_write(&e->names, fp)) { |
830 | 0 | return POLICYDB_ERROR; |
831 | 0 | } |
832 | 3 | if ((p->policy_type != POLICY_KERN && |
833 | 0 | type_set_write(e->type_names, fp)) || |
834 | 3 | (p->policy_type == POLICY_KERN && |
835 | 3 | (p->policyvers >= |
836 | 3 | POLICYDB_VERSION_CONSTRAINT_NAMES) && |
837 | 1 | type_set_write(e->type_names, fp))) { |
838 | 0 | return POLICYDB_ERROR; |
839 | 0 | } |
840 | 3 | break; |
841 | 3.69k | default: |
842 | 3.69k | break; |
843 | 3.69k | } |
844 | 3.69k | } |
845 | 1.06k | } |
846 | | |
847 | 6.02k | return POLICYDB_SUCCESS; |
848 | 6.02k | } |
849 | | |
850 | | static int class_write(hashtab_key_t key, hashtab_datum_t datum, void *ptr) |
851 | 3.01k | { |
852 | 3.01k | class_datum_t *cladatum; |
853 | 3.01k | constraint_node_t *c; |
854 | 3.01k | uint32_t buf[32], ncons; |
855 | 3.01k | size_t items, items2, len, len2; |
856 | 3.01k | struct policy_data *pd = ptr; |
857 | 3.01k | struct policy_file *fp = pd->fp; |
858 | 3.01k | struct policydb *p = pd->p; |
859 | | |
860 | 3.01k | cladatum = (class_datum_t *)datum; |
861 | | |
862 | 3.01k | len = strlen(key); |
863 | 3.01k | if (cladatum->comkey) |
864 | 0 | len2 = strlen(cladatum->comkey); |
865 | 3.01k | else |
866 | 3.01k | len2 = 0; |
867 | | |
868 | 3.01k | ncons = 0; |
869 | 4.03k | for (c = cladatum->constraints; c; c = c->next) { |
870 | 1.02k | ncons++; |
871 | 1.02k | } |
872 | | |
873 | 3.01k | items = 0; |
874 | 3.01k | buf[items++] = cpu_to_le32(len); |
875 | 3.01k | buf[items++] = cpu_to_le32(len2); |
876 | 3.01k | buf[items++] = cpu_to_le32(cladatum->s.value); |
877 | 3.01k | buf[items++] = cpu_to_le32(cladatum->permissions.nprim); |
878 | 3.01k | if (cladatum->permissions.table) |
879 | 3.01k | buf[items++] = cpu_to_le32(cladatum->permissions.table->nel); |
880 | 0 | else |
881 | 0 | buf[items++] = 0; |
882 | 3.01k | buf[items++] = cpu_to_le32(ncons); |
883 | 3.01k | items2 = put_entry(buf, sizeof(uint32_t), items, fp); |
884 | 3.01k | if (items != items2) |
885 | 0 | return POLICYDB_ERROR; |
886 | | |
887 | 3.01k | items = put_entry(key, 1, len, fp); |
888 | 3.01k | if (items != len) |
889 | 0 | return POLICYDB_ERROR; |
890 | | |
891 | 3.01k | if (cladatum->comkey) { |
892 | 0 | items = put_entry(cladatum->comkey, 1, len2, fp); |
893 | 0 | if (items != len2) |
894 | 0 | return POLICYDB_ERROR; |
895 | 0 | } |
896 | 3.01k | if (hashtab_map(cladatum->permissions.table, perm_write, pd)) |
897 | 0 | return POLICYDB_ERROR; |
898 | | |
899 | 3.01k | if (write_cons_helper(p, cladatum->constraints, 0, fp)) |
900 | 0 | return POLICYDB_ERROR; |
901 | | |
902 | 3.01k | if ((p->policy_type == POLICY_KERN) || |
903 | 3.01k | (p->policy_type == POLICY_BASE)) { |
904 | | /* write out the validatetrans rule */ |
905 | 3.01k | ncons = 0; |
906 | 3.05k | for (c = cladatum->validatetrans; c; c = c->next) { |
907 | 44 | ncons++; |
908 | 44 | } |
909 | 3.01k | buf[0] = cpu_to_le32(ncons); |
910 | 3.01k | items = put_entry(buf, sizeof(uint32_t), 1, fp); |
911 | 3.01k | if (items != 1) |
912 | 0 | return POLICYDB_ERROR; |
913 | 3.01k | if (write_cons_helper(p, cladatum->validatetrans, 1, fp)) |
914 | 0 | return POLICYDB_ERROR; |
915 | 3.01k | } |
916 | | |
917 | 3.01k | if ((p->policy_type == POLICY_KERN && |
918 | 3.00k | p->policyvers >= POLICYDB_VERSION_NEW_OBJECT_DEFAULTS) || |
919 | 47 | (p->policy_type == POLICY_BASE && |
920 | 2.96k | p->policyvers >= MOD_POLICYDB_VERSION_NEW_OBJECT_DEFAULTS)) { |
921 | 2.96k | char default_range = cladatum->default_range; |
922 | | |
923 | 2.96k | buf[0] = cpu_to_le32(cladatum->default_user); |
924 | 2.96k | buf[1] = cpu_to_le32(cladatum->default_role); |
925 | 2.96k | if (!glblub_version && default_range == DEFAULT_GLBLUB) { |
926 | 70 | WARN(fp->handle, |
927 | 70 | "class %s default_range set to GLBLUB but %spolicy version is %d (%d required), discarding", |
928 | 70 | p->p_class_val_to_name[cladatum->s.value - 1], |
929 | 70 | p->policy_type == POLICY_KERN ? "" : "module ", |
930 | 70 | p->policyvers, |
931 | 70 | p->policy_type == POLICY_KERN ? |
932 | 70 | POLICYDB_VERSION_GLBLUB : |
933 | 70 | MOD_POLICYDB_VERSION_GLBLUB); |
934 | 70 | default_range = 0; |
935 | 70 | } |
936 | 2.96k | buf[2] = cpu_to_le32(default_range); |
937 | 2.96k | items = put_entry(buf, sizeof(uint32_t), 3, fp); |
938 | 2.96k | if (items != 3) |
939 | 0 | return POLICYDB_ERROR; |
940 | 2.96k | } |
941 | | |
942 | 3.01k | if ((p->policy_type == POLICY_KERN && |
943 | 3.00k | p->policyvers >= POLICYDB_VERSION_DEFAULT_TYPE) || |
944 | 55 | (p->policy_type == POLICY_BASE && |
945 | 2.96k | p->policyvers >= MOD_POLICYDB_VERSION_DEFAULT_TYPE)) { |
946 | 2.96k | buf[0] = cpu_to_le32(cladatum->default_type); |
947 | 2.96k | items = put_entry(buf, sizeof(uint32_t), 1, fp); |
948 | 2.96k | if (items != 1) |
949 | 0 | return POLICYDB_ERROR; |
950 | 2.96k | } |
951 | | |
952 | 3.01k | return POLICYDB_SUCCESS; |
953 | 3.01k | } |
954 | | |
955 | | static int role_write(hashtab_key_t key, hashtab_datum_t datum, void *ptr) |
956 | 7.94k | { |
957 | 7.94k | role_datum_t *role; |
958 | 7.94k | uint32_t buf[32]; |
959 | 7.94k | size_t items, items2, len; |
960 | 7.94k | struct policy_data *pd = ptr; |
961 | 7.94k | struct policy_file *fp = pd->fp; |
962 | 7.94k | struct policydb *p = pd->p; |
963 | | |
964 | 7.94k | role = (role_datum_t *)datum; |
965 | | |
966 | | /* |
967 | | * Role attributes are redundant for policy.X, skip them |
968 | | * when writing the roles symbol table. They are also skipped |
969 | | * when pp is downgraded. |
970 | | * |
971 | | * Their numbers would be deducted in policydb_write(). |
972 | | */ |
973 | 7.94k | if ((role->flavor == ROLE_ATTRIB) && |
974 | 164 | ((p->policy_type == POLICY_KERN) || |
975 | 0 | (p->policy_type != POLICY_KERN && |
976 | 0 | p->policyvers < MOD_POLICYDB_VERSION_ROLEATTRIB))) |
977 | 164 | return POLICYDB_SUCCESS; |
978 | | |
979 | 7.77k | len = strlen(key); |
980 | 7.77k | items = 0; |
981 | 7.77k | buf[items++] = cpu_to_le32(len); |
982 | 7.77k | buf[items++] = cpu_to_le32(role->s.value); |
983 | 7.77k | buf[items++] = cpu_to_le32(role->bounds); |
984 | 7.77k | items2 = put_entry(buf, sizeof(uint32_t), items, fp); |
985 | 7.77k | if (items != items2) |
986 | 0 | return POLICYDB_ERROR; |
987 | | |
988 | 7.77k | items = put_entry(key, 1, len, fp); |
989 | 7.77k | if (items != len) |
990 | 0 | return POLICYDB_ERROR; |
991 | | |
992 | 7.77k | if (ebitmap_write(&role->dominates, fp)) |
993 | 0 | return POLICYDB_ERROR; |
994 | 7.77k | if (p->policy_type == POLICY_KERN) { |
995 | 7.60k | if (role->s.value == OBJECT_R_VAL) { |
996 | | /* |
997 | | * CIL populates object_r's types map |
998 | | * rather than handling it as a special case. |
999 | | * However, this creates an inconsistency with |
1000 | | * the kernel policy read from /sys/fs/selinux/policy |
1001 | | * because the kernel ignores everything except for |
1002 | | * object_r's value from the policy file. |
1003 | | * Make them consistent by writing an empty |
1004 | | * ebitmap instead. |
1005 | | */ |
1006 | 1.25k | ebitmap_t empty; |
1007 | 1.25k | ebitmap_init(&empty); |
1008 | 1.25k | if (ebitmap_write(&empty, fp)) |
1009 | 0 | return POLICYDB_ERROR; |
1010 | 6.35k | } else { |
1011 | 6.35k | if (ebitmap_write(&role->types.types, fp)) |
1012 | 0 | return POLICYDB_ERROR; |
1013 | 6.35k | } |
1014 | 7.60k | } else { |
1015 | 168 | if (type_set_write(&role->types, fp)) |
1016 | 0 | return POLICYDB_ERROR; |
1017 | 168 | } |
1018 | | |
1019 | 7.77k | if (p->policy_type != POLICY_KERN && |
1020 | 168 | p->policyvers >= MOD_POLICYDB_VERSION_ROLEATTRIB) { |
1021 | 116 | buf[0] = cpu_to_le32(role->flavor); |
1022 | 116 | items = put_entry(buf, sizeof(uint32_t), 1, fp); |
1023 | 116 | if (items != 1) |
1024 | 0 | return POLICYDB_ERROR; |
1025 | | |
1026 | 116 | if (ebitmap_write(&role->roles, fp)) |
1027 | 0 | return POLICYDB_ERROR; |
1028 | 116 | } |
1029 | | |
1030 | 7.77k | return POLICYDB_SUCCESS; |
1031 | 7.77k | } |
1032 | | |
1033 | | static int type_write(hashtab_key_t key, hashtab_datum_t datum, void *ptr) |
1034 | 1.92k | { |
1035 | 1.92k | type_datum_t *typdatum; |
1036 | 1.92k | uint32_t buf[32]; |
1037 | 1.92k | size_t items, items2, len; |
1038 | 1.92k | struct policy_data *pd = ptr; |
1039 | 1.92k | struct policy_file *fp = pd->fp; |
1040 | 1.92k | struct policydb *p = pd->p; |
1041 | | |
1042 | 1.92k | typdatum = (type_datum_t *)datum; |
1043 | | |
1044 | 1.92k | len = strlen(key); |
1045 | 1.92k | items = 0; |
1046 | 1.92k | buf[items++] = cpu_to_le32(len); |
1047 | 1.92k | buf[items++] = cpu_to_le32(typdatum->s.value); |
1048 | | |
1049 | 1.92k | if (p->policy_type != POLICY_KERN && |
1050 | 0 | p->policyvers < MOD_POLICYDB_VERSION_NEVERAUDIT && |
1051 | 0 | typdatum->flags & TYPE_FLAGS_NEVERAUDIT) |
1052 | 1.92k | WARN(fp->handle, |
1053 | 1.92k | "Warning! Module policy " |
1054 | 1.92k | "version %d cannot support neveraudit " |
1055 | 1.92k | "types, but one was defined", |
1056 | 1.92k | p->policyvers); |
1057 | | |
1058 | 1.92k | uint32_t properties = 0; |
1059 | | |
1060 | 1.92k | if (p->policy_type != POLICY_KERN) |
1061 | 0 | buf[items++] = cpu_to_le32(typdatum->primary); |
1062 | | |
1063 | 1.92k | if (typdatum->primary) |
1064 | 1.61k | properties |= TYPEDATUM_PROPERTY_PRIMARY; |
1065 | | |
1066 | 1.92k | if (typdatum->flavor == TYPE_ATTRIB) { |
1067 | 400 | properties |= TYPEDATUM_PROPERTY_ATTRIBUTE; |
1068 | 1.52k | } else if (typdatum->flavor == TYPE_ALIAS && |
1069 | 0 | p->policy_type != POLICY_KERN) |
1070 | 0 | properties |= TYPEDATUM_PROPERTY_ALIAS; |
1071 | | |
1072 | 1.92k | if (typdatum->flags & TYPE_FLAGS_PERMISSIVE && |
1073 | 0 | p->policy_type != POLICY_KERN) |
1074 | 0 | properties |= TYPEDATUM_PROPERTY_PERMISSIVE; |
1075 | | |
1076 | 1.92k | if (typdatum->flags & TYPE_FLAGS_NEVERAUDIT && |
1077 | 0 | p->policy_type != POLICY_KERN && |
1078 | 0 | p->policyvers >= MOD_POLICYDB_VERSION_NEVERAUDIT) |
1079 | 0 | properties |= TYPEDATUM_PROPERTY_NEVERAUDIT; |
1080 | | |
1081 | 1.92k | buf[items++] = cpu_to_le32(properties); |
1082 | 1.92k | buf[items++] = cpu_to_le32(typdatum->bounds); |
1083 | | |
1084 | 1.92k | items2 = put_entry(buf, sizeof(uint32_t), items, fp); |
1085 | 1.92k | if (items != items2) |
1086 | 0 | return POLICYDB_ERROR; |
1087 | | |
1088 | 1.92k | if (p->policy_type != POLICY_KERN) { |
1089 | 0 | if (ebitmap_write(&typdatum->types, fp)) |
1090 | 0 | return POLICYDB_ERROR; |
1091 | 0 | } |
1092 | | |
1093 | 1.92k | items = put_entry(key, 1, len, fp); |
1094 | 1.92k | if (items != len) |
1095 | 0 | return POLICYDB_ERROR; |
1096 | | |
1097 | 1.92k | return POLICYDB_SUCCESS; |
1098 | 1.92k | } |
1099 | | |
1100 | | static int user_write(hashtab_key_t key, hashtab_datum_t datum, void *ptr) |
1101 | 635 | { |
1102 | 635 | user_datum_t *usrdatum; |
1103 | 635 | uint32_t buf[32]; |
1104 | 635 | size_t items, items2, len; |
1105 | 635 | struct policy_data *pd = ptr; |
1106 | 635 | struct policy_file *fp = pd->fp; |
1107 | 635 | struct policydb *p = pd->p; |
1108 | | |
1109 | 635 | usrdatum = (user_datum_t *)datum; |
1110 | | |
1111 | 635 | len = strlen(key); |
1112 | 635 | items = 0; |
1113 | 635 | buf[items++] = cpu_to_le32(len); |
1114 | 635 | buf[items++] = cpu_to_le32(usrdatum->s.value); |
1115 | 635 | buf[items++] = cpu_to_le32(usrdatum->bounds); |
1116 | 635 | items2 = put_entry(buf, sizeof(uint32_t), items, fp); |
1117 | 635 | if (items != items2) |
1118 | 0 | return POLICYDB_ERROR; |
1119 | | |
1120 | 635 | items = put_entry(key, 1, len, fp); |
1121 | 635 | if (items != len) |
1122 | 0 | return POLICYDB_ERROR; |
1123 | | |
1124 | 635 | if (p->policy_type == POLICY_KERN) { |
1125 | 576 | if (ebitmap_write(&usrdatum->roles.roles, fp)) |
1126 | 0 | return POLICYDB_ERROR; |
1127 | 576 | } else { |
1128 | 59 | if (role_set_write(&usrdatum->roles, fp)) |
1129 | 0 | return POLICYDB_ERROR; |
1130 | 59 | } |
1131 | | |
1132 | 635 | if (p->policy_type == POLICY_KERN) { |
1133 | 576 | if (mls_write_range_helper(&usrdatum->exp_range, fp)) |
1134 | 0 | return POLICYDB_ERROR; |
1135 | 576 | if (mls_write_level(&usrdatum->exp_dfltlevel, fp)) |
1136 | 0 | return POLICYDB_ERROR; |
1137 | 576 | } else { |
1138 | 59 | if (mls_write_semantic_range_helper(&usrdatum->range, fp)) |
1139 | 0 | return -1; |
1140 | 59 | if (mls_write_semantic_level_helper(&usrdatum->dfltlevel, fp)) |
1141 | 0 | return -1; |
1142 | 59 | } |
1143 | | |
1144 | 635 | return POLICYDB_SUCCESS; |
1145 | 635 | } |
1146 | | |
1147 | | static int (*const write_f[SYM_NUM])(hashtab_key_t key, hashtab_datum_t datum, |
1148 | | void *datap) = { |
1149 | | common_write, class_write, role_write, type_write, |
1150 | | user_write, cond_write_bool, sens_write, cat_write, |
1151 | | }; |
1152 | | |
1153 | | static int ocontext_write_xen(const struct policydb_compat_info *info, |
1154 | | policydb_t *p, struct policy_file *fp) |
1155 | 216 | { |
1156 | 216 | unsigned int i, j; |
1157 | 216 | size_t nel, items, len; |
1158 | 216 | uint32_t buf[32]; |
1159 | 216 | ocontext_t *c; |
1160 | 1.50k | for (i = 0; i < info->ocon_num; i++) { |
1161 | 1.29k | nel = 0; |
1162 | 1.45k | for (c = p->ocontexts[i]; c; c = c->next) { |
1163 | 165 | if (i == OCON_XEN_ISID && !c->context[0].user) { |
1164 | 0 | INFO(fp->handle, |
1165 | 0 | "No context assigned to SID %s, omitting from policy", |
1166 | 0 | c->u.name); |
1167 | 0 | continue; |
1168 | 0 | } |
1169 | 165 | nel++; |
1170 | 165 | } |
1171 | 1.29k | buf[0] = cpu_to_le32(nel); |
1172 | 1.29k | items = put_entry(buf, sizeof(uint32_t), 1, fp); |
1173 | 1.29k | if (items != 1) |
1174 | 0 | return POLICYDB_ERROR; |
1175 | 1.45k | for (c = p->ocontexts[i]; c; c = c->next) { |
1176 | 165 | switch (i) { |
1177 | 165 | case OCON_XEN_ISID: |
1178 | 165 | if (!c->context[0].user) |
1179 | 0 | break; |
1180 | 165 | buf[0] = cpu_to_le32(c->sid[0]); |
1181 | 165 | items = put_entry(buf, sizeof(uint32_t), 1, fp); |
1182 | 165 | if (items != 1) |
1183 | 0 | return POLICYDB_ERROR; |
1184 | 165 | if (context_write(p, &c->context[0], fp)) |
1185 | 0 | return POLICYDB_ERROR; |
1186 | 165 | break; |
1187 | 165 | case OCON_XEN_PIRQ: |
1188 | 0 | buf[0] = cpu_to_le32(c->u.pirq); |
1189 | 0 | items = put_entry(buf, sizeof(uint32_t), 1, fp); |
1190 | 0 | if (items != 1) |
1191 | 0 | return POLICYDB_ERROR; |
1192 | 0 | if (context_write(p, &c->context[0], fp)) |
1193 | 0 | return POLICYDB_ERROR; |
1194 | 0 | break; |
1195 | 0 | case OCON_XEN_IOPORT: |
1196 | 0 | buf[0] = c->u.ioport.low_ioport; |
1197 | 0 | buf[1] = c->u.ioport.high_ioport; |
1198 | 0 | for (j = 0; j < 2; j++) |
1199 | 0 | buf[j] = cpu_to_le32(buf[j]); |
1200 | 0 | items = put_entry(buf, sizeof(uint32_t), 2, fp); |
1201 | 0 | if (items != 2) |
1202 | 0 | return POLICYDB_ERROR; |
1203 | 0 | if (context_write(p, &c->context[0], fp)) |
1204 | 0 | return POLICYDB_ERROR; |
1205 | 0 | break; |
1206 | 0 | case OCON_XEN_IOMEM: |
1207 | 0 | if (p->policyvers >= |
1208 | 0 | POLICYDB_VERSION_XEN_DEVICETREE) { |
1209 | 0 | uint64_t b64[2]; |
1210 | 0 | b64[0] = c->u.iomem.low_iomem; |
1211 | 0 | b64[1] = c->u.iomem.high_iomem; |
1212 | 0 | for (j = 0; j < 2; j++) |
1213 | 0 | b64[j] = cpu_to_le64(b64[j]); |
1214 | 0 | items = put_entry(b64, sizeof(uint64_t), |
1215 | 0 | 2, fp); |
1216 | 0 | if (items != 2) |
1217 | 0 | return POLICYDB_ERROR; |
1218 | 0 | } else { |
1219 | 0 | if (c->u.iomem.high_iomem > |
1220 | 0 | 0xFFFFFFFFULL) { |
1221 | 0 | ERR(fp->handle, |
1222 | 0 | "policy version %d" |
1223 | 0 | " cannot represent IOMEM addresses over 16TB", |
1224 | 0 | p->policyvers); |
1225 | 0 | return POLICYDB_ERROR; |
1226 | 0 | } |
1227 | | |
1228 | 0 | buf[0] = c->u.iomem.low_iomem; |
1229 | 0 | buf[1] = c->u.iomem.high_iomem; |
1230 | 0 | for (j = 0; j < 2; j++) |
1231 | 0 | buf[j] = cpu_to_le32(buf[j]); |
1232 | 0 | items = put_entry(buf, sizeof(uint32_t), |
1233 | 0 | 2, fp); |
1234 | 0 | if (items != 2) |
1235 | 0 | return POLICYDB_ERROR; |
1236 | 0 | } |
1237 | 0 | if (context_write(p, &c->context[0], fp)) |
1238 | 0 | return POLICYDB_ERROR; |
1239 | 0 | break; |
1240 | 0 | case OCON_XEN_PCIDEVICE: |
1241 | 0 | buf[0] = cpu_to_le32(c->u.device); |
1242 | 0 | items = put_entry(buf, sizeof(uint32_t), 1, fp); |
1243 | 0 | if (items != 1) |
1244 | 0 | return POLICYDB_ERROR; |
1245 | 0 | if (context_write(p, &c->context[0], fp)) |
1246 | 0 | return POLICYDB_ERROR; |
1247 | 0 | break; |
1248 | 0 | case OCON_XEN_DEVICETREE: |
1249 | 0 | len = strlen(c->u.name); |
1250 | 0 | buf[0] = cpu_to_le32(len); |
1251 | 0 | items = put_entry(buf, sizeof(uint32_t), 1, fp); |
1252 | 0 | if (items != 1) |
1253 | 0 | return POLICYDB_ERROR; |
1254 | 0 | items = put_entry(c->u.name, 1, len, fp); |
1255 | 0 | if (items != len) |
1256 | 0 | return POLICYDB_ERROR; |
1257 | 0 | if (context_write(p, &c->context[0], fp)) |
1258 | 0 | return POLICYDB_ERROR; |
1259 | 0 | break; |
1260 | 165 | } |
1261 | 165 | } |
1262 | 1.29k | } |
1263 | 216 | return POLICYDB_SUCCESS; |
1264 | 216 | } |
1265 | | |
1266 | | static int ocontext_write_selinux(const struct policydb_compat_info *info, |
1267 | | policydb_t *p, struct policy_file *fp) |
1268 | 1.20k | { |
1269 | 1.20k | unsigned int i, j; |
1270 | 1.20k | size_t nel, items, len; |
1271 | 1.20k | uint32_t buf[32]; |
1272 | 1.20k | ocontext_t *c; |
1273 | 11.5k | for (i = 0; i < info->ocon_num; i++) { |
1274 | 10.3k | nel = 0; |
1275 | 10.8k | for (c = p->ocontexts[i]; c; c = c->next) { |
1276 | 508 | if (i == OCON_ISID && !c->context[0].user) { |
1277 | 0 | INFO(fp->handle, |
1278 | 0 | "No context assigned to SID %s, omitting from policy", |
1279 | 0 | c->u.name); |
1280 | 0 | continue; |
1281 | 0 | } |
1282 | 508 | nel++; |
1283 | 508 | } |
1284 | 10.3k | buf[0] = cpu_to_le32(nel); |
1285 | 10.3k | items = put_entry(buf, sizeof(uint32_t), 1, fp); |
1286 | 10.3k | if (items != 1) |
1287 | 0 | return POLICYDB_ERROR; |
1288 | 10.8k | for (c = p->ocontexts[i]; c; c = c->next) { |
1289 | 508 | switch (i) { |
1290 | 460 | case OCON_ISID: |
1291 | 460 | if (!c->context[0].user) |
1292 | 0 | break; |
1293 | 460 | buf[0] = cpu_to_le32(c->sid[0]); |
1294 | 460 | items = put_entry(buf, sizeof(uint32_t), 1, fp); |
1295 | 460 | if (items != 1) |
1296 | 0 | return POLICYDB_ERROR; |
1297 | 460 | if (context_write(p, &c->context[0], fp)) |
1298 | 0 | return POLICYDB_ERROR; |
1299 | 460 | break; |
1300 | 460 | case OCON_FS: |
1301 | 0 | case OCON_NETIF: |
1302 | 0 | len = strlen(c->u.name); |
1303 | 0 | buf[0] = cpu_to_le32(len); |
1304 | 0 | items = put_entry(buf, sizeof(uint32_t), 1, fp); |
1305 | 0 | if (items != 1) |
1306 | 0 | return POLICYDB_ERROR; |
1307 | 0 | items = put_entry(c->u.name, 1, len, fp); |
1308 | 0 | if (items != len) |
1309 | 0 | return POLICYDB_ERROR; |
1310 | 0 | if (context_write(p, &c->context[0], fp)) |
1311 | 0 | return POLICYDB_ERROR; |
1312 | 0 | if (context_write(p, &c->context[1], fp)) |
1313 | 0 | return POLICYDB_ERROR; |
1314 | 0 | break; |
1315 | 10 | case OCON_IBPKEY: |
1316 | | /* The subnet prefix is in network order */ |
1317 | 10 | memcpy(buf, &c->u.ibpkey.subnet_prefix, |
1318 | 10 | sizeof(c->u.ibpkey.subnet_prefix)); |
1319 | | |
1320 | 10 | buf[2] = cpu_to_le32(c->u.ibpkey.low_pkey); |
1321 | 10 | buf[3] = cpu_to_le32(c->u.ibpkey.high_pkey); |
1322 | | |
1323 | 10 | items = put_entry(buf, sizeof(uint32_t), 4, fp); |
1324 | 10 | if (items != 4) |
1325 | 0 | return POLICYDB_ERROR; |
1326 | | |
1327 | 10 | if (context_write(p, &c->context[0], fp)) |
1328 | 0 | return POLICYDB_ERROR; |
1329 | 10 | break; |
1330 | 10 | case OCON_IBENDPORT: |
1331 | 0 | len = strlen(c->u.ibendport.dev_name); |
1332 | 0 | buf[0] = cpu_to_le32(len); |
1333 | 0 | buf[1] = cpu_to_le32(c->u.ibendport.port); |
1334 | 0 | items = put_entry(buf, sizeof(uint32_t), 2, fp); |
1335 | 0 | if (items != 2) |
1336 | 0 | return POLICYDB_ERROR; |
1337 | 0 | items = put_entry(c->u.ibendport.dev_name, 1, |
1338 | 0 | len, fp); |
1339 | 0 | if (items != len) |
1340 | 0 | return POLICYDB_ERROR; |
1341 | | |
1342 | 0 | if (context_write(p, &c->context[0], fp)) |
1343 | 0 | return POLICYDB_ERROR; |
1344 | 0 | break; |
1345 | 0 | case OCON_PORT: |
1346 | 0 | buf[0] = c->u.port.protocol; |
1347 | 0 | buf[1] = c->u.port.low_port; |
1348 | 0 | buf[2] = c->u.port.high_port; |
1349 | 0 | for (j = 0; j < 3; j++) { |
1350 | 0 | buf[j] = cpu_to_le32(buf[j]); |
1351 | 0 | } |
1352 | 0 | items = put_entry(buf, sizeof(uint32_t), 3, fp); |
1353 | 0 | if (items != 3) |
1354 | 0 | return POLICYDB_ERROR; |
1355 | 0 | if (context_write(p, &c->context[0], fp)) |
1356 | 0 | return POLICYDB_ERROR; |
1357 | 0 | break; |
1358 | 0 | case OCON_NODE: |
1359 | 0 | buf[0] = c->u.node.addr; /* network order */ |
1360 | 0 | buf[1] = c->u.node.mask; /* network order */ |
1361 | 0 | items = put_entry(buf, sizeof(uint32_t), 2, fp); |
1362 | 0 | if (items != 2) |
1363 | 0 | return POLICYDB_ERROR; |
1364 | 0 | if (context_write(p, &c->context[0], fp)) |
1365 | 0 | return POLICYDB_ERROR; |
1366 | 0 | break; |
1367 | 32 | case OCON_FSUSE: |
1368 | 32 | buf[0] = cpu_to_le32(c->v.behavior); |
1369 | 32 | len = strlen(c->u.name); |
1370 | 32 | buf[1] = cpu_to_le32(len); |
1371 | 32 | items = put_entry(buf, sizeof(uint32_t), 2, fp); |
1372 | 32 | if (items != 2) |
1373 | 0 | return POLICYDB_ERROR; |
1374 | 32 | items = put_entry(c->u.name, 1, len, fp); |
1375 | 32 | if (items != len) |
1376 | 0 | return POLICYDB_ERROR; |
1377 | 32 | if (context_write(p, &c->context[0], fp)) |
1378 | 0 | return POLICYDB_ERROR; |
1379 | 32 | break; |
1380 | 32 | case OCON_NODE6: |
1381 | 30 | for (j = 0; j < 4; j++) |
1382 | 24 | buf[j] = |
1383 | 24 | c->u.node6.addr |
1384 | 24 | [j]; /* network order */ |
1385 | 30 | for (j = 0; j < 4; j++) |
1386 | 24 | buf[j + 4] = |
1387 | 24 | c->u.node6.mask |
1388 | 24 | [j]; /* network order */ |
1389 | 6 | items = put_entry(buf, sizeof(uint32_t), 8, fp); |
1390 | 6 | if (items != 8) |
1391 | 0 | return POLICYDB_ERROR; |
1392 | 6 | if (context_write(p, &c->context[0], fp)) |
1393 | 0 | return POLICYDB_ERROR; |
1394 | 6 | break; |
1395 | 508 | } |
1396 | 508 | } |
1397 | 10.3k | } |
1398 | 1.20k | return POLICYDB_SUCCESS; |
1399 | 1.20k | } |
1400 | | |
1401 | | static int ocontext_write(const struct policydb_compat_info *info, |
1402 | | policydb_t *p, struct policy_file *fp) |
1403 | 1.42k | { |
1404 | 1.42k | int rc = POLICYDB_ERROR; |
1405 | 1.42k | switch (p->target_platform) { |
1406 | 1.20k | case SEPOL_TARGET_SELINUX: |
1407 | 1.20k | rc = ocontext_write_selinux(info, p, fp); |
1408 | 1.20k | break; |
1409 | 216 | case SEPOL_TARGET_XEN: |
1410 | 216 | rc = ocontext_write_xen(info, p, fp); |
1411 | 216 | break; |
1412 | 1.42k | } |
1413 | 1.42k | return rc; |
1414 | 1.42k | } |
1415 | | |
1416 | | static int genfs_write(policydb_t *p, struct policy_file *fp) |
1417 | 1.42k | { |
1418 | 1.42k | genfs_t *genfs; |
1419 | 1.42k | ocontext_t *c; |
1420 | 1.42k | size_t nel = 0, items, len; |
1421 | 1.42k | uint32_t buf[32]; |
1422 | | |
1423 | 1.42k | for (genfs = p->genfs; genfs; genfs = genfs->next) |
1424 | 3 | nel++; |
1425 | 1.42k | buf[0] = cpu_to_le32(nel); |
1426 | 1.42k | items = put_entry(buf, sizeof(uint32_t), 1, fp); |
1427 | 1.42k | if (items != 1) |
1428 | 0 | return POLICYDB_ERROR; |
1429 | 1.42k | for (genfs = p->genfs; genfs; genfs = genfs->next) { |
1430 | 3 | len = strlen(genfs->fstype); |
1431 | 3 | buf[0] = cpu_to_le32(len); |
1432 | 3 | items = put_entry(buf, sizeof(uint32_t), 1, fp); |
1433 | 3 | if (items != 1) |
1434 | 0 | return POLICYDB_ERROR; |
1435 | 3 | items = put_entry(genfs->fstype, 1, len, fp); |
1436 | 3 | if (items != len) |
1437 | 0 | return POLICYDB_ERROR; |
1438 | 3 | nel = 0; |
1439 | 3 | for (c = genfs->head; c; c = c->next) |
1440 | 0 | nel++; |
1441 | 3 | buf[0] = cpu_to_le32(nel); |
1442 | 3 | items = put_entry(buf, sizeof(uint32_t), 1, fp); |
1443 | 3 | if (items != 1) |
1444 | 0 | return POLICYDB_ERROR; |
1445 | 3 | for (c = genfs->head; c; c = c->next) { |
1446 | 0 | len = strlen(c->u.name); |
1447 | 0 | buf[0] = cpu_to_le32(len); |
1448 | 0 | items = put_entry(buf, sizeof(uint32_t), 1, fp); |
1449 | 0 | if (items != 1) |
1450 | 0 | return POLICYDB_ERROR; |
1451 | 0 | items = put_entry(c->u.name, 1, len, fp); |
1452 | 0 | if (items != len) |
1453 | 0 | return POLICYDB_ERROR; |
1454 | 0 | buf[0] = cpu_to_le32(c->v.sclass); |
1455 | 0 | items = put_entry(buf, sizeof(uint32_t), 1, fp); |
1456 | 0 | if (items != 1) |
1457 | 0 | return POLICYDB_ERROR; |
1458 | 0 | if (context_write(p, &c->context[0], fp)) |
1459 | 0 | return POLICYDB_ERROR; |
1460 | 0 | } |
1461 | 3 | } |
1462 | 1.42k | return POLICYDB_SUCCESS; |
1463 | 1.42k | } |
1464 | | |
1465 | | struct rangetrans_write_args { |
1466 | | size_t nel; |
1467 | | int new_rangetr; |
1468 | | struct policy_file *fp; |
1469 | | struct policydb *p; |
1470 | | }; |
1471 | | |
1472 | | static int rangetrans_count(hashtab_key_t key, |
1473 | | void *data __attribute__((unused)), void *ptr) |
1474 | 0 | { |
1475 | 0 | struct range_trans *rt = (struct range_trans *)key; |
1476 | 0 | struct rangetrans_write_args *args = ptr; |
1477 | 0 | struct policydb *p = args->p; |
1478 | | |
1479 | | /* all range_transitions are written for the new format, only |
1480 | | process related range_transitions are written for the old |
1481 | | format, so count accordingly */ |
1482 | 0 | if (args->new_rangetr || rt->target_class == p->process_class) |
1483 | 0 | args->nel++; |
1484 | 0 | return 0; |
1485 | 0 | } |
1486 | | |
1487 | | static int range_write_helper(hashtab_key_t key, void *data, void *ptr) |
1488 | 0 | { |
1489 | 0 | uint32_t buf[2]; |
1490 | 0 | struct range_trans *rt = (struct range_trans *)key; |
1491 | 0 | struct mls_range *r = data; |
1492 | 0 | struct rangetrans_write_args *args = ptr; |
1493 | 0 | struct policy_file *fp = args->fp; |
1494 | 0 | struct policydb *p = args->p; |
1495 | 0 | int new_rangetr = args->new_rangetr; |
1496 | 0 | size_t items; |
1497 | 0 | static int warning_issued = 0; |
1498 | 0 | int rc; |
1499 | |
|
1500 | 0 | if (!new_rangetr && rt->target_class != p->process_class) { |
1501 | 0 | if (!warning_issued) |
1502 | 0 | WARN(fp->handle, |
1503 | 0 | "Discarding range_transition " |
1504 | 0 | "rules for security classes other than " |
1505 | 0 | "\"process\""); |
1506 | 0 | warning_issued = 1; |
1507 | 0 | return 0; |
1508 | 0 | } |
1509 | | |
1510 | 0 | buf[0] = cpu_to_le32(rt->source_type); |
1511 | 0 | buf[1] = cpu_to_le32(rt->target_type); |
1512 | 0 | items = put_entry(buf, sizeof(uint32_t), 2, fp); |
1513 | 0 | if (items != 2) |
1514 | 0 | return POLICYDB_ERROR; |
1515 | 0 | if (new_rangetr) { |
1516 | 0 | buf[0] = cpu_to_le32(rt->target_class); |
1517 | 0 | items = put_entry(buf, sizeof(uint32_t), 1, fp); |
1518 | 0 | if (items != 1) |
1519 | 0 | return POLICYDB_ERROR; |
1520 | 0 | } |
1521 | 0 | rc = mls_write_range_helper(r, fp); |
1522 | 0 | if (rc) |
1523 | 0 | return rc; |
1524 | | |
1525 | 0 | return 0; |
1526 | 0 | } |
1527 | | |
1528 | | static int range_write(policydb_t *p, struct policy_file *fp) |
1529 | 1.25k | { |
1530 | 1.25k | size_t items; |
1531 | 1.25k | uint32_t buf[2]; |
1532 | 1.25k | int new_rangetr = (p->policy_type == POLICY_KERN); |
1533 | 1.25k | struct rangetrans_write_args args; |
1534 | 1.25k | int rc; |
1535 | | |
1536 | 1.25k | args.nel = 0; |
1537 | 1.25k | args.new_rangetr = new_rangetr; |
1538 | 1.25k | args.fp = fp; |
1539 | 1.25k | args.p = p; |
1540 | 1.25k | rc = hashtab_map(p->range_tr, rangetrans_count, &args); |
1541 | 1.25k | if (rc) |
1542 | 0 | return rc; |
1543 | | |
1544 | 1.25k | buf[0] = cpu_to_le32(args.nel); |
1545 | 1.25k | items = put_entry(buf, sizeof(uint32_t), 1, fp); |
1546 | 1.25k | if (items != 1) |
1547 | 0 | return POLICYDB_ERROR; |
1548 | | |
1549 | 1.25k | return hashtab_map(p->range_tr, range_write_helper, &args); |
1550 | 1.25k | } |
1551 | | |
1552 | | /************** module writing functions below **************/ |
1553 | | |
1554 | | static int avrule_write(policydb_t *p, avrule_t *avrule, struct policy_file *fp, |
1555 | | unsigned conditional) |
1556 | 40 | { |
1557 | 40 | size_t items, items2; |
1558 | 40 | uint32_t buf[32], len; |
1559 | 40 | class_perm_node_t *cur; |
1560 | | |
1561 | 40 | if (p->policyvers < MOD_POLICYDB_VERSION_SELF_TYPETRANS && |
1562 | 40 | (avrule->specified & AVRULE_TYPE) && (avrule->flags & RULE_SELF)) { |
1563 | 0 | ERR(fp->handle, |
1564 | 0 | "Module contains a self rule not supported by the target module policy version"); |
1565 | 0 | return POLICYDB_ERROR; |
1566 | 0 | } |
1567 | | |
1568 | 40 | items = 0; |
1569 | 40 | buf[items++] = cpu_to_le32(avrule->specified); |
1570 | 40 | buf[items++] = cpu_to_le32(avrule->flags); |
1571 | 40 | items2 = put_entry(buf, sizeof(uint32_t), items, fp); |
1572 | 40 | if (items2 != items) |
1573 | 0 | return POLICYDB_ERROR; |
1574 | | |
1575 | 40 | if (type_set_write(&avrule->stypes, fp)) |
1576 | 0 | return POLICYDB_ERROR; |
1577 | | |
1578 | 40 | if (type_set_write(&avrule->ttypes, fp)) |
1579 | 0 | return POLICYDB_ERROR; |
1580 | | |
1581 | 40 | cur = avrule->perms; |
1582 | 40 | len = 0; |
1583 | 40 | while (cur) { |
1584 | 0 | len++; |
1585 | 0 | cur = cur->next; |
1586 | 0 | } |
1587 | 40 | items = 0; |
1588 | 40 | buf[items++] = cpu_to_le32(len); |
1589 | 40 | items2 = put_entry(buf, sizeof(uint32_t), items, fp); |
1590 | 40 | if (items2 != items) |
1591 | 0 | return POLICYDB_ERROR; |
1592 | 40 | cur = avrule->perms; |
1593 | 40 | while (cur) { |
1594 | 0 | items = 0; |
1595 | 0 | buf[items++] = cpu_to_le32(cur->tclass); |
1596 | 0 | buf[items++] = cpu_to_le32(cur->data); |
1597 | 0 | items2 = put_entry(buf, sizeof(uint32_t), items, fp); |
1598 | 0 | if (items2 != items) |
1599 | 0 | return POLICYDB_ERROR; |
1600 | | |
1601 | 0 | cur = cur->next; |
1602 | 0 | } |
1603 | | |
1604 | 40 | if (avrule->specified & AVRULE_XPERMS) { |
1605 | 0 | size_t nel = ARRAY_SIZE(avrule->xperms->perms); |
1606 | 0 | uint32_t buf32[nel]; |
1607 | 0 | uint8_t buf8; |
1608 | 0 | unsigned int i; |
1609 | |
|
1610 | 0 | if (p->policyvers < MOD_POLICYDB_VERSION_XPERMS_IOCTL) { |
1611 | 0 | ERR(fp->handle, |
1612 | 0 | "module policy version %u does not support" |
1613 | 0 | " extended permissions rules and one was specified", |
1614 | 0 | p->policyvers); |
1615 | 0 | return POLICYDB_ERROR; |
1616 | 0 | } |
1617 | | |
1618 | 0 | if (conditional && !policydb_has_cond_xperms_feature(p)) { |
1619 | 0 | ERR(fp->handle, |
1620 | 0 | "module policy version %u does not support" |
1621 | 0 | " extended permissions rules in conditional policies and one was specified", |
1622 | 0 | p->policyvers); |
1623 | 0 | return POLICYDB_ERROR; |
1624 | 0 | } |
1625 | | |
1626 | 0 | if (p->target_platform != SEPOL_TARGET_SELINUX) { |
1627 | 0 | ERR(fp->handle, |
1628 | 0 | "Target platform %s does not support" |
1629 | 0 | " extended permissions rules and one was specified", |
1630 | 0 | policydb_target_strings[p->target_platform]); |
1631 | 0 | return POLICYDB_ERROR; |
1632 | 0 | } |
1633 | | |
1634 | 0 | buf8 = avrule->xperms->specified; |
1635 | 0 | items = put_entry(&buf8, sizeof(uint8_t), 1, fp); |
1636 | 0 | if (items != 1) |
1637 | 0 | return POLICYDB_ERROR; |
1638 | 0 | buf8 = avrule->xperms->driver; |
1639 | 0 | items = put_entry(&buf8, sizeof(uint8_t), 1, fp); |
1640 | 0 | if (items != 1) |
1641 | 0 | return POLICYDB_ERROR; |
1642 | 0 | for (i = 0; i < nel; i++) |
1643 | 0 | buf32[i] = cpu_to_le32(avrule->xperms->perms[i]); |
1644 | 0 | items = put_entry(buf32, sizeof(uint32_t), nel, fp); |
1645 | 0 | if (items != nel) |
1646 | 0 | return POLICYDB_ERROR; |
1647 | 0 | } |
1648 | | |
1649 | 40 | return POLICYDB_SUCCESS; |
1650 | 40 | } |
1651 | | |
1652 | | static int avrule_write_list(policydb_t *p, avrule_t *avrules, |
1653 | | struct policy_file *fp, unsigned conditional) |
1654 | 240 | { |
1655 | 240 | uint32_t buf[32], len; |
1656 | 240 | avrule_t *avrule; |
1657 | | |
1658 | 240 | avrule = avrules; |
1659 | 240 | len = 0; |
1660 | 280 | while (avrule) { |
1661 | 40 | len++; |
1662 | 40 | avrule = avrule->next; |
1663 | 40 | } |
1664 | | |
1665 | 240 | buf[0] = cpu_to_le32(len); |
1666 | 240 | if (put_entry(buf, sizeof(uint32_t), 1, fp) != 1) |
1667 | 0 | return POLICYDB_ERROR; |
1668 | | |
1669 | 240 | avrule = avrules; |
1670 | 280 | while (avrule) { |
1671 | 40 | if (avrule_write(p, avrule, fp, conditional)) |
1672 | 0 | return POLICYDB_ERROR; |
1673 | 40 | avrule = avrule->next; |
1674 | 40 | } |
1675 | | |
1676 | 240 | return POLICYDB_SUCCESS; |
1677 | 240 | } |
1678 | | |
1679 | | static int only_process(ebitmap_t *in, struct policydb *p) |
1680 | 0 | { |
1681 | 0 | unsigned int i, value; |
1682 | 0 | ebitmap_node_t *node; |
1683 | |
|
1684 | 0 | if (!p->process_class) |
1685 | 0 | return 0; |
1686 | | |
1687 | 0 | value = p->process_class - 1; |
1688 | |
|
1689 | 0 | ebitmap_for_each_positive_bit(in, node, i) { |
1690 | 0 | if (i != value) |
1691 | 0 | return 0; |
1692 | 0 | } |
1693 | 0 | return 1; |
1694 | 0 | } |
1695 | | |
1696 | | static int role_trans_rule_write(policydb_t *p, role_trans_rule_t *t, |
1697 | | struct policy_file *fp) |
1698 | 240 | { |
1699 | 240 | int nel = 0; |
1700 | 240 | size_t items; |
1701 | 240 | uint32_t buf[1]; |
1702 | 240 | role_trans_rule_t *tr; |
1703 | 240 | int warned = 0; |
1704 | 240 | int new_role = p->policyvers >= MOD_POLICYDB_VERSION_ROLETRANS; |
1705 | | |
1706 | 244 | for (tr = t; tr; tr = tr->next) |
1707 | 4 | if (new_role || only_process(&tr->classes, p)) |
1708 | 4 | nel++; |
1709 | | |
1710 | 240 | buf[0] = cpu_to_le32(nel); |
1711 | 240 | items = put_entry(buf, sizeof(uint32_t), 1, fp); |
1712 | 240 | if (items != 1) |
1713 | 0 | return POLICYDB_ERROR; |
1714 | 244 | for (tr = t; tr; tr = tr->next) { |
1715 | 4 | if (!new_role && !only_process(&tr->classes, p)) { |
1716 | 0 | if (!warned) |
1717 | 0 | WARN(fp->handle, |
1718 | 0 | "Discarding role_transition " |
1719 | 0 | "rules for security classes other than " |
1720 | 0 | "\"process\""); |
1721 | 0 | warned = 1; |
1722 | 0 | continue; |
1723 | 0 | } |
1724 | 4 | if (role_set_write(&tr->roles, fp)) |
1725 | 0 | return POLICYDB_ERROR; |
1726 | 4 | if (type_set_write(&tr->types, fp)) |
1727 | 0 | return POLICYDB_ERROR; |
1728 | 4 | if (new_role) |
1729 | 4 | if (ebitmap_write(&tr->classes, fp)) |
1730 | 0 | return POLICYDB_ERROR; |
1731 | 4 | buf[0] = cpu_to_le32(tr->new_role); |
1732 | 4 | items = put_entry(buf, sizeof(uint32_t), 1, fp); |
1733 | 4 | if (items != 1) |
1734 | 0 | return POLICYDB_ERROR; |
1735 | 4 | } |
1736 | 240 | return POLICYDB_SUCCESS; |
1737 | 240 | } |
1738 | | |
1739 | | static int role_allow_rule_write(role_allow_rule_t *r, struct policy_file *fp) |
1740 | 240 | { |
1741 | 240 | int nel = 0; |
1742 | 240 | size_t items; |
1743 | 240 | uint32_t buf[1]; |
1744 | 240 | role_allow_rule_t *ra; |
1745 | | |
1746 | 302 | for (ra = r; ra; ra = ra->next) |
1747 | 62 | nel++; |
1748 | 240 | buf[0] = cpu_to_le32(nel); |
1749 | 240 | items = put_entry(buf, sizeof(uint32_t), 1, fp); |
1750 | 240 | if (items != 1) |
1751 | 0 | return POLICYDB_ERROR; |
1752 | 302 | for (ra = r; ra; ra = ra->next) { |
1753 | 62 | if (role_set_write(&ra->roles, fp)) |
1754 | 0 | return POLICYDB_ERROR; |
1755 | 62 | if (role_set_write(&ra->new_roles, fp)) |
1756 | 0 | return POLICYDB_ERROR; |
1757 | 62 | } |
1758 | 240 | return POLICYDB_SUCCESS; |
1759 | 240 | } |
1760 | | |
1761 | | static int filename_trans_rule_write(policydb_t *p, filename_trans_rule_t *t, |
1762 | | struct policy_file *fp) |
1763 | 189 | { |
1764 | 189 | int nel = 0; |
1765 | 189 | size_t items, entries; |
1766 | 189 | uint32_t buf[3], len; |
1767 | 189 | filename_trans_rule_t *ftr; |
1768 | | |
1769 | 189 | for (ftr = t; ftr; ftr = ftr->next) |
1770 | 0 | nel++; |
1771 | | |
1772 | 189 | buf[0] = cpu_to_le32(nel); |
1773 | 189 | items = put_entry(buf, sizeof(uint32_t), 1, fp); |
1774 | 189 | if (items != 1) |
1775 | 0 | return POLICYDB_ERROR; |
1776 | | |
1777 | 189 | for (ftr = t; ftr; ftr = ftr->next) { |
1778 | 0 | len = strlen(ftr->name); |
1779 | 0 | buf[0] = cpu_to_le32(len); |
1780 | 0 | items = put_entry(buf, sizeof(uint32_t), 1, fp); |
1781 | 0 | if (items != 1) |
1782 | 0 | return POLICYDB_ERROR; |
1783 | | |
1784 | 0 | items = put_entry(ftr->name, sizeof(char), len, fp); |
1785 | 0 | if (items != len) |
1786 | 0 | return POLICYDB_ERROR; |
1787 | | |
1788 | 0 | if (type_set_write(&ftr->stypes, fp)) |
1789 | 0 | return POLICYDB_ERROR; |
1790 | 0 | if (type_set_write(&ftr->ttypes, fp)) |
1791 | 0 | return POLICYDB_ERROR; |
1792 | | |
1793 | 0 | buf[0] = cpu_to_le32(ftr->tclass); |
1794 | 0 | buf[1] = cpu_to_le32(ftr->otype); |
1795 | 0 | buf[2] = cpu_to_le32(ftr->flags); |
1796 | |
|
1797 | 0 | if (p->policyvers >= MOD_POLICYDB_VERSION_SELF_TYPETRANS) { |
1798 | 0 | entries = 3; |
1799 | 0 | } else if (!(ftr->flags & RULE_SELF)) { |
1800 | 0 | entries = 2; |
1801 | 0 | } else { |
1802 | 0 | ERR(fp->handle, |
1803 | 0 | "Module contains a self rule not supported by the target module policy version"); |
1804 | 0 | return POLICYDB_ERROR; |
1805 | 0 | } |
1806 | | |
1807 | 0 | items = put_entry(buf, sizeof(uint32_t), entries, fp); |
1808 | 0 | if (items != entries) |
1809 | 0 | return POLICYDB_ERROR; |
1810 | 0 | } |
1811 | 189 | return POLICYDB_SUCCESS; |
1812 | 189 | } |
1813 | | |
1814 | | static int range_trans_rule_write(range_trans_rule_t *t, struct policy_file *fp) |
1815 | 240 | { |
1816 | 240 | int nel = 0; |
1817 | 240 | size_t items; |
1818 | 240 | uint32_t buf[1]; |
1819 | 240 | range_trans_rule_t *rt; |
1820 | | |
1821 | 240 | for (rt = t; rt; rt = rt->next) |
1822 | 0 | nel++; |
1823 | 240 | buf[0] = cpu_to_le32(nel); |
1824 | 240 | items = put_entry(buf, sizeof(uint32_t), 1, fp); |
1825 | 240 | if (items != 1) |
1826 | 0 | return POLICYDB_ERROR; |
1827 | 240 | for (rt = t; rt; rt = rt->next) { |
1828 | 0 | if (type_set_write(&rt->stypes, fp)) |
1829 | 0 | return POLICYDB_ERROR; |
1830 | 0 | if (type_set_write(&rt->ttypes, fp)) |
1831 | 0 | return POLICYDB_ERROR; |
1832 | 0 | if (ebitmap_write(&rt->tclasses, fp)) |
1833 | 0 | return POLICYDB_ERROR; |
1834 | 0 | if (mls_write_semantic_range_helper(&rt->trange, fp)) |
1835 | 0 | return POLICYDB_ERROR; |
1836 | 0 | } |
1837 | 240 | return POLICYDB_SUCCESS; |
1838 | 240 | } |
1839 | | |
1840 | | static int scope_index_write(scope_index_t *scope_index, |
1841 | | unsigned int num_scope_syms, |
1842 | | struct policy_file *fp) |
1843 | 480 | { |
1844 | 480 | unsigned int i; |
1845 | 480 | uint32_t buf[1]; |
1846 | 4.32k | for (i = 0; i < num_scope_syms; i++) { |
1847 | 3.84k | if (ebitmap_write(scope_index->scope + i, fp) == -1) { |
1848 | 0 | return POLICYDB_ERROR; |
1849 | 0 | } |
1850 | 3.84k | } |
1851 | 480 | buf[0] = cpu_to_le32(scope_index->class_perms_len); |
1852 | 480 | if (put_entry(buf, sizeof(uint32_t), 1, fp) != 1) { |
1853 | 0 | return POLICYDB_ERROR; |
1854 | 0 | } |
1855 | 481 | for (i = 0; i < scope_index->class_perms_len; i++) { |
1856 | 1 | if (ebitmap_write(scope_index->class_perms_map + i, fp) == -1) { |
1857 | 0 | return POLICYDB_ERROR; |
1858 | 0 | } |
1859 | 1 | } |
1860 | 480 | return POLICYDB_SUCCESS; |
1861 | 480 | } |
1862 | | |
1863 | | static int avrule_decl_write(avrule_decl_t *decl, int num_scope_syms, |
1864 | | policydb_t *p, struct policy_file *fp) |
1865 | 240 | { |
1866 | 240 | struct policy_data pd; |
1867 | 240 | uint32_t buf[2]; |
1868 | 240 | int i; |
1869 | 240 | buf[0] = cpu_to_le32(decl->decl_id); |
1870 | 240 | buf[1] = cpu_to_le32(decl->enabled); |
1871 | 240 | if (put_entry(buf, sizeof(uint32_t), 2, fp) != 2) { |
1872 | 0 | return POLICYDB_ERROR; |
1873 | 0 | } |
1874 | 240 | if (cond_write_list(p, decl->cond_list, fp) == -1 || |
1875 | 240 | avrule_write_list(p, decl->avrules, fp, 0) == -1 || |
1876 | 240 | role_trans_rule_write(p, decl->role_tr_rules, fp) == -1 || |
1877 | 240 | role_allow_rule_write(decl->role_allow_rules, fp) == -1) { |
1878 | 0 | return POLICYDB_ERROR; |
1879 | 0 | } |
1880 | | |
1881 | 240 | if (p->policyvers >= MOD_POLICYDB_VERSION_FILENAME_TRANS && |
1882 | 189 | filename_trans_rule_write(p, decl->filename_trans_rules, fp)) |
1883 | 0 | return POLICYDB_ERROR; |
1884 | | |
1885 | 240 | if (range_trans_rule_write(decl->range_tr_rules, fp) == -1) { |
1886 | 0 | return POLICYDB_ERROR; |
1887 | 0 | } |
1888 | 240 | if (scope_index_write(&decl->required, num_scope_syms, fp) == -1 || |
1889 | 240 | scope_index_write(&decl->declared, num_scope_syms, fp) == -1) { |
1890 | 0 | return POLICYDB_ERROR; |
1891 | 0 | } |
1892 | 240 | pd.fp = fp; |
1893 | 240 | pd.p = p; |
1894 | 2.16k | for (i = 0; i < num_scope_syms; i++) { |
1895 | 1.92k | buf[0] = cpu_to_le32(decl->symtab[i].nprim); |
1896 | 1.92k | buf[1] = cpu_to_le32(decl->symtab[i].table->nel); |
1897 | 1.92k | if (put_entry(buf, sizeof(uint32_t), 2, fp) != 2) { |
1898 | 0 | return POLICYDB_ERROR; |
1899 | 0 | } |
1900 | 1.92k | if (hashtab_map(decl->symtab[i].table, write_f[i], &pd)) { |
1901 | 0 | return POLICYDB_ERROR; |
1902 | 0 | } |
1903 | 1.92k | } |
1904 | 240 | return POLICYDB_SUCCESS; |
1905 | 240 | } |
1906 | | |
1907 | | static int avrule_block_write(avrule_block_t *block, int num_scope_syms, |
1908 | | policydb_t *p, struct policy_file *fp) |
1909 | 167 | { |
1910 | | /* first write a count of the total number of blocks */ |
1911 | 167 | uint32_t buf[1], num_blocks = 0; |
1912 | 167 | avrule_block_t *cur; |
1913 | 1.86k | for (cur = block; cur != NULL; cur = cur->next) { |
1914 | 1.69k | num_blocks++; |
1915 | 1.69k | } |
1916 | 167 | buf[0] = cpu_to_le32(num_blocks); |
1917 | 167 | if (put_entry(buf, sizeof(uint32_t), 1, fp) != 1) { |
1918 | 0 | return POLICYDB_ERROR; |
1919 | 0 | } |
1920 | | |
1921 | | /* now write each block */ |
1922 | 1.86k | for (cur = block; cur != NULL; cur = cur->next) { |
1923 | 1.69k | uint32_t num_decls = 0; |
1924 | 1.69k | avrule_decl_t *decl; |
1925 | | /* write a count of number of branches */ |
1926 | 1.93k | for (decl = cur->branch_list; decl != NULL; decl = decl->next) { |
1927 | 240 | num_decls++; |
1928 | 240 | } |
1929 | 1.69k | buf[0] = cpu_to_le32(num_decls); |
1930 | 1.69k | if (put_entry(buf, sizeof(uint32_t), 1, fp) != 1) { |
1931 | 0 | return POLICYDB_ERROR; |
1932 | 0 | } |
1933 | 1.93k | for (decl = cur->branch_list; decl != NULL; decl = decl->next) { |
1934 | 240 | if (avrule_decl_write(decl, num_scope_syms, p, fp) == |
1935 | 240 | -1) { |
1936 | 0 | return POLICYDB_ERROR; |
1937 | 0 | } |
1938 | 240 | } |
1939 | 1.69k | } |
1940 | 167 | return POLICYDB_SUCCESS; |
1941 | 167 | } |
1942 | | |
1943 | | static int scope_write(hashtab_key_t key, hashtab_datum_t datum, void *ptr) |
1944 | 175 | { |
1945 | 175 | scope_datum_t *scope = (scope_datum_t *)datum; |
1946 | 175 | struct policy_data *pd = ptr; |
1947 | 175 | struct policy_file *fp = pd->fp; |
1948 | 175 | uint32_t static_buf[32], *dyn_buf = NULL, *buf; |
1949 | 175 | size_t key_len = strlen(key); |
1950 | 175 | size_t items = 2 + scope->decl_ids_len; |
1951 | 175 | uint32_t i; |
1952 | 175 | int rc; |
1953 | | |
1954 | 175 | buf = static_buf; |
1955 | 175 | if (items >= (sizeof(static_buf) / 4)) { |
1956 | | /* too many things required, so dynamically create a |
1957 | | * buffer. this would have been easier with C99's |
1958 | | * dynamic arrays... */ |
1959 | 0 | rc = POLICYDB_ERROR; |
1960 | 0 | dyn_buf = calloc(items, sizeof(*dyn_buf)); |
1961 | 0 | if (!dyn_buf) |
1962 | 0 | goto err; |
1963 | 0 | buf = dyn_buf; |
1964 | 0 | } |
1965 | 175 | buf[0] = cpu_to_le32(key_len); |
1966 | | |
1967 | 175 | rc = POLICYDB_ERROR; |
1968 | 175 | if (put_entry(buf, sizeof(*buf), 1, fp) != 1 || |
1969 | 175 | put_entry(key, 1, key_len, fp) != key_len) |
1970 | 0 | goto err; |
1971 | 175 | buf[0] = cpu_to_le32(scope->scope); |
1972 | 175 | buf[1] = cpu_to_le32(scope->decl_ids_len); |
1973 | | |
1974 | 392 | for (i = 0; i < scope->decl_ids_len; i++) |
1975 | 217 | buf[2 + i] = cpu_to_le32(scope->decl_ids[i]); |
1976 | | |
1977 | 175 | rc = POLICYDB_ERROR; |
1978 | 175 | if (put_entry(buf, sizeof(*buf), items, fp) != items) |
1979 | 0 | goto err; |
1980 | 175 | rc = POLICYDB_SUCCESS; |
1981 | 175 | err: |
1982 | 175 | free(dyn_buf); |
1983 | 175 | return rc; |
1984 | 175 | } |
1985 | | |
1986 | | static int role_attr_uncount(hashtab_key_t key __attribute__((unused)), |
1987 | | hashtab_datum_t datum, void *args) |
1988 | 7.82k | { |
1989 | 7.82k | role_datum_t *role = datum; |
1990 | 7.82k | uint32_t *p_nel = args; |
1991 | | |
1992 | 7.82k | if (role->flavor == ROLE_ATTRIB) { |
1993 | | /* uncount attribute from total number of roles */ |
1994 | 164 | (*p_nel)--; |
1995 | 164 | } |
1996 | 7.82k | return 0; |
1997 | 7.82k | } |
1998 | | |
1999 | | /* |
2000 | | * Write the configuration data in a policy database |
2001 | | * structure to a policy database binary representation |
2002 | | * file. |
2003 | | */ |
2004 | | int policydb_write(policydb_t *p, struct policy_file *fp) |
2005 | 1.42k | { |
2006 | 1.42k | unsigned int i, num_syms; |
2007 | 1.42k | uint32_t buf[32], config; |
2008 | 1.42k | size_t items, items2, len; |
2009 | 1.42k | const struct policydb_compat_info *info; |
2010 | 1.42k | struct policy_data pd; |
2011 | 1.42k | const char *policydb_str; |
2012 | | |
2013 | 1.42k | if (p->unsupported_format) |
2014 | 0 | return POLICYDB_UNSUPPORTED; |
2015 | | |
2016 | 1.42k | pd.fp = fp; |
2017 | 1.42k | pd.p = p; |
2018 | | |
2019 | 1.42k | config = 0; |
2020 | 1.42k | if (p->mls) |
2021 | 1.10k | config |= POLICYDB_CONFIG_MLS; |
2022 | | |
2023 | 1.42k | config |= (POLICYDB_CONFIG_UNKNOWN_MASK & p->handle_unknown); |
2024 | | |
2025 | | /* Write the magic number and string identifiers. */ |
2026 | 1.42k | items = 0; |
2027 | 1.42k | if (p->policy_type == POLICY_KERN) { |
2028 | 1.25k | buf[items++] = cpu_to_le32(POLICYDB_MAGIC); |
2029 | 1.25k | len = strlen(policydb_target_strings[p->target_platform]); |
2030 | 1.25k | policydb_str = policydb_target_strings[p->target_platform]; |
2031 | 1.25k | } else { |
2032 | 167 | buf[items++] = cpu_to_le32(POLICYDB_MOD_MAGIC); |
2033 | 167 | len = strlen(POLICYDB_MOD_STRING); |
2034 | 167 | policydb_str = POLICYDB_MOD_STRING; |
2035 | 167 | } |
2036 | 1.42k | buf[items++] = cpu_to_le32(len); |
2037 | 1.42k | items2 = put_entry(buf, sizeof(uint32_t), items, fp); |
2038 | 1.42k | if (items != items2) |
2039 | 0 | return POLICYDB_ERROR; |
2040 | 1.42k | items = put_entry(policydb_str, 1, len, fp); |
2041 | 1.42k | if (items != len) |
2042 | 0 | return POLICYDB_ERROR; |
2043 | | |
2044 | | /* Write the version, config, and table sizes. */ |
2045 | 1.42k | items = 0; |
2046 | 1.42k | info = policydb_lookup_compat(p->policyvers, p->policy_type, |
2047 | 1.42k | p->target_platform); |
2048 | 1.42k | if (!info) { |
2049 | 0 | ERR(fp->handle, |
2050 | 0 | "compatibility lookup failed for %s%s policy version %d", |
2051 | 0 | p->target_platform == SEPOL_TARGET_SELINUX ? "selinux" : |
2052 | 0 | "xen", |
2053 | 0 | p->policy_type == POLICY_KERN ? "" : " module", |
2054 | 0 | p->policyvers); |
2055 | 0 | return POLICYDB_ERROR; |
2056 | 0 | } |
2057 | | |
2058 | 1.42k | if (p->policy_type != POLICY_KERN) { |
2059 | 167 | buf[items++] = cpu_to_le32(p->policy_type); |
2060 | 167 | } |
2061 | 1.42k | buf[items++] = cpu_to_le32(p->policyvers); |
2062 | 1.42k | buf[items++] = cpu_to_le32(config); |
2063 | 1.42k | buf[items++] = cpu_to_le32(info->sym_num); |
2064 | 1.42k | buf[items++] = cpu_to_le32(info->ocon_num); |
2065 | | |
2066 | 1.42k | items2 = put_entry(buf, sizeof(uint32_t), items, fp); |
2067 | 1.42k | if (items != items2) |
2068 | 0 | return POLICYDB_ERROR; |
2069 | | |
2070 | 1.42k | if (p->policy_type == POLICY_MOD) { |
2071 | | /* Write module name and version */ |
2072 | 8 | len = strlen(p->name); |
2073 | 8 | buf[0] = cpu_to_le32(len); |
2074 | 8 | items = put_entry(buf, sizeof(uint32_t), 1, fp); |
2075 | 8 | if (items != 1) |
2076 | 0 | return POLICYDB_ERROR; |
2077 | 8 | items = put_entry(p->name, 1, len, fp); |
2078 | 8 | if (items != len) |
2079 | 0 | return POLICYDB_ERROR; |
2080 | 8 | len = strlen(p->version); |
2081 | 8 | buf[0] = cpu_to_le32(len); |
2082 | 8 | items = put_entry(buf, sizeof(uint32_t), 1, fp); |
2083 | 8 | if (items != 1) |
2084 | 0 | return POLICYDB_ERROR; |
2085 | 8 | items = put_entry(p->version, 1, len, fp); |
2086 | 8 | if (items != len) |
2087 | 0 | return POLICYDB_ERROR; |
2088 | 8 | } |
2089 | | |
2090 | 1.42k | if (ebitmap_write(&p->policycaps, fp) == -1) |
2091 | 0 | return POLICYDB_ERROR; |
2092 | | |
2093 | 1.42k | if (p->policy_type == POLICY_KERN) { |
2094 | 1.25k | if (ebitmap_write(&p->permissive_map, fp) == -1) |
2095 | 0 | return POLICYDB_ERROR; |
2096 | | |
2097 | 1.25k | if (p->policyvers < POLICYDB_VERSION_NEVERAUDIT) { |
2098 | 1.06k | ebitmap_node_t *tnode; |
2099 | | |
2100 | 1.06k | ebitmap_for_each_positive_bit(&p->neveraudit_map, tnode, |
2101 | 0 | i) { |
2102 | 0 | WARN(fp->handle, |
2103 | 0 | "Warning! Policy version %d cannot " |
2104 | 0 | "support neveraudit types, but some were defined", |
2105 | 0 | p->policyvers); |
2106 | 0 | break; |
2107 | 0 | } |
2108 | 1.06k | } else if (ebitmap_write(&p->neveraudit_map, fp) == -1) |
2109 | 0 | return POLICYDB_ERROR; |
2110 | 1.25k | } |
2111 | | |
2112 | 1.42k | num_syms = info->sym_num; |
2113 | 12.8k | for (i = 0; i < num_syms; i++) { |
2114 | 11.3k | buf[0] = cpu_to_le32(p->symtab[i].nprim); |
2115 | 11.3k | buf[1] = p->symtab[i].table->nel; |
2116 | | |
2117 | | /* |
2118 | | * Another special case when writing role/attribute symbol |
2119 | | * table, role attributes are redundant for policy.X, or |
2120 | | * when the pp's version is not big enough. So deduct |
2121 | | * their numbers from p_roles.table->nel. |
2122 | | */ |
2123 | 11.3k | if ((i == SYM_ROLES) && |
2124 | 1.42k | ((p->policy_type == POLICY_KERN) || |
2125 | 167 | (p->policy_type != POLICY_KERN && |
2126 | 167 | p->policyvers < MOD_POLICYDB_VERSION_ROLEATTRIB))) |
2127 | 1.30k | (void)hashtab_map(p->symtab[i].table, role_attr_uncount, |
2128 | 1.30k | &buf[1]); |
2129 | | |
2130 | 11.3k | buf[1] = cpu_to_le32(buf[1]); |
2131 | 11.3k | items = put_entry(buf, sizeof(uint32_t), 2, fp); |
2132 | 11.3k | if (items != 2) |
2133 | 0 | return POLICYDB_ERROR; |
2134 | 11.3k | if (hashtab_map(p->symtab[i].table, write_f[i], &pd)) |
2135 | 0 | return POLICYDB_ERROR; |
2136 | 11.3k | } |
2137 | | |
2138 | 1.42k | if (p->policy_type == POLICY_KERN) { |
2139 | 1.25k | if (avtab_write(p, &p->te_avtab, fp)) |
2140 | 0 | return POLICYDB_ERROR; |
2141 | 1.25k | if (cond_write_list(p, p->cond_list, fp)) |
2142 | 0 | return POLICYDB_ERROR; |
2143 | 1.25k | if (role_trans_write(p, fp)) |
2144 | 0 | return POLICYDB_ERROR; |
2145 | 1.25k | if (role_allow_write(p->role_allow, fp)) |
2146 | 0 | return POLICYDB_ERROR; |
2147 | 1.25k | if (p->policyvers >= POLICYDB_VERSION_FILENAME_TRANS) { |
2148 | 1.24k | if (filename_trans_write(p, fp)) |
2149 | 0 | return POLICYDB_ERROR; |
2150 | 1.24k | } else { |
2151 | 7 | if (p->filename_trans) |
2152 | 7 | WARN(fp->handle, |
2153 | 7 | "Discarding filename type transition rules"); |
2154 | 7 | } |
2155 | 1.25k | } else { |
2156 | 167 | if (avrule_block_write(p->global, num_syms, p, fp) == -1) { |
2157 | 0 | return POLICYDB_ERROR; |
2158 | 0 | } |
2159 | | |
2160 | 1.50k | for (i = 0; i < num_syms; i++) { |
2161 | 1.33k | buf[0] = cpu_to_le32(p->scope[i].table->nel); |
2162 | 1.33k | if (put_entry(buf, sizeof(uint32_t), 1, fp) != 1) { |
2163 | 0 | return POLICYDB_ERROR; |
2164 | 0 | } |
2165 | 1.33k | if (hashtab_map(p->scope[i].table, scope_write, &pd)) |
2166 | 0 | return POLICYDB_ERROR; |
2167 | 1.33k | } |
2168 | 167 | } |
2169 | | |
2170 | 1.42k | if (ocontext_write(info, p, fp) == -1 || genfs_write(p, fp) == -1) { |
2171 | 0 | return POLICYDB_ERROR; |
2172 | 0 | } |
2173 | | |
2174 | 1.42k | if (p->policy_type == POLICY_KERN) { |
2175 | 1.25k | if (range_write(p, fp)) { |
2176 | 0 | return POLICYDB_ERROR; |
2177 | 0 | } |
2178 | 1.25k | } |
2179 | | |
2180 | 1.42k | if (p->policy_type == POLICY_KERN) { |
2181 | 2.93k | for (i = 0; i < p->p_types.nprim; i++) { |
2182 | 1.68k | if (ebitmap_write(&p->type_attr_map[i], fp) == -1) |
2183 | 0 | return POLICYDB_ERROR; |
2184 | 1.68k | } |
2185 | 1.25k | } |
2186 | | |
2187 | 1.42k | return POLICYDB_SUCCESS; |
2188 | 1.42k | } |