~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/security/selinux/ss/conditional.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /* SPDX-License-Identifier: GPL-2.0-only */
  2 /* Authors: Karl MacMillan <kmacmillan@tresys.com>
  3  *          Frank Mayer <mayerf@tresys.com>
  4  *          Copyright (C) 2003 - 2004 Tresys Technology, LLC
  5  */
  6 
  7 #include <linux/kernel.h>
  8 #include <linux/errno.h>
  9 #include <linux/string.h>
 10 #include <linux/spinlock.h>
 11 #include <linux/slab.h>
 12 
 13 #include "security.h"
 14 #include "conditional.h"
 15 #include "services.h"
 16 
 17 /*
 18  * cond_evaluate_expr evaluates a conditional expr
 19  * in reverse polish notation. It returns true (1), false (0),
 20  * or undefined (-1). Undefined occurs when the expression
 21  * exceeds the stack depth of COND_EXPR_MAXDEPTH.
 22  */
 23 static int cond_evaluate_expr(struct policydb *p, struct cond_expr *expr)
 24 {
 25         u32 i;
 26         int s[COND_EXPR_MAXDEPTH];
 27         int sp = -1;
 28 
 29         if (expr->len == 0)
 30                 return -1;
 31 
 32         for (i = 0; i < expr->len; i++) {
 33                 struct cond_expr_node *node = &expr->nodes[i];
 34 
 35                 switch (node->expr_type) {
 36                 case COND_BOOL:
 37                         if (sp == (COND_EXPR_MAXDEPTH - 1))
 38                                 return -1;
 39                         sp++;
 40                         s[sp] = p->bool_val_to_struct[node->boolean - 1]->state;
 41                         break;
 42                 case COND_NOT:
 43                         if (sp < 0)
 44                                 return -1;
 45                         s[sp] = !s[sp];
 46                         break;
 47                 case COND_OR:
 48                         if (sp < 1)
 49                                 return -1;
 50                         sp--;
 51                         s[sp] |= s[sp + 1];
 52                         break;
 53                 case COND_AND:
 54                         if (sp < 1)
 55                                 return -1;
 56                         sp--;
 57                         s[sp] &= s[sp + 1];
 58                         break;
 59                 case COND_XOR:
 60                         if (sp < 1)
 61                                 return -1;
 62                         sp--;
 63                         s[sp] ^= s[sp + 1];
 64                         break;
 65                 case COND_EQ:
 66                         if (sp < 1)
 67                                 return -1;
 68                         sp--;
 69                         s[sp] = (s[sp] == s[sp + 1]);
 70                         break;
 71                 case COND_NEQ:
 72                         if (sp < 1)
 73                                 return -1;
 74                         sp--;
 75                         s[sp] = (s[sp] != s[sp + 1]);
 76                         break;
 77                 default:
 78                         return -1;
 79                 }
 80         }
 81         return s[0];
 82 }
 83 
 84 /*
 85  * evaluate_cond_node evaluates the conditional stored in
 86  * a struct cond_node and if the result is different than the
 87  * current state of the node it sets the rules in the true/false
 88  * list appropriately. If the result of the expression is undefined
 89  * all of the rules are disabled for safety.
 90  */
 91 static void evaluate_cond_node(struct policydb *p, struct cond_node *node)
 92 {
 93         struct avtab_node *avnode;
 94         int new_state;
 95         u32 i;
 96 
 97         new_state = cond_evaluate_expr(p, &node->expr);
 98         if (new_state != node->cur_state) {
 99                 node->cur_state = new_state;
100                 if (new_state == -1)
101                         pr_err("SELinux: expression result was undefined - disabling all rules.\n");
102                 /* turn the rules on or off */
103                 for (i = 0; i < node->true_list.len; i++) {
104                         avnode = node->true_list.nodes[i];
105                         if (new_state <= 0)
106                                 avnode->key.specified &= ~AVTAB_ENABLED;
107                         else
108                                 avnode->key.specified |= AVTAB_ENABLED;
109                 }
110 
111                 for (i = 0; i < node->false_list.len; i++) {
112                         avnode = node->false_list.nodes[i];
113                         /* -1 or 1 */
114                         if (new_state)
115                                 avnode->key.specified &= ~AVTAB_ENABLED;
116                         else
117                                 avnode->key.specified |= AVTAB_ENABLED;
118                 }
119         }
120 }
121 
122 void evaluate_cond_nodes(struct policydb *p)
123 {
124         u32 i;
125 
126         for (i = 0; i < p->cond_list_len; i++)
127                 evaluate_cond_node(p, &p->cond_list[i]);
128 }
129 
130 void cond_policydb_init(struct policydb *p)
131 {
132         p->bool_val_to_struct = NULL;
133         p->cond_list = NULL;
134         p->cond_list_len = 0;
135 
136         avtab_init(&p->te_cond_avtab);
137 }
138 
139 static void cond_node_destroy(struct cond_node *node)
140 {
141         kfree(node->expr.nodes);
142         /* the avtab_ptr_t nodes are destroyed by the avtab */
143         kfree(node->true_list.nodes);
144         kfree(node->false_list.nodes);
145 }
146 
147 static void cond_list_destroy(struct policydb *p)
148 {
149         u32 i;
150 
151         for (i = 0; i < p->cond_list_len; i++)
152                 cond_node_destroy(&p->cond_list[i]);
153         kfree(p->cond_list);
154         p->cond_list = NULL;
155         p->cond_list_len = 0;
156 }
157 
158 void cond_policydb_destroy(struct policydb *p)
159 {
160         kfree(p->bool_val_to_struct);
161         avtab_destroy(&p->te_cond_avtab);
162         cond_list_destroy(p);
163 }
164 
165 int cond_init_bool_indexes(struct policydb *p)
166 {
167         kfree(p->bool_val_to_struct);
168         p->bool_val_to_struct = kmalloc_array(
169                 p->p_bools.nprim, sizeof(*p->bool_val_to_struct), GFP_KERNEL);
170         if (!p->bool_val_to_struct)
171                 return -ENOMEM;
172 
173         avtab_hash_eval(&p->te_cond_avtab, "conditional_rules");
174 
175         return 0;
176 }
177 
178 int cond_destroy_bool(void *key, void *datum, void *p)
179 {
180         kfree(key);
181         kfree(datum);
182         return 0;
183 }
184 
185 int cond_index_bool(void *key, void *datum, void *datap)
186 {
187         struct policydb *p;
188         struct cond_bool_datum *booldatum;
189 
190         booldatum = datum;
191         p = datap;
192 
193         if (!booldatum->value || booldatum->value > p->p_bools.nprim)
194                 return -EINVAL;
195 
196         p->sym_val_to_name[SYM_BOOLS][booldatum->value - 1] = key;
197         p->bool_val_to_struct[booldatum->value - 1] = booldatum;
198 
199         return 0;
200 }
201 
202 static int bool_isvalid(struct cond_bool_datum *b)
203 {
204         if (!(b->state == 0 || b->state == 1))
205                 return 0;
206         return 1;
207 }
208 
209 int cond_read_bool(struct policydb *p, struct symtab *s, void *fp)
210 {
211         char *key = NULL;
212         struct cond_bool_datum *booldatum;
213         __le32 buf[3];
214         u32 len;
215         int rc;
216 
217         booldatum = kzalloc(sizeof(*booldatum), GFP_KERNEL);
218         if (!booldatum)
219                 return -ENOMEM;
220 
221         rc = next_entry(buf, fp, sizeof(buf));
222         if (rc)
223                 goto err;
224 
225         booldatum->value = le32_to_cpu(buf[0]);
226         booldatum->state = le32_to_cpu(buf[1]);
227 
228         rc = -EINVAL;
229         if (!bool_isvalid(booldatum))
230                 goto err;
231 
232         len = le32_to_cpu(buf[2]);
233         if (((len == 0) || (len == (u32)-1)))
234                 goto err;
235 
236         rc = -ENOMEM;
237         key = kmalloc(len + 1, GFP_KERNEL);
238         if (!key)
239                 goto err;
240         rc = next_entry(key, fp, len);
241         if (rc)
242                 goto err;
243         key[len] = '\0';
244         rc = symtab_insert(s, key, booldatum);
245         if (rc)
246                 goto err;
247 
248         return 0;
249 err:
250         cond_destroy_bool(key, booldatum, NULL);
251         return rc;
252 }
253 
254 struct cond_insertf_data {
255         struct policydb *p;
256         struct avtab_node **dst;
257         struct cond_av_list *other;
258 };
259 
260 static int cond_insertf(struct avtab *a, const struct avtab_key *k,
261                         const struct avtab_datum *d, void *ptr)
262 {
263         struct cond_insertf_data *data = ptr;
264         struct policydb *p = data->p;
265         struct cond_av_list *other = data->other;
266         struct avtab_node *node_ptr;
267         u32 i;
268         bool found;
269 
270         /*
271          * For type rules we have to make certain there aren't any
272          * conflicting rules by searching the te_avtab and the
273          * cond_te_avtab.
274          */
275         if (k->specified & AVTAB_TYPE) {
276                 if (avtab_search_node(&p->te_avtab, k)) {
277                         pr_err("SELinux: type rule already exists outside of a conditional.\n");
278                         return -EINVAL;
279                 }
280                 /*
281                  * If we are reading the false list other will be a pointer to
282                  * the true list. We can have duplicate entries if there is only
283                  * 1 other entry and it is in our true list.
284                  *
285                  * If we are reading the true list (other == NULL) there shouldn't
286                  * be any other entries.
287                  */
288                 if (other) {
289                         node_ptr = avtab_search_node(&p->te_cond_avtab, k);
290                         if (node_ptr) {
291                                 if (avtab_search_node_next(node_ptr,
292                                                            k->specified)) {
293                                         pr_err("SELinux: too many conflicting type rules.\n");
294                                         return -EINVAL;
295                                 }
296                                 found = false;
297                                 for (i = 0; i < other->len; i++) {
298                                         if (other->nodes[i] == node_ptr) {
299                                                 found = true;
300                                                 break;
301                                         }
302                                 }
303                                 if (!found) {
304                                         pr_err("SELinux: conflicting type rules.\n");
305                                         return -EINVAL;
306                                 }
307                         }
308                 } else {
309                         if (avtab_search_node(&p->te_cond_avtab, k)) {
310                                 pr_err("SELinux: conflicting type rules when adding type rule for true.\n");
311                                 return -EINVAL;
312                         }
313                 }
314         }
315 
316         node_ptr = avtab_insert_nonunique(&p->te_cond_avtab, k, d);
317         if (!node_ptr) {
318                 pr_err("SELinux: could not insert rule.\n");
319                 return -ENOMEM;
320         }
321 
322         *data->dst = node_ptr;
323         return 0;
324 }
325 
326 static int cond_read_av_list(struct policydb *p, void *fp,
327                              struct cond_av_list *list,
328                              struct cond_av_list *other)
329 {
330         int rc;
331         __le32 buf[1];
332         u32 i, len;
333         struct cond_insertf_data data;
334 
335         rc = next_entry(buf, fp, sizeof(u32));
336         if (rc)
337                 return rc;
338 
339         len = le32_to_cpu(buf[0]);
340         if (len == 0)
341                 return 0;
342 
343         list->nodes = kcalloc(len, sizeof(*list->nodes), GFP_KERNEL);
344         if (!list->nodes)
345                 return -ENOMEM;
346 
347         data.p = p;
348         data.other = other;
349         for (i = 0; i < len; i++) {
350                 data.dst = &list->nodes[i];
351                 rc = avtab_read_item(&p->te_cond_avtab, fp, p, cond_insertf,
352                                      &data);
353                 if (rc) {
354                         kfree(list->nodes);
355                         list->nodes = NULL;
356                         return rc;
357                 }
358         }
359 
360         list->len = len;
361         return 0;
362 }
363 
364 static int expr_node_isvalid(struct policydb *p, struct cond_expr_node *expr)
365 {
366         if (expr->expr_type <= 0 || expr->expr_type > COND_LAST) {
367                 pr_err("SELinux: conditional expressions uses unknown operator.\n");
368                 return 0;
369         }
370 
371         if (expr->boolean > p->p_bools.nprim) {
372                 pr_err("SELinux: conditional expressions uses unknown bool.\n");
373                 return 0;
374         }
375         return 1;
376 }
377 
378 static int cond_read_node(struct policydb *p, struct cond_node *node, void *fp)
379 {
380         __le32 buf[2];
381         u32 i, len;
382         int rc;
383 
384         rc = next_entry(buf, fp, sizeof(u32) * 2);
385         if (rc)
386                 return rc;
387 
388         node->cur_state = le32_to_cpu(buf[0]);
389 
390         /* expr */
391         len = le32_to_cpu(buf[1]);
392         node->expr.nodes = kcalloc(len, sizeof(*node->expr.nodes), GFP_KERNEL);
393         if (!node->expr.nodes)
394                 return -ENOMEM;
395 
396         node->expr.len = len;
397 
398         for (i = 0; i < len; i++) {
399                 struct cond_expr_node *expr = &node->expr.nodes[i];
400 
401                 rc = next_entry(buf, fp, sizeof(u32) * 2);
402                 if (rc)
403                         return rc;
404 
405                 expr->expr_type = le32_to_cpu(buf[0]);
406                 expr->boolean = le32_to_cpu(buf[1]);
407 
408                 if (!expr_node_isvalid(p, expr))
409                         return -EINVAL;
410         }
411 
412         rc = cond_read_av_list(p, fp, &node->true_list, NULL);
413         if (rc)
414                 return rc;
415         return cond_read_av_list(p, fp, &node->false_list, &node->true_list);
416 }
417 
418 int cond_read_list(struct policydb *p, void *fp)
419 {
420         __le32 buf[1];
421         u32 i, len;
422         int rc;
423 
424         rc = next_entry(buf, fp, sizeof(buf));
425         if (rc)
426                 return rc;
427 
428         len = le32_to_cpu(buf[0]);
429 
430         p->cond_list = kcalloc(len, sizeof(*p->cond_list), GFP_KERNEL);
431         if (!p->cond_list)
432                 return -ENOMEM;
433 
434         rc = avtab_alloc(&(p->te_cond_avtab), p->te_avtab.nel);
435         if (rc)
436                 goto err;
437 
438         p->cond_list_len = len;
439 
440         for (i = 0; i < len; i++) {
441                 rc = cond_read_node(p, &p->cond_list[i], fp);
442                 if (rc)
443                         goto err;
444         }
445         return 0;
446 err:
447         cond_list_destroy(p);
448         return rc;
449 }
450 
451 int cond_write_bool(void *vkey, void *datum, void *ptr)
452 {
453         char *key = vkey;
454         struct cond_bool_datum *booldatum = datum;
455         struct policy_data *pd = ptr;
456         void *fp = pd->fp;
457         __le32 buf[3];
458         u32 len;
459         int rc;
460 
461         len = strlen(key);
462         buf[0] = cpu_to_le32(booldatum->value);
463         buf[1] = cpu_to_le32(booldatum->state);
464         buf[2] = cpu_to_le32(len);
465         rc = put_entry(buf, sizeof(u32), 3, fp);
466         if (rc)
467                 return rc;
468         rc = put_entry(key, 1, len, fp);
469         if (rc)
470                 return rc;
471         return 0;
472 }
473 
474 /*
475  * cond_write_cond_av_list doesn't write out the av_list nodes.
476  * Instead it writes out the key/value pairs from the avtab. This
477  * is necessary because there is no way to uniquely identifying rules
478  * in the avtab so it is not possible to associate individual rules
479  * in the avtab with a conditional without saving them as part of
480  * the conditional. This means that the avtab with the conditional
481  * rules will not be saved but will be rebuilt on policy load.
482  */
483 static int cond_write_av_list(struct policydb *p, struct cond_av_list *list,
484                               struct policy_file *fp)
485 {
486         __le32 buf[1];
487         u32 i;
488         int rc;
489 
490         buf[0] = cpu_to_le32(list->len);
491         rc = put_entry(buf, sizeof(u32), 1, fp);
492         if (rc)
493                 return rc;
494 
495         for (i = 0; i < list->len; i++) {
496                 rc = avtab_write_item(p, list->nodes[i], fp);
497                 if (rc)
498                         return rc;
499         }
500 
501         return 0;
502 }
503 
504 static int cond_write_node(struct policydb *p, struct cond_node *node,
505                            struct policy_file *fp)
506 {
507         __le32 buf[2];
508         int rc;
509         u32 i;
510 
511         buf[0] = cpu_to_le32(node->cur_state);
512         rc = put_entry(buf, sizeof(u32), 1, fp);
513         if (rc)
514                 return rc;
515 
516         buf[0] = cpu_to_le32(node->expr.len);
517         rc = put_entry(buf, sizeof(u32), 1, fp);
518         if (rc)
519                 return rc;
520 
521         for (i = 0; i < node->expr.len; i++) {
522                 buf[0] = cpu_to_le32(node->expr.nodes[i].expr_type);
523                 buf[1] = cpu_to_le32(node->expr.nodes[i].boolean);
524                 rc = put_entry(buf, sizeof(u32), 2, fp);
525                 if (rc)
526                         return rc;
527         }
528 
529         rc = cond_write_av_list(p, &node->true_list, fp);
530         if (rc)
531                 return rc;
532         rc = cond_write_av_list(p, &node->false_list, fp);
533         if (rc)
534                 return rc;
535 
536         return 0;
537 }
538 
539 int cond_write_list(struct policydb *p, void *fp)
540 {
541         u32 i;
542         __le32 buf[1];
543         int rc;
544 
545         buf[0] = cpu_to_le32(p->cond_list_len);
546         rc = put_entry(buf, sizeof(u32), 1, fp);
547         if (rc)
548                 return rc;
549 
550         for (i = 0; i < p->cond_list_len; i++) {
551                 rc = cond_write_node(p, &p->cond_list[i], fp);
552                 if (rc)
553                         return rc;
554         }
555 
556         return 0;
557 }
558 
559 void cond_compute_xperms(struct avtab *ctab, struct avtab_key *key,
560                          struct extended_perms_decision *xpermd)
561 {
562         struct avtab_node *node;
563 
564         if (!ctab || !key || !xpermd)
565                 return;
566 
567         for (node = avtab_search_node(ctab, key); node;
568              node = avtab_search_node_next(node, key->specified)) {
569                 if (node->key.specified & AVTAB_ENABLED)
570                         services_compute_xperms_decision(xpermd, node);
571         }
572 }
573 /* Determine whether additional permissions are granted by the conditional
574  * av table, and if so, add them to the result
575  */
576 void cond_compute_av(struct avtab *ctab, struct avtab_key *key,
577                      struct av_decision *avd, struct extended_perms *xperms)
578 {
579         struct avtab_node *node;
580 
581         if (!ctab || !key || !avd)
582                 return;
583 
584         for (node = avtab_search_node(ctab, key); node;
585              node = avtab_search_node_next(node, key->specified)) {
586                 if ((u16)(AVTAB_ALLOWED | AVTAB_ENABLED) ==
587                     (node->key.specified & (AVTAB_ALLOWED | AVTAB_ENABLED)))
588                         avd->allowed |= node->datum.u.data;
589                 if ((u16)(AVTAB_AUDITDENY | AVTAB_ENABLED) ==
590                     (node->key.specified & (AVTAB_AUDITDENY | AVTAB_ENABLED)))
591                         /* Since a '' in an auditdeny mask represents a
592                          * permission we do NOT want to audit (dontaudit), we use
593                          * the '&' operand to ensure that all ''s in the mask
594                          * are retained (much unlike the allow and auditallow cases).
595                          */
596                         avd->auditdeny &= node->datum.u.data;
597                 if ((u16)(AVTAB_AUDITALLOW | AVTAB_ENABLED) ==
598                     (node->key.specified & (AVTAB_AUDITALLOW | AVTAB_ENABLED)))
599                         avd->auditallow |= node->datum.u.data;
600                 if (xperms && (node->key.specified & AVTAB_ENABLED) &&
601                     (node->key.specified & AVTAB_XPERMS))
602                         services_compute_xperms_drivers(xperms, node);
603         }
604 }
605 
606 static int cond_dup_av_list(struct cond_av_list *new,
607                             const struct cond_av_list *orig,
608                             struct avtab *avtab)
609 {
610         u32 i;
611 
612         memset(new, 0, sizeof(*new));
613 
614         new->nodes = kcalloc(orig->len, sizeof(*new->nodes), GFP_KERNEL);
615         if (!new->nodes)
616                 return -ENOMEM;
617 
618         for (i = 0; i < orig->len; i++) {
619                 new->nodes[i] = avtab_insert_nonunique(
620                         avtab, &orig->nodes[i]->key, &orig->nodes[i]->datum);
621                 if (!new->nodes[i])
622                         return -ENOMEM;
623                 new->len++;
624         }
625 
626         return 0;
627 }
628 
629 static int duplicate_policydb_cond_list(struct policydb *newp,
630                                         const struct policydb *origp)
631 {
632         int rc;
633         u32 i;
634 
635         rc = avtab_alloc_dup(&newp->te_cond_avtab, &origp->te_cond_avtab);
636         if (rc)
637                 return rc;
638 
639         newp->cond_list_len = 0;
640         newp->cond_list = kcalloc(origp->cond_list_len,
641                                   sizeof(*newp->cond_list), GFP_KERNEL);
642         if (!newp->cond_list)
643                 goto error;
644 
645         for (i = 0; i < origp->cond_list_len; i++) {
646                 struct cond_node *newn = &newp->cond_list[i];
647                 const struct cond_node *orign = &origp->cond_list[i];
648 
649                 newp->cond_list_len++;
650 
651                 newn->cur_state = orign->cur_state;
652                 newn->expr.nodes =
653                         kmemdup(orign->expr.nodes,
654                                 orign->expr.len * sizeof(*orign->expr.nodes),
655                                 GFP_KERNEL);
656                 if (!newn->expr.nodes)
657                         goto error;
658 
659                 newn->expr.len = orign->expr.len;
660 
661                 rc = cond_dup_av_list(&newn->true_list, &orign->true_list,
662                                       &newp->te_cond_avtab);
663                 if (rc)
664                         goto error;
665 
666                 rc = cond_dup_av_list(&newn->false_list, &orign->false_list,
667                                       &newp->te_cond_avtab);
668                 if (rc)
669                         goto error;
670         }
671 
672         return 0;
673 
674 error:
675         avtab_destroy(&newp->te_cond_avtab);
676         cond_list_destroy(newp);
677         return -ENOMEM;
678 }
679 
680 static int cond_bools_destroy(void *key, void *datum, void *args)
681 {
682         /* key was not copied so no need to free here */
683         kfree(datum);
684         return 0;
685 }
686 
687 static int cond_bools_copy(struct hashtab_node *new,
688                            const struct hashtab_node *orig, void *args)
689 {
690         struct cond_bool_datum *datum;
691 
692         datum = kmemdup(orig->datum, sizeof(struct cond_bool_datum),
693                         GFP_KERNEL);
694         if (!datum)
695                 return -ENOMEM;
696 
697         new->key = orig->key; /* No need to copy, never modified */
698         new->datum = datum;
699         return 0;
700 }
701 
702 static int cond_bools_index(void *key, void *datum, void *args)
703 {
704         struct cond_bool_datum *booldatum, **cond_bool_array;
705 
706         booldatum = datum;
707         cond_bool_array = args;
708         cond_bool_array[booldatum->value - 1] = booldatum;
709 
710         return 0;
711 }
712 
713 static int duplicate_policydb_bools(struct policydb *newdb,
714                                     const struct policydb *orig)
715 {
716         struct cond_bool_datum **cond_bool_array;
717         int rc;
718 
719         cond_bool_array = kmalloc_array(orig->p_bools.nprim,
720                                         sizeof(*orig->bool_val_to_struct),
721                                         GFP_KERNEL);
722         if (!cond_bool_array)
723                 return -ENOMEM;
724 
725         rc = hashtab_duplicate(&newdb->p_bools.table, &orig->p_bools.table,
726                                cond_bools_copy, cond_bools_destroy, NULL);
727         if (rc) {
728                 kfree(cond_bool_array);
729                 return -ENOMEM;
730         }
731 
732         hashtab_map(&newdb->p_bools.table, cond_bools_index, cond_bool_array);
733         newdb->bool_val_to_struct = cond_bool_array;
734 
735         newdb->p_bools.nprim = orig->p_bools.nprim;
736 
737         return 0;
738 }
739 
740 void cond_policydb_destroy_dup(struct policydb *p)
741 {
742         hashtab_map(&p->p_bools.table, cond_bools_destroy, NULL);
743         hashtab_destroy(&p->p_bools.table);
744         cond_policydb_destroy(p);
745 }
746 
747 int cond_policydb_dup(struct policydb *new, const struct policydb *orig)
748 {
749         cond_policydb_init(new);
750 
751         if (duplicate_policydb_bools(new, orig))
752                 return -ENOMEM;
753 
754         if (duplicate_policydb_cond_list(new, orig)) {
755                 cond_policydb_destroy_dup(new);
756                 return -ENOMEM;
757         }
758 
759         return 0;
760 }
761 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php