1a10e763bSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds * Implementation of the security services.
41da177e4SLinus Torvalds *
50fe53224SStephen Smalley * Authors : Stephen Smalley, <stephen.smalley.work@gmail.com>
61da177e4SLinus Torvalds * James Morris <jmorris@redhat.com>
71da177e4SLinus Torvalds *
81da177e4SLinus Torvalds * Updated: Trusted Computer Solutions, Inc. <dgoeddel@trustedcs.com>
91da177e4SLinus Torvalds *
101da177e4SLinus Torvalds * Support for enhanced MLS infrastructure.
11376bd9cbSDarrel Goeddel * Support for context based audit filters.
121da177e4SLinus Torvalds *
131da177e4SLinus Torvalds * Updated: Frank Mayer <mayerf@tresys.com> and Karl MacMillan <kmacmillan@tresys.com>
141da177e4SLinus Torvalds *
151da177e4SLinus Torvalds * Added conditional policy language extensions
161da177e4SLinus Torvalds *
1782c21bfaSPaul Moore * Updated: Hewlett-Packard <paul@paul-moore.com>
187420ed23SVenkat Yekkirala *
197420ed23SVenkat Yekkirala * Added support for NetLabel
203bb56b25SPaul Moore * Added support for the policy capability bitmap
217420ed23SVenkat Yekkirala *
22b94c7e67SChad Sellers * Updated: Chad Sellers <csellers@tresys.com>
23b94c7e67SChad Sellers *
24b94c7e67SChad Sellers * Added validation of kernel classes and permissions
25b94c7e67SChad Sellers *
2644c2d9bdSKaiGai Kohei * Updated: KaiGai Kohei <kaigai@ak.jp.nec.com>
2744c2d9bdSKaiGai Kohei *
2844c2d9bdSKaiGai Kohei * Added support for bounds domain and audit messaged on masked permissions
2944c2d9bdSKaiGai Kohei *
300719aaf5SGuido Trentalancia * Updated: Guido Trentalancia <guido@trentalancia.com>
310719aaf5SGuido Trentalancia *
320719aaf5SGuido Trentalancia * Added support for runtime switching of the policy type
330719aaf5SGuido Trentalancia *
3444c2d9bdSKaiGai Kohei * Copyright (C) 2008, 2009 NEC Corporation
353bb56b25SPaul Moore * Copyright (C) 2006, 2007 Hewlett-Packard Development Company, L.P.
36376bd9cbSDarrel Goeddel * Copyright (C) 2004-2006 Trusted Computer Solutions, Inc.
37b94c7e67SChad Sellers * Copyright (C) 2003 - 2004, 2006 Tresys Technology, LLC
381da177e4SLinus Torvalds * Copyright (C) 2003 Red Hat, Inc., James Morris <jmorris@redhat.com>
391da177e4SLinus Torvalds */
401da177e4SLinus Torvalds #include <linux/kernel.h>
411da177e4SLinus Torvalds #include <linux/slab.h>
421da177e4SLinus Torvalds #include <linux/string.h>
431da177e4SLinus Torvalds #include <linux/spinlock.h>
449f2ad665SPaul Moore #include <linux/rcupdate.h>
451da177e4SLinus Torvalds #include <linux/errno.h>
461da177e4SLinus Torvalds #include <linux/in.h>
471da177e4SLinus Torvalds #include <linux/sched.h>
481da177e4SLinus Torvalds #include <linux/audit.h>
49f0d3d989SStephen Rothwell #include <linux/vmalloc.h>
501aea7808SCasey Schaufler #include <linux/lsm_hooks.h>
517420ed23SVenkat Yekkirala #include <net/netlabel.h>
52bb003079SIngo Molnar
531da177e4SLinus Torvalds #include "flask.h"
541da177e4SLinus Torvalds #include "avc.h"
551da177e4SLinus Torvalds #include "avc_ss.h"
561da177e4SLinus Torvalds #include "security.h"
571da177e4SLinus Torvalds #include "context.h"
581da177e4SLinus Torvalds #include "policydb.h"
591da177e4SLinus Torvalds #include "sidtab.h"
601da177e4SLinus Torvalds #include "services.h"
611da177e4SLinus Torvalds #include "conditional.h"
621da177e4SLinus Torvalds #include "mls.h"
637420ed23SVenkat Yekkirala #include "objsec.h"
64c60475bfSPaul Moore #include "netlabel.h"
653de4bab5SPaul Moore #include "xfrm.h"
6602752760SPaul Moore #include "ebitmap.h"
679d57a7f9SAhmed S. Darwish #include "audit.h"
68339949beSStephen Smalley #include "policycap_names.h"
69fdd1ffe8SLakshmi Ramasubramanian #include "ima.h"
704dc2fce3SStephen Smalley
716406887aSOndrej Mosnacek struct selinux_policy_convert_data {
726406887aSOndrej Mosnacek struct convert_context_args args;
736406887aSOndrej Mosnacek struct sidtab_convert_params sidtab_params;
746406887aSOndrej Mosnacek };
756406887aSOndrej Mosnacek
761da177e4SLinus Torvalds /* Forward declaration. */
77aa8e712cSStephen Smalley static int context_struct_to_string(struct policydb *policydb,
78aa8e712cSStephen Smalley struct context *context,
79aa8e712cSStephen Smalley char **scontext,
801da177e4SLinus Torvalds u32 *scontext_len);
811da177e4SLinus Torvalds
82d97bd23cSOndrej Mosnacek static int sidtab_entry_to_string(struct policydb *policydb,
83d97bd23cSOndrej Mosnacek struct sidtab *sidtab,
84d97bd23cSOndrej Mosnacek struct sidtab_entry *entry,
85d97bd23cSOndrej Mosnacek char **scontext,
86d97bd23cSOndrej Mosnacek u32 *scontext_len);
87d97bd23cSOndrej Mosnacek
88aa8e712cSStephen Smalley static void context_struct_compute_av(struct policydb *policydb,
89aa8e712cSStephen Smalley struct context *scontext,
90d9250deaSKaiGai Kohei struct context *tcontext,
91d9250deaSKaiGai Kohei u16 tclass,
92fa1aa143SJeff Vander Stoep struct av_decision *avd,
93fa1aa143SJeff Vander Stoep struct extended_perms *xperms);
94c6d3aaa4SStephen Smalley
selinux_set_mapping(struct policydb * pol,const struct security_class_mapping * map,struct selinux_map * out_map)95c6d3aaa4SStephen Smalley static int selinux_set_mapping(struct policydb *pol,
96ded34574SChristian Göttsche const struct security_class_mapping *map,
97aa8e712cSStephen Smalley struct selinux_map *out_map)
98c6d3aaa4SStephen Smalley {
99c6d3aaa4SStephen Smalley u16 i, j;
100c6d3aaa4SStephen Smalley bool print_unknown_handle = false;
101c6d3aaa4SStephen Smalley
102c6d3aaa4SStephen Smalley /* Find number of classes in the input mapping */
103c6d3aaa4SStephen Smalley if (!map)
104c6d3aaa4SStephen Smalley return -EINVAL;
105c6d3aaa4SStephen Smalley i = 0;
106c6d3aaa4SStephen Smalley while (map[i].name)
107c6d3aaa4SStephen Smalley i++;
108c6d3aaa4SStephen Smalley
109c6d3aaa4SStephen Smalley /* Allocate space for the class records, plus one for class zero */
110aa8e712cSStephen Smalley out_map->mapping = kcalloc(++i, sizeof(*out_map->mapping), GFP_ATOMIC);
111aa8e712cSStephen Smalley if (!out_map->mapping)
112c6d3aaa4SStephen Smalley return -ENOMEM;
113c6d3aaa4SStephen Smalley
114c6d3aaa4SStephen Smalley /* Store the raw class and permission values */
115c6d3aaa4SStephen Smalley j = 0;
116c6d3aaa4SStephen Smalley while (map[j].name) {
117ded34574SChristian Göttsche const struct security_class_mapping *p_in = map + (j++);
118aa8e712cSStephen Smalley struct selinux_mapping *p_out = out_map->mapping + j;
119002903e1SChristian Göttsche u16 k;
120c6d3aaa4SStephen Smalley
121c6d3aaa4SStephen Smalley /* An empty class string skips ahead */
122c6d3aaa4SStephen Smalley if (!strcmp(p_in->name, "")) {
123c6d3aaa4SStephen Smalley p_out->num_perms = 0;
124c6d3aaa4SStephen Smalley continue;
125c6d3aaa4SStephen Smalley }
126c6d3aaa4SStephen Smalley
127c6d3aaa4SStephen Smalley p_out->value = string_to_security_class(pol, p_in->name);
128c6d3aaa4SStephen Smalley if (!p_out->value) {
129b54c85c1Speter enderborg pr_info("SELinux: Class %s not defined in policy.\n",
130c6d3aaa4SStephen Smalley p_in->name);
131c6d3aaa4SStephen Smalley if (pol->reject_unknown)
132c6d3aaa4SStephen Smalley goto err;
133c6d3aaa4SStephen Smalley p_out->num_perms = 0;
134c6d3aaa4SStephen Smalley print_unknown_handle = true;
135c6d3aaa4SStephen Smalley continue;
136c6d3aaa4SStephen Smalley }
137c6d3aaa4SStephen Smalley
138c6d3aaa4SStephen Smalley k = 0;
139342e9157SMatthias Kaehlcke while (p_in->perms[k]) {
140c6d3aaa4SStephen Smalley /* An empty permission string skips ahead */
141c6d3aaa4SStephen Smalley if (!*p_in->perms[k]) {
142c6d3aaa4SStephen Smalley k++;
143c6d3aaa4SStephen Smalley continue;
144c6d3aaa4SStephen Smalley }
145c6d3aaa4SStephen Smalley p_out->perms[k] = string_to_av_perm(pol, p_out->value,
146c6d3aaa4SStephen Smalley p_in->perms[k]);
147c6d3aaa4SStephen Smalley if (!p_out->perms[k]) {
148b54c85c1Speter enderborg pr_info("SELinux: Permission %s in class %s not defined in policy.\n",
149c6d3aaa4SStephen Smalley p_in->perms[k], p_in->name);
150c6d3aaa4SStephen Smalley if (pol->reject_unknown)
151c6d3aaa4SStephen Smalley goto err;
152c6d3aaa4SStephen Smalley print_unknown_handle = true;
153c6d3aaa4SStephen Smalley }
154c6d3aaa4SStephen Smalley
155c6d3aaa4SStephen Smalley k++;
156c6d3aaa4SStephen Smalley }
157c6d3aaa4SStephen Smalley p_out->num_perms = k;
158c6d3aaa4SStephen Smalley }
159c6d3aaa4SStephen Smalley
160c6d3aaa4SStephen Smalley if (print_unknown_handle)
161b54c85c1Speter enderborg pr_info("SELinux: the above unknown classes and permissions will be %s\n",
162c6d3aaa4SStephen Smalley pol->allow_unknown ? "allowed" : "denied");
163c6d3aaa4SStephen Smalley
164aa8e712cSStephen Smalley out_map->size = i;
165c6d3aaa4SStephen Smalley return 0;
166c6d3aaa4SStephen Smalley err:
167aa8e712cSStephen Smalley kfree(out_map->mapping);
168aa8e712cSStephen Smalley out_map->mapping = NULL;
169c6d3aaa4SStephen Smalley return -EINVAL;
170c6d3aaa4SStephen Smalley }
171c6d3aaa4SStephen Smalley
172c6d3aaa4SStephen Smalley /*
173c6d3aaa4SStephen Smalley * Get real, policy values from mapped values
174c6d3aaa4SStephen Smalley */
175c6d3aaa4SStephen Smalley
unmap_class(struct selinux_map * map,u16 tclass)176aa8e712cSStephen Smalley static u16 unmap_class(struct selinux_map *map, u16 tclass)
177c6d3aaa4SStephen Smalley {
178aa8e712cSStephen Smalley if (tclass < map->size)
179aa8e712cSStephen Smalley return map->mapping[tclass].value;
180c6d3aaa4SStephen Smalley
181c6d3aaa4SStephen Smalley return tclass;
182c6d3aaa4SStephen Smalley }
183c6d3aaa4SStephen Smalley
1846f5317e7SHarry Ciao /*
1856f5317e7SHarry Ciao * Get kernel value for class from its policy value
1866f5317e7SHarry Ciao */
map_class(struct selinux_map * map,u16 pol_value)187aa8e712cSStephen Smalley static u16 map_class(struct selinux_map *map, u16 pol_value)
1886f5317e7SHarry Ciao {
1896f5317e7SHarry Ciao u16 i;
1906f5317e7SHarry Ciao
191aa8e712cSStephen Smalley for (i = 1; i < map->size; i++) {
192aa8e712cSStephen Smalley if (map->mapping[i].value == pol_value)
1936f5317e7SHarry Ciao return i;
1946f5317e7SHarry Ciao }
1956f5317e7SHarry Ciao
19685cd6da5SStephen Smalley return SECCLASS_NULL;
1976f5317e7SHarry Ciao }
1986f5317e7SHarry Ciao
map_decision(struct selinux_map * map,u16 tclass,struct av_decision * avd,int allow_unknown)199aa8e712cSStephen Smalley static void map_decision(struct selinux_map *map,
200aa8e712cSStephen Smalley u16 tclass, struct av_decision *avd,
201c6d3aaa4SStephen Smalley int allow_unknown)
202c6d3aaa4SStephen Smalley {
203aa8e712cSStephen Smalley if (tclass < map->size) {
204aa8e712cSStephen Smalley struct selinux_mapping *mapping = &map->mapping[tclass];
205aa8e712cSStephen Smalley unsigned int i, n = mapping->num_perms;
206c6d3aaa4SStephen Smalley u32 result;
207c6d3aaa4SStephen Smalley
208c6d3aaa4SStephen Smalley for (i = 0, result = 0; i < n; i++) {
209aa8e712cSStephen Smalley if (avd->allowed & mapping->perms[i])
210aa4b6051SChristian Göttsche result |= (u32)1<<i;
211aa8e712cSStephen Smalley if (allow_unknown && !mapping->perms[i])
212aa4b6051SChristian Göttsche result |= (u32)1<<i;
213c6d3aaa4SStephen Smalley }
214c6d3aaa4SStephen Smalley avd->allowed = result;
215c6d3aaa4SStephen Smalley
216c6d3aaa4SStephen Smalley for (i = 0, result = 0; i < n; i++)
217aa8e712cSStephen Smalley if (avd->auditallow & mapping->perms[i])
218aa4b6051SChristian Göttsche result |= (u32)1<<i;
219c6d3aaa4SStephen Smalley avd->auditallow = result;
220c6d3aaa4SStephen Smalley
221c6d3aaa4SStephen Smalley for (i = 0, result = 0; i < n; i++) {
222aa8e712cSStephen Smalley if (avd->auditdeny & mapping->perms[i])
223aa4b6051SChristian Göttsche result |= (u32)1<<i;
224aa8e712cSStephen Smalley if (!allow_unknown && !mapping->perms[i])
225aa4b6051SChristian Göttsche result |= (u32)1<<i;
226c6d3aaa4SStephen Smalley }
2270bce9527SEric Paris /*
2280bce9527SEric Paris * In case the kernel has a bug and requests a permission
2290bce9527SEric Paris * between num_perms and the maximum permission number, we
2300bce9527SEric Paris * should audit that denial
2310bce9527SEric Paris */
2320bce9527SEric Paris for (; i < (sizeof(u32)*8); i++)
233aa4b6051SChristian Göttsche result |= (u32)1<<i;
234c6d3aaa4SStephen Smalley avd->auditdeny = result;
235c6d3aaa4SStephen Smalley }
236c6d3aaa4SStephen Smalley }
237c6d3aaa4SStephen Smalley
security_mls_enabled(void)238e67b7985SStephen Smalley int security_mls_enabled(void)
2390719aaf5SGuido Trentalancia {
24046169802SStephen Smalley int mls_enabled;
2411b8b31a2SStephen Smalley struct selinux_policy *policy;
242aa8e712cSStephen Smalley
243e67b7985SStephen Smalley if (!selinux_initialized())
24446169802SStephen Smalley return 0;
24546169802SStephen Smalley
2461b8b31a2SStephen Smalley rcu_read_lock();
247e67b7985SStephen Smalley policy = rcu_dereference(selinux_state.policy);
2481b8b31a2SStephen Smalley mls_enabled = policy->policydb.mls_enabled;
2491b8b31a2SStephen Smalley rcu_read_unlock();
25046169802SStephen Smalley return mls_enabled;
2510719aaf5SGuido Trentalancia }
252c6d3aaa4SStephen Smalley
2531da177e4SLinus Torvalds /*
2541da177e4SLinus Torvalds * Return the boolean value of a constraint expression
2551da177e4SLinus Torvalds * when it is applied to the specified source and target
2561da177e4SLinus Torvalds * security contexts.
2571da177e4SLinus Torvalds *
2581da177e4SLinus Torvalds * xcontext is a special beast... It is used by the validatetrans rules
2591da177e4SLinus Torvalds * only. For these rules, scontext is the context before the transition,
2601da177e4SLinus Torvalds * tcontext is the context after the transition, and xcontext is the context
2611da177e4SLinus Torvalds * of the process performing the transition. All other callers of
2621da177e4SLinus Torvalds * constraint_expr_eval should pass in NULL for xcontext.
2631da177e4SLinus Torvalds */
constraint_expr_eval(struct policydb * policydb,struct context * scontext,struct context * tcontext,struct context * xcontext,struct constraint_expr * cexpr)264aa8e712cSStephen Smalley static int constraint_expr_eval(struct policydb *policydb,
265aa8e712cSStephen Smalley struct context *scontext,
2661da177e4SLinus Torvalds struct context *tcontext,
2671da177e4SLinus Torvalds struct context *xcontext,
2681da177e4SLinus Torvalds struct constraint_expr *cexpr)
2691da177e4SLinus Torvalds {
2701da177e4SLinus Torvalds u32 val1, val2;
2711da177e4SLinus Torvalds struct context *c;
2721da177e4SLinus Torvalds struct role_datum *r1, *r2;
2731da177e4SLinus Torvalds struct mls_level *l1, *l2;
2741da177e4SLinus Torvalds struct constraint_expr *e;
2751da177e4SLinus Torvalds int s[CEXPR_MAXDEPTH];
2761da177e4SLinus Torvalds int sp = -1;
2771da177e4SLinus Torvalds
2781da177e4SLinus Torvalds for (e = cexpr; e; e = e->next) {
2791da177e4SLinus Torvalds switch (e->expr_type) {
2801da177e4SLinus Torvalds case CEXPR_NOT:
2811da177e4SLinus Torvalds BUG_ON(sp < 0);
2821da177e4SLinus Torvalds s[sp] = !s[sp];
2831da177e4SLinus Torvalds break;
2841da177e4SLinus Torvalds case CEXPR_AND:
2851da177e4SLinus Torvalds BUG_ON(sp < 1);
2861da177e4SLinus Torvalds sp--;
2871da177e4SLinus Torvalds s[sp] &= s[sp + 1];
2881da177e4SLinus Torvalds break;
2891da177e4SLinus Torvalds case CEXPR_OR:
2901da177e4SLinus Torvalds BUG_ON(sp < 1);
2911da177e4SLinus Torvalds sp--;
2921da177e4SLinus Torvalds s[sp] |= s[sp + 1];
2931da177e4SLinus Torvalds break;
2941da177e4SLinus Torvalds case CEXPR_ATTR:
2951da177e4SLinus Torvalds if (sp == (CEXPR_MAXDEPTH - 1))
2961da177e4SLinus Torvalds return 0;
2971da177e4SLinus Torvalds switch (e->attr) {
2981da177e4SLinus Torvalds case CEXPR_USER:
2991da177e4SLinus Torvalds val1 = scontext->user;
3001da177e4SLinus Torvalds val2 = tcontext->user;
3011da177e4SLinus Torvalds break;
3021da177e4SLinus Torvalds case CEXPR_TYPE:
3031da177e4SLinus Torvalds val1 = scontext->type;
3041da177e4SLinus Torvalds val2 = tcontext->type;
3051da177e4SLinus Torvalds break;
3061da177e4SLinus Torvalds case CEXPR_ROLE:
3071da177e4SLinus Torvalds val1 = scontext->role;
3081da177e4SLinus Torvalds val2 = tcontext->role;
309aa8e712cSStephen Smalley r1 = policydb->role_val_to_struct[val1 - 1];
310aa8e712cSStephen Smalley r2 = policydb->role_val_to_struct[val2 - 1];
3111da177e4SLinus Torvalds switch (e->op) {
3121da177e4SLinus Torvalds case CEXPR_DOM:
3131da177e4SLinus Torvalds s[++sp] = ebitmap_get_bit(&r1->dominates,
3141da177e4SLinus Torvalds val2 - 1);
3151da177e4SLinus Torvalds continue;
3161da177e4SLinus Torvalds case CEXPR_DOMBY:
3171da177e4SLinus Torvalds s[++sp] = ebitmap_get_bit(&r2->dominates,
3181da177e4SLinus Torvalds val1 - 1);
3191da177e4SLinus Torvalds continue;
3201da177e4SLinus Torvalds case CEXPR_INCOMP:
3211da177e4SLinus Torvalds s[++sp] = (!ebitmap_get_bit(&r1->dominates,
3221da177e4SLinus Torvalds val2 - 1) &&
3231da177e4SLinus Torvalds !ebitmap_get_bit(&r2->dominates,
3241da177e4SLinus Torvalds val1 - 1));
3251da177e4SLinus Torvalds continue;
3261da177e4SLinus Torvalds default:
3271da177e4SLinus Torvalds break;
3281da177e4SLinus Torvalds }
3291da177e4SLinus Torvalds break;
3301da177e4SLinus Torvalds case CEXPR_L1L2:
3311da177e4SLinus Torvalds l1 = &(scontext->range.level[0]);
3321da177e4SLinus Torvalds l2 = &(tcontext->range.level[0]);
3331da177e4SLinus Torvalds goto mls_ops;
3341da177e4SLinus Torvalds case CEXPR_L1H2:
3351da177e4SLinus Torvalds l1 = &(scontext->range.level[0]);
3361da177e4SLinus Torvalds l2 = &(tcontext->range.level[1]);
3371da177e4SLinus Torvalds goto mls_ops;
3381da177e4SLinus Torvalds case CEXPR_H1L2:
3391da177e4SLinus Torvalds l1 = &(scontext->range.level[1]);
3401da177e4SLinus Torvalds l2 = &(tcontext->range.level[0]);
3411da177e4SLinus Torvalds goto mls_ops;
3421da177e4SLinus Torvalds case CEXPR_H1H2:
3431da177e4SLinus Torvalds l1 = &(scontext->range.level[1]);
3441da177e4SLinus Torvalds l2 = &(tcontext->range.level[1]);
3451da177e4SLinus Torvalds goto mls_ops;
3461da177e4SLinus Torvalds case CEXPR_L1H1:
3471da177e4SLinus Torvalds l1 = &(scontext->range.level[0]);
3481da177e4SLinus Torvalds l2 = &(scontext->range.level[1]);
3491da177e4SLinus Torvalds goto mls_ops;
3501da177e4SLinus Torvalds case CEXPR_L2H2:
3511da177e4SLinus Torvalds l1 = &(tcontext->range.level[0]);
3521da177e4SLinus Torvalds l2 = &(tcontext->range.level[1]);
3531da177e4SLinus Torvalds goto mls_ops;
3541da177e4SLinus Torvalds mls_ops:
3551da177e4SLinus Torvalds switch (e->op) {
3561da177e4SLinus Torvalds case CEXPR_EQ:
3571da177e4SLinus Torvalds s[++sp] = mls_level_eq(l1, l2);
3581da177e4SLinus Torvalds continue;
3591da177e4SLinus Torvalds case CEXPR_NEQ:
3601da177e4SLinus Torvalds s[++sp] = !mls_level_eq(l1, l2);
3611da177e4SLinus Torvalds continue;
3621da177e4SLinus Torvalds case CEXPR_DOM:
3631da177e4SLinus Torvalds s[++sp] = mls_level_dom(l1, l2);
3641da177e4SLinus Torvalds continue;
3651da177e4SLinus Torvalds case CEXPR_DOMBY:
3661da177e4SLinus Torvalds s[++sp] = mls_level_dom(l2, l1);
3671da177e4SLinus Torvalds continue;
3681da177e4SLinus Torvalds case CEXPR_INCOMP:
3691da177e4SLinus Torvalds s[++sp] = mls_level_incomp(l2, l1);
3701da177e4SLinus Torvalds continue;
3711da177e4SLinus Torvalds default:
3721da177e4SLinus Torvalds BUG();
3731da177e4SLinus Torvalds return 0;
3741da177e4SLinus Torvalds }
3751da177e4SLinus Torvalds break;
3761da177e4SLinus Torvalds default:
3771da177e4SLinus Torvalds BUG();
3781da177e4SLinus Torvalds return 0;
3791da177e4SLinus Torvalds }
3801da177e4SLinus Torvalds
3811da177e4SLinus Torvalds switch (e->op) {
3821da177e4SLinus Torvalds case CEXPR_EQ:
3831da177e4SLinus Torvalds s[++sp] = (val1 == val2);
3841da177e4SLinus Torvalds break;
3851da177e4SLinus Torvalds case CEXPR_NEQ:
3861da177e4SLinus Torvalds s[++sp] = (val1 != val2);
3871da177e4SLinus Torvalds break;
3881da177e4SLinus Torvalds default:
3891da177e4SLinus Torvalds BUG();
3901da177e4SLinus Torvalds return 0;
3911da177e4SLinus Torvalds }
3921da177e4SLinus Torvalds break;
3931da177e4SLinus Torvalds case CEXPR_NAMES:
3941da177e4SLinus Torvalds if (sp == (CEXPR_MAXDEPTH-1))
3951da177e4SLinus Torvalds return 0;
3961da177e4SLinus Torvalds c = scontext;
3971da177e4SLinus Torvalds if (e->attr & CEXPR_TARGET)
3981da177e4SLinus Torvalds c = tcontext;
3991da177e4SLinus Torvalds else if (e->attr & CEXPR_XTARGET) {
4001da177e4SLinus Torvalds c = xcontext;
4011da177e4SLinus Torvalds if (!c) {
4021da177e4SLinus Torvalds BUG();
4031da177e4SLinus Torvalds return 0;
4041da177e4SLinus Torvalds }
4051da177e4SLinus Torvalds }
4061da177e4SLinus Torvalds if (e->attr & CEXPR_USER)
4071da177e4SLinus Torvalds val1 = c->user;
4081da177e4SLinus Torvalds else if (e->attr & CEXPR_ROLE)
4091da177e4SLinus Torvalds val1 = c->role;
4101da177e4SLinus Torvalds else if (e->attr & CEXPR_TYPE)
4111da177e4SLinus Torvalds val1 = c->type;
4121da177e4SLinus Torvalds else {
4131da177e4SLinus Torvalds BUG();
4141da177e4SLinus Torvalds return 0;
4151da177e4SLinus Torvalds }
4161da177e4SLinus Torvalds
4171da177e4SLinus Torvalds switch (e->op) {
4181da177e4SLinus Torvalds case CEXPR_EQ:
4191da177e4SLinus Torvalds s[++sp] = ebitmap_get_bit(&e->names, val1 - 1);
4201da177e4SLinus Torvalds break;
4211da177e4SLinus Torvalds case CEXPR_NEQ:
4221da177e4SLinus Torvalds s[++sp] = !ebitmap_get_bit(&e->names, val1 - 1);
4231da177e4SLinus Torvalds break;
4241da177e4SLinus Torvalds default:
4251da177e4SLinus Torvalds BUG();
4261da177e4SLinus Torvalds return 0;
4271da177e4SLinus Torvalds }
4281da177e4SLinus Torvalds break;
4291da177e4SLinus Torvalds default:
4301da177e4SLinus Torvalds BUG();
4311da177e4SLinus Torvalds return 0;
4321da177e4SLinus Torvalds }
4331da177e4SLinus Torvalds }
4341da177e4SLinus Torvalds
4351da177e4SLinus Torvalds BUG_ON(sp != 0);
4361da177e4SLinus Torvalds return s[0];
4371da177e4SLinus Torvalds }
4381da177e4SLinus Torvalds
4391da177e4SLinus Torvalds /*
44044c2d9bdSKaiGai Kohei * security_dump_masked_av - dumps masked permissions during
44144c2d9bdSKaiGai Kohei * security_compute_av due to RBAC, MLS/Constraint and Type bounds.
44244c2d9bdSKaiGai Kohei */
dump_masked_av_helper(void * k,void * d,void * args)44344c2d9bdSKaiGai Kohei static int dump_masked_av_helper(void *k, void *d, void *args)
44444c2d9bdSKaiGai Kohei {
44544c2d9bdSKaiGai Kohei struct perm_datum *pdatum = d;
44644c2d9bdSKaiGai Kohei char **permission_names = args;
44744c2d9bdSKaiGai Kohei
44844c2d9bdSKaiGai Kohei BUG_ON(pdatum->value < 1 || pdatum->value > 32);
44944c2d9bdSKaiGai Kohei
45044c2d9bdSKaiGai Kohei permission_names[pdatum->value - 1] = (char *)k;
45144c2d9bdSKaiGai Kohei
45244c2d9bdSKaiGai Kohei return 0;
45344c2d9bdSKaiGai Kohei }
45444c2d9bdSKaiGai Kohei
security_dump_masked_av(struct policydb * policydb,struct context * scontext,struct context * tcontext,u16 tclass,u32 permissions,const char * reason)455aa8e712cSStephen Smalley static void security_dump_masked_av(struct policydb *policydb,
456aa8e712cSStephen Smalley struct context *scontext,
45744c2d9bdSKaiGai Kohei struct context *tcontext,
45844c2d9bdSKaiGai Kohei u16 tclass,
45944c2d9bdSKaiGai Kohei u32 permissions,
46044c2d9bdSKaiGai Kohei const char *reason)
46144c2d9bdSKaiGai Kohei {
46244c2d9bdSKaiGai Kohei struct common_datum *common_dat;
46344c2d9bdSKaiGai Kohei struct class_datum *tclass_dat;
46444c2d9bdSKaiGai Kohei struct audit_buffer *ab;
46544c2d9bdSKaiGai Kohei char *tclass_name;
46644c2d9bdSKaiGai Kohei char *scontext_name = NULL;
46744c2d9bdSKaiGai Kohei char *tcontext_name = NULL;
46844c2d9bdSKaiGai Kohei char *permission_names[32];
4692da5d31bSJames Morris int index;
4702da5d31bSJames Morris u32 length;
47144c2d9bdSKaiGai Kohei bool need_comma = false;
47244c2d9bdSKaiGai Kohei
47344c2d9bdSKaiGai Kohei if (!permissions)
47444c2d9bdSKaiGai Kohei return;
47544c2d9bdSKaiGai Kohei
476aa8e712cSStephen Smalley tclass_name = sym_name(policydb, SYM_CLASSES, tclass - 1);
477aa8e712cSStephen Smalley tclass_dat = policydb->class_val_to_struct[tclass - 1];
47844c2d9bdSKaiGai Kohei common_dat = tclass_dat->comdatum;
47944c2d9bdSKaiGai Kohei
48044c2d9bdSKaiGai Kohei /* init permission_names */
48144c2d9bdSKaiGai Kohei if (common_dat &&
48203414a49SOndrej Mosnacek hashtab_map(&common_dat->permissions.table,
48344c2d9bdSKaiGai Kohei dump_masked_av_helper, permission_names) < 0)
48444c2d9bdSKaiGai Kohei goto out;
48544c2d9bdSKaiGai Kohei
48603414a49SOndrej Mosnacek if (hashtab_map(&tclass_dat->permissions.table,
48744c2d9bdSKaiGai Kohei dump_masked_av_helper, permission_names) < 0)
48844c2d9bdSKaiGai Kohei goto out;
48944c2d9bdSKaiGai Kohei
49044c2d9bdSKaiGai Kohei /* get scontext/tcontext in text form */
491aa8e712cSStephen Smalley if (context_struct_to_string(policydb, scontext,
49244c2d9bdSKaiGai Kohei &scontext_name, &length) < 0)
49344c2d9bdSKaiGai Kohei goto out;
49444c2d9bdSKaiGai Kohei
495aa8e712cSStephen Smalley if (context_struct_to_string(policydb, tcontext,
49644c2d9bdSKaiGai Kohei &tcontext_name, &length) < 0)
49744c2d9bdSKaiGai Kohei goto out;
49844c2d9bdSKaiGai Kohei
49944c2d9bdSKaiGai Kohei /* audit a message */
500cdfb6b34SRichard Guy Briggs ab = audit_log_start(audit_context(),
50144c2d9bdSKaiGai Kohei GFP_ATOMIC, AUDIT_SELINUX_ERR);
50244c2d9bdSKaiGai Kohei if (!ab)
50344c2d9bdSKaiGai Kohei goto out;
50444c2d9bdSKaiGai Kohei
50544c2d9bdSKaiGai Kohei audit_log_format(ab, "op=security_compute_av reason=%s "
50644c2d9bdSKaiGai Kohei "scontext=%s tcontext=%s tclass=%s perms=",
50744c2d9bdSKaiGai Kohei reason, scontext_name, tcontext_name, tclass_name);
50844c2d9bdSKaiGai Kohei
50944c2d9bdSKaiGai Kohei for (index = 0; index < 32; index++) {
51044c2d9bdSKaiGai Kohei u32 mask = (1 << index);
51144c2d9bdSKaiGai Kohei
51244c2d9bdSKaiGai Kohei if ((mask & permissions) == 0)
51344c2d9bdSKaiGai Kohei continue;
51444c2d9bdSKaiGai Kohei
51544c2d9bdSKaiGai Kohei audit_log_format(ab, "%s%s",
51644c2d9bdSKaiGai Kohei need_comma ? "," : "",
51744c2d9bdSKaiGai Kohei permission_names[index]
51844c2d9bdSKaiGai Kohei ? permission_names[index] : "????");
51944c2d9bdSKaiGai Kohei need_comma = true;
52044c2d9bdSKaiGai Kohei }
52144c2d9bdSKaiGai Kohei audit_log_end(ab);
52244c2d9bdSKaiGai Kohei out:
52344c2d9bdSKaiGai Kohei /* release scontext/tcontext */
52444c2d9bdSKaiGai Kohei kfree(tcontext_name);
52544c2d9bdSKaiGai Kohei kfree(scontext_name);
52644c2d9bdSKaiGai Kohei }
52744c2d9bdSKaiGai Kohei
52844c2d9bdSKaiGai Kohei /*
529d9250deaSKaiGai Kohei * security_boundary_permission - drops violated permissions
530d9250deaSKaiGai Kohei * on boundary constraint.
531d9250deaSKaiGai Kohei */
type_attribute_bounds_av(struct policydb * policydb,struct context * scontext,struct context * tcontext,u16 tclass,struct av_decision * avd)532aa8e712cSStephen Smalley static void type_attribute_bounds_av(struct policydb *policydb,
533aa8e712cSStephen Smalley struct context *scontext,
534d9250deaSKaiGai Kohei struct context *tcontext,
535d9250deaSKaiGai Kohei u16 tclass,
536d9250deaSKaiGai Kohei struct av_decision *avd)
537d9250deaSKaiGai Kohei {
5382ae3ba39SKaiGai Kohei struct context lo_scontext;
5397ea59202SStephen Smalley struct context lo_tcontext, *tcontextp = tcontext;
5402ae3ba39SKaiGai Kohei struct av_decision lo_avd;
54123bdecb0SEric Paris struct type_datum *source;
54223bdecb0SEric Paris struct type_datum *target;
5432ae3ba39SKaiGai Kohei u32 masked = 0;
544d9250deaSKaiGai Kohei
545f07ea1d4SOndrej Mosnacek source = policydb->type_val_to_struct[scontext->type - 1];
54623bdecb0SEric Paris BUG_ON(!source);
54723bdecb0SEric Paris
5487ea59202SStephen Smalley if (!source->bounds)
5497ea59202SStephen Smalley return;
5507ea59202SStephen Smalley
551f07ea1d4SOndrej Mosnacek target = policydb->type_val_to_struct[tcontext->type - 1];
55223bdecb0SEric Paris BUG_ON(!target);
55323bdecb0SEric Paris
554d9250deaSKaiGai Kohei memset(&lo_avd, 0, sizeof(lo_avd));
555d9250deaSKaiGai Kohei
556d9250deaSKaiGai Kohei memcpy(&lo_scontext, scontext, sizeof(lo_scontext));
557d9250deaSKaiGai Kohei lo_scontext.type = source->bounds;
558d9250deaSKaiGai Kohei
5592ae3ba39SKaiGai Kohei if (target->bounds) {
5602ae3ba39SKaiGai Kohei memcpy(&lo_tcontext, tcontext, sizeof(lo_tcontext));
5612ae3ba39SKaiGai Kohei lo_tcontext.type = target->bounds;
5627ea59202SStephen Smalley tcontextp = &lo_tcontext;
5632ae3ba39SKaiGai Kohei }
5642ae3ba39SKaiGai Kohei
565aa8e712cSStephen Smalley context_struct_compute_av(policydb, &lo_scontext,
5667ea59202SStephen Smalley tcontextp,
5672ae3ba39SKaiGai Kohei tclass,
568fa1aa143SJeff Vander Stoep &lo_avd,
569fa1aa143SJeff Vander Stoep NULL);
5702ae3ba39SKaiGai Kohei
5717ea59202SStephen Smalley masked = ~lo_avd.allowed & avd->allowed;
5727ea59202SStephen Smalley
5737ea59202SStephen Smalley if (likely(!masked))
5747ea59202SStephen Smalley return; /* no masked permission */
5757ea59202SStephen Smalley
576d9250deaSKaiGai Kohei /* mask violated permissions */
577d9250deaSKaiGai Kohei avd->allowed &= ~masked;
578d9250deaSKaiGai Kohei
57944c2d9bdSKaiGai Kohei /* audit masked permissions */
580aa8e712cSStephen Smalley security_dump_masked_av(policydb, scontext, tcontext,
58144c2d9bdSKaiGai Kohei tclass, masked, "bounds");
582d9250deaSKaiGai Kohei }
583d9250deaSKaiGai Kohei
584d9250deaSKaiGai Kohei /*
585fa1aa143SJeff Vander Stoep * flag which drivers have permissions
5863d9047a0SChristian Göttsche * only looking for ioctl based extended permissions
587fa1aa143SJeff Vander Stoep */
services_compute_xperms_drivers(struct extended_perms * xperms,struct avtab_node * node)588fa1aa143SJeff Vander Stoep void services_compute_xperms_drivers(
589fa1aa143SJeff Vander Stoep struct extended_perms *xperms,
590fa1aa143SJeff Vander Stoep struct avtab_node *node)
591fa1aa143SJeff Vander Stoep {
592fa1aa143SJeff Vander Stoep unsigned int i;
593fa1aa143SJeff Vander Stoep
594fa1aa143SJeff Vander Stoep if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) {
595fa1aa143SJeff Vander Stoep /* if one or more driver has all permissions allowed */
596fa1aa143SJeff Vander Stoep for (i = 0; i < ARRAY_SIZE(xperms->drivers.p); i++)
597fa1aa143SJeff Vander Stoep xperms->drivers.p[i] |= node->datum.u.xperms->perms.p[i];
598fa1aa143SJeff Vander Stoep } else if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) {
599fa1aa143SJeff Vander Stoep /* if allowing permissions within a driver */
600fa1aa143SJeff Vander Stoep security_xperm_set(xperms->drivers.p,
601fa1aa143SJeff Vander Stoep node->datum.u.xperms->driver);
602fa1aa143SJeff Vander Stoep }
603fa1aa143SJeff Vander Stoep
604fa1aa143SJeff Vander Stoep xperms->len = 1;
605fa1aa143SJeff Vander Stoep }
606fa1aa143SJeff Vander Stoep
607fa1aa143SJeff Vander Stoep /*
608fa1aa143SJeff Vander Stoep * Compute access vectors and extended permissions based on a context
609fa1aa143SJeff Vander Stoep * structure pair for the permissions in a particular class.
6101da177e4SLinus Torvalds */
context_struct_compute_av(struct policydb * policydb,struct context * scontext,struct context * tcontext,u16 tclass,struct av_decision * avd,struct extended_perms * xperms)611aa8e712cSStephen Smalley static void context_struct_compute_av(struct policydb *policydb,
612aa8e712cSStephen Smalley struct context *scontext,
6131da177e4SLinus Torvalds struct context *tcontext,
6141da177e4SLinus Torvalds u16 tclass,
615fa1aa143SJeff Vander Stoep struct av_decision *avd,
616fa1aa143SJeff Vander Stoep struct extended_perms *xperms)
6171da177e4SLinus Torvalds {
6181da177e4SLinus Torvalds struct constraint_node *constraint;
6191da177e4SLinus Torvalds struct role_allow *ra;
6201da177e4SLinus Torvalds struct avtab_key avkey;
621782ebb99SStephen Smalley struct avtab_node *node;
6221da177e4SLinus Torvalds struct class_datum *tclass_datum;
623782ebb99SStephen Smalley struct ebitmap *sattr, *tattr;
624782ebb99SStephen Smalley struct ebitmap_node *snode, *tnode;
625782ebb99SStephen Smalley unsigned int i, j;
6261da177e4SLinus Torvalds
6271da177e4SLinus Torvalds avd->allowed = 0;
6281da177e4SLinus Torvalds avd->auditallow = 0;
6291da177e4SLinus Torvalds avd->auditdeny = 0xffffffff;
630fa1aa143SJeff Vander Stoep if (xperms) {
631fa1aa143SJeff Vander Stoep memset(&xperms->drivers, 0, sizeof(xperms->drivers));
632fa1aa143SJeff Vander Stoep xperms->len = 0;
633fa1aa143SJeff Vander Stoep }
6341da177e4SLinus Torvalds
635aa8e712cSStephen Smalley if (unlikely(!tclass || tclass > policydb->p_classes.nprim)) {
636c6d3aaa4SStephen Smalley if (printk_ratelimit())
637b54c85c1Speter enderborg pr_warn("SELinux: Invalid class %hu\n", tclass);
63819439d05SStephen Smalley return;
639c6d3aaa4SStephen Smalley }
6403f12070eSEric Paris
641aa8e712cSStephen Smalley tclass_datum = policydb->class_val_to_struct[tclass - 1];
6423f12070eSEric Paris
6433f12070eSEric Paris /*
6441da177e4SLinus Torvalds * If a specific type enforcement rule was defined for
6451da177e4SLinus Torvalds * this permission check, then use it.
6461da177e4SLinus Torvalds */
6471da177e4SLinus Torvalds avkey.target_class = tclass;
648fa1aa143SJeff Vander Stoep avkey.specified = AVTAB_AV | AVTAB_XPERMS;
649acdf52d9SKent Overstreet sattr = &policydb->type_attr_map_array[scontext->type - 1];
650acdf52d9SKent Overstreet tattr = &policydb->type_attr_map_array[tcontext->type - 1];
6519fe79ad1SKaiGai Kohei ebitmap_for_each_positive_bit(sattr, snode, i) {
6529fe79ad1SKaiGai Kohei ebitmap_for_each_positive_bit(tattr, tnode, j) {
653782ebb99SStephen Smalley avkey.source_type = i + 1;
654782ebb99SStephen Smalley avkey.target_type = j + 1;
655aa8e712cSStephen Smalley for (node = avtab_search_node(&policydb->te_avtab,
656aa8e712cSStephen Smalley &avkey);
657dbc74c65SVesa-Matti Kari node;
658782ebb99SStephen Smalley node = avtab_search_node_next(node, avkey.specified)) {
659782ebb99SStephen Smalley if (node->key.specified == AVTAB_ALLOWED)
660fa1aa143SJeff Vander Stoep avd->allowed |= node->datum.u.data;
661782ebb99SStephen Smalley else if (node->key.specified == AVTAB_AUDITALLOW)
662fa1aa143SJeff Vander Stoep avd->auditallow |= node->datum.u.data;
663782ebb99SStephen Smalley else if (node->key.specified == AVTAB_AUDITDENY)
664fa1aa143SJeff Vander Stoep avd->auditdeny &= node->datum.u.data;
665fa1aa143SJeff Vander Stoep else if (xperms && (node->key.specified & AVTAB_XPERMS))
666fa1aa143SJeff Vander Stoep services_compute_xperms_drivers(xperms, node);
6671da177e4SLinus Torvalds }
6681da177e4SLinus Torvalds
6691da177e4SLinus Torvalds /* Check conditional av table for additional permissions */
670aa8e712cSStephen Smalley cond_compute_av(&policydb->te_cond_avtab, &avkey,
671fa1aa143SJeff Vander Stoep avd, xperms);
6721da177e4SLinus Torvalds
673782ebb99SStephen Smalley }
674782ebb99SStephen Smalley }
675782ebb99SStephen Smalley
6761da177e4SLinus Torvalds /*
6771da177e4SLinus Torvalds * Remove any permissions prohibited by a constraint (this includes
6781da177e4SLinus Torvalds * the MLS policy).
6791da177e4SLinus Torvalds */
6801da177e4SLinus Torvalds constraint = tclass_datum->constraints;
6811da177e4SLinus Torvalds while (constraint) {
6821da177e4SLinus Torvalds if ((constraint->permissions & (avd->allowed)) &&
683aa8e712cSStephen Smalley !constraint_expr_eval(policydb, scontext, tcontext, NULL,
6841da177e4SLinus Torvalds constraint->expr)) {
685caabbdc0SKaiGai Kohei avd->allowed &= ~(constraint->permissions);
6861da177e4SLinus Torvalds }
6871da177e4SLinus Torvalds constraint = constraint->next;
6881da177e4SLinus Torvalds }
6891da177e4SLinus Torvalds
6901da177e4SLinus Torvalds /*
6911da177e4SLinus Torvalds * If checking process transition permission and the
6921da177e4SLinus Torvalds * role is changing, then check the (current_role, new_role)
6931da177e4SLinus Torvalds * pair.
6941da177e4SLinus Torvalds */
695aa8e712cSStephen Smalley if (tclass == policydb->process_class &&
696aa8e712cSStephen Smalley (avd->allowed & policydb->process_trans_perms) &&
6971da177e4SLinus Torvalds scontext->role != tcontext->role) {
698aa8e712cSStephen Smalley for (ra = policydb->role_allow; ra; ra = ra->next) {
6991da177e4SLinus Torvalds if (scontext->role == ra->role &&
7001da177e4SLinus Torvalds tcontext->role == ra->new_role)
7011da177e4SLinus Torvalds break;
7021da177e4SLinus Torvalds }
7031da177e4SLinus Torvalds if (!ra)
704aa8e712cSStephen Smalley avd->allowed &= ~policydb->process_trans_perms;
7051da177e4SLinus Torvalds }
7061da177e4SLinus Torvalds
707d9250deaSKaiGai Kohei /*
708d9250deaSKaiGai Kohei * If the given source and target types have boundary
709d9250deaSKaiGai Kohei * constraint, lazy checks have to mask any violated
710d9250deaSKaiGai Kohei * permission and notice it to userspace via audit.
711d9250deaSKaiGai Kohei */
712aa8e712cSStephen Smalley type_attribute_bounds_av(policydb, scontext, tcontext,
71319439d05SStephen Smalley tclass, avd);
71422df4adbSStephen Smalley }
71522df4adbSStephen Smalley
security_validtrans_handle_fail(struct selinux_policy * policy,struct sidtab_entry * oentry,struct sidtab_entry * nentry,struct sidtab_entry * tentry,u16 tclass)716e67b7985SStephen Smalley static int security_validtrans_handle_fail(struct selinux_policy *policy,
717d97bd23cSOndrej Mosnacek struct sidtab_entry *oentry,
718d97bd23cSOndrej Mosnacek struct sidtab_entry *nentry,
719d97bd23cSOndrej Mosnacek struct sidtab_entry *tentry,
7201da177e4SLinus Torvalds u16 tclass)
7211da177e4SLinus Torvalds {
7221b8b31a2SStephen Smalley struct policydb *p = &policy->policydb;
7231b8b31a2SStephen Smalley struct sidtab *sidtab = policy->sidtab;
7241da177e4SLinus Torvalds char *o = NULL, *n = NULL, *t = NULL;
7251da177e4SLinus Torvalds u32 olen, nlen, tlen;
7261da177e4SLinus Torvalds
727d97bd23cSOndrej Mosnacek if (sidtab_entry_to_string(p, sidtab, oentry, &o, &olen))
7281da177e4SLinus Torvalds goto out;
729d97bd23cSOndrej Mosnacek if (sidtab_entry_to_string(p, sidtab, nentry, &n, &nlen))
7301da177e4SLinus Torvalds goto out;
731d97bd23cSOndrej Mosnacek if (sidtab_entry_to_string(p, sidtab, tentry, &t, &tlen))
7321da177e4SLinus Torvalds goto out;
733cdfb6b34SRichard Guy Briggs audit_log(audit_context(), GFP_ATOMIC, AUDIT_SELINUX_ERR,
7344093a844SRichard Guy Briggs "op=security_validate_transition seresult=denied"
7351da177e4SLinus Torvalds " oldcontext=%s newcontext=%s taskcontext=%s tclass=%s",
736aa8e712cSStephen Smalley o, n, t, sym_name(p, SYM_CLASSES, tclass-1));
7371da177e4SLinus Torvalds out:
7381da177e4SLinus Torvalds kfree(o);
7391da177e4SLinus Torvalds kfree(n);
7401da177e4SLinus Torvalds kfree(t);
7411da177e4SLinus Torvalds
742e67b7985SStephen Smalley if (!enforcing_enabled())
7431da177e4SLinus Torvalds return 0;
7441da177e4SLinus Torvalds return -EPERM;
7451da177e4SLinus Torvalds }
7461da177e4SLinus Torvalds
security_compute_validatetrans(u32 oldsid,u32 newsid,u32 tasksid,u16 orig_tclass,bool user)747e67b7985SStephen Smalley static int security_compute_validatetrans(u32 oldsid, u32 newsid, u32 tasksid,
748f9df6458SAndrew Perepechko u16 orig_tclass, bool user)
7491da177e4SLinus Torvalds {
7501b8b31a2SStephen Smalley struct selinux_policy *policy;
751aa8e712cSStephen Smalley struct policydb *policydb;
752aa8e712cSStephen Smalley struct sidtab *sidtab;
753d97bd23cSOndrej Mosnacek struct sidtab_entry *oentry;
754d97bd23cSOndrej Mosnacek struct sidtab_entry *nentry;
755d97bd23cSOndrej Mosnacek struct sidtab_entry *tentry;
7561da177e4SLinus Torvalds struct class_datum *tclass_datum;
7571da177e4SLinus Torvalds struct constraint_node *constraint;
758c6d3aaa4SStephen Smalley u16 tclass;
7591da177e4SLinus Torvalds int rc = 0;
7601da177e4SLinus Torvalds
761aa8e712cSStephen Smalley
762e67b7985SStephen Smalley if (!selinux_initialized())
7631da177e4SLinus Torvalds return 0;
7641da177e4SLinus Torvalds
7651b8b31a2SStephen Smalley rcu_read_lock();
766aa8e712cSStephen Smalley
767e67b7985SStephen Smalley policy = rcu_dereference(selinux_state.policy);
7681b8b31a2SStephen Smalley policydb = &policy->policydb;
7691b8b31a2SStephen Smalley sidtab = policy->sidtab;
7701da177e4SLinus Torvalds
771f9df6458SAndrew Perepechko if (!user)
7721b8b31a2SStephen Smalley tclass = unmap_class(&policy->map, orig_tclass);
773f9df6458SAndrew Perepechko else
774f9df6458SAndrew Perepechko tclass = orig_tclass;
775c6d3aaa4SStephen Smalley
776aa8e712cSStephen Smalley if (!tclass || tclass > policydb->p_classes.nprim) {
7771da177e4SLinus Torvalds rc = -EINVAL;
7781da177e4SLinus Torvalds goto out;
7791da177e4SLinus Torvalds }
780aa8e712cSStephen Smalley tclass_datum = policydb->class_val_to_struct[tclass - 1];
7811da177e4SLinus Torvalds
782d97bd23cSOndrej Mosnacek oentry = sidtab_search_entry(sidtab, oldsid);
783d97bd23cSOndrej Mosnacek if (!oentry) {
784b54c85c1Speter enderborg pr_err("SELinux: %s: unrecognized SID %d\n",
785744ba35eSEric Paris __func__, oldsid);
7861da177e4SLinus Torvalds rc = -EINVAL;
7871da177e4SLinus Torvalds goto out;
7881da177e4SLinus Torvalds }
7891da177e4SLinus Torvalds
790d97bd23cSOndrej Mosnacek nentry = sidtab_search_entry(sidtab, newsid);
791d97bd23cSOndrej Mosnacek if (!nentry) {
792b54c85c1Speter enderborg pr_err("SELinux: %s: unrecognized SID %d\n",
793744ba35eSEric Paris __func__, newsid);
7941da177e4SLinus Torvalds rc = -EINVAL;
7951da177e4SLinus Torvalds goto out;
7961da177e4SLinus Torvalds }
7971da177e4SLinus Torvalds
798d97bd23cSOndrej Mosnacek tentry = sidtab_search_entry(sidtab, tasksid);
799d97bd23cSOndrej Mosnacek if (!tentry) {
800b54c85c1Speter enderborg pr_err("SELinux: %s: unrecognized SID %d\n",
801744ba35eSEric Paris __func__, tasksid);
8021da177e4SLinus Torvalds rc = -EINVAL;
8031da177e4SLinus Torvalds goto out;
8041da177e4SLinus Torvalds }
8051da177e4SLinus Torvalds
8061da177e4SLinus Torvalds constraint = tclass_datum->validatetrans;
8071da177e4SLinus Torvalds while (constraint) {
808d97bd23cSOndrej Mosnacek if (!constraint_expr_eval(policydb, &oentry->context,
809d97bd23cSOndrej Mosnacek &nentry->context, &tentry->context,
810d97bd23cSOndrej Mosnacek constraint->expr)) {
811f9df6458SAndrew Perepechko if (user)
812f9df6458SAndrew Perepechko rc = -EPERM;
813f9df6458SAndrew Perepechko else
814e67b7985SStephen Smalley rc = security_validtrans_handle_fail(policy,
815d97bd23cSOndrej Mosnacek oentry,
816d97bd23cSOndrej Mosnacek nentry,
817d97bd23cSOndrej Mosnacek tentry,
818f9df6458SAndrew Perepechko tclass);
8191da177e4SLinus Torvalds goto out;
8201da177e4SLinus Torvalds }
8211da177e4SLinus Torvalds constraint = constraint->next;
8221da177e4SLinus Torvalds }
8231da177e4SLinus Torvalds
8241da177e4SLinus Torvalds out:
8251b8b31a2SStephen Smalley rcu_read_unlock();
8261da177e4SLinus Torvalds return rc;
8271da177e4SLinus Torvalds }
8281da177e4SLinus Torvalds
security_validate_transition_user(u32 oldsid,u32 newsid,u32 tasksid,u16 tclass)829e67b7985SStephen Smalley int security_validate_transition_user(u32 oldsid, u32 newsid, u32 tasksid,
830f9df6458SAndrew Perepechko u16 tclass)
831f9df6458SAndrew Perepechko {
832e67b7985SStephen Smalley return security_compute_validatetrans(oldsid, newsid, tasksid,
833f9df6458SAndrew Perepechko tclass, true);
834f9df6458SAndrew Perepechko }
835f9df6458SAndrew Perepechko
security_validate_transition(u32 oldsid,u32 newsid,u32 tasksid,u16 orig_tclass)836e67b7985SStephen Smalley int security_validate_transition(u32 oldsid, u32 newsid, u32 tasksid,
837f9df6458SAndrew Perepechko u16 orig_tclass)
838f9df6458SAndrew Perepechko {
839e67b7985SStephen Smalley return security_compute_validatetrans(oldsid, newsid, tasksid,
840f9df6458SAndrew Perepechko orig_tclass, false);
841f9df6458SAndrew Perepechko }
842f9df6458SAndrew Perepechko
843d9250deaSKaiGai Kohei /*
844d9250deaSKaiGai Kohei * security_bounded_transition - check whether the given
845d9250deaSKaiGai Kohei * transition is directed to bounded, or not.
846d9250deaSKaiGai Kohei * It returns 0, if @newsid is bounded by @oldsid.
847d9250deaSKaiGai Kohei * Otherwise, it returns error code.
848d9250deaSKaiGai Kohei *
849d9250deaSKaiGai Kohei * @oldsid : current security identifier
850d9250deaSKaiGai Kohei * @newsid : destinated security identifier
851d9250deaSKaiGai Kohei */
security_bounded_transition(u32 old_sid,u32 new_sid)852e67b7985SStephen Smalley int security_bounded_transition(u32 old_sid, u32 new_sid)
853d9250deaSKaiGai Kohei {
8541b8b31a2SStephen Smalley struct selinux_policy *policy;
855aa8e712cSStephen Smalley struct policydb *policydb;
856aa8e712cSStephen Smalley struct sidtab *sidtab;
857d97bd23cSOndrej Mosnacek struct sidtab_entry *old_entry, *new_entry;
858d9250deaSKaiGai Kohei struct type_datum *type;
859c50e125dSChristian Göttsche u32 index;
8604b02b524SEric Paris int rc;
861d9250deaSKaiGai Kohei
862e67b7985SStephen Smalley if (!selinux_initialized())
8634b14752eSPaul Moore return 0;
8644b14752eSPaul Moore
8651b8b31a2SStephen Smalley rcu_read_lock();
866e67b7985SStephen Smalley policy = rcu_dereference(selinux_state.policy);
8671b8b31a2SStephen Smalley policydb = &policy->policydb;
8681b8b31a2SStephen Smalley sidtab = policy->sidtab;
869d9250deaSKaiGai Kohei
8704b02b524SEric Paris rc = -EINVAL;
871d97bd23cSOndrej Mosnacek old_entry = sidtab_search_entry(sidtab, old_sid);
872d97bd23cSOndrej Mosnacek if (!old_entry) {
873b54c85c1Speter enderborg pr_err("SELinux: %s: unrecognized SID %u\n",
874d9250deaSKaiGai Kohei __func__, old_sid);
875d9250deaSKaiGai Kohei goto out;
876d9250deaSKaiGai Kohei }
877d9250deaSKaiGai Kohei
8784b02b524SEric Paris rc = -EINVAL;
879d97bd23cSOndrej Mosnacek new_entry = sidtab_search_entry(sidtab, new_sid);
880d97bd23cSOndrej Mosnacek if (!new_entry) {
881b54c85c1Speter enderborg pr_err("SELinux: %s: unrecognized SID %u\n",
882d9250deaSKaiGai Kohei __func__, new_sid);
883d9250deaSKaiGai Kohei goto out;
884d9250deaSKaiGai Kohei }
885d9250deaSKaiGai Kohei
886d9250deaSKaiGai Kohei rc = 0;
8874b02b524SEric Paris /* type/domain unchanged */
888d97bd23cSOndrej Mosnacek if (old_entry->context.type == new_entry->context.type)
889d9250deaSKaiGai Kohei goto out;
890d9250deaSKaiGai Kohei
891d97bd23cSOndrej Mosnacek index = new_entry->context.type;
892d9250deaSKaiGai Kohei while (true) {
893f07ea1d4SOndrej Mosnacek type = policydb->type_val_to_struct[index - 1];
894d9250deaSKaiGai Kohei BUG_ON(!type);
895d9250deaSKaiGai Kohei
896d9250deaSKaiGai Kohei /* not bounded anymore */
897d9250deaSKaiGai Kohei rc = -EPERM;
8984b02b524SEric Paris if (!type->bounds)
899d9250deaSKaiGai Kohei break;
900d9250deaSKaiGai Kohei
901d9250deaSKaiGai Kohei /* @newsid is bounded by @oldsid */
902d9250deaSKaiGai Kohei rc = 0;
903d97bd23cSOndrej Mosnacek if (type->bounds == old_entry->context.type)
904d9250deaSKaiGai Kohei break;
9054b02b524SEric Paris
906d9250deaSKaiGai Kohei index = type->bounds;
907d9250deaSKaiGai Kohei }
90844c2d9bdSKaiGai Kohei
90944c2d9bdSKaiGai Kohei if (rc) {
91044c2d9bdSKaiGai Kohei char *old_name = NULL;
91144c2d9bdSKaiGai Kohei char *new_name = NULL;
9122da5d31bSJames Morris u32 length;
91344c2d9bdSKaiGai Kohei
914d97bd23cSOndrej Mosnacek if (!sidtab_entry_to_string(policydb, sidtab, old_entry,
91544c2d9bdSKaiGai Kohei &old_name, &length) &&
916d97bd23cSOndrej Mosnacek !sidtab_entry_to_string(policydb, sidtab, new_entry,
91744c2d9bdSKaiGai Kohei &new_name, &length)) {
918cdfb6b34SRichard Guy Briggs audit_log(audit_context(),
91944c2d9bdSKaiGai Kohei GFP_ATOMIC, AUDIT_SELINUX_ERR,
92044c2d9bdSKaiGai Kohei "op=security_bounded_transition "
9214093a844SRichard Guy Briggs "seresult=denied "
92244c2d9bdSKaiGai Kohei "oldcontext=%s newcontext=%s",
92344c2d9bdSKaiGai Kohei old_name, new_name);
92444c2d9bdSKaiGai Kohei }
92544c2d9bdSKaiGai Kohei kfree(new_name);
92644c2d9bdSKaiGai Kohei kfree(old_name);
92744c2d9bdSKaiGai Kohei }
928d9250deaSKaiGai Kohei out:
9291b8b31a2SStephen Smalley rcu_read_unlock();
930d9250deaSKaiGai Kohei
931d9250deaSKaiGai Kohei return rc;
932d9250deaSKaiGai Kohei }
933d9250deaSKaiGai Kohei
avd_init(struct selinux_policy * policy,struct av_decision * avd)9341b8b31a2SStephen Smalley static void avd_init(struct selinux_policy *policy, struct av_decision *avd)
935c6d3aaa4SStephen Smalley {
93619439d05SStephen Smalley avd->allowed = 0;
93719439d05SStephen Smalley avd->auditallow = 0;
93819439d05SStephen Smalley avd->auditdeny = 0xffffffff;
9391b8b31a2SStephen Smalley if (policy)
9401b8b31a2SStephen Smalley avd->seqno = policy->latest_granting;
9411b8b31a2SStephen Smalley else
9421b8b31a2SStephen Smalley avd->seqno = 0;
94319439d05SStephen Smalley avd->flags = 0;
944c6d3aaa4SStephen Smalley }
945c6d3aaa4SStephen Smalley
services_compute_xperms_decision(struct extended_perms_decision * xpermd,struct avtab_node * node)946fa1aa143SJeff Vander Stoep void services_compute_xperms_decision(struct extended_perms_decision *xpermd,
947fa1aa143SJeff Vander Stoep struct avtab_node *node)
948fa1aa143SJeff Vander Stoep {
949fa1aa143SJeff Vander Stoep unsigned int i;
950fa1aa143SJeff Vander Stoep
951fa1aa143SJeff Vander Stoep if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) {
952fa1aa143SJeff Vander Stoep if (xpermd->driver != node->datum.u.xperms->driver)
953fa1aa143SJeff Vander Stoep return;
954fa1aa143SJeff Vander Stoep } else if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) {
955fa1aa143SJeff Vander Stoep if (!security_xperm_test(node->datum.u.xperms->perms.p,
956fa1aa143SJeff Vander Stoep xpermd->driver))
957fa1aa143SJeff Vander Stoep return;
958fa1aa143SJeff Vander Stoep } else {
959*c1dbd28aSThiébaud Weksteen pr_warn_once(
960*c1dbd28aSThiébaud Weksteen "SELinux: unknown extended permission (%u) will be ignored\n",
961*c1dbd28aSThiébaud Weksteen node->datum.u.xperms->specified);
962*c1dbd28aSThiébaud Weksteen return;
963fa1aa143SJeff Vander Stoep }
964fa1aa143SJeff Vander Stoep
965fa1aa143SJeff Vander Stoep if (node->key.specified == AVTAB_XPERMS_ALLOWED) {
966fa1aa143SJeff Vander Stoep xpermd->used |= XPERMS_ALLOWED;
967fa1aa143SJeff Vander Stoep if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) {
968fa1aa143SJeff Vander Stoep memset(xpermd->allowed->p, 0xff,
969fa1aa143SJeff Vander Stoep sizeof(xpermd->allowed->p));
970fa1aa143SJeff Vander Stoep }
971fa1aa143SJeff Vander Stoep if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) {
972fa1aa143SJeff Vander Stoep for (i = 0; i < ARRAY_SIZE(xpermd->allowed->p); i++)
973fa1aa143SJeff Vander Stoep xpermd->allowed->p[i] |=
974fa1aa143SJeff Vander Stoep node->datum.u.xperms->perms.p[i];
975fa1aa143SJeff Vander Stoep }
976fa1aa143SJeff Vander Stoep } else if (node->key.specified == AVTAB_XPERMS_AUDITALLOW) {
977fa1aa143SJeff Vander Stoep xpermd->used |= XPERMS_AUDITALLOW;
978fa1aa143SJeff Vander Stoep if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) {
979fa1aa143SJeff Vander Stoep memset(xpermd->auditallow->p, 0xff,
980fa1aa143SJeff Vander Stoep sizeof(xpermd->auditallow->p));
981fa1aa143SJeff Vander Stoep }
982fa1aa143SJeff Vander Stoep if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) {
983fa1aa143SJeff Vander Stoep for (i = 0; i < ARRAY_SIZE(xpermd->auditallow->p); i++)
984fa1aa143SJeff Vander Stoep xpermd->auditallow->p[i] |=
985fa1aa143SJeff Vander Stoep node->datum.u.xperms->perms.p[i];
986fa1aa143SJeff Vander Stoep }
987fa1aa143SJeff Vander Stoep } else if (node->key.specified == AVTAB_XPERMS_DONTAUDIT) {
988fa1aa143SJeff Vander Stoep xpermd->used |= XPERMS_DONTAUDIT;
989fa1aa143SJeff Vander Stoep if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) {
990fa1aa143SJeff Vander Stoep memset(xpermd->dontaudit->p, 0xff,
991fa1aa143SJeff Vander Stoep sizeof(xpermd->dontaudit->p));
992fa1aa143SJeff Vander Stoep }
993fa1aa143SJeff Vander Stoep if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) {
994fa1aa143SJeff Vander Stoep for (i = 0; i < ARRAY_SIZE(xpermd->dontaudit->p); i++)
995fa1aa143SJeff Vander Stoep xpermd->dontaudit->p[i] |=
996fa1aa143SJeff Vander Stoep node->datum.u.xperms->perms.p[i];
997fa1aa143SJeff Vander Stoep }
998fa1aa143SJeff Vander Stoep } else {
999*c1dbd28aSThiébaud Weksteen pr_warn_once("SELinux: unknown specified key (%u)\n",
1000*c1dbd28aSThiébaud Weksteen node->key.specified);
1001fa1aa143SJeff Vander Stoep }
1002fa1aa143SJeff Vander Stoep }
1003fa1aa143SJeff Vander Stoep
security_compute_xperms_decision(u32 ssid,u32 tsid,u16 orig_tclass,u8 driver,struct extended_perms_decision * xpermd)1004e67b7985SStephen Smalley void security_compute_xperms_decision(u32 ssid,
1005fa1aa143SJeff Vander Stoep u32 tsid,
1006fa1aa143SJeff Vander Stoep u16 orig_tclass,
1007fa1aa143SJeff Vander Stoep u8 driver,
1008fa1aa143SJeff Vander Stoep struct extended_perms_decision *xpermd)
1009fa1aa143SJeff Vander Stoep {
10101b8b31a2SStephen Smalley struct selinux_policy *policy;
1011aa8e712cSStephen Smalley struct policydb *policydb;
1012aa8e712cSStephen Smalley struct sidtab *sidtab;
1013fa1aa143SJeff Vander Stoep u16 tclass;
1014fa1aa143SJeff Vander Stoep struct context *scontext, *tcontext;
1015fa1aa143SJeff Vander Stoep struct avtab_key avkey;
1016fa1aa143SJeff Vander Stoep struct avtab_node *node;
1017fa1aa143SJeff Vander Stoep struct ebitmap *sattr, *tattr;
1018fa1aa143SJeff Vander Stoep struct ebitmap_node *snode, *tnode;
1019fa1aa143SJeff Vander Stoep unsigned int i, j;
1020fa1aa143SJeff Vander Stoep
1021fa1aa143SJeff Vander Stoep xpermd->driver = driver;
1022fa1aa143SJeff Vander Stoep xpermd->used = 0;
1023fa1aa143SJeff Vander Stoep memset(xpermd->allowed->p, 0, sizeof(xpermd->allowed->p));
1024fa1aa143SJeff Vander Stoep memset(xpermd->auditallow->p, 0, sizeof(xpermd->auditallow->p));
1025fa1aa143SJeff Vander Stoep memset(xpermd->dontaudit->p, 0, sizeof(xpermd->dontaudit->p));
1026fa1aa143SJeff Vander Stoep
10271b8b31a2SStephen Smalley rcu_read_lock();
1028e67b7985SStephen Smalley if (!selinux_initialized())
1029fa1aa143SJeff Vander Stoep goto allow;
1030fa1aa143SJeff Vander Stoep
1031e67b7985SStephen Smalley policy = rcu_dereference(selinux_state.policy);
10321b8b31a2SStephen Smalley policydb = &policy->policydb;
10331b8b31a2SStephen Smalley sidtab = policy->sidtab;
1034aa8e712cSStephen Smalley
1035aa8e712cSStephen Smalley scontext = sidtab_search(sidtab, ssid);
1036fa1aa143SJeff Vander Stoep if (!scontext) {
1037b54c85c1Speter enderborg pr_err("SELinux: %s: unrecognized SID %d\n",
1038fa1aa143SJeff Vander Stoep __func__, ssid);
1039fa1aa143SJeff Vander Stoep goto out;
1040fa1aa143SJeff Vander Stoep }
1041fa1aa143SJeff Vander Stoep
1042aa8e712cSStephen Smalley tcontext = sidtab_search(sidtab, tsid);
1043fa1aa143SJeff Vander Stoep if (!tcontext) {
1044b54c85c1Speter enderborg pr_err("SELinux: %s: unrecognized SID %d\n",
1045fa1aa143SJeff Vander Stoep __func__, tsid);
1046fa1aa143SJeff Vander Stoep goto out;
1047fa1aa143SJeff Vander Stoep }
1048fa1aa143SJeff Vander Stoep
10491b8b31a2SStephen Smalley tclass = unmap_class(&policy->map, orig_tclass);
1050fa1aa143SJeff Vander Stoep if (unlikely(orig_tclass && !tclass)) {
1051aa8e712cSStephen Smalley if (policydb->allow_unknown)
1052fa1aa143SJeff Vander Stoep goto allow;
1053fa1aa143SJeff Vander Stoep goto out;
1054fa1aa143SJeff Vander Stoep }
1055fa1aa143SJeff Vander Stoep
1056fa1aa143SJeff Vander Stoep
1057aa8e712cSStephen Smalley if (unlikely(!tclass || tclass > policydb->p_classes.nprim)) {
1058fa1aa143SJeff Vander Stoep pr_warn_ratelimited("SELinux: Invalid class %hu\n", tclass);
1059fa1aa143SJeff Vander Stoep goto out;
1060fa1aa143SJeff Vander Stoep }
1061fa1aa143SJeff Vander Stoep
1062fa1aa143SJeff Vander Stoep avkey.target_class = tclass;
1063fa1aa143SJeff Vander Stoep avkey.specified = AVTAB_XPERMS;
1064acdf52d9SKent Overstreet sattr = &policydb->type_attr_map_array[scontext->type - 1];
1065acdf52d9SKent Overstreet tattr = &policydb->type_attr_map_array[tcontext->type - 1];
1066fa1aa143SJeff Vander Stoep ebitmap_for_each_positive_bit(sattr, snode, i) {
1067fa1aa143SJeff Vander Stoep ebitmap_for_each_positive_bit(tattr, tnode, j) {
1068fa1aa143SJeff Vander Stoep avkey.source_type = i + 1;
1069fa1aa143SJeff Vander Stoep avkey.target_type = j + 1;
1070aa8e712cSStephen Smalley for (node = avtab_search_node(&policydb->te_avtab,
1071aa8e712cSStephen Smalley &avkey);
1072fa1aa143SJeff Vander Stoep node;
1073fa1aa143SJeff Vander Stoep node = avtab_search_node_next(node, avkey.specified))
1074fa1aa143SJeff Vander Stoep services_compute_xperms_decision(xpermd, node);
1075fa1aa143SJeff Vander Stoep
1076aa8e712cSStephen Smalley cond_compute_xperms(&policydb->te_cond_avtab,
1077fa1aa143SJeff Vander Stoep &avkey, xpermd);
1078fa1aa143SJeff Vander Stoep }
1079fa1aa143SJeff Vander Stoep }
1080fa1aa143SJeff Vander Stoep out:
10811b8b31a2SStephen Smalley rcu_read_unlock();
1082fa1aa143SJeff Vander Stoep return;
1083fa1aa143SJeff Vander Stoep allow:
1084fa1aa143SJeff Vander Stoep memset(xpermd->allowed->p, 0xff, sizeof(xpermd->allowed->p));
1085fa1aa143SJeff Vander Stoep goto out;
1086fa1aa143SJeff Vander Stoep }
1087c6d3aaa4SStephen Smalley
10881da177e4SLinus Torvalds /**
10891da177e4SLinus Torvalds * security_compute_av - Compute access vector decisions.
10901da177e4SLinus Torvalds * @ssid: source security identifier
10911da177e4SLinus Torvalds * @tsid: target security identifier
1092e9fd7292SPaul Moore * @orig_tclass: target security class
10931da177e4SLinus Torvalds * @avd: access vector decisions
1094fa1aa143SJeff Vander Stoep * @xperms: extended permissions
10951da177e4SLinus Torvalds *
10961da177e4SLinus Torvalds * Compute a set of access vector decisions based on the
10971da177e4SLinus Torvalds * SID pair (@ssid, @tsid) for the permissions in @tclass.
10981da177e4SLinus Torvalds */
security_compute_av(u32 ssid,u32 tsid,u16 orig_tclass,struct av_decision * avd,struct extended_perms * xperms)1099e67b7985SStephen Smalley void security_compute_av(u32 ssid,
11001da177e4SLinus Torvalds u32 tsid,
1101c6d3aaa4SStephen Smalley u16 orig_tclass,
1102fa1aa143SJeff Vander Stoep struct av_decision *avd,
1103fa1aa143SJeff Vander Stoep struct extended_perms *xperms)
1104c6d3aaa4SStephen Smalley {
11051b8b31a2SStephen Smalley struct selinux_policy *policy;
1106aa8e712cSStephen Smalley struct policydb *policydb;
1107aa8e712cSStephen Smalley struct sidtab *sidtab;
1108c6d3aaa4SStephen Smalley u16 tclass;
110919439d05SStephen Smalley struct context *scontext = NULL, *tcontext = NULL;
1110c6d3aaa4SStephen Smalley
11111b8b31a2SStephen Smalley rcu_read_lock();
1112e67b7985SStephen Smalley policy = rcu_dereference(selinux_state.policy);
11131b8b31a2SStephen Smalley avd_init(policy, avd);
1114fa1aa143SJeff Vander Stoep xperms->len = 0;
1115e67b7985SStephen Smalley if (!selinux_initialized())
1116c6d3aaa4SStephen Smalley goto allow;
1117c6d3aaa4SStephen Smalley
11181b8b31a2SStephen Smalley policydb = &policy->policydb;
11191b8b31a2SStephen Smalley sidtab = policy->sidtab;
1120aa8e712cSStephen Smalley
1121aa8e712cSStephen Smalley scontext = sidtab_search(sidtab, ssid);
112219439d05SStephen Smalley if (!scontext) {
1123b54c85c1Speter enderborg pr_err("SELinux: %s: unrecognized SID %d\n",
112419439d05SStephen Smalley __func__, ssid);
112519439d05SStephen Smalley goto out;
112619439d05SStephen Smalley }
112719439d05SStephen Smalley
112819439d05SStephen Smalley /* permissive domain? */
1129aa8e712cSStephen Smalley if (ebitmap_get_bit(&policydb->permissive_map, scontext->type))
113019439d05SStephen Smalley avd->flags |= AVD_FLAGS_PERMISSIVE;
113119439d05SStephen Smalley
1132aa8e712cSStephen Smalley tcontext = sidtab_search(sidtab, tsid);
113319439d05SStephen Smalley if (!tcontext) {
1134b54c85c1Speter enderborg pr_err("SELinux: %s: unrecognized SID %d\n",
113519439d05SStephen Smalley __func__, tsid);
113619439d05SStephen Smalley goto out;
113719439d05SStephen Smalley }
113819439d05SStephen Smalley
11391b8b31a2SStephen Smalley tclass = unmap_class(&policy->map, orig_tclass);
1140c6d3aaa4SStephen Smalley if (unlikely(orig_tclass && !tclass)) {
1141aa8e712cSStephen Smalley if (policydb->allow_unknown)
1142c6d3aaa4SStephen Smalley goto allow;
1143b7f3008aSStephen Smalley goto out;
1144c6d3aaa4SStephen Smalley }
1145aa8e712cSStephen Smalley context_struct_compute_av(policydb, scontext, tcontext, tclass, avd,
1146aa8e712cSStephen Smalley xperms);
11471b8b31a2SStephen Smalley map_decision(&policy->map, orig_tclass, avd,
1148aa8e712cSStephen Smalley policydb->allow_unknown);
1149b7f3008aSStephen Smalley out:
11501b8b31a2SStephen Smalley rcu_read_unlock();
115119439d05SStephen Smalley return;
1152c6d3aaa4SStephen Smalley allow:
1153c6d3aaa4SStephen Smalley avd->allowed = 0xffffffff;
1154b7f3008aSStephen Smalley goto out;
1155c6d3aaa4SStephen Smalley }
1156c6d3aaa4SStephen Smalley
security_compute_av_user(u32 ssid,u32 tsid,u16 tclass,struct av_decision * avd)1157e67b7985SStephen Smalley void security_compute_av_user(u32 ssid,
1158c6d3aaa4SStephen Smalley u32 tsid,
11591da177e4SLinus Torvalds u16 tclass,
11601da177e4SLinus Torvalds struct av_decision *avd)
11611da177e4SLinus Torvalds {
11621b8b31a2SStephen Smalley struct selinux_policy *policy;
1163aa8e712cSStephen Smalley struct policydb *policydb;
1164aa8e712cSStephen Smalley struct sidtab *sidtab;
116519439d05SStephen Smalley struct context *scontext = NULL, *tcontext = NULL;
11661da177e4SLinus Torvalds
11671b8b31a2SStephen Smalley rcu_read_lock();
1168e67b7985SStephen Smalley policy = rcu_dereference(selinux_state.policy);
11691b8b31a2SStephen Smalley avd_init(policy, avd);
1170e67b7985SStephen Smalley if (!selinux_initialized())
117119439d05SStephen Smalley goto allow;
117219439d05SStephen Smalley
11731b8b31a2SStephen Smalley policydb = &policy->policydb;
11741b8b31a2SStephen Smalley sidtab = policy->sidtab;
1175aa8e712cSStephen Smalley
1176aa8e712cSStephen Smalley scontext = sidtab_search(sidtab, ssid);
117719439d05SStephen Smalley if (!scontext) {
1178b54c85c1Speter enderborg pr_err("SELinux: %s: unrecognized SID %d\n",
117919439d05SStephen Smalley __func__, ssid);
118019439d05SStephen Smalley goto out;
118119439d05SStephen Smalley }
118219439d05SStephen Smalley
118319439d05SStephen Smalley /* permissive domain? */
1184aa8e712cSStephen Smalley if (ebitmap_get_bit(&policydb->permissive_map, scontext->type))
118519439d05SStephen Smalley avd->flags |= AVD_FLAGS_PERMISSIVE;
118619439d05SStephen Smalley
1187aa8e712cSStephen Smalley tcontext = sidtab_search(sidtab, tsid);
118819439d05SStephen Smalley if (!tcontext) {
1189b54c85c1Speter enderborg pr_err("SELinux: %s: unrecognized SID %d\n",
119019439d05SStephen Smalley __func__, tsid);
119119439d05SStephen Smalley goto out;
119219439d05SStephen Smalley }
119319439d05SStephen Smalley
119419439d05SStephen Smalley if (unlikely(!tclass)) {
1195aa8e712cSStephen Smalley if (policydb->allow_unknown)
119619439d05SStephen Smalley goto allow;
119719439d05SStephen Smalley goto out;
119819439d05SStephen Smalley }
119919439d05SStephen Smalley
1200aa8e712cSStephen Smalley context_struct_compute_av(policydb, scontext, tcontext, tclass, avd,
1201aa8e712cSStephen Smalley NULL);
120219439d05SStephen Smalley out:
12031b8b31a2SStephen Smalley rcu_read_unlock();
120419439d05SStephen Smalley return;
120519439d05SStephen Smalley allow:
120619439d05SStephen Smalley avd->allowed = 0xffffffff;
120719439d05SStephen Smalley goto out;
12081da177e4SLinus Torvalds }
12091da177e4SLinus Torvalds
12101da177e4SLinus Torvalds /*
12111da177e4SLinus Torvalds * Write the security context string representation of
12121da177e4SLinus Torvalds * the context structure `context' into a dynamically
12131da177e4SLinus Torvalds * allocated string of the correct size. Set `*scontext'
12141da177e4SLinus Torvalds * to point to this string and set `*scontext_len' to
12151da177e4SLinus Torvalds * the length of the string.
12161da177e4SLinus Torvalds */
context_struct_to_string(struct policydb * p,struct context * context,char ** scontext,u32 * scontext_len)1217aa8e712cSStephen Smalley static int context_struct_to_string(struct policydb *p,
1218aa8e712cSStephen Smalley struct context *context,
1219aa8e712cSStephen Smalley char **scontext, u32 *scontext_len)
12201da177e4SLinus Torvalds {
12211da177e4SLinus Torvalds char *scontextp;
12221da177e4SLinus Torvalds
1223d5630b9dSEric Paris if (scontext)
12241da177e4SLinus Torvalds *scontext = NULL;
12251da177e4SLinus Torvalds *scontext_len = 0;
12261da177e4SLinus Torvalds
122712b29f34SStephen Smalley if (context->len) {
122812b29f34SStephen Smalley *scontext_len = context->len;
1229bb7081abSEric Paris if (scontext) {
123012b29f34SStephen Smalley *scontext = kstrdup(context->str, GFP_ATOMIC);
123112b29f34SStephen Smalley if (!(*scontext))
123212b29f34SStephen Smalley return -ENOMEM;
1233bb7081abSEric Paris }
123412b29f34SStephen Smalley return 0;
123512b29f34SStephen Smalley }
123612b29f34SStephen Smalley
12371da177e4SLinus Torvalds /* Compute the size of the context. */
1238aa8e712cSStephen Smalley *scontext_len += strlen(sym_name(p, SYM_USERS, context->user - 1)) + 1;
1239aa8e712cSStephen Smalley *scontext_len += strlen(sym_name(p, SYM_ROLES, context->role - 1)) + 1;
1240aa8e712cSStephen Smalley *scontext_len += strlen(sym_name(p, SYM_TYPES, context->type - 1)) + 1;
1241aa8e712cSStephen Smalley *scontext_len += mls_compute_context_len(p, context);
12421da177e4SLinus Torvalds
1243d5630b9dSEric Paris if (!scontext)
1244d5630b9dSEric Paris return 0;
1245d5630b9dSEric Paris
12461da177e4SLinus Torvalds /* Allocate space for the context; caller must free this space. */
12471da177e4SLinus Torvalds scontextp = kmalloc(*scontext_len, GFP_ATOMIC);
12485d55a345SEric Paris if (!scontextp)
12491da177e4SLinus Torvalds return -ENOMEM;
12501da177e4SLinus Torvalds *scontext = scontextp;
12511da177e4SLinus Torvalds
12521da177e4SLinus Torvalds /*
12531da177e4SLinus Torvalds * Copy the user name, role name and type name into the context.
12541da177e4SLinus Torvalds */
12559529c788SRasmus Villemoes scontextp += sprintf(scontextp, "%s:%s:%s",
1256aa8e712cSStephen Smalley sym_name(p, SYM_USERS, context->user - 1),
1257aa8e712cSStephen Smalley sym_name(p, SYM_ROLES, context->role - 1),
1258aa8e712cSStephen Smalley sym_name(p, SYM_TYPES, context->type - 1));
12591da177e4SLinus Torvalds
1260aa8e712cSStephen Smalley mls_sid_to_context(p, context, &scontextp);
12611da177e4SLinus Torvalds
12621da177e4SLinus Torvalds *scontextp = 0;
12631da177e4SLinus Torvalds
12641da177e4SLinus Torvalds return 0;
12651da177e4SLinus Torvalds }
12661da177e4SLinus Torvalds
sidtab_entry_to_string(struct policydb * p,struct sidtab * sidtab,struct sidtab_entry * entry,char ** scontext,u32 * scontext_len)1267d97bd23cSOndrej Mosnacek static int sidtab_entry_to_string(struct policydb *p,
1268d97bd23cSOndrej Mosnacek struct sidtab *sidtab,
1269d97bd23cSOndrej Mosnacek struct sidtab_entry *entry,
1270d97bd23cSOndrej Mosnacek char **scontext, u32 *scontext_len)
1271d97bd23cSOndrej Mosnacek {
1272d97bd23cSOndrej Mosnacek int rc = sidtab_sid2str_get(sidtab, entry, scontext, scontext_len);
1273d97bd23cSOndrej Mosnacek
1274d97bd23cSOndrej Mosnacek if (rc != -ENOENT)
1275d97bd23cSOndrej Mosnacek return rc;
1276d97bd23cSOndrej Mosnacek
1277d97bd23cSOndrej Mosnacek rc = context_struct_to_string(p, &entry->context, scontext,
1278d97bd23cSOndrej Mosnacek scontext_len);
1279d97bd23cSOndrej Mosnacek if (!rc && scontext)
1280d97bd23cSOndrej Mosnacek sidtab_sid2str_put(sidtab, entry, *scontext, *scontext_len);
1281d97bd23cSOndrej Mosnacek return rc;
1282d97bd23cSOndrej Mosnacek }
1283d97bd23cSOndrej Mosnacek
12841da177e4SLinus Torvalds #include "initial_sid_to_string.h"
12851da177e4SLinus Torvalds
security_sidtab_hash_stats(char * page)1286e67b7985SStephen Smalley int security_sidtab_hash_stats(char *page)
128766f8e2f0SJeff Vander Stoep {
12881b8b31a2SStephen Smalley struct selinux_policy *policy;
128966f8e2f0SJeff Vander Stoep int rc;
129066f8e2f0SJeff Vander Stoep
1291e67b7985SStephen Smalley if (!selinux_initialized()) {
129215b590a8SPaul Moore pr_err("SELinux: %s: called before initial load_policy\n",
129315b590a8SPaul Moore __func__);
129415b590a8SPaul Moore return -EINVAL;
129515b590a8SPaul Moore }
129615b590a8SPaul Moore
12971b8b31a2SStephen Smalley rcu_read_lock();
1298e67b7985SStephen Smalley policy = rcu_dereference(selinux_state.policy);
12991b8b31a2SStephen Smalley rc = sidtab_hash_stats(policy->sidtab, page);
13001b8b31a2SStephen Smalley rcu_read_unlock();
130166f8e2f0SJeff Vander Stoep
130266f8e2f0SJeff Vander Stoep return rc;
130366f8e2f0SJeff Vander Stoep }
130466f8e2f0SJeff Vander Stoep
security_get_initial_sid_context(u32 sid)1305f0ee2e46SJames Carter const char *security_get_initial_sid_context(u32 sid)
1306f0ee2e46SJames Carter {
1307f0ee2e46SJames Carter if (unlikely(sid > SECINITSID_NUM))
1308f0ee2e46SJames Carter return NULL;
1309f0ee2e46SJames Carter return initial_sid_to_string[sid];
1310f0ee2e46SJames Carter }
1311f0ee2e46SJames Carter
security_sid_to_context_core(u32 sid,char ** scontext,u32 * scontext_len,int force,int only_invalid)1312e67b7985SStephen Smalley static int security_sid_to_context_core(u32 sid, char **scontext,
1313fede1483SOndrej Mosnacek u32 *scontext_len, int force,
1314fede1483SOndrej Mosnacek int only_invalid)
13151da177e4SLinus Torvalds {
13161b8b31a2SStephen Smalley struct selinux_policy *policy;
1317aa8e712cSStephen Smalley struct policydb *policydb;
1318aa8e712cSStephen Smalley struct sidtab *sidtab;
1319d97bd23cSOndrej Mosnacek struct sidtab_entry *entry;
13201da177e4SLinus Torvalds int rc = 0;
13211da177e4SLinus Torvalds
1322d5630b9dSEric Paris if (scontext)
13234f4acf3aSStephen Smalley *scontext = NULL;
13244f4acf3aSStephen Smalley *scontext_len = 0;
13254f4acf3aSStephen Smalley
1326e67b7985SStephen Smalley if (!selinux_initialized()) {
13271da177e4SLinus Torvalds if (sid <= SECINITSID_NUM) {
13281da177e4SLinus Torvalds char *scontextp;
1329e3e0b582SStephen Smalley const char *s = initial_sid_to_string[sid];
13301da177e4SLinus Torvalds
1331e3e0b582SStephen Smalley if (!s)
1332e3e0b582SStephen Smalley return -EINVAL;
1333e3e0b582SStephen Smalley *scontext_len = strlen(s) + 1;
1334d5630b9dSEric Paris if (!scontext)
1335e3e0b582SStephen Smalley return 0;
1336e3e0b582SStephen Smalley scontextp = kmemdup(s, *scontext_len, GFP_ATOMIC);
1337e3e0b582SStephen Smalley if (!scontextp)
1338e3e0b582SStephen Smalley return -ENOMEM;
13391da177e4SLinus Torvalds *scontext = scontextp;
1340e3e0b582SStephen Smalley return 0;
13411da177e4SLinus Torvalds }
1342b54c85c1Speter enderborg pr_err("SELinux: %s: called before initial "
1343744ba35eSEric Paris "load_policy on unknown SID %d\n", __func__, sid);
1344e3e0b582SStephen Smalley return -EINVAL;
13451da177e4SLinus Torvalds }
13461b8b31a2SStephen Smalley rcu_read_lock();
1347e67b7985SStephen Smalley policy = rcu_dereference(selinux_state.policy);
13481b8b31a2SStephen Smalley policydb = &policy->policydb;
13491b8b31a2SStephen Smalley sidtab = policy->sidtab;
1350d97bd23cSOndrej Mosnacek
135112b29f34SStephen Smalley if (force)
1352d97bd23cSOndrej Mosnacek entry = sidtab_search_entry_force(sidtab, sid);
135312b29f34SStephen Smalley else
1354d97bd23cSOndrej Mosnacek entry = sidtab_search_entry(sidtab, sid);
1355d97bd23cSOndrej Mosnacek if (!entry) {
1356b54c85c1Speter enderborg pr_err("SELinux: %s: unrecognized SID %d\n",
1357744ba35eSEric Paris __func__, sid);
13581da177e4SLinus Torvalds rc = -EINVAL;
13591da177e4SLinus Torvalds goto out_unlock;
13601da177e4SLinus Torvalds }
1361d97bd23cSOndrej Mosnacek if (only_invalid && !entry->context.len)
1362d97bd23cSOndrej Mosnacek goto out_unlock;
1363d97bd23cSOndrej Mosnacek
1364d97bd23cSOndrej Mosnacek rc = sidtab_entry_to_string(policydb, sidtab, entry, scontext,
1365aa8e712cSStephen Smalley scontext_len);
1366d97bd23cSOndrej Mosnacek
13671da177e4SLinus Torvalds out_unlock:
13681b8b31a2SStephen Smalley rcu_read_unlock();
13691da177e4SLinus Torvalds return rc;
13701da177e4SLinus Torvalds
13711da177e4SLinus Torvalds }
13721da177e4SLinus Torvalds
137312b29f34SStephen Smalley /**
137412b29f34SStephen Smalley * security_sid_to_context - Obtain a context for a given SID.
137512b29f34SStephen Smalley * @sid: security identifier, SID
137612b29f34SStephen Smalley * @scontext: security context
137712b29f34SStephen Smalley * @scontext_len: length in bytes
137812b29f34SStephen Smalley *
137912b29f34SStephen Smalley * Write the string representation of the context associated with @sid
138012b29f34SStephen Smalley * into a dynamically allocated string of the correct size. Set @scontext
138112b29f34SStephen Smalley * to point to this string and set @scontext_len to the length of the string.
138212b29f34SStephen Smalley */
security_sid_to_context(u32 sid,char ** scontext,u32 * scontext_len)1383e67b7985SStephen Smalley int security_sid_to_context(u32 sid, char **scontext, u32 *scontext_len)
13841da177e4SLinus Torvalds {
1385e67b7985SStephen Smalley return security_sid_to_context_core(sid, scontext,
1386fede1483SOndrej Mosnacek scontext_len, 0, 0);
138712b29f34SStephen Smalley }
138812b29f34SStephen Smalley
security_sid_to_context_force(u32 sid,char ** scontext,u32 * scontext_len)1389e67b7985SStephen Smalley int security_sid_to_context_force(u32 sid,
1390aa8e712cSStephen Smalley char **scontext, u32 *scontext_len)
139112b29f34SStephen Smalley {
1392e67b7985SStephen Smalley return security_sid_to_context_core(sid, scontext,
1393fede1483SOndrej Mosnacek scontext_len, 1, 0);
1394fede1483SOndrej Mosnacek }
1395fede1483SOndrej Mosnacek
1396fede1483SOndrej Mosnacek /**
1397fede1483SOndrej Mosnacek * security_sid_to_context_inval - Obtain a context for a given SID if it
1398fede1483SOndrej Mosnacek * is invalid.
1399fede1483SOndrej Mosnacek * @sid: security identifier, SID
1400fede1483SOndrej Mosnacek * @scontext: security context
1401fede1483SOndrej Mosnacek * @scontext_len: length in bytes
1402fede1483SOndrej Mosnacek *
1403fede1483SOndrej Mosnacek * Write the string representation of the context associated with @sid
1404fede1483SOndrej Mosnacek * into a dynamically allocated string of the correct size, but only if the
1405fede1483SOndrej Mosnacek * context is invalid in the current policy. Set @scontext to point to
1406fede1483SOndrej Mosnacek * this string (or NULL if the context is valid) and set @scontext_len to
1407fede1483SOndrej Mosnacek * the length of the string (or 0 if the context is valid).
1408fede1483SOndrej Mosnacek */
security_sid_to_context_inval(u32 sid,char ** scontext,u32 * scontext_len)1409e67b7985SStephen Smalley int security_sid_to_context_inval(u32 sid,
1410fede1483SOndrej Mosnacek char **scontext, u32 *scontext_len)
1411fede1483SOndrej Mosnacek {
1412e67b7985SStephen Smalley return security_sid_to_context_core(sid, scontext,
1413fede1483SOndrej Mosnacek scontext_len, 1, 1);
141412b29f34SStephen Smalley }
141512b29f34SStephen Smalley
14169a59daa0SStephen Smalley /*
14179a59daa0SStephen Smalley * Caveat: Mutates scontext.
14189a59daa0SStephen Smalley */
string_to_context_struct(struct policydb * pol,struct sidtab * sidtabp,char * scontext,struct context * ctx,u32 def_sid)141912b29f34SStephen Smalley static int string_to_context_struct(struct policydb *pol,
142012b29f34SStephen Smalley struct sidtab *sidtabp,
14219a59daa0SStephen Smalley char *scontext,
142212b29f34SStephen Smalley struct context *ctx,
14239a59daa0SStephen Smalley u32 def_sid)
142412b29f34SStephen Smalley {
14251da177e4SLinus Torvalds struct role_datum *role;
14261da177e4SLinus Torvalds struct type_datum *typdatum;
14271da177e4SLinus Torvalds struct user_datum *usrdatum;
14281da177e4SLinus Torvalds char *scontextp, *p, oldc;
14291da177e4SLinus Torvalds int rc = 0;
14301da177e4SLinus Torvalds
143112b29f34SStephen Smalley context_init(ctx);
143212b29f34SStephen Smalley
143312b29f34SStephen Smalley /* Parse the security context. */
143412b29f34SStephen Smalley
143512b29f34SStephen Smalley rc = -EINVAL;
14360b3c2b3dSChristian Göttsche scontextp = scontext;
143712b29f34SStephen Smalley
143812b29f34SStephen Smalley /* Extract the user. */
143912b29f34SStephen Smalley p = scontextp;
144012b29f34SStephen Smalley while (*p && *p != ':')
144112b29f34SStephen Smalley p++;
144212b29f34SStephen Smalley
144312b29f34SStephen Smalley if (*p == 0)
144412b29f34SStephen Smalley goto out;
144512b29f34SStephen Smalley
144612b29f34SStephen Smalley *p++ = 0;
144712b29f34SStephen Smalley
1448237389e3SOndrej Mosnacek usrdatum = symtab_search(&pol->p_users, scontextp);
144912b29f34SStephen Smalley if (!usrdatum)
145012b29f34SStephen Smalley goto out;
145112b29f34SStephen Smalley
145212b29f34SStephen Smalley ctx->user = usrdatum->value;
145312b29f34SStephen Smalley
145412b29f34SStephen Smalley /* Extract role. */
145512b29f34SStephen Smalley scontextp = p;
145612b29f34SStephen Smalley while (*p && *p != ':')
145712b29f34SStephen Smalley p++;
145812b29f34SStephen Smalley
145912b29f34SStephen Smalley if (*p == 0)
146012b29f34SStephen Smalley goto out;
146112b29f34SStephen Smalley
146212b29f34SStephen Smalley *p++ = 0;
146312b29f34SStephen Smalley
1464237389e3SOndrej Mosnacek role = symtab_search(&pol->p_roles, scontextp);
146512b29f34SStephen Smalley if (!role)
146612b29f34SStephen Smalley goto out;
146712b29f34SStephen Smalley ctx->role = role->value;
146812b29f34SStephen Smalley
146912b29f34SStephen Smalley /* Extract type. */
147012b29f34SStephen Smalley scontextp = p;
147112b29f34SStephen Smalley while (*p && *p != ':')
147212b29f34SStephen Smalley p++;
147312b29f34SStephen Smalley oldc = *p;
147412b29f34SStephen Smalley *p++ = 0;
147512b29f34SStephen Smalley
1476237389e3SOndrej Mosnacek typdatum = symtab_search(&pol->p_types, scontextp);
1477d9250deaSKaiGai Kohei if (!typdatum || typdatum->attribute)
147812b29f34SStephen Smalley goto out;
147912b29f34SStephen Smalley
148012b29f34SStephen Smalley ctx->type = typdatum->value;
148112b29f34SStephen Smalley
148295ffe194SJann Horn rc = mls_context_to_sid(pol, oldc, p, ctx, sidtabp, def_sid);
148312b29f34SStephen Smalley if (rc)
148412b29f34SStephen Smalley goto out;
148512b29f34SStephen Smalley
148612b29f34SStephen Smalley /* Check the validity of the new context. */
148795ffe194SJann Horn rc = -EINVAL;
14884b02b524SEric Paris if (!policydb_context_isvalid(pol, ctx))
148912b29f34SStephen Smalley goto out;
149012b29f34SStephen Smalley rc = 0;
149112b29f34SStephen Smalley out:
14928e531af9SEric Paris if (rc)
14938e531af9SEric Paris context_destroy(ctx);
149412b29f34SStephen Smalley return rc;
149512b29f34SStephen Smalley }
149612b29f34SStephen Smalley
security_context_to_sid_core(const char * scontext,u32 scontext_len,u32 * sid,u32 def_sid,gfp_t gfp_flags,int force)1497e67b7985SStephen Smalley static int security_context_to_sid_core(const char *scontext, u32 scontext_len,
149812b29f34SStephen Smalley u32 *sid, u32 def_sid, gfp_t gfp_flags,
149912b29f34SStephen Smalley int force)
150012b29f34SStephen Smalley {
15011b8b31a2SStephen Smalley struct selinux_policy *policy;
1502aa8e712cSStephen Smalley struct policydb *policydb;
1503aa8e712cSStephen Smalley struct sidtab *sidtab;
15049a59daa0SStephen Smalley char *scontext2, *str = NULL;
150512b29f34SStephen Smalley struct context context;
150612b29f34SStephen Smalley int rc = 0;
150712b29f34SStephen Smalley
15082172fa70SStephen Smalley /* An empty security context is never valid. */
15092172fa70SStephen Smalley if (!scontext_len)
15102172fa70SStephen Smalley return -EINVAL;
15112172fa70SStephen Smalley
1512ef28df55SPaul Moore /* Copy the string to allow changes and ensure a NUL terminator */
1513ef28df55SPaul Moore scontext2 = kmemdup_nul(scontext, scontext_len, gfp_flags);
1514ef28df55SPaul Moore if (!scontext2)
1515ef28df55SPaul Moore return -ENOMEM;
1516ef28df55SPaul Moore
1517e67b7985SStephen Smalley if (!selinux_initialized()) {
1518c50e125dSChristian Göttsche u32 i;
15191da177e4SLinus Torvalds
15201da177e4SLinus Torvalds for (i = 1; i < SECINITSID_NUM; i++) {
1521e3e0b582SStephen Smalley const char *s = initial_sid_to_string[i];
1522e3e0b582SStephen Smalley
1523e3e0b582SStephen Smalley if (s && !strcmp(s, scontext2)) {
15241da177e4SLinus Torvalds *sid = i;
1525ef28df55SPaul Moore goto out;
15261da177e4SLinus Torvalds }
15271da177e4SLinus Torvalds }
15281da177e4SLinus Torvalds *sid = SECINITSID_KERNEL;
1529ef28df55SPaul Moore goto out;
15301da177e4SLinus Torvalds }
15311da177e4SLinus Torvalds *sid = SECSID_NULL;
15321da177e4SLinus Torvalds
15339a59daa0SStephen Smalley if (force) {
15349a59daa0SStephen Smalley /* Save another copy for storing in uninterpreted form */
15354b02b524SEric Paris rc = -ENOMEM;
15369a59daa0SStephen Smalley str = kstrdup(scontext2, gfp_flags);
15374b02b524SEric Paris if (!str)
15384b02b524SEric Paris goto out;
15399a59daa0SStephen Smalley }
15409ad6e9cbSOndrej Mosnacek retry:
15411b8b31a2SStephen Smalley rcu_read_lock();
1542e67b7985SStephen Smalley policy = rcu_dereference(selinux_state.policy);
15431b8b31a2SStephen Smalley policydb = &policy->policydb;
15441b8b31a2SStephen Smalley sidtab = policy->sidtab;
1545aa8e712cSStephen Smalley rc = string_to_context_struct(policydb, sidtab, scontext2,
154695ffe194SJann Horn &context, def_sid);
154712b29f34SStephen Smalley if (rc == -EINVAL && force) {
15489a59daa0SStephen Smalley context.str = str;
1549efe3de79SSachin Grover context.len = strlen(str) + 1;
15509a59daa0SStephen Smalley str = NULL;
155112b29f34SStephen Smalley } else if (rc)
15524b02b524SEric Paris goto out_unlock;
1553225621c9SOndrej Mosnacek rc = sidtab_context_to_sid(sidtab, &context, sid);
15549ad6e9cbSOndrej Mosnacek if (rc == -ESTALE) {
15559ad6e9cbSOndrej Mosnacek rcu_read_unlock();
15569ad6e9cbSOndrej Mosnacek if (context.str) {
15579ad6e9cbSOndrej Mosnacek str = context.str;
15589ad6e9cbSOndrej Mosnacek context.str = NULL;
15599ad6e9cbSOndrej Mosnacek }
15609ad6e9cbSOndrej Mosnacek context_destroy(&context);
15619ad6e9cbSOndrej Mosnacek goto retry;
15629ad6e9cbSOndrej Mosnacek }
15631da177e4SLinus Torvalds context_destroy(&context);
15644b02b524SEric Paris out_unlock:
15651b8b31a2SStephen Smalley rcu_read_unlock();
15664b02b524SEric Paris out:
15679a59daa0SStephen Smalley kfree(scontext2);
15689a59daa0SStephen Smalley kfree(str);
15691da177e4SLinus Torvalds return rc;
15701da177e4SLinus Torvalds }
15711da177e4SLinus Torvalds
1572f5c1d5b2SJames Morris /**
1573f5c1d5b2SJames Morris * security_context_to_sid - Obtain a SID for a given security context.
1574f5c1d5b2SJames Morris * @scontext: security context
1575f5c1d5b2SJames Morris * @scontext_len: length in bytes
1576f5c1d5b2SJames Morris * @sid: security identifier, SID
157752a4c640SNikolay Aleksandrov * @gfp: context for the allocation
1578f5c1d5b2SJames Morris *
1579f5c1d5b2SJames Morris * Obtains a SID associated with the security context that
1580f5c1d5b2SJames Morris * has the string representation specified by @scontext.
1581f5c1d5b2SJames Morris * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient
1582f5c1d5b2SJames Morris * memory is available, or 0 on success.
1583f5c1d5b2SJames Morris */
security_context_to_sid(const char * scontext,u32 scontext_len,u32 * sid,gfp_t gfp)1584e67b7985SStephen Smalley int security_context_to_sid(const char *scontext, u32 scontext_len, u32 *sid,
158552a4c640SNikolay Aleksandrov gfp_t gfp)
1586f5c1d5b2SJames Morris {
1587e67b7985SStephen Smalley return security_context_to_sid_core(scontext, scontext_len,
158852a4c640SNikolay Aleksandrov sid, SECSID_NULL, gfp, 0);
1589f5c1d5b2SJames Morris }
1590f5c1d5b2SJames Morris
security_context_str_to_sid(const char * scontext,u32 * sid,gfp_t gfp)1591e67b7985SStephen Smalley int security_context_str_to_sid(const char *scontext, u32 *sid, gfp_t gfp)
159244be2f65SRasmus Villemoes {
1593e67b7985SStephen Smalley return security_context_to_sid(scontext, strlen(scontext),
1594aa8e712cSStephen Smalley sid, gfp);
159544be2f65SRasmus Villemoes }
159644be2f65SRasmus Villemoes
1597f5c1d5b2SJames Morris /**
1598f5c1d5b2SJames Morris * security_context_to_sid_default - Obtain a SID for a given security context,
1599f5c1d5b2SJames Morris * falling back to specified default if needed.
1600f5c1d5b2SJames Morris *
1601f5c1d5b2SJames Morris * @scontext: security context
1602f5c1d5b2SJames Morris * @scontext_len: length in bytes
1603f5c1d5b2SJames Morris * @sid: security identifier, SID
1604d133a960SGabriel Craciunescu * @def_sid: default SID to assign on error
1605e9fd7292SPaul Moore * @gfp_flags: the allocator get-free-page (GFP) flags
1606f5c1d5b2SJames Morris *
1607f5c1d5b2SJames Morris * Obtains a SID associated with the security context that
1608f5c1d5b2SJames Morris * has the string representation specified by @scontext.
1609f5c1d5b2SJames Morris * The default SID is passed to the MLS layer to be used to allow
1610f5c1d5b2SJames Morris * kernel labeling of the MLS field if the MLS field is not present
1611f5c1d5b2SJames Morris * (for upgrading to MLS without full relabel).
161212b29f34SStephen Smalley * Implicitly forces adding of the context even if it cannot be mapped yet.
1613f5c1d5b2SJames Morris * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient
1614f5c1d5b2SJames Morris * memory is available, or 0 on success.
1615f5c1d5b2SJames Morris */
security_context_to_sid_default(const char * scontext,u32 scontext_len,u32 * sid,u32 def_sid,gfp_t gfp_flags)1616e67b7985SStephen Smalley int security_context_to_sid_default(const char *scontext, u32 scontext_len,
16177bf570dcSDavid Howells u32 *sid, u32 def_sid, gfp_t gfp_flags)
1618f5c1d5b2SJames Morris {
1619e67b7985SStephen Smalley return security_context_to_sid_core(scontext, scontext_len,
162012b29f34SStephen Smalley sid, def_sid, gfp_flags, 1);
162112b29f34SStephen Smalley }
162212b29f34SStephen Smalley
security_context_to_sid_force(const char * scontext,u32 scontext_len,u32 * sid)1623e67b7985SStephen Smalley int security_context_to_sid_force(const char *scontext, u32 scontext_len,
162412b29f34SStephen Smalley u32 *sid)
162512b29f34SStephen Smalley {
1626e67b7985SStephen Smalley return security_context_to_sid_core(scontext, scontext_len,
162712b29f34SStephen Smalley sid, SECSID_NULL, GFP_KERNEL, 1);
1628f5c1d5b2SJames Morris }
1629f5c1d5b2SJames Morris
compute_sid_handle_invalid_context(struct selinux_policy * policy,struct sidtab_entry * sentry,struct sidtab_entry * tentry,u16 tclass,struct context * newcontext)16301da177e4SLinus Torvalds static int compute_sid_handle_invalid_context(
16311b8b31a2SStephen Smalley struct selinux_policy *policy,
1632d97bd23cSOndrej Mosnacek struct sidtab_entry *sentry,
1633d97bd23cSOndrej Mosnacek struct sidtab_entry *tentry,
16341da177e4SLinus Torvalds u16 tclass,
16351da177e4SLinus Torvalds struct context *newcontext)
16361da177e4SLinus Torvalds {
16371b8b31a2SStephen Smalley struct policydb *policydb = &policy->policydb;
16381b8b31a2SStephen Smalley struct sidtab *sidtab = policy->sidtab;
16391da177e4SLinus Torvalds char *s = NULL, *t = NULL, *n = NULL;
16401da177e4SLinus Torvalds u32 slen, tlen, nlen;
1641ea74a685SRichard Guy Briggs struct audit_buffer *ab;
16421da177e4SLinus Torvalds
1643d97bd23cSOndrej Mosnacek if (sidtab_entry_to_string(policydb, sidtab, sentry, &s, &slen))
16441da177e4SLinus Torvalds goto out;
1645d97bd23cSOndrej Mosnacek if (sidtab_entry_to_string(policydb, sidtab, tentry, &t, &tlen))
16461da177e4SLinus Torvalds goto out;
1647aa8e712cSStephen Smalley if (context_struct_to_string(policydb, newcontext, &n, &nlen))
16481da177e4SLinus Torvalds goto out;
1649ea74a685SRichard Guy Briggs ab = audit_log_start(audit_context(), GFP_ATOMIC, AUDIT_SELINUX_ERR);
1650893c47d1SAustin Kim if (!ab)
1651893c47d1SAustin Kim goto out;
1652ea74a685SRichard Guy Briggs audit_log_format(ab,
1653ea74a685SRichard Guy Briggs "op=security_compute_sid invalid_context=");
1654ea74a685SRichard Guy Briggs /* no need to record the NUL with untrusted strings */
1655ea74a685SRichard Guy Briggs audit_log_n_untrustedstring(ab, n, nlen - 1);
1656ea74a685SRichard Guy Briggs audit_log_format(ab, " scontext=%s tcontext=%s tclass=%s",
1657ea74a685SRichard Guy Briggs s, t, sym_name(policydb, SYM_CLASSES, tclass-1));
1658ea74a685SRichard Guy Briggs audit_log_end(ab);
16591da177e4SLinus Torvalds out:
16601da177e4SLinus Torvalds kfree(s);
16611da177e4SLinus Torvalds kfree(t);
16621da177e4SLinus Torvalds kfree(n);
1663e67b7985SStephen Smalley if (!enforcing_enabled())
16641da177e4SLinus Torvalds return 0;
16651da177e4SLinus Torvalds return -EACCES;
16661da177e4SLinus Torvalds }
16671da177e4SLinus Torvalds
filename_compute_type(struct policydb * policydb,struct context * newcontext,u32 stype,u32 ttype,u16 tclass,const char * objname)1668aa8e712cSStephen Smalley static void filename_compute_type(struct policydb *policydb,
1669aa8e712cSStephen Smalley struct context *newcontext,
16702667991fSEric Paris u32 stype, u32 ttype, u16 tclass,
1671f50a3ec9SKohei Kaigai const char *objname)
1672652bb9b0SEric Paris {
1673c3a27611SOndrej Mosnacek struct filename_trans_key ft;
1674c3a27611SOndrej Mosnacek struct filename_trans_datum *datum;
167503a4c018SEric Paris
167603a4c018SEric Paris /*
167703a4c018SEric Paris * Most filename trans rules are going to live in specific directories
167803a4c018SEric Paris * like /dev or /var/run. This bitmap will quickly skip rule searches
167903a4c018SEric Paris * if the ttype does not contain any rules.
168003a4c018SEric Paris */
1681aa8e712cSStephen Smalley if (!ebitmap_get_bit(&policydb->filename_trans_ttypes, ttype))
1682652bb9b0SEric Paris return;
168303a4c018SEric Paris
16842463c26dSEric Paris ft.ttype = ttype;
16852463c26dSEric Paris ft.tclass = tclass;
16862463c26dSEric Paris ft.name = objname;
16872463c26dSEric Paris
168824def7bbSOndrej Mosnacek datum = policydb_filenametr_search(policydb, &ft);
1689c3a27611SOndrej Mosnacek while (datum) {
1690c3a27611SOndrej Mosnacek if (ebitmap_get_bit(&datum->stypes, stype - 1)) {
1691c3a27611SOndrej Mosnacek newcontext->type = datum->otype;
1692c3a27611SOndrej Mosnacek return;
1693c3a27611SOndrej Mosnacek }
1694c3a27611SOndrej Mosnacek datum = datum->next;
1695c3a27611SOndrej Mosnacek }
1696652bb9b0SEric Paris }
1697652bb9b0SEric Paris
security_compute_sid(u32 ssid,u32 tsid,u16 orig_tclass,u16 specified,const char * objname,u32 * out_sid,bool kern)1698e67b7985SStephen Smalley static int security_compute_sid(u32 ssid,
16991da177e4SLinus Torvalds u32 tsid,
1700c6d3aaa4SStephen Smalley u16 orig_tclass,
17017128578cSChristian Göttsche u16 specified,
1702f50a3ec9SKohei Kaigai const char *objname,
1703c6d3aaa4SStephen Smalley u32 *out_sid,
1704c6d3aaa4SStephen Smalley bool kern)
17051da177e4SLinus Torvalds {
17061b8b31a2SStephen Smalley struct selinux_policy *policy;
1707aa8e712cSStephen Smalley struct policydb *policydb;
1708aa8e712cSStephen Smalley struct sidtab *sidtab;
17099ad6e9cbSOndrej Mosnacek struct class_datum *cladatum;
1710d97bd23cSOndrej Mosnacek struct context *scontext, *tcontext, newcontext;
1711d97bd23cSOndrej Mosnacek struct sidtab_entry *sentry, *tentry;
17121da177e4SLinus Torvalds struct avtab_key avkey;
171308a12b39SChristian Göttsche struct avtab_node *avnode, *node;
1714c6d3aaa4SStephen Smalley u16 tclass;
17151da177e4SLinus Torvalds int rc = 0;
17166f5317e7SHarry Ciao bool sock;
17171da177e4SLinus Torvalds
1718e67b7985SStephen Smalley if (!selinux_initialized()) {
1719c6d3aaa4SStephen Smalley switch (orig_tclass) {
1720c6d3aaa4SStephen Smalley case SECCLASS_PROCESS: /* kernel value */
17211da177e4SLinus Torvalds *out_sid = ssid;
17221da177e4SLinus Torvalds break;
17231da177e4SLinus Torvalds default:
17241da177e4SLinus Torvalds *out_sid = tsid;
17251da177e4SLinus Torvalds break;
17261da177e4SLinus Torvalds }
17271da177e4SLinus Torvalds goto out;
17281da177e4SLinus Torvalds }
17291da177e4SLinus Torvalds
17309ad6e9cbSOndrej Mosnacek retry:
17319ad6e9cbSOndrej Mosnacek cladatum = NULL;
1732851f8a69SVenkat Yekkirala context_init(&newcontext);
1733851f8a69SVenkat Yekkirala
17341b8b31a2SStephen Smalley rcu_read_lock();
17351b8b31a2SStephen Smalley
1736e67b7985SStephen Smalley policy = rcu_dereference(selinux_state.policy);
17371da177e4SLinus Torvalds
17386f5317e7SHarry Ciao if (kern) {
17391b8b31a2SStephen Smalley tclass = unmap_class(&policy->map, orig_tclass);
17406f5317e7SHarry Ciao sock = security_is_socket_class(orig_tclass);
17416f5317e7SHarry Ciao } else {
1742c6d3aaa4SStephen Smalley tclass = orig_tclass;
17431b8b31a2SStephen Smalley sock = security_is_socket_class(map_class(&policy->map,
1744aa8e712cSStephen Smalley tclass));
17456f5317e7SHarry Ciao }
1746c6d3aaa4SStephen Smalley
17471b8b31a2SStephen Smalley policydb = &policy->policydb;
17481b8b31a2SStephen Smalley sidtab = policy->sidtab;
1749aa8e712cSStephen Smalley
1750d97bd23cSOndrej Mosnacek sentry = sidtab_search_entry(sidtab, ssid);
1751d97bd23cSOndrej Mosnacek if (!sentry) {
1752b54c85c1Speter enderborg pr_err("SELinux: %s: unrecognized SID %d\n",
1753744ba35eSEric Paris __func__, ssid);
17541da177e4SLinus Torvalds rc = -EINVAL;
17551da177e4SLinus Torvalds goto out_unlock;
17561da177e4SLinus Torvalds }
1757d97bd23cSOndrej Mosnacek tentry = sidtab_search_entry(sidtab, tsid);
1758d97bd23cSOndrej Mosnacek if (!tentry) {
1759b54c85c1Speter enderborg pr_err("SELinux: %s: unrecognized SID %d\n",
1760744ba35eSEric Paris __func__, tsid);
17611da177e4SLinus Torvalds rc = -EINVAL;
17621da177e4SLinus Torvalds goto out_unlock;
17631da177e4SLinus Torvalds }
17641da177e4SLinus Torvalds
1765d97bd23cSOndrej Mosnacek scontext = &sentry->context;
1766d97bd23cSOndrej Mosnacek tcontext = &tentry->context;
1767d97bd23cSOndrej Mosnacek
1768aa8e712cSStephen Smalley if (tclass && tclass <= policydb->p_classes.nprim)
1769aa8e712cSStephen Smalley cladatum = policydb->class_val_to_struct[tclass - 1];
1770aa893269SEric Paris
17711da177e4SLinus Torvalds /* Set the user identity. */
17721da177e4SLinus Torvalds switch (specified) {
17731da177e4SLinus Torvalds case AVTAB_TRANSITION:
17741da177e4SLinus Torvalds case AVTAB_CHANGE:
1775aa893269SEric Paris if (cladatum && cladatum->default_user == DEFAULT_TARGET) {
1776aa893269SEric Paris newcontext.user = tcontext->user;
1777aa893269SEric Paris } else {
1778aa893269SEric Paris /* notice this gets both DEFAULT_SOURCE and unset */
17791da177e4SLinus Torvalds /* Use the process user identity. */
17801da177e4SLinus Torvalds newcontext.user = scontext->user;
1781aa893269SEric Paris }
17821da177e4SLinus Torvalds break;
17831da177e4SLinus Torvalds case AVTAB_MEMBER:
17841da177e4SLinus Torvalds /* Use the related object owner. */
17851da177e4SLinus Torvalds newcontext.user = tcontext->user;
17861da177e4SLinus Torvalds break;
17871da177e4SLinus Torvalds }
17881da177e4SLinus Torvalds
1789aa893269SEric Paris /* Set the role to default values. */
1790aa893269SEric Paris if (cladatum && cladatum->default_role == DEFAULT_SOURCE) {
17911da177e4SLinus Torvalds newcontext.role = scontext->role;
1792aa893269SEric Paris } else if (cladatum && cladatum->default_role == DEFAULT_TARGET) {
1793aa893269SEric Paris newcontext.role = tcontext->role;
1794aa893269SEric Paris } else {
17954b850396SZou Wei if ((tclass == policydb->process_class) || sock)
1796aa893269SEric Paris newcontext.role = scontext->role;
1797aa893269SEric Paris else
1798aa893269SEric Paris newcontext.role = OBJECT_R_VAL;
1799aa893269SEric Paris }
1800aa893269SEric Paris
1801aa893269SEric Paris /* Set the type to default values. */
1802eed7795dSEric Paris if (cladatum && cladatum->default_type == DEFAULT_SOURCE) {
1803eed7795dSEric Paris newcontext.type = scontext->type;
1804eed7795dSEric Paris } else if (cladatum && cladatum->default_type == DEFAULT_TARGET) {
1805eed7795dSEric Paris newcontext.type = tcontext->type;
1806eed7795dSEric Paris } else {
18074b850396SZou Wei if ((tclass == policydb->process_class) || sock) {
1808aa893269SEric Paris /* Use the type of process. */
18091da177e4SLinus Torvalds newcontext.type = scontext->type;
1810c6d3aaa4SStephen Smalley } else {
18111da177e4SLinus Torvalds /* Use the type of the related object. */
18121da177e4SLinus Torvalds newcontext.type = tcontext->type;
18131da177e4SLinus Torvalds }
1814eed7795dSEric Paris }
18151da177e4SLinus Torvalds
18161da177e4SLinus Torvalds /* Look for a type transition/member/change rule. */
18171da177e4SLinus Torvalds avkey.source_type = scontext->type;
18181da177e4SLinus Torvalds avkey.target_type = tcontext->type;
18191da177e4SLinus Torvalds avkey.target_class = tclass;
1820782ebb99SStephen Smalley avkey.specified = specified;
182108a12b39SChristian Göttsche avnode = avtab_search_node(&policydb->te_avtab, &avkey);
18221da177e4SLinus Torvalds
18231da177e4SLinus Torvalds /* If no permanent rule, also check for enabled conditional rules */
182408a12b39SChristian Göttsche if (!avnode) {
1825aa8e712cSStephen Smalley node = avtab_search_node(&policydb->te_cond_avtab, &avkey);
1826dbc74c65SVesa-Matti Kari for (; node; node = avtab_search_node_next(node, specified)) {
1827782ebb99SStephen Smalley if (node->key.specified & AVTAB_ENABLED) {
182808a12b39SChristian Göttsche avnode = node;
18291da177e4SLinus Torvalds break;
18301da177e4SLinus Torvalds }
18311da177e4SLinus Torvalds }
18321da177e4SLinus Torvalds }
18331da177e4SLinus Torvalds
183408a12b39SChristian Göttsche if (avnode) {
18351da177e4SLinus Torvalds /* Use the type from the type transition/member/change rule. */
183608a12b39SChristian Göttsche newcontext.type = avnode->datum.u.data;
18371da177e4SLinus Torvalds }
18381da177e4SLinus Torvalds
18394742600cSEric Paris /* if we have a objname this is a file trans check so check those rules */
1840f50a3ec9SKohei Kaigai if (objname)
1841aa8e712cSStephen Smalley filename_compute_type(policydb, &newcontext, scontext->type,
1842f50a3ec9SKohei Kaigai tcontext->type, tclass, objname);
1843652bb9b0SEric Paris
18441da177e4SLinus Torvalds /* Check for class-specific changes. */
18451da177e4SLinus Torvalds if (specified & AVTAB_TRANSITION) {
18461da177e4SLinus Torvalds /* Look for a role transition rule. */
1847e67b2ec9SOndrej Mosnacek struct role_trans_datum *rtd;
1848e67b2ec9SOndrej Mosnacek struct role_trans_key rtk = {
1849e67b2ec9SOndrej Mosnacek .role = scontext->role,
1850e67b2ec9SOndrej Mosnacek .type = tcontext->type,
1851e67b2ec9SOndrej Mosnacek .tclass = tclass,
1852e67b2ec9SOndrej Mosnacek };
1853e67b2ec9SOndrej Mosnacek
185424def7bbSOndrej Mosnacek rtd = policydb_roletr_search(policydb, &rtk);
1855e67b2ec9SOndrej Mosnacek if (rtd)
1856e67b2ec9SOndrej Mosnacek newcontext.role = rtd->new_role;
18571da177e4SLinus Torvalds }
18581da177e4SLinus Torvalds
18591da177e4SLinus Torvalds /* Set the MLS attributes.
18601da177e4SLinus Torvalds This is done last because it may allocate memory. */
1861aa8e712cSStephen Smalley rc = mls_compute_sid(policydb, scontext, tcontext, tclass, specified,
18626f5317e7SHarry Ciao &newcontext, sock);
18631da177e4SLinus Torvalds if (rc)
18641da177e4SLinus Torvalds goto out_unlock;
18651da177e4SLinus Torvalds
18661da177e4SLinus Torvalds /* Check the validity of the context. */
1867aa8e712cSStephen Smalley if (!policydb_context_isvalid(policydb, &newcontext)) {
1868e67b7985SStephen Smalley rc = compute_sid_handle_invalid_context(policy, sentry,
18691b8b31a2SStephen Smalley tentry, tclass,
18701b8b31a2SStephen Smalley &newcontext);
18711da177e4SLinus Torvalds if (rc)
18721da177e4SLinus Torvalds goto out_unlock;
18731da177e4SLinus Torvalds }
18741da177e4SLinus Torvalds /* Obtain the sid for the context. */
1875225621c9SOndrej Mosnacek rc = sidtab_context_to_sid(sidtab, &newcontext, out_sid);
18769ad6e9cbSOndrej Mosnacek if (rc == -ESTALE) {
18779ad6e9cbSOndrej Mosnacek rcu_read_unlock();
18789ad6e9cbSOndrej Mosnacek context_destroy(&newcontext);
18799ad6e9cbSOndrej Mosnacek goto retry;
18809ad6e9cbSOndrej Mosnacek }
18811da177e4SLinus Torvalds out_unlock:
18821b8b31a2SStephen Smalley rcu_read_unlock();
18831da177e4SLinus Torvalds context_destroy(&newcontext);
18841da177e4SLinus Torvalds out:
18851da177e4SLinus Torvalds return rc;
18861da177e4SLinus Torvalds }
18871da177e4SLinus Torvalds
18881da177e4SLinus Torvalds /**
18891da177e4SLinus Torvalds * security_transition_sid - Compute the SID for a new subject/object.
18901da177e4SLinus Torvalds * @ssid: source security identifier
18911da177e4SLinus Torvalds * @tsid: target security identifier
18921da177e4SLinus Torvalds * @tclass: target security class
1893e9fd7292SPaul Moore * @qstr: object name
18941da177e4SLinus Torvalds * @out_sid: security identifier for new subject/object
18951da177e4SLinus Torvalds *
18961da177e4SLinus Torvalds * Compute a SID to use for labeling a new subject or object in the
18971da177e4SLinus Torvalds * class @tclass based on a SID pair (@ssid, @tsid).
18981da177e4SLinus Torvalds * Return -%EINVAL if any of the parameters are invalid, -%ENOMEM
18991da177e4SLinus Torvalds * if insufficient memory is available, or %0 if the new SID was
19001da177e4SLinus Torvalds * computed successfully.
19011da177e4SLinus Torvalds */
security_transition_sid(u32 ssid,u32 tsid,u16 tclass,const struct qstr * qstr,u32 * out_sid)1902e67b7985SStephen Smalley int security_transition_sid(u32 ssid, u32 tsid, u16 tclass,
1903652bb9b0SEric Paris const struct qstr *qstr, u32 *out_sid)
19041da177e4SLinus Torvalds {
1905e67b7985SStephen Smalley return security_compute_sid(ssid, tsid, tclass,
1906aa8e712cSStephen Smalley AVTAB_TRANSITION,
1907f50a3ec9SKohei Kaigai qstr ? qstr->name : NULL, out_sid, true);
1908c6d3aaa4SStephen Smalley }
1909c6d3aaa4SStephen Smalley
security_transition_sid_user(u32 ssid,u32 tsid,u16 tclass,const char * objname,u32 * out_sid)1910e67b7985SStephen Smalley int security_transition_sid_user(u32 ssid, u32 tsid, u16 tclass,
1911f50a3ec9SKohei Kaigai const char *objname, u32 *out_sid)
1912c6d3aaa4SStephen Smalley {
1913e67b7985SStephen Smalley return security_compute_sid(ssid, tsid, tclass,
1914aa8e712cSStephen Smalley AVTAB_TRANSITION,
1915f50a3ec9SKohei Kaigai objname, out_sid, false);
19161da177e4SLinus Torvalds }
19171da177e4SLinus Torvalds
19181da177e4SLinus Torvalds /**
19191da177e4SLinus Torvalds * security_member_sid - Compute the SID for member selection.
19201da177e4SLinus Torvalds * @ssid: source security identifier
19211da177e4SLinus Torvalds * @tsid: target security identifier
19221da177e4SLinus Torvalds * @tclass: target security class
19231da177e4SLinus Torvalds * @out_sid: security identifier for selected member
19241da177e4SLinus Torvalds *
19251da177e4SLinus Torvalds * Compute a SID to use when selecting a member of a polyinstantiated
19261da177e4SLinus Torvalds * object of class @tclass based on a SID pair (@ssid, @tsid).
19271da177e4SLinus Torvalds * Return -%EINVAL if any of the parameters are invalid, -%ENOMEM
19281da177e4SLinus Torvalds * if insufficient memory is available, or %0 if the SID was
19291da177e4SLinus Torvalds * computed successfully.
19301da177e4SLinus Torvalds */
security_member_sid(u32 ssid,u32 tsid,u16 tclass,u32 * out_sid)1931e67b7985SStephen Smalley int security_member_sid(u32 ssid,
19321da177e4SLinus Torvalds u32 tsid,
19331da177e4SLinus Torvalds u16 tclass,
19341da177e4SLinus Torvalds u32 *out_sid)
19351da177e4SLinus Torvalds {
1936e67b7985SStephen Smalley return security_compute_sid(ssid, tsid, tclass,
1937aa8e712cSStephen Smalley AVTAB_MEMBER, NULL,
1938652bb9b0SEric Paris out_sid, false);
19391da177e4SLinus Torvalds }
19401da177e4SLinus Torvalds
19411da177e4SLinus Torvalds /**
19421da177e4SLinus Torvalds * security_change_sid - Compute the SID for object relabeling.
19431da177e4SLinus Torvalds * @ssid: source security identifier
19441da177e4SLinus Torvalds * @tsid: target security identifier
19451da177e4SLinus Torvalds * @tclass: target security class
19461da177e4SLinus Torvalds * @out_sid: security identifier for selected member
19471da177e4SLinus Torvalds *
19481da177e4SLinus Torvalds * Compute a SID to use for relabeling an object of class @tclass
19491da177e4SLinus Torvalds * based on a SID pair (@ssid, @tsid).
19501da177e4SLinus Torvalds * Return -%EINVAL if any of the parameters are invalid, -%ENOMEM
19511da177e4SLinus Torvalds * if insufficient memory is available, or %0 if the SID was
19521da177e4SLinus Torvalds * computed successfully.
19531da177e4SLinus Torvalds */
security_change_sid(u32 ssid,u32 tsid,u16 tclass,u32 * out_sid)1954e67b7985SStephen Smalley int security_change_sid(u32 ssid,
19551da177e4SLinus Torvalds u32 tsid,
19561da177e4SLinus Torvalds u16 tclass,
19571da177e4SLinus Torvalds u32 *out_sid)
19581da177e4SLinus Torvalds {
1959e67b7985SStephen Smalley return security_compute_sid(ssid, tsid, tclass, AVTAB_CHANGE, NULL,
1960652bb9b0SEric Paris out_sid, false);
1961b94c7e67SChad Sellers }
1962b94c7e67SChad Sellers
convert_context_handle_invalid_context(struct policydb * policydb,struct context * context)1963aa8e712cSStephen Smalley static inline int convert_context_handle_invalid_context(
19641b8b31a2SStephen Smalley struct policydb *policydb,
1965aa8e712cSStephen Smalley struct context *context)
19661da177e4SLinus Torvalds {
19671da177e4SLinus Torvalds char *s;
19681da177e4SLinus Torvalds u32 len;
19691da177e4SLinus Torvalds
1970e67b7985SStephen Smalley if (enforcing_enabled())
19714b02b524SEric Paris return -EINVAL;
19724b02b524SEric Paris
1973aa8e712cSStephen Smalley if (!context_struct_to_string(policydb, context, &s, &len)) {
1974b54c85c1Speter enderborg pr_warn("SELinux: Context %s would be invalid if enforcing\n",
1975b54c85c1Speter enderborg s);
19761da177e4SLinus Torvalds kfree(s);
19771da177e4SLinus Torvalds }
19784b02b524SEric Paris return 0;
19791da177e4SLinus Torvalds }
19801da177e4SLinus Torvalds
1981048be156SPaul Moore /**
1982048be156SPaul Moore * services_convert_context - Convert a security context across policies.
1983048be156SPaul Moore * @args: populated convert_context_args struct
1984048be156SPaul Moore * @oldc: original context
1985048be156SPaul Moore * @newc: converted context
198657888f7bSLinus Torvalds * @gfp_flags: allocation flags
1987048be156SPaul Moore *
1988048be156SPaul Moore * Convert the values in the security context structure @oldc from the values
1989048be156SPaul Moore * specified in the policy @args->oldp to the values specified in the policy
1990048be156SPaul Moore * @args->newp, storing the new context in @newc, and verifying that the
1991048be156SPaul Moore * context is valid under the new policy.
19921da177e4SLinus Torvalds */
services_convert_context(struct convert_context_args * args,struct context * oldc,struct context * newc,gfp_t gfp_flags)1993048be156SPaul Moore int services_convert_context(struct convert_context_args *args,
199457888f7bSLinus Torvalds struct context *oldc, struct context *newc,
1995abe3c631SGONG, Ruiqi gfp_t gfp_flags)
19961da177e4SLinus Torvalds {
19970719aaf5SGuido Trentalancia struct ocontext *oc;
19981da177e4SLinus Torvalds struct role_datum *role;
19991da177e4SLinus Torvalds struct type_datum *typdatum;
20001da177e4SLinus Torvalds struct user_datum *usrdatum;
20011da177e4SLinus Torvalds char *s;
20021da177e4SLinus Torvalds u32 len;
200324ed7fdaSOndrej Mosnacek int rc;
20041da177e4SLinus Torvalds
2005ee1a84fdSOndrej Mosnacek if (oldc->str) {
2006abe3c631SGONG, Ruiqi s = kstrdup(oldc->str, gfp_flags);
20074b02b524SEric Paris if (!s)
2008ee1a84fdSOndrej Mosnacek return -ENOMEM;
20094b02b524SEric Paris
2010048be156SPaul Moore rc = string_to_context_struct(args->newp, NULL, s, newc, SECSID_NULL);
2011ee1a84fdSOndrej Mosnacek if (rc == -EINVAL) {
20122a524393SOndrej Mosnacek /*
20132a524393SOndrej Mosnacek * Retain string representation for later mapping.
20142a524393SOndrej Mosnacek *
20152a524393SOndrej Mosnacek * IMPORTANT: We need to copy the contents of oldc->str
20162a524393SOndrej Mosnacek * back into s again because string_to_context_struct()
20172a524393SOndrej Mosnacek * may have garbled it.
20182a524393SOndrej Mosnacek */
20192a524393SOndrej Mosnacek memcpy(s, oldc->str, oldc->len);
2020ee1a84fdSOndrej Mosnacek context_init(newc);
2021ee1a84fdSOndrej Mosnacek newc->str = s;
2022ee1a84fdSOndrej Mosnacek newc->len = oldc->len;
2023ee1a84fdSOndrej Mosnacek return 0;
2024ee1a84fdSOndrej Mosnacek }
2025ee1a84fdSOndrej Mosnacek kfree(s);
2026ee1a84fdSOndrej Mosnacek if (rc) {
202712b29f34SStephen Smalley /* Other error condition, e.g. ENOMEM. */
2028b54c85c1Speter enderborg pr_err("SELinux: Unable to map context %s, rc = %d.\n",
2029ee1a84fdSOndrej Mosnacek oldc->str, -rc);
2030ee1a84fdSOndrej Mosnacek return rc;
203112b29f34SStephen Smalley }
2032ee1a84fdSOndrej Mosnacek pr_info("SELinux: Context %s became valid (mapped).\n",
2033ee1a84fdSOndrej Mosnacek oldc->str);
2034ee1a84fdSOndrej Mosnacek return 0;
203512b29f34SStephen Smalley }
203612b29f34SStephen Smalley
2037ee1a84fdSOndrej Mosnacek context_init(newc);
20381da177e4SLinus Torvalds
20391da177e4SLinus Torvalds /* Convert the user. */
2040237389e3SOndrej Mosnacek usrdatum = symtab_search(&args->newp->p_users,
2041048be156SPaul Moore sym_name(args->oldp, SYM_USERS, oldc->user - 1));
20425d55a345SEric Paris if (!usrdatum)
20431da177e4SLinus Torvalds goto bad;
2044ee1a84fdSOndrej Mosnacek newc->user = usrdatum->value;
20451da177e4SLinus Torvalds
20461da177e4SLinus Torvalds /* Convert the role. */
2047237389e3SOndrej Mosnacek role = symtab_search(&args->newp->p_roles,
2048ee1a84fdSOndrej Mosnacek sym_name(args->oldp, SYM_ROLES, oldc->role - 1));
20495d55a345SEric Paris if (!role)
20501da177e4SLinus Torvalds goto bad;
2051ee1a84fdSOndrej Mosnacek newc->role = role->value;
20521da177e4SLinus Torvalds
20531da177e4SLinus Torvalds /* Convert the type. */
2054237389e3SOndrej Mosnacek typdatum = symtab_search(&args->newp->p_types,
2055048be156SPaul Moore sym_name(args->oldp, SYM_TYPES, oldc->type - 1));
20565d55a345SEric Paris if (!typdatum)
20571da177e4SLinus Torvalds goto bad;
2058ee1a84fdSOndrej Mosnacek newc->type = typdatum->value;
20591da177e4SLinus Torvalds
20600719aaf5SGuido Trentalancia /* Convert the MLS fields if dealing with MLS policies */
20610719aaf5SGuido Trentalancia if (args->oldp->mls_enabled && args->newp->mls_enabled) {
2062ee1a84fdSOndrej Mosnacek rc = mls_convert_context(args->oldp, args->newp, oldc, newc);
20631da177e4SLinus Torvalds if (rc)
20641da177e4SLinus Torvalds goto bad;
20650719aaf5SGuido Trentalancia } else if (!args->oldp->mls_enabled && args->newp->mls_enabled) {
20660719aaf5SGuido Trentalancia /*
20670719aaf5SGuido Trentalancia * Switching between non-MLS and MLS policy:
20680719aaf5SGuido Trentalancia * ensure that the MLS fields of the context for all
20690719aaf5SGuido Trentalancia * existing entries in the sidtab are filled in with a
20700719aaf5SGuido Trentalancia * suitable default value, likely taken from one of the
20710719aaf5SGuido Trentalancia * initial SIDs.
20720719aaf5SGuido Trentalancia */
20730719aaf5SGuido Trentalancia oc = args->newp->ocontexts[OCON_ISID];
20740719aaf5SGuido Trentalancia while (oc && oc->sid[0] != SECINITSID_UNLABELED)
20750719aaf5SGuido Trentalancia oc = oc->next;
20760719aaf5SGuido Trentalancia if (!oc) {
2077b54c85c1Speter enderborg pr_err("SELinux: unable to look up"
20780719aaf5SGuido Trentalancia " the initial SIDs list\n");
20790719aaf5SGuido Trentalancia goto bad;
20800719aaf5SGuido Trentalancia }
2081ee1a84fdSOndrej Mosnacek rc = mls_range_set(newc, &oc->context[0].range);
20820719aaf5SGuido Trentalancia if (rc)
20830719aaf5SGuido Trentalancia goto bad;
20840719aaf5SGuido Trentalancia }
20851da177e4SLinus Torvalds
20861da177e4SLinus Torvalds /* Check the validity of the new context. */
2087ee1a84fdSOndrej Mosnacek if (!policydb_context_isvalid(args->newp, newc)) {
2088e67b7985SStephen Smalley rc = convert_context_handle_invalid_context(args->oldp, oldc);
20891da177e4SLinus Torvalds if (rc)
20901da177e4SLinus Torvalds goto bad;
20911da177e4SLinus Torvalds }
20921da177e4SLinus Torvalds
2093ee1a84fdSOndrej Mosnacek return 0;
20941da177e4SLinus Torvalds bad:
209512b29f34SStephen Smalley /* Map old representation to string and save it. */
2096ee1a84fdSOndrej Mosnacek rc = context_struct_to_string(args->oldp, oldc, &s, &len);
20974b02b524SEric Paris if (rc)
20984b02b524SEric Paris return rc;
2099ee1a84fdSOndrej Mosnacek context_destroy(newc);
2100ee1a84fdSOndrej Mosnacek newc->str = s;
2101ee1a84fdSOndrej Mosnacek newc->len = len;
2102b54c85c1Speter enderborg pr_info("SELinux: Context %s became invalid (unmapped).\n",
2103ee1a84fdSOndrej Mosnacek newc->str);
2104ee1a84fdSOndrej Mosnacek return 0;
21051da177e4SLinus Torvalds }
21061da177e4SLinus Torvalds
security_load_policycaps(struct selinux_policy * policy)2107e67b7985SStephen Smalley static void security_load_policycaps(struct selinux_policy *policy)
21083bb56b25SPaul Moore {
210946169802SStephen Smalley struct policydb *p;
21104dc2fce3SStephen Smalley unsigned int i;
21114dc2fce3SStephen Smalley struct ebitmap_node *node;
21124dc2fce3SStephen Smalley
21131b8b31a2SStephen Smalley p = &policy->policydb;
211446169802SStephen Smalley
2115e67b7985SStephen Smalley for (i = 0; i < ARRAY_SIZE(selinux_state.policycap); i++)
2116e67b7985SStephen Smalley WRITE_ONCE(selinux_state.policycap[i],
2117e8ba53d0SStephen Smalley ebitmap_get_bit(&p->policycaps, i));
21184dc2fce3SStephen Smalley
21194dc2fce3SStephen Smalley for (i = 0; i < ARRAY_SIZE(selinux_policycap_names); i++)
21204dc2fce3SStephen Smalley pr_info("SELinux: policy capability %s=%d\n",
21214dc2fce3SStephen Smalley selinux_policycap_names[i],
2122aa8e712cSStephen Smalley ebitmap_get_bit(&p->policycaps, i));
21234dc2fce3SStephen Smalley
2124aa8e712cSStephen Smalley ebitmap_for_each_positive_bit(&p->policycaps, node, i) {
21254dc2fce3SStephen Smalley if (i >= ARRAY_SIZE(selinux_policycap_names))
21264dc2fce3SStephen Smalley pr_info("SELinux: unknown policy capability %u\n",
21274dc2fce3SStephen Smalley i);
21284dc2fce3SStephen Smalley }
21293bb56b25SPaul Moore }
21303bb56b25SPaul Moore
21311b8b31a2SStephen Smalley static int security_preserve_bools(struct selinux_policy *oldpolicy,
21321b8b31a2SStephen Smalley struct selinux_policy *newpolicy);
21331da177e4SLinus Torvalds
selinux_policy_free(struct selinux_policy * policy)213446169802SStephen Smalley static void selinux_policy_free(struct selinux_policy *policy)
213546169802SStephen Smalley {
213646169802SStephen Smalley if (!policy)
213746169802SStephen Smalley return;
213846169802SStephen Smalley
2139c7c556f1SStephen Smalley sidtab_destroy(policy->sidtab);
214046169802SStephen Smalley kfree(policy->map.mapping);
21410256b0aaSDan Carpenter policydb_destroy(&policy->policydb);
21420256b0aaSDan Carpenter kfree(policy->sidtab);
214346169802SStephen Smalley kfree(policy);
214446169802SStephen Smalley }
214546169802SStephen Smalley
selinux_policy_cond_free(struct selinux_policy * policy)21461b8b31a2SStephen Smalley static void selinux_policy_cond_free(struct selinux_policy *policy)
21471b8b31a2SStephen Smalley {
21481b8b31a2SStephen Smalley cond_policydb_destroy_dup(&policy->policydb);
21491b8b31a2SStephen Smalley kfree(policy);
21501b8b31a2SStephen Smalley }
21511b8b31a2SStephen Smalley
selinux_policy_cancel(struct selinux_load_state * load_state)2152e67b7985SStephen Smalley void selinux_policy_cancel(struct selinux_load_state *load_state)
215302a52c5cSStephen Smalley {
2154e67b7985SStephen Smalley struct selinux_state *state = &selinux_state;
21551b8b31a2SStephen Smalley struct selinux_policy *oldpolicy;
21561b8b31a2SStephen Smalley
21579ff9abc4SStephen Smalley oldpolicy = rcu_dereference_protected(state->policy,
21589ff9abc4SStephen Smalley lockdep_is_held(&state->policy_mutex));
21591b8b31a2SStephen Smalley
21601b8b31a2SStephen Smalley sidtab_cancel_convert(oldpolicy->sidtab);
21616406887aSOndrej Mosnacek selinux_policy_free(load_state->policy);
21626406887aSOndrej Mosnacek kfree(load_state->convert_data);
216302a52c5cSStephen Smalley }
216402a52c5cSStephen Smalley
selinux_notify_policy_change(u32 seqno)2165e67b7985SStephen Smalley static void selinux_notify_policy_change(u32 seqno)
2166c7c556f1SStephen Smalley {
2167c7c556f1SStephen Smalley /* Flush external caches and notify userspace of policy load */
2168e67b7985SStephen Smalley avc_ss_reset(seqno);
2169c7c556f1SStephen Smalley selnl_notify_policyload(seqno);
2170e67b7985SStephen Smalley selinux_status_update_policyload(seqno);
2171c7c556f1SStephen Smalley selinux_netlbl_cache_invalidate();
2172c7c556f1SStephen Smalley selinux_xfrm_notify_policyload();
2173e67b7985SStephen Smalley selinux_ima_measure_state_locked();
2174c7c556f1SStephen Smalley }
2175c7c556f1SStephen Smalley
selinux_policy_commit(struct selinux_load_state * load_state)2176e67b7985SStephen Smalley void selinux_policy_commit(struct selinux_load_state *load_state)
217746169802SStephen Smalley {
2178e67b7985SStephen Smalley struct selinux_state *state = &selinux_state;
21796406887aSOndrej Mosnacek struct selinux_policy *oldpolicy, *newpolicy = load_state->policy;
21809ad6e9cbSOndrej Mosnacek unsigned long flags;
218146169802SStephen Smalley u32 seqno;
218246169802SStephen Smalley
21839ff9abc4SStephen Smalley oldpolicy = rcu_dereference_protected(state->policy,
21849ff9abc4SStephen Smalley lockdep_is_held(&state->policy_mutex));
218546169802SStephen Smalley
218646169802SStephen Smalley /* If switching between different policy types, log MLS status */
218746169802SStephen Smalley if (oldpolicy) {
218846169802SStephen Smalley if (oldpolicy->policydb.mls_enabled && !newpolicy->policydb.mls_enabled)
218946169802SStephen Smalley pr_info("SELinux: Disabling MLS support...\n");
219046169802SStephen Smalley else if (!oldpolicy->policydb.mls_enabled && newpolicy->policydb.mls_enabled)
219146169802SStephen Smalley pr_info("SELinux: Enabling MLS support...\n");
219246169802SStephen Smalley }
219346169802SStephen Smalley
21941b8b31a2SStephen Smalley /* Set latest granting seqno for new policy. */
21951b8b31a2SStephen Smalley if (oldpolicy)
21961b8b31a2SStephen Smalley newpolicy->latest_granting = oldpolicy->latest_granting + 1;
21971b8b31a2SStephen Smalley else
21981b8b31a2SStephen Smalley newpolicy->latest_granting = 1;
21991b8b31a2SStephen Smalley seqno = newpolicy->latest_granting;
22001b8b31a2SStephen Smalley
220146169802SStephen Smalley /* Install the new policy. */
22029ad6e9cbSOndrej Mosnacek if (oldpolicy) {
22039ad6e9cbSOndrej Mosnacek sidtab_freeze_begin(oldpolicy->sidtab, &flags);
22041b8b31a2SStephen Smalley rcu_assign_pointer(state->policy, newpolicy);
22059ad6e9cbSOndrej Mosnacek sidtab_freeze_end(oldpolicy->sidtab, &flags);
22069ad6e9cbSOndrej Mosnacek } else {
22079ad6e9cbSOndrej Mosnacek rcu_assign_pointer(state->policy, newpolicy);
22089ad6e9cbSOndrej Mosnacek }
220946169802SStephen Smalley
221046169802SStephen Smalley /* Load the policycaps from the new policy */
2211e67b7985SStephen Smalley security_load_policycaps(newpolicy);
221246169802SStephen Smalley
2213e67b7985SStephen Smalley if (!selinux_initialized()) {
221446169802SStephen Smalley /*
221546169802SStephen Smalley * After first policy load, the security server is
221646169802SStephen Smalley * marked as initialized and ready to handle requests and
221746169802SStephen Smalley * any objects created prior to policy load are then labeled.
221846169802SStephen Smalley */
2219e67b7985SStephen Smalley selinux_mark_initialized();
222046169802SStephen Smalley selinux_complete_init();
222146169802SStephen Smalley }
222246169802SStephen Smalley
222346169802SStephen Smalley /* Free the old policy */
22241b8b31a2SStephen Smalley synchronize_rcu();
222546169802SStephen Smalley selinux_policy_free(oldpolicy);
22266406887aSOndrej Mosnacek kfree(load_state->convert_data);
222746169802SStephen Smalley
2228c7c556f1SStephen Smalley /* Notify others of the policy change */
2229e67b7985SStephen Smalley selinux_notify_policy_change(seqno);
223046169802SStephen Smalley }
223146169802SStephen Smalley
22321da177e4SLinus Torvalds /**
22331da177e4SLinus Torvalds * security_load_policy - Load a security policy configuration.
22341da177e4SLinus Torvalds * @data: binary policy data
22351da177e4SLinus Torvalds * @len: length of data in bytes
2236e9fd7292SPaul Moore * @load_state: policy load state
22371da177e4SLinus Torvalds *
22381da177e4SLinus Torvalds * Load a new set of security policy configuration data,
22391da177e4SLinus Torvalds * validate it and convert the SID table as necessary.
22401da177e4SLinus Torvalds * This function will flush the access vector cache after
22411da177e4SLinus Torvalds * loading the new policy.
22421da177e4SLinus Torvalds */
security_load_policy(void * data,size_t len,struct selinux_load_state * load_state)2243e67b7985SStephen Smalley int security_load_policy(void *data, size_t len,
22446406887aSOndrej Mosnacek struct selinux_load_state *load_state)
22451da177e4SLinus Torvalds {
2246e67b7985SStephen Smalley struct selinux_state *state = &selinux_state;
22471b8b31a2SStephen Smalley struct selinux_policy *newpolicy, *oldpolicy;
22486406887aSOndrej Mosnacek struct selinux_policy_convert_data *convert_data;
22491da177e4SLinus Torvalds int rc = 0;
22501da177e4SLinus Torvalds struct policy_file file = { data, len }, *fp = &file;
22511da177e4SLinus Torvalds
225246169802SStephen Smalley newpolicy = kzalloc(sizeof(*newpolicy), GFP_KERNEL);
225346169802SStephen Smalley if (!newpolicy)
2254dd89b9d9SOndrej Mosnacek return -ENOMEM;
2255aa8e712cSStephen Smalley
2256c7c556f1SStephen Smalley newpolicy->sidtab = kzalloc(sizeof(*newpolicy->sidtab), GFP_KERNEL);
22570256b0aaSDan Carpenter if (!newpolicy->sidtab) {
22580256b0aaSDan Carpenter rc = -ENOMEM;
22590256b0aaSDan Carpenter goto err_policy;
22600256b0aaSDan Carpenter }
2261c7c556f1SStephen Smalley
226246169802SStephen Smalley rc = policydb_read(&newpolicy->policydb, fp);
2263a2000050SEric Paris if (rc)
22640256b0aaSDan Carpenter goto err_sidtab;
2265b94c7e67SChad Sellers
226646169802SStephen Smalley newpolicy->policydb.len = len;
226746169802SStephen Smalley rc = selinux_set_mapping(&newpolicy->policydb, secclass_map,
226846169802SStephen Smalley &newpolicy->map);
226946169802SStephen Smalley if (rc)
22700256b0aaSDan Carpenter goto err_policydb;
227146169802SStephen Smalley
2272c7c556f1SStephen Smalley rc = policydb_load_isids(&newpolicy->policydb, newpolicy->sidtab);
227346169802SStephen Smalley if (rc) {
227446169802SStephen Smalley pr_err("SELinux: unable to load the initial SIDs\n");
22750256b0aaSDan Carpenter goto err_mapping;
227646169802SStephen Smalley }
227746169802SStephen Smalley
2278e67b7985SStephen Smalley if (!selinux_initialized()) {
227946169802SStephen Smalley /* First policy load, so no need to preserve state from old policy */
22806406887aSOndrej Mosnacek load_state->policy = newpolicy;
22816406887aSOndrej Mosnacek load_state->convert_data = NULL;
228246169802SStephen Smalley return 0;
228346169802SStephen Smalley }
228446169802SStephen Smalley
22859ff9abc4SStephen Smalley oldpolicy = rcu_dereference_protected(state->policy,
22869ff9abc4SStephen Smalley lockdep_is_held(&state->policy_mutex));
22871b8b31a2SStephen Smalley
228846169802SStephen Smalley /* Preserve active boolean values from the old policy */
22891b8b31a2SStephen Smalley rc = security_preserve_bools(oldpolicy, newpolicy);
2290e900a7d9SStephen Smalley if (rc) {
2291b54c85c1Speter enderborg pr_err("SELinux: unable to preserve booleans\n");
22920256b0aaSDan Carpenter goto err_free_isids;
2293e900a7d9SStephen Smalley }
2294e900a7d9SStephen Smalley
2295048be156SPaul Moore /*
2296048be156SPaul Moore * Convert the internal representations of contexts
2297048be156SPaul Moore * in the new SID table.
2298048be156SPaul Moore */
2299048be156SPaul Moore
23006406887aSOndrej Mosnacek convert_data = kmalloc(sizeof(*convert_data), GFP_KERNEL);
23016406887aSOndrej Mosnacek if (!convert_data) {
23026406887aSOndrej Mosnacek rc = -ENOMEM;
23036406887aSOndrej Mosnacek goto err_free_isids;
23046406887aSOndrej Mosnacek }
23056406887aSOndrej Mosnacek
23066406887aSOndrej Mosnacek convert_data->args.oldp = &oldpolicy->policydb;
23076406887aSOndrej Mosnacek convert_data->args.newp = &newpolicy->policydb;
2308ee1a84fdSOndrej Mosnacek
23096406887aSOndrej Mosnacek convert_data->sidtab_params.args = &convert_data->args;
23106406887aSOndrej Mosnacek convert_data->sidtab_params.target = newpolicy->sidtab;
2311ee1a84fdSOndrej Mosnacek
23126406887aSOndrej Mosnacek rc = sidtab_convert(oldpolicy->sidtab, &convert_data->sidtab_params);
23130719aaf5SGuido Trentalancia if (rc) {
2314b54c85c1Speter enderborg pr_err("SELinux: unable to convert the internal"
23150719aaf5SGuido Trentalancia " representation of contexts in the new SID"
23160719aaf5SGuido Trentalancia " table\n");
23176406887aSOndrej Mosnacek goto err_free_convert_data;
23180719aaf5SGuido Trentalancia }
23191da177e4SLinus Torvalds
23206406887aSOndrej Mosnacek load_state->policy = newpolicy;
23216406887aSOndrej Mosnacek load_state->convert_data = convert_data;
232246169802SStephen Smalley return 0;
23230256b0aaSDan Carpenter
23246406887aSOndrej Mosnacek err_free_convert_data:
23256406887aSOndrej Mosnacek kfree(convert_data);
23260256b0aaSDan Carpenter err_free_isids:
23270256b0aaSDan Carpenter sidtab_destroy(newpolicy->sidtab);
23280256b0aaSDan Carpenter err_mapping:
23290256b0aaSDan Carpenter kfree(newpolicy->map.mapping);
23300256b0aaSDan Carpenter err_policydb:
23310256b0aaSDan Carpenter policydb_destroy(&newpolicy->policydb);
23320256b0aaSDan Carpenter err_sidtab:
23330256b0aaSDan Carpenter kfree(newpolicy->sidtab);
23340256b0aaSDan Carpenter err_policy:
23350256b0aaSDan Carpenter kfree(newpolicy);
23360256b0aaSDan Carpenter
2337b5495b42STim Gardner return rc;
23381da177e4SLinus Torvalds }
23391da177e4SLinus Torvalds
23401da177e4SLinus Torvalds /**
2341cbfcd13bSOndrej Mosnacek * ocontext_to_sid - Helper to safely get sid for an ocontext
2342cbfcd13bSOndrej Mosnacek * @sidtab: SID table
2343cbfcd13bSOndrej Mosnacek * @c: ocontext structure
2344cbfcd13bSOndrej Mosnacek * @index: index of the context entry (0 or 1)
2345cbfcd13bSOndrej Mosnacek * @out_sid: pointer to the resulting SID value
2346cbfcd13bSOndrej Mosnacek *
2347cbfcd13bSOndrej Mosnacek * For all ocontexts except OCON_ISID the SID fields are populated
2348cbfcd13bSOndrej Mosnacek * on-demand when needed. Since updating the SID value is an SMP-sensitive
2349cbfcd13bSOndrej Mosnacek * operation, this helper must be used to do that safely.
2350cbfcd13bSOndrej Mosnacek *
2351cbfcd13bSOndrej Mosnacek * WARNING: This function may return -ESTALE, indicating that the caller
2352cbfcd13bSOndrej Mosnacek * must retry the operation after re-acquiring the policy pointer!
2353cbfcd13bSOndrej Mosnacek */
ocontext_to_sid(struct sidtab * sidtab,struct ocontext * c,size_t index,u32 * out_sid)2354cbfcd13bSOndrej Mosnacek static int ocontext_to_sid(struct sidtab *sidtab, struct ocontext *c,
2355cbfcd13bSOndrej Mosnacek size_t index, u32 *out_sid)
2356cbfcd13bSOndrej Mosnacek {
2357cbfcd13bSOndrej Mosnacek int rc;
2358cbfcd13bSOndrej Mosnacek u32 sid;
2359cbfcd13bSOndrej Mosnacek
2360cbfcd13bSOndrej Mosnacek /* Ensure the associated sidtab entry is visible to this thread. */
2361cbfcd13bSOndrej Mosnacek sid = smp_load_acquire(&c->sid[index]);
2362cbfcd13bSOndrej Mosnacek if (!sid) {
2363cbfcd13bSOndrej Mosnacek rc = sidtab_context_to_sid(sidtab, &c->context[index], &sid);
2364cbfcd13bSOndrej Mosnacek if (rc)
2365cbfcd13bSOndrej Mosnacek return rc;
2366cbfcd13bSOndrej Mosnacek
2367cbfcd13bSOndrej Mosnacek /*
2368cbfcd13bSOndrej Mosnacek * Ensure the new sidtab entry is visible to other threads
2369cbfcd13bSOndrej Mosnacek * when they see the SID.
2370cbfcd13bSOndrej Mosnacek */
2371cbfcd13bSOndrej Mosnacek smp_store_release(&c->sid[index], sid);
2372cbfcd13bSOndrej Mosnacek }
2373cbfcd13bSOndrej Mosnacek *out_sid = sid;
2374cbfcd13bSOndrej Mosnacek return 0;
2375cbfcd13bSOndrej Mosnacek }
2376cbfcd13bSOndrej Mosnacek
2377cbfcd13bSOndrej Mosnacek /**
23781da177e4SLinus Torvalds * security_port_sid - Obtain the SID for a port.
23791da177e4SLinus Torvalds * @protocol: protocol number
23801da177e4SLinus Torvalds * @port: port number
23811da177e4SLinus Torvalds * @out_sid: security identifier
23821da177e4SLinus Torvalds */
security_port_sid(u8 protocol,u16 port,u32 * out_sid)2383e67b7985SStephen Smalley int security_port_sid(u8 protocol, u16 port, u32 *out_sid)
23841da177e4SLinus Torvalds {
23851b8b31a2SStephen Smalley struct selinux_policy *policy;
2386aa8e712cSStephen Smalley struct policydb *policydb;
2387225621c9SOndrej Mosnacek struct sidtab *sidtab;
23881da177e4SLinus Torvalds struct ocontext *c;
23899ad6e9cbSOndrej Mosnacek int rc;
23901da177e4SLinus Torvalds
2391e67b7985SStephen Smalley if (!selinux_initialized()) {
239237ea433cSStephen Smalley *out_sid = SECINITSID_PORT;
239337ea433cSStephen Smalley return 0;
239437ea433cSStephen Smalley }
239537ea433cSStephen Smalley
23969ad6e9cbSOndrej Mosnacek retry:
23979ad6e9cbSOndrej Mosnacek rc = 0;
23981b8b31a2SStephen Smalley rcu_read_lock();
2399e67b7985SStephen Smalley policy = rcu_dereference(selinux_state.policy);
24001b8b31a2SStephen Smalley policydb = &policy->policydb;
24011b8b31a2SStephen Smalley sidtab = policy->sidtab;
2402aa8e712cSStephen Smalley
2403aa8e712cSStephen Smalley c = policydb->ocontexts[OCON_PORT];
24041da177e4SLinus Torvalds while (c) {
24051da177e4SLinus Torvalds if (c->u.port.protocol == protocol &&
24061da177e4SLinus Torvalds c->u.port.low_port <= port &&
24071da177e4SLinus Torvalds c->u.port.high_port >= port)
24081da177e4SLinus Torvalds break;
24091da177e4SLinus Torvalds c = c->next;
24101da177e4SLinus Torvalds }
24111da177e4SLinus Torvalds
24121da177e4SLinus Torvalds if (c) {
2413cbfcd13bSOndrej Mosnacek rc = ocontext_to_sid(sidtab, c, 0, out_sid);
24149ad6e9cbSOndrej Mosnacek if (rc == -ESTALE) {
24159ad6e9cbSOndrej Mosnacek rcu_read_unlock();
24169ad6e9cbSOndrej Mosnacek goto retry;
24179ad6e9cbSOndrej Mosnacek }
24181da177e4SLinus Torvalds if (rc)
24191da177e4SLinus Torvalds goto out;
24201da177e4SLinus Torvalds } else {
24211da177e4SLinus Torvalds *out_sid = SECINITSID_PORT;
24221da177e4SLinus Torvalds }
24231da177e4SLinus Torvalds
24241da177e4SLinus Torvalds out:
24251b8b31a2SStephen Smalley rcu_read_unlock();
24261da177e4SLinus Torvalds return rc;
24271da177e4SLinus Torvalds }
24281da177e4SLinus Torvalds
24291da177e4SLinus Torvalds /**
2430d0a83314SYang Li * security_ib_pkey_sid - Obtain the SID for a pkey.
2431cfc4d882SDaniel Jurgens * @subnet_prefix: Subnet Prefix
2432cfc4d882SDaniel Jurgens * @pkey_num: pkey number
2433cfc4d882SDaniel Jurgens * @out_sid: security identifier
2434cfc4d882SDaniel Jurgens */
security_ib_pkey_sid(u64 subnet_prefix,u16 pkey_num,u32 * out_sid)2435e67b7985SStephen Smalley int security_ib_pkey_sid(u64 subnet_prefix, u16 pkey_num, u32 *out_sid)
2436cfc4d882SDaniel Jurgens {
24371b8b31a2SStephen Smalley struct selinux_policy *policy;
2438aa8e712cSStephen Smalley struct policydb *policydb;
2439225621c9SOndrej Mosnacek struct sidtab *sidtab;
2440cfc4d882SDaniel Jurgens struct ocontext *c;
24419ad6e9cbSOndrej Mosnacek int rc;
2442cfc4d882SDaniel Jurgens
2443e67b7985SStephen Smalley if (!selinux_initialized()) {
244437ea433cSStephen Smalley *out_sid = SECINITSID_UNLABELED;
244537ea433cSStephen Smalley return 0;
244637ea433cSStephen Smalley }
244737ea433cSStephen Smalley
24489ad6e9cbSOndrej Mosnacek retry:
24499ad6e9cbSOndrej Mosnacek rc = 0;
24501b8b31a2SStephen Smalley rcu_read_lock();
2451e67b7985SStephen Smalley policy = rcu_dereference(selinux_state.policy);
24521b8b31a2SStephen Smalley policydb = &policy->policydb;
24531b8b31a2SStephen Smalley sidtab = policy->sidtab;
2454aa8e712cSStephen Smalley
2455aa8e712cSStephen Smalley c = policydb->ocontexts[OCON_IBPKEY];
2456cfc4d882SDaniel Jurgens while (c) {
2457cfc4d882SDaniel Jurgens if (c->u.ibpkey.low_pkey <= pkey_num &&
2458cfc4d882SDaniel Jurgens c->u.ibpkey.high_pkey >= pkey_num &&
2459cfc4d882SDaniel Jurgens c->u.ibpkey.subnet_prefix == subnet_prefix)
2460cfc4d882SDaniel Jurgens break;
2461cfc4d882SDaniel Jurgens
2462cfc4d882SDaniel Jurgens c = c->next;
2463cfc4d882SDaniel Jurgens }
2464cfc4d882SDaniel Jurgens
2465cfc4d882SDaniel Jurgens if (c) {
2466cbfcd13bSOndrej Mosnacek rc = ocontext_to_sid(sidtab, c, 0, out_sid);
24679ad6e9cbSOndrej Mosnacek if (rc == -ESTALE) {
24689ad6e9cbSOndrej Mosnacek rcu_read_unlock();
24699ad6e9cbSOndrej Mosnacek goto retry;
24709ad6e9cbSOndrej Mosnacek }
2471cfc4d882SDaniel Jurgens if (rc)
2472cfc4d882SDaniel Jurgens goto out;
2473cfc4d882SDaniel Jurgens } else
2474cfc4d882SDaniel Jurgens *out_sid = SECINITSID_UNLABELED;
2475cfc4d882SDaniel Jurgens
2476cfc4d882SDaniel Jurgens out:
24771b8b31a2SStephen Smalley rcu_read_unlock();
2478cfc4d882SDaniel Jurgens return rc;
2479cfc4d882SDaniel Jurgens }
2480cfc4d882SDaniel Jurgens
2481cfc4d882SDaniel Jurgens /**
2482ab861dfcSDaniel Jurgens * security_ib_endport_sid - Obtain the SID for a subnet management interface.
2483ab861dfcSDaniel Jurgens * @dev_name: device name
2484e9fd7292SPaul Moore * @port_num: port number
2485ab861dfcSDaniel Jurgens * @out_sid: security identifier
2486ab861dfcSDaniel Jurgens */
security_ib_endport_sid(const char * dev_name,u8 port_num,u32 * out_sid)2487e67b7985SStephen Smalley int security_ib_endport_sid(const char *dev_name, u8 port_num, u32 *out_sid)
2488ab861dfcSDaniel Jurgens {
24891b8b31a2SStephen Smalley struct selinux_policy *policy;
2490aa8e712cSStephen Smalley struct policydb *policydb;
2491225621c9SOndrej Mosnacek struct sidtab *sidtab;
2492ab861dfcSDaniel Jurgens struct ocontext *c;
24939ad6e9cbSOndrej Mosnacek int rc;
2494ab861dfcSDaniel Jurgens
2495e67b7985SStephen Smalley if (!selinux_initialized()) {
249637ea433cSStephen Smalley *out_sid = SECINITSID_UNLABELED;
249737ea433cSStephen Smalley return 0;
249837ea433cSStephen Smalley }
249937ea433cSStephen Smalley
25009ad6e9cbSOndrej Mosnacek retry:
25019ad6e9cbSOndrej Mosnacek rc = 0;
25021b8b31a2SStephen Smalley rcu_read_lock();
2503e67b7985SStephen Smalley policy = rcu_dereference(selinux_state.policy);
25041b8b31a2SStephen Smalley policydb = &policy->policydb;
25051b8b31a2SStephen Smalley sidtab = policy->sidtab;
2506aa8e712cSStephen Smalley
2507aa8e712cSStephen Smalley c = policydb->ocontexts[OCON_IBENDPORT];
2508ab861dfcSDaniel Jurgens while (c) {
2509ab861dfcSDaniel Jurgens if (c->u.ibendport.port == port_num &&
2510ab861dfcSDaniel Jurgens !strncmp(c->u.ibendport.dev_name,
2511ab861dfcSDaniel Jurgens dev_name,
2512ab861dfcSDaniel Jurgens IB_DEVICE_NAME_MAX))
2513ab861dfcSDaniel Jurgens break;
2514ab861dfcSDaniel Jurgens
2515ab861dfcSDaniel Jurgens c = c->next;
2516ab861dfcSDaniel Jurgens }
2517ab861dfcSDaniel Jurgens
2518ab861dfcSDaniel Jurgens if (c) {
2519cbfcd13bSOndrej Mosnacek rc = ocontext_to_sid(sidtab, c, 0, out_sid);
25209ad6e9cbSOndrej Mosnacek if (rc == -ESTALE) {
25219ad6e9cbSOndrej Mosnacek rcu_read_unlock();
25229ad6e9cbSOndrej Mosnacek goto retry;
25239ad6e9cbSOndrej Mosnacek }
2524ab861dfcSDaniel Jurgens if (rc)
2525ab861dfcSDaniel Jurgens goto out;
2526ab861dfcSDaniel Jurgens } else
2527ab861dfcSDaniel Jurgens *out_sid = SECINITSID_UNLABELED;
2528ab861dfcSDaniel Jurgens
2529ab861dfcSDaniel Jurgens out:
25301b8b31a2SStephen Smalley rcu_read_unlock();
2531ab861dfcSDaniel Jurgens return rc;
2532ab861dfcSDaniel Jurgens }
2533ab861dfcSDaniel Jurgens
2534ab861dfcSDaniel Jurgens /**
25351da177e4SLinus Torvalds * security_netif_sid - Obtain the SID for a network interface.
25361da177e4SLinus Torvalds * @name: interface name
25371da177e4SLinus Torvalds * @if_sid: interface SID
25381da177e4SLinus Torvalds */
security_netif_sid(char * name,u32 * if_sid)2539e67b7985SStephen Smalley int security_netif_sid(char *name, u32 *if_sid)
25401da177e4SLinus Torvalds {
25411b8b31a2SStephen Smalley struct selinux_policy *policy;
2542aa8e712cSStephen Smalley struct policydb *policydb;
2543225621c9SOndrej Mosnacek struct sidtab *sidtab;
25449ad6e9cbSOndrej Mosnacek int rc;
25451da177e4SLinus Torvalds struct ocontext *c;
25461da177e4SLinus Torvalds
2547e67b7985SStephen Smalley if (!selinux_initialized()) {
254837ea433cSStephen Smalley *if_sid = SECINITSID_NETIF;
254937ea433cSStephen Smalley return 0;
255037ea433cSStephen Smalley }
255137ea433cSStephen Smalley
25529ad6e9cbSOndrej Mosnacek retry:
25539ad6e9cbSOndrej Mosnacek rc = 0;
25541b8b31a2SStephen Smalley rcu_read_lock();
2555e67b7985SStephen Smalley policy = rcu_dereference(selinux_state.policy);
25561b8b31a2SStephen Smalley policydb = &policy->policydb;
25571b8b31a2SStephen Smalley sidtab = policy->sidtab;
2558aa8e712cSStephen Smalley
2559aa8e712cSStephen Smalley c = policydb->ocontexts[OCON_NETIF];
25601da177e4SLinus Torvalds while (c) {
25611da177e4SLinus Torvalds if (strcmp(name, c->u.name) == 0)
25621da177e4SLinus Torvalds break;
25631da177e4SLinus Torvalds c = c->next;
25641da177e4SLinus Torvalds }
25651da177e4SLinus Torvalds
25661da177e4SLinus Torvalds if (c) {
2567cbfcd13bSOndrej Mosnacek rc = ocontext_to_sid(sidtab, c, 0, if_sid);
25689ad6e9cbSOndrej Mosnacek if (rc == -ESTALE) {
25699ad6e9cbSOndrej Mosnacek rcu_read_unlock();
25709ad6e9cbSOndrej Mosnacek goto retry;
25719ad6e9cbSOndrej Mosnacek }
25721da177e4SLinus Torvalds if (rc)
25731da177e4SLinus Torvalds goto out;
2574e8bfdb9dSPaul Moore } else
25751da177e4SLinus Torvalds *if_sid = SECINITSID_NETIF;
25761da177e4SLinus Torvalds
25771da177e4SLinus Torvalds out:
25781b8b31a2SStephen Smalley rcu_read_unlock();
25791da177e4SLinus Torvalds return rc;
25801da177e4SLinus Torvalds }
25811da177e4SLinus Torvalds
match_ipv6_addrmask(u32 * input,u32 * addr,u32 * mask)25821da177e4SLinus Torvalds static int match_ipv6_addrmask(u32 *input, u32 *addr, u32 *mask)
25831da177e4SLinus Torvalds {
25841da177e4SLinus Torvalds int i, fail = 0;
25851da177e4SLinus Torvalds
25861da177e4SLinus Torvalds for (i = 0; i < 4; i++)
25871da177e4SLinus Torvalds if (addr[i] != (input[i] & mask[i])) {
25881da177e4SLinus Torvalds fail = 1;
25891da177e4SLinus Torvalds break;
25901da177e4SLinus Torvalds }
25911da177e4SLinus Torvalds
25921da177e4SLinus Torvalds return !fail;
25931da177e4SLinus Torvalds }
25941da177e4SLinus Torvalds
25951da177e4SLinus Torvalds /**
25961da177e4SLinus Torvalds * security_node_sid - Obtain the SID for a node (host).
25971da177e4SLinus Torvalds * @domain: communication domain aka address family
25981da177e4SLinus Torvalds * @addrp: address
25991da177e4SLinus Torvalds * @addrlen: address length in bytes
26001da177e4SLinus Torvalds * @out_sid: security identifier
26011da177e4SLinus Torvalds */
security_node_sid(u16 domain,void * addrp,u32 addrlen,u32 * out_sid)2602e67b7985SStephen Smalley int security_node_sid(u16 domain,
26031da177e4SLinus Torvalds void *addrp,
26041da177e4SLinus Torvalds u32 addrlen,
26051da177e4SLinus Torvalds u32 *out_sid)
26061da177e4SLinus Torvalds {
26071b8b31a2SStephen Smalley struct selinux_policy *policy;
2608aa8e712cSStephen Smalley struct policydb *policydb;
2609225621c9SOndrej Mosnacek struct sidtab *sidtab;
26104b02b524SEric Paris int rc;
26111da177e4SLinus Torvalds struct ocontext *c;
26121da177e4SLinus Torvalds
2613e67b7985SStephen Smalley if (!selinux_initialized()) {
261437ea433cSStephen Smalley *out_sid = SECINITSID_NODE;
261537ea433cSStephen Smalley return 0;
261637ea433cSStephen Smalley }
261737ea433cSStephen Smalley
26189ad6e9cbSOndrej Mosnacek retry:
26191b8b31a2SStephen Smalley rcu_read_lock();
2620e67b7985SStephen Smalley policy = rcu_dereference(selinux_state.policy);
26211b8b31a2SStephen Smalley policydb = &policy->policydb;
26221b8b31a2SStephen Smalley sidtab = policy->sidtab;
26231da177e4SLinus Torvalds
26241da177e4SLinus Torvalds switch (domain) {
26251da177e4SLinus Torvalds case AF_INET: {
26261da177e4SLinus Torvalds u32 addr;
26271da177e4SLinus Torvalds
26281da177e4SLinus Torvalds rc = -EINVAL;
26294b02b524SEric Paris if (addrlen != sizeof(u32))
26301da177e4SLinus Torvalds goto out;
26311da177e4SLinus Torvalds
26321da177e4SLinus Torvalds addr = *((u32 *)addrp);
26331da177e4SLinus Torvalds
2634aa8e712cSStephen Smalley c = policydb->ocontexts[OCON_NODE];
26351da177e4SLinus Torvalds while (c) {
26361da177e4SLinus Torvalds if (c->u.node.addr == (addr & c->u.node.mask))
26371da177e4SLinus Torvalds break;
26381da177e4SLinus Torvalds c = c->next;
26391da177e4SLinus Torvalds }
26401da177e4SLinus Torvalds break;
26411da177e4SLinus Torvalds }
26421da177e4SLinus Torvalds
26431da177e4SLinus Torvalds case AF_INET6:
26441da177e4SLinus Torvalds rc = -EINVAL;
26454b02b524SEric Paris if (addrlen != sizeof(u64) * 2)
26461da177e4SLinus Torvalds goto out;
2647aa8e712cSStephen Smalley c = policydb->ocontexts[OCON_NODE6];
26481da177e4SLinus Torvalds while (c) {
26491da177e4SLinus Torvalds if (match_ipv6_addrmask(addrp, c->u.node6.addr,
26501da177e4SLinus Torvalds c->u.node6.mask))
26511da177e4SLinus Torvalds break;
26521da177e4SLinus Torvalds c = c->next;
26531da177e4SLinus Torvalds }
26541da177e4SLinus Torvalds break;
26551da177e4SLinus Torvalds
26561da177e4SLinus Torvalds default:
26574b02b524SEric Paris rc = 0;
26581da177e4SLinus Torvalds *out_sid = SECINITSID_NODE;
26591da177e4SLinus Torvalds goto out;
26601da177e4SLinus Torvalds }
26611da177e4SLinus Torvalds
26621da177e4SLinus Torvalds if (c) {
2663cbfcd13bSOndrej Mosnacek rc = ocontext_to_sid(sidtab, c, 0, out_sid);
26649ad6e9cbSOndrej Mosnacek if (rc == -ESTALE) {
26659ad6e9cbSOndrej Mosnacek rcu_read_unlock();
26669ad6e9cbSOndrej Mosnacek goto retry;
26679ad6e9cbSOndrej Mosnacek }
26681da177e4SLinus Torvalds if (rc)
26691da177e4SLinus Torvalds goto out;
26701da177e4SLinus Torvalds } else {
26711da177e4SLinus Torvalds *out_sid = SECINITSID_NODE;
26721da177e4SLinus Torvalds }
26731da177e4SLinus Torvalds
26744b02b524SEric Paris rc = 0;
26751da177e4SLinus Torvalds out:
26761b8b31a2SStephen Smalley rcu_read_unlock();
26771da177e4SLinus Torvalds return rc;
26781da177e4SLinus Torvalds }
26791da177e4SLinus Torvalds
26801da177e4SLinus Torvalds #define SIDS_NEL 25
26811da177e4SLinus Torvalds
26821da177e4SLinus Torvalds /**
26831da177e4SLinus Torvalds * security_get_user_sids - Obtain reachable SIDs for a user.
26841da177e4SLinus Torvalds * @fromsid: starting SID
26851da177e4SLinus Torvalds * @username: username
26861da177e4SLinus Torvalds * @sids: array of reachable SIDs for user
26871da177e4SLinus Torvalds * @nel: number of elements in @sids
26881da177e4SLinus Torvalds *
26891da177e4SLinus Torvalds * Generate the set of SIDs for legal security contexts
26901da177e4SLinus Torvalds * for a given user that can be reached by @fromsid.
26911da177e4SLinus Torvalds * Set *@sids to point to a dynamically allocated
26921da177e4SLinus Torvalds * array containing the set of SIDs. Set *@nel to the
26931da177e4SLinus Torvalds * number of elements in the array.
26941da177e4SLinus Torvalds */
26951da177e4SLinus Torvalds
security_get_user_sids(u32 fromsid,char * username,u32 ** sids,u32 * nel)2696e67b7985SStephen Smalley int security_get_user_sids(u32 fromsid,
26971da177e4SLinus Torvalds char *username,
26981da177e4SLinus Torvalds u32 **sids,
26991da177e4SLinus Torvalds u32 *nel)
27001da177e4SLinus Torvalds {
27011b8b31a2SStephen Smalley struct selinux_policy *policy;
2702aa8e712cSStephen Smalley struct policydb *policydb;
2703aa8e712cSStephen Smalley struct sidtab *sidtab;
27041da177e4SLinus Torvalds struct context *fromcon, usercon;
27052c3c05dbSStephen Smalley u32 *mysids = NULL, *mysids2, sid;
27069ad6e9cbSOndrej Mosnacek u32 i, j, mynel, maxnel = SIDS_NEL;
27071da177e4SLinus Torvalds struct user_datum *user;
27081da177e4SLinus Torvalds struct role_datum *role;
2709782ebb99SStephen Smalley struct ebitmap_node *rnode, *tnode;
27109ad6e9cbSOndrej Mosnacek int rc;
27111da177e4SLinus Torvalds
27121da177e4SLinus Torvalds *sids = NULL;
27131da177e4SLinus Torvalds *nel = 0;
27142c3c05dbSStephen Smalley
2715e67b7985SStephen Smalley if (!selinux_initialized())
27169ad6e9cbSOndrej Mosnacek return 0;
27171da177e4SLinus Torvalds
27189ad6e9cbSOndrej Mosnacek mysids = kcalloc(maxnel, sizeof(*mysids), GFP_KERNEL);
27199ad6e9cbSOndrej Mosnacek if (!mysids)
27209ad6e9cbSOndrej Mosnacek return -ENOMEM;
27219ad6e9cbSOndrej Mosnacek
27229ad6e9cbSOndrej Mosnacek retry:
27239ad6e9cbSOndrej Mosnacek mynel = 0;
27241b8b31a2SStephen Smalley rcu_read_lock();
2725e67b7985SStephen Smalley policy = rcu_dereference(selinux_state.policy);
27261b8b31a2SStephen Smalley policydb = &policy->policydb;
27271b8b31a2SStephen Smalley sidtab = policy->sidtab;
27281da177e4SLinus Torvalds
272912b29f34SStephen Smalley context_init(&usercon);
273012b29f34SStephen Smalley
27314b02b524SEric Paris rc = -EINVAL;
2732aa8e712cSStephen Smalley fromcon = sidtab_search(sidtab, fromsid);
27334b02b524SEric Paris if (!fromcon)
27341da177e4SLinus Torvalds goto out_unlock;
27351da177e4SLinus Torvalds
27361da177e4SLinus Torvalds rc = -EINVAL;
2737237389e3SOndrej Mosnacek user = symtab_search(&policydb->p_users, username);
27384b02b524SEric Paris if (!user)
27391da177e4SLinus Torvalds goto out_unlock;
27404b02b524SEric Paris
27411da177e4SLinus Torvalds usercon.user = user->value;
27421da177e4SLinus Torvalds
27439fe79ad1SKaiGai Kohei ebitmap_for_each_positive_bit(&user->roles, rnode, i) {
2744aa8e712cSStephen Smalley role = policydb->role_val_to_struct[i];
27451da177e4SLinus Torvalds usercon.role = i + 1;
27469fe79ad1SKaiGai Kohei ebitmap_for_each_positive_bit(&role->types, tnode, j) {
27471da177e4SLinus Torvalds usercon.type = j + 1;
27481da177e4SLinus Torvalds
2749aa8e712cSStephen Smalley if (mls_setup_user_range(policydb, fromcon, user,
2750aa8e712cSStephen Smalley &usercon))
27511da177e4SLinus Torvalds continue;
27521da177e4SLinus Torvalds
2753225621c9SOndrej Mosnacek rc = sidtab_context_to_sid(sidtab, &usercon, &sid);
27549ad6e9cbSOndrej Mosnacek if (rc == -ESTALE) {
27559ad6e9cbSOndrej Mosnacek rcu_read_unlock();
27569ad6e9cbSOndrej Mosnacek goto retry;
27579ad6e9cbSOndrej Mosnacek }
27582c3c05dbSStephen Smalley if (rc)
27591da177e4SLinus Torvalds goto out_unlock;
27601da177e4SLinus Torvalds if (mynel < maxnel) {
27611da177e4SLinus Torvalds mysids[mynel++] = sid;
27621da177e4SLinus Torvalds } else {
27634b02b524SEric Paris rc = -ENOMEM;
27641da177e4SLinus Torvalds maxnel += SIDS_NEL;
276589d155efSJames Morris mysids2 = kcalloc(maxnel, sizeof(*mysids2), GFP_ATOMIC);
27664b02b524SEric Paris if (!mysids2)
27671da177e4SLinus Torvalds goto out_unlock;
27681da177e4SLinus Torvalds memcpy(mysids2, mysids, mynel * sizeof(*mysids2));
27691da177e4SLinus Torvalds kfree(mysids);
27701da177e4SLinus Torvalds mysids = mysids2;
27711da177e4SLinus Torvalds mysids[mynel++] = sid;
27721da177e4SLinus Torvalds }
27731da177e4SLinus Torvalds }
27741da177e4SLinus Torvalds }
27754b02b524SEric Paris rc = 0;
27761da177e4SLinus Torvalds out_unlock:
27771b8b31a2SStephen Smalley rcu_read_unlock();
27782c3c05dbSStephen Smalley if (rc || !mynel) {
27792c3c05dbSStephen Smalley kfree(mysids);
27809ad6e9cbSOndrej Mosnacek return rc;
27812c3c05dbSStephen Smalley }
27822c3c05dbSStephen Smalley
27834b02b524SEric Paris rc = -ENOMEM;
27842c3c05dbSStephen Smalley mysids2 = kcalloc(mynel, sizeof(*mysids2), GFP_KERNEL);
27852c3c05dbSStephen Smalley if (!mysids2) {
27862c3c05dbSStephen Smalley kfree(mysids);
27879ad6e9cbSOndrej Mosnacek return rc;
27882c3c05dbSStephen Smalley }
27892c3c05dbSStephen Smalley for (i = 0, j = 0; i < mynel; i++) {
2790f01e1af4SLinus Torvalds struct av_decision dummy_avd;
2791e67b7985SStephen Smalley rc = avc_has_perm_noaudit(fromsid, mysids[i],
2792c6d3aaa4SStephen Smalley SECCLASS_PROCESS, /* kernel value */
27932c3c05dbSStephen Smalley PROCESS__TRANSITION, AVC_STRICT,
2794f01e1af4SLinus Torvalds &dummy_avd);
27952c3c05dbSStephen Smalley if (!rc)
27962c3c05dbSStephen Smalley mysids2[j++] = mysids[i];
27972c3c05dbSStephen Smalley cond_resched();
27982c3c05dbSStephen Smalley }
27992c3c05dbSStephen Smalley kfree(mysids);
28002c3c05dbSStephen Smalley *sids = mysids2;
28012c3c05dbSStephen Smalley *nel = j;
28029ad6e9cbSOndrej Mosnacek return 0;
28031da177e4SLinus Torvalds }
28041da177e4SLinus Torvalds
28051da177e4SLinus Torvalds /**
2806f31e7994SWaiman Long * __security_genfs_sid - Helper to obtain a SID for a file in a filesystem
2807e9fd7292SPaul Moore * @policy: policy
28081da177e4SLinus Torvalds * @fstype: filesystem type
28091da177e4SLinus Torvalds * @path: path from root of mount
2810e9fd7292SPaul Moore * @orig_sclass: file security class
28111da177e4SLinus Torvalds * @sid: SID for path
28121da177e4SLinus Torvalds *
28131da177e4SLinus Torvalds * Obtain a SID to use for a file in a filesystem that
28141da177e4SLinus Torvalds * cannot support xattr or use a fixed labeling behavior like
28151da177e4SLinus Torvalds * transition SIDs or task SIDs.
28169ad6e9cbSOndrej Mosnacek *
28179ad6e9cbSOndrej Mosnacek * WARNING: This function may return -ESTALE, indicating that the caller
28189ad6e9cbSOndrej Mosnacek * must retry the operation after re-acquiring the policy pointer!
28191da177e4SLinus Torvalds */
__security_genfs_sid(struct selinux_policy * policy,const char * fstype,const char * path,u16 orig_sclass,u32 * sid)282002a52c5cSStephen Smalley static inline int __security_genfs_sid(struct selinux_policy *policy,
2821aa8e712cSStephen Smalley const char *fstype,
282208df4905SChristian Göttsche const char *path,
2823c6d3aaa4SStephen Smalley u16 orig_sclass,
28241da177e4SLinus Torvalds u32 *sid)
28251da177e4SLinus Torvalds {
282602a52c5cSStephen Smalley struct policydb *policydb = &policy->policydb;
2827c7c556f1SStephen Smalley struct sidtab *sidtab = policy->sidtab;
2828c6d3aaa4SStephen Smalley u16 sclass;
28291da177e4SLinus Torvalds struct genfs *genfs;
28301da177e4SLinus Torvalds struct ocontext *c;
2831cbfcd13bSOndrej Mosnacek int cmp = 0;
28321da177e4SLinus Torvalds
2833b1aa5301SStephen Smalley while (path[0] == '/' && path[1] == '/')
2834b1aa5301SStephen Smalley path++;
2835b1aa5301SStephen Smalley
283602a52c5cSStephen Smalley sclass = unmap_class(&policy->map, orig_sclass);
28374b02b524SEric Paris *sid = SECINITSID_UNLABELED;
2838c6d3aaa4SStephen Smalley
2839aa8e712cSStephen Smalley for (genfs = policydb->genfs; genfs; genfs = genfs->next) {
28401da177e4SLinus Torvalds cmp = strcmp(fstype, genfs->fstype);
28411da177e4SLinus Torvalds if (cmp <= 0)
28421da177e4SLinus Torvalds break;
28431da177e4SLinus Torvalds }
28441da177e4SLinus Torvalds
28454b02b524SEric Paris if (!genfs || cmp)
2846cbfcd13bSOndrej Mosnacek return -ENOENT;
28471da177e4SLinus Torvalds
28481da177e4SLinus Torvalds for (c = genfs->head; c; c = c->next) {
2849c50e125dSChristian Göttsche size_t len = strlen(c->u.name);
28501da177e4SLinus Torvalds if ((!c->v.sclass || sclass == c->v.sclass) &&
28511da177e4SLinus Torvalds (strncmp(c->u.name, path, len) == 0))
28521da177e4SLinus Torvalds break;
28531da177e4SLinus Torvalds }
28541da177e4SLinus Torvalds
28554b02b524SEric Paris if (!c)
2856cbfcd13bSOndrej Mosnacek return -ENOENT;
28571da177e4SLinus Torvalds
2858cbfcd13bSOndrej Mosnacek return ocontext_to_sid(sidtab, c, 0, sid);
28591da177e4SLinus Torvalds }
28601da177e4SLinus Torvalds
28611da177e4SLinus Torvalds /**
2862f31e7994SWaiman Long * security_genfs_sid - Obtain a SID for a file in a filesystem
2863f31e7994SWaiman Long * @fstype: filesystem type
2864f31e7994SWaiman Long * @path: path from root of mount
2865e9fd7292SPaul Moore * @orig_sclass: file security class
2866f31e7994SWaiman Long * @sid: SID for path
2867f31e7994SWaiman Long *
2868f31e7994SWaiman Long * Acquire policy_rwlock before calling __security_genfs_sid() and release
2869f31e7994SWaiman Long * it afterward.
2870f31e7994SWaiman Long */
security_genfs_sid(const char * fstype,const char * path,u16 orig_sclass,u32 * sid)2871e67b7985SStephen Smalley int security_genfs_sid(const char *fstype,
287208df4905SChristian Göttsche const char *path,
2873f31e7994SWaiman Long u16 orig_sclass,
2874f31e7994SWaiman Long u32 *sid)
2875f31e7994SWaiman Long {
28761b8b31a2SStephen Smalley struct selinux_policy *policy;
2877f31e7994SWaiman Long int retval;
2878f31e7994SWaiman Long
2879e67b7985SStephen Smalley if (!selinux_initialized()) {
288037ea433cSStephen Smalley *sid = SECINITSID_UNLABELED;
288137ea433cSStephen Smalley return 0;
288237ea433cSStephen Smalley }
288337ea433cSStephen Smalley
28849ad6e9cbSOndrej Mosnacek do {
28851b8b31a2SStephen Smalley rcu_read_lock();
2886e67b7985SStephen Smalley policy = rcu_dereference(selinux_state.policy);
28879ad6e9cbSOndrej Mosnacek retval = __security_genfs_sid(policy, fstype, path,
28889ad6e9cbSOndrej Mosnacek orig_sclass, sid);
28891b8b31a2SStephen Smalley rcu_read_unlock();
28909ad6e9cbSOndrej Mosnacek } while (retval == -ESTALE);
2891f31e7994SWaiman Long return retval;
2892f31e7994SWaiman Long }
2893f31e7994SWaiman Long
selinux_policy_genfs_sid(struct selinux_policy * policy,const char * fstype,const char * path,u16 orig_sclass,u32 * sid)289402a52c5cSStephen Smalley int selinux_policy_genfs_sid(struct selinux_policy *policy,
289502a52c5cSStephen Smalley const char *fstype,
289608df4905SChristian Göttsche const char *path,
289702a52c5cSStephen Smalley u16 orig_sclass,
289802a52c5cSStephen Smalley u32 *sid)
289902a52c5cSStephen Smalley {
290002a52c5cSStephen Smalley /* no lock required, policy is not yet accessible by other threads */
290102a52c5cSStephen Smalley return __security_genfs_sid(policy, fstype, path, orig_sclass, sid);
290202a52c5cSStephen Smalley }
290302a52c5cSStephen Smalley
2904f31e7994SWaiman Long /**
29051da177e4SLinus Torvalds * security_fs_use - Determine how to handle labeling for a filesystem.
2906a64c54cfSEric Paris * @sb: superblock in question
29071da177e4SLinus Torvalds */
security_fs_use(struct super_block * sb)2908e67b7985SStephen Smalley int security_fs_use(struct super_block *sb)
29091da177e4SLinus Torvalds {
29101b8b31a2SStephen Smalley struct selinux_policy *policy;
2911aa8e712cSStephen Smalley struct policydb *policydb;
2912225621c9SOndrej Mosnacek struct sidtab *sidtab;
29139ad6e9cbSOndrej Mosnacek int rc;
29141da177e4SLinus Torvalds struct ocontext *c;
29151aea7808SCasey Schaufler struct superblock_security_struct *sbsec = selinux_superblock(sb);
2916a64c54cfSEric Paris const char *fstype = sb->s_type->name;
29171da177e4SLinus Torvalds
2918e67b7985SStephen Smalley if (!selinux_initialized()) {
291937ea433cSStephen Smalley sbsec->behavior = SECURITY_FS_USE_NONE;
292037ea433cSStephen Smalley sbsec->sid = SECINITSID_UNLABELED;
292137ea433cSStephen Smalley return 0;
292237ea433cSStephen Smalley }
292337ea433cSStephen Smalley
29249ad6e9cbSOndrej Mosnacek retry:
29251b8b31a2SStephen Smalley rcu_read_lock();
2926e67b7985SStephen Smalley policy = rcu_dereference(selinux_state.policy);
29271b8b31a2SStephen Smalley policydb = &policy->policydb;
29281b8b31a2SStephen Smalley sidtab = policy->sidtab;
2929aa8e712cSStephen Smalley
2930aa8e712cSStephen Smalley c = policydb->ocontexts[OCON_FSUSE];
29314d546f81SPaul Moore while (c) {
29324d546f81SPaul Moore if (strcmp(fstype, c->u.name) == 0)
29331da177e4SLinus Torvalds break;
29344d546f81SPaul Moore c = c->next;
29351da177e4SLinus Torvalds }
29361da177e4SLinus Torvalds
29371da177e4SLinus Torvalds if (c) {
2938a64c54cfSEric Paris sbsec->behavior = c->v.behavior;
2939cbfcd13bSOndrej Mosnacek rc = ocontext_to_sid(sidtab, c, 0, &sbsec->sid);
29409ad6e9cbSOndrej Mosnacek if (rc == -ESTALE) {
29419ad6e9cbSOndrej Mosnacek rcu_read_unlock();
29429ad6e9cbSOndrej Mosnacek goto retry;
29439ad6e9cbSOndrej Mosnacek }
29441da177e4SLinus Torvalds if (rc)
29451da177e4SLinus Torvalds goto out;
2946089be43eSJames Morris } else {
29471b8b31a2SStephen Smalley rc = __security_genfs_sid(policy, fstype, "/",
294802a52c5cSStephen Smalley SECCLASS_DIR, &sbsec->sid);
29499ad6e9cbSOndrej Mosnacek if (rc == -ESTALE) {
29509ad6e9cbSOndrej Mosnacek rcu_read_unlock();
29519ad6e9cbSOndrej Mosnacek goto retry;
29529ad6e9cbSOndrej Mosnacek }
29531da177e4SLinus Torvalds if (rc) {
2954a64c54cfSEric Paris sbsec->behavior = SECURITY_FS_USE_NONE;
29551da177e4SLinus Torvalds rc = 0;
29561da177e4SLinus Torvalds } else {
2957a64c54cfSEric Paris sbsec->behavior = SECURITY_FS_USE_GENFS;
29581da177e4SLinus Torvalds }
2959089be43eSJames Morris }
29601da177e4SLinus Torvalds
29611da177e4SLinus Torvalds out:
29621b8b31a2SStephen Smalley rcu_read_unlock();
29631da177e4SLinus Torvalds return rc;
29641da177e4SLinus Torvalds }
29651da177e4SLinus Torvalds
security_get_bools(struct selinux_policy * policy,u32 * len,char *** names,int ** values)296602a52c5cSStephen Smalley int security_get_bools(struct selinux_policy *policy,
296760abd318SOndrej Mosnacek u32 *len, char ***names, int **values)
29681da177e4SLinus Torvalds {
2969aa8e712cSStephen Smalley struct policydb *policydb;
297060abd318SOndrej Mosnacek u32 i;
297160abd318SOndrej Mosnacek int rc;
29721da177e4SLinus Torvalds
297302a52c5cSStephen Smalley policydb = &policy->policydb;
2974aa8e712cSStephen Smalley
29751da177e4SLinus Torvalds *names = NULL;
29761da177e4SLinus Torvalds *values = NULL;
29771da177e4SLinus Torvalds
29781da177e4SLinus Torvalds rc = 0;
2979aa8e712cSStephen Smalley *len = policydb->p_bools.nprim;
29804b02b524SEric Paris if (!*len)
29811da177e4SLinus Torvalds goto out;
29821da177e4SLinus Torvalds
29834b02b524SEric Paris rc = -ENOMEM;
2984e0795cf4SJesper Juhl *names = kcalloc(*len, sizeof(char *), GFP_ATOMIC);
29851da177e4SLinus Torvalds if (!*names)
29861da177e4SLinus Torvalds goto err;
29871da177e4SLinus Torvalds
29884b02b524SEric Paris rc = -ENOMEM;
2989e0795cf4SJesper Juhl *values = kcalloc(*len, sizeof(int), GFP_ATOMIC);
29901da177e4SLinus Torvalds if (!*values)
29911da177e4SLinus Torvalds goto err;
29921da177e4SLinus Torvalds
29931da177e4SLinus Torvalds for (i = 0; i < *len; i++) {
2994aa8e712cSStephen Smalley (*values)[i] = policydb->bool_val_to_struct[i]->state;
29954b02b524SEric Paris
29964b02b524SEric Paris rc = -ENOMEM;
2997aa8e712cSStephen Smalley (*names)[i] = kstrdup(sym_name(policydb, SYM_BOOLS, i),
2998aa8e712cSStephen Smalley GFP_ATOMIC);
29991da177e4SLinus Torvalds if (!(*names)[i])
30001da177e4SLinus Torvalds goto err;
30011da177e4SLinus Torvalds }
30021da177e4SLinus Torvalds rc = 0;
30031da177e4SLinus Torvalds out:
30041da177e4SLinus Torvalds return rc;
30051da177e4SLinus Torvalds err:
30061da177e4SLinus Torvalds if (*names) {
30071da177e4SLinus Torvalds for (i = 0; i < *len; i++)
30081da177e4SLinus Torvalds kfree((*names)[i]);
300965de5096STom Rix kfree(*names);
30101da177e4SLinus Torvalds }
30111da177e4SLinus Torvalds kfree(*values);
301265de5096STom Rix *len = 0;
301365de5096STom Rix *names = NULL;
301465de5096STom Rix *values = NULL;
30151da177e4SLinus Torvalds goto out;
30161da177e4SLinus Torvalds }
30171da177e4SLinus Torvalds
30181da177e4SLinus Torvalds
security_set_bools(u32 len,int * values)3019e67b7985SStephen Smalley int security_set_bools(u32 len, int *values)
30201da177e4SLinus Torvalds {
3021e67b7985SStephen Smalley struct selinux_state *state = &selinux_state;
3022c7c556f1SStephen Smalley struct selinux_policy *newpolicy, *oldpolicy;
302360abd318SOndrej Mosnacek int rc;
3024c7c556f1SStephen Smalley u32 i, seqno = 0;
30251da177e4SLinus Torvalds
3026e67b7985SStephen Smalley if (!selinux_initialized())
302737ea433cSStephen Smalley return -EINVAL;
302837ea433cSStephen Smalley
30299ff9abc4SStephen Smalley oldpolicy = rcu_dereference_protected(state->policy,
30309ff9abc4SStephen Smalley lockdep_is_held(&state->policy_mutex));
30311b8b31a2SStephen Smalley
3032c7c556f1SStephen Smalley /* Consistency check on number of booleans, should never fail */
30331b8b31a2SStephen Smalley if (WARN_ON(len != oldpolicy->policydb.p_bools.nprim))
3034c7c556f1SStephen Smalley return -EINVAL;
30351da177e4SLinus Torvalds
30361b8b31a2SStephen Smalley newpolicy = kmemdup(oldpolicy, sizeof(*newpolicy), GFP_KERNEL);
3037c7c556f1SStephen Smalley if (!newpolicy)
3038c7c556f1SStephen Smalley return -ENOMEM;
30391da177e4SLinus Torvalds
3040c7c556f1SStephen Smalley /*
3041c7c556f1SStephen Smalley * Deep copy only the parts of the policydb that might be
3042c7c556f1SStephen Smalley * modified as a result of changing booleans.
3043c7c556f1SStephen Smalley */
3044c7c556f1SStephen Smalley rc = cond_policydb_dup(&newpolicy->policydb, &oldpolicy->policydb);
3045c7c556f1SStephen Smalley if (rc) {
3046c7c556f1SStephen Smalley kfree(newpolicy);
3047c7c556f1SStephen Smalley return -ENOMEM;
3048c7c556f1SStephen Smalley }
3049c7c556f1SStephen Smalley
3050c7c556f1SStephen Smalley /* Update the boolean states in the copy */
30511da177e4SLinus Torvalds for (i = 0; i < len; i++) {
3052c7c556f1SStephen Smalley int new_state = !!values[i];
3053c7c556f1SStephen Smalley int old_state = newpolicy->policydb.bool_val_to_struct[i]->state;
3054c7c556f1SStephen Smalley
3055c7c556f1SStephen Smalley if (new_state != old_state) {
3056cdfb6b34SRichard Guy Briggs audit_log(audit_context(), GFP_ATOMIC,
3057af601e46SSteve Grubb AUDIT_MAC_CONFIG_CHANGE,
30584746ec5bSEric Paris "bool=%s val=%d old_val=%d auid=%u ses=%u",
3059c7c556f1SStephen Smalley sym_name(&newpolicy->policydb, SYM_BOOLS, i),
3060c7c556f1SStephen Smalley new_state,
3061c7c556f1SStephen Smalley old_state,
3062581abc09SEric W. Biederman from_kuid(&init_user_ns, audit_get_loginuid(current)),
30634746ec5bSEric Paris audit_get_sessionid(current));
3064c7c556f1SStephen Smalley newpolicy->policydb.bool_val_to_struct[i]->state = new_state;
3065af601e46SSteve Grubb }
30661da177e4SLinus Torvalds }
30671da177e4SLinus Torvalds
3068c7c556f1SStephen Smalley /* Re-evaluate the conditional rules in the copy */
3069c7c556f1SStephen Smalley evaluate_cond_nodes(&newpolicy->policydb);
30701da177e4SLinus Torvalds
30711b8b31a2SStephen Smalley /* Set latest granting seqno for new policy */
30721b8b31a2SStephen Smalley newpolicy->latest_granting = oldpolicy->latest_granting + 1;
30731b8b31a2SStephen Smalley seqno = newpolicy->latest_granting;
30741b8b31a2SStephen Smalley
3075c7c556f1SStephen Smalley /* Install the new policy */
30761b8b31a2SStephen Smalley rcu_assign_pointer(state->policy, newpolicy);
3077c7c556f1SStephen Smalley
3078c7c556f1SStephen Smalley /*
3079c7c556f1SStephen Smalley * Free the conditional portions of the old policydb
30801b8b31a2SStephen Smalley * that were copied for the new policy, and the oldpolicy
30811b8b31a2SStephen Smalley * structure itself but not what it references.
3082c7c556f1SStephen Smalley */
30831b8b31a2SStephen Smalley synchronize_rcu();
30841b8b31a2SStephen Smalley selinux_policy_cond_free(oldpolicy);
3085c7c556f1SStephen Smalley
3086c7c556f1SStephen Smalley /* Notify others of the policy change */
3087e67b7985SStephen Smalley selinux_notify_policy_change(seqno);
3088c7c556f1SStephen Smalley return 0;
30891da177e4SLinus Torvalds }
30901da177e4SLinus Torvalds
security_get_bool_value(u32 index)3091e67b7985SStephen Smalley int security_get_bool_value(u32 index)
30921da177e4SLinus Torvalds {
30931b8b31a2SStephen Smalley struct selinux_policy *policy;
3094aa8e712cSStephen Smalley struct policydb *policydb;
30954b02b524SEric Paris int rc;
309660abd318SOndrej Mosnacek u32 len;
30971da177e4SLinus Torvalds
3098e67b7985SStephen Smalley if (!selinux_initialized())
309937ea433cSStephen Smalley return 0;
310037ea433cSStephen Smalley
31011b8b31a2SStephen Smalley rcu_read_lock();
3102e67b7985SStephen Smalley policy = rcu_dereference(selinux_state.policy);
31031b8b31a2SStephen Smalley policydb = &policy->policydb;
31041da177e4SLinus Torvalds
31051da177e4SLinus Torvalds rc = -EFAULT;
3106aa8e712cSStephen Smalley len = policydb->p_bools.nprim;
31070fd71a62SPrarit Bhargava if (index >= len)
31081da177e4SLinus Torvalds goto out;
31091da177e4SLinus Torvalds
3110aa8e712cSStephen Smalley rc = policydb->bool_val_to_struct[index]->state;
31111da177e4SLinus Torvalds out:
31121b8b31a2SStephen Smalley rcu_read_unlock();
31131da177e4SLinus Torvalds return rc;
31141da177e4SLinus Torvalds }
3115376bd9cbSDarrel Goeddel
security_preserve_bools(struct selinux_policy * oldpolicy,struct selinux_policy * newpolicy)31161b8b31a2SStephen Smalley static int security_preserve_bools(struct selinux_policy *oldpolicy,
31171b8b31a2SStephen Smalley struct selinux_policy *newpolicy)
3118e900a7d9SStephen Smalley {
311960abd318SOndrej Mosnacek int rc, *bvalues = NULL;
3120e900a7d9SStephen Smalley char **bnames = NULL;
3121e900a7d9SStephen Smalley struct cond_bool_datum *booldatum;
312260abd318SOndrej Mosnacek u32 i, nbools = 0;
3123e900a7d9SStephen Smalley
31241b8b31a2SStephen Smalley rc = security_get_bools(oldpolicy, &nbools, &bnames, &bvalues);
3125e900a7d9SStephen Smalley if (rc)
3126e900a7d9SStephen Smalley goto out;
3127e900a7d9SStephen Smalley for (i = 0; i < nbools; i++) {
31281b8b31a2SStephen Smalley booldatum = symtab_search(&newpolicy->policydb.p_bools,
31291b8b31a2SStephen Smalley bnames[i]);
3130e900a7d9SStephen Smalley if (booldatum)
3131e900a7d9SStephen Smalley booldatum->state = bvalues[i];
3132e900a7d9SStephen Smalley }
31331b8b31a2SStephen Smalley evaluate_cond_nodes(&newpolicy->policydb);
3134e900a7d9SStephen Smalley
3135e900a7d9SStephen Smalley out:
3136e900a7d9SStephen Smalley if (bnames) {
3137e900a7d9SStephen Smalley for (i = 0; i < nbools; i++)
3138e900a7d9SStephen Smalley kfree(bnames[i]);
3139e900a7d9SStephen Smalley }
3140e900a7d9SStephen Smalley kfree(bnames);
3141e900a7d9SStephen Smalley kfree(bvalues);
3142e900a7d9SStephen Smalley return rc;
3143e900a7d9SStephen Smalley }
3144e900a7d9SStephen Smalley
314508554d6bSVenkat Yekkirala /*
314608554d6bSVenkat Yekkirala * security_sid_mls_copy() - computes a new sid based on the given
314708554d6bSVenkat Yekkirala * sid and the mls portion of mls_sid.
314808554d6bSVenkat Yekkirala */
security_sid_mls_copy(u32 sid,u32 mls_sid,u32 * new_sid)3149e67b7985SStephen Smalley int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid)
315008554d6bSVenkat Yekkirala {
31511b8b31a2SStephen Smalley struct selinux_policy *policy;
315246169802SStephen Smalley struct policydb *policydb;
315346169802SStephen Smalley struct sidtab *sidtab;
315408554d6bSVenkat Yekkirala struct context *context1;
315508554d6bSVenkat Yekkirala struct context *context2;
315608554d6bSVenkat Yekkirala struct context newcon;
315708554d6bSVenkat Yekkirala char *s;
315808554d6bSVenkat Yekkirala u32 len;
31594b02b524SEric Paris int rc;
316008554d6bSVenkat Yekkirala
3161e67b7985SStephen Smalley if (!selinux_initialized()) {
316208554d6bSVenkat Yekkirala *new_sid = sid;
31639ad6e9cbSOndrej Mosnacek return 0;
316408554d6bSVenkat Yekkirala }
316508554d6bSVenkat Yekkirala
31669ad6e9cbSOndrej Mosnacek retry:
31679ad6e9cbSOndrej Mosnacek rc = 0;
316808554d6bSVenkat Yekkirala context_init(&newcon);
316908554d6bSVenkat Yekkirala
31701b8b31a2SStephen Smalley rcu_read_lock();
3171e67b7985SStephen Smalley policy = rcu_dereference(selinux_state.policy);
31721b8b31a2SStephen Smalley policydb = &policy->policydb;
31731b8b31a2SStephen Smalley sidtab = policy->sidtab;
317446169802SStephen Smalley
317546169802SStephen Smalley if (!policydb->mls_enabled) {
317646169802SStephen Smalley *new_sid = sid;
317746169802SStephen Smalley goto out_unlock;
317846169802SStephen Smalley }
317946169802SStephen Smalley
31804b02b524SEric Paris rc = -EINVAL;
3181aa8e712cSStephen Smalley context1 = sidtab_search(sidtab, sid);
318208554d6bSVenkat Yekkirala if (!context1) {
3183b54c85c1Speter enderborg pr_err("SELinux: %s: unrecognized SID %d\n",
3184744ba35eSEric Paris __func__, sid);
318508554d6bSVenkat Yekkirala goto out_unlock;
318608554d6bSVenkat Yekkirala }
318708554d6bSVenkat Yekkirala
31884b02b524SEric Paris rc = -EINVAL;
3189aa8e712cSStephen Smalley context2 = sidtab_search(sidtab, mls_sid);
319008554d6bSVenkat Yekkirala if (!context2) {
3191b54c85c1Speter enderborg pr_err("SELinux: %s: unrecognized SID %d\n",
3192744ba35eSEric Paris __func__, mls_sid);
319308554d6bSVenkat Yekkirala goto out_unlock;
319408554d6bSVenkat Yekkirala }
319508554d6bSVenkat Yekkirala
319608554d6bSVenkat Yekkirala newcon.user = context1->user;
319708554d6bSVenkat Yekkirala newcon.role = context1->role;
319808554d6bSVenkat Yekkirala newcon.type = context1->type;
31990efc61eaSVenkat Yekkirala rc = mls_context_cpy(&newcon, context2);
320008554d6bSVenkat Yekkirala if (rc)
320108554d6bSVenkat Yekkirala goto out_unlock;
320208554d6bSVenkat Yekkirala
320308554d6bSVenkat Yekkirala /* Check the validity of the new context. */
3204aa8e712cSStephen Smalley if (!policydb_context_isvalid(policydb, &newcon)) {
3205e67b7985SStephen Smalley rc = convert_context_handle_invalid_context(policydb,
32061b8b31a2SStephen Smalley &newcon);
32074b02b524SEric Paris if (rc) {
3208aa8e712cSStephen Smalley if (!context_struct_to_string(policydb, &newcon, &s,
3209aa8e712cSStephen Smalley &len)) {
3210ea74a685SRichard Guy Briggs struct audit_buffer *ab;
3211ea74a685SRichard Guy Briggs
3212ea74a685SRichard Guy Briggs ab = audit_log_start(audit_context(),
3213ea74a685SRichard Guy Briggs GFP_ATOMIC,
3214ea74a685SRichard Guy Briggs AUDIT_SELINUX_ERR);
3215ea74a685SRichard Guy Briggs audit_log_format(ab,
3216ea74a685SRichard Guy Briggs "op=security_sid_mls_copy invalid_context=");
3217ea74a685SRichard Guy Briggs /* don't record NUL with untrusted strings */
3218ea74a685SRichard Guy Briggs audit_log_n_untrustedstring(ab, s, len - 1);
3219ea74a685SRichard Guy Briggs audit_log_end(ab);
322008554d6bSVenkat Yekkirala kfree(s);
322108554d6bSVenkat Yekkirala }
32224b02b524SEric Paris goto out_unlock;
32234b02b524SEric Paris }
32244b02b524SEric Paris }
3225225621c9SOndrej Mosnacek rc = sidtab_context_to_sid(sidtab, &newcon, new_sid);
32269ad6e9cbSOndrej Mosnacek if (rc == -ESTALE) {
32279ad6e9cbSOndrej Mosnacek rcu_read_unlock();
32289ad6e9cbSOndrej Mosnacek context_destroy(&newcon);
32299ad6e9cbSOndrej Mosnacek goto retry;
32309ad6e9cbSOndrej Mosnacek }
323108554d6bSVenkat Yekkirala out_unlock:
32321b8b31a2SStephen Smalley rcu_read_unlock();
323308554d6bSVenkat Yekkirala context_destroy(&newcon);
323408554d6bSVenkat Yekkirala return rc;
323508554d6bSVenkat Yekkirala }
323608554d6bSVenkat Yekkirala
3237220deb96SPaul Moore /**
3238220deb96SPaul Moore * security_net_peersid_resolve - Compare and resolve two network peer SIDs
3239220deb96SPaul Moore * @nlbl_sid: NetLabel SID
3240220deb96SPaul Moore * @nlbl_type: NetLabel labeling protocol type
3241220deb96SPaul Moore * @xfrm_sid: XFRM SID
3242e9fd7292SPaul Moore * @peer_sid: network peer sid
3243220deb96SPaul Moore *
3244220deb96SPaul Moore * Description:
3245220deb96SPaul Moore * Compare the @nlbl_sid and @xfrm_sid values and if the two SIDs can be
3246220deb96SPaul Moore * resolved into a single SID it is returned via @peer_sid and the function
3247220deb96SPaul Moore * returns zero. Otherwise @peer_sid is set to SECSID_NULL and the function
3248220deb96SPaul Moore * returns a negative value. A table summarizing the behavior is below:
3249220deb96SPaul Moore *
3250220deb96SPaul Moore * | function return | @sid
3251220deb96SPaul Moore * ------------------------------+-----------------+-----------------
3252220deb96SPaul Moore * no peer labels | 0 | SECSID_NULL
3253220deb96SPaul Moore * single peer label | 0 | <peer_label>
3254220deb96SPaul Moore * multiple, consistent labels | 0 | <peer_label>
3255220deb96SPaul Moore * multiple, inconsistent labels | -<errno> | SECSID_NULL
3256220deb96SPaul Moore *
3257220deb96SPaul Moore */
security_net_peersid_resolve(u32 nlbl_sid,u32 nlbl_type,u32 xfrm_sid,u32 * peer_sid)3258e67b7985SStephen Smalley int security_net_peersid_resolve(u32 nlbl_sid, u32 nlbl_type,
3259220deb96SPaul Moore u32 xfrm_sid,
3260220deb96SPaul Moore u32 *peer_sid)
3261220deb96SPaul Moore {
32621b8b31a2SStephen Smalley struct selinux_policy *policy;
326346169802SStephen Smalley struct policydb *policydb;
326446169802SStephen Smalley struct sidtab *sidtab;
3265220deb96SPaul Moore int rc;
3266220deb96SPaul Moore struct context *nlbl_ctx;
3267220deb96SPaul Moore struct context *xfrm_ctx;
3268220deb96SPaul Moore
32694b02b524SEric Paris *peer_sid = SECSID_NULL;
32704b02b524SEric Paris
3271220deb96SPaul Moore /* handle the common (which also happens to be the set of easy) cases
3272220deb96SPaul Moore * right away, these two if statements catch everything involving a
3273220deb96SPaul Moore * single or absent peer SID/label */
3274220deb96SPaul Moore if (xfrm_sid == SECSID_NULL) {
3275220deb96SPaul Moore *peer_sid = nlbl_sid;
3276220deb96SPaul Moore return 0;
3277220deb96SPaul Moore }
3278220deb96SPaul Moore /* NOTE: an nlbl_type == NETLBL_NLTYPE_UNLABELED is a "fallback" label
3279220deb96SPaul Moore * and is treated as if nlbl_sid == SECSID_NULL when a XFRM SID/label
3280220deb96SPaul Moore * is present */
3281220deb96SPaul Moore if (nlbl_sid == SECSID_NULL || nlbl_type == NETLBL_NLTYPE_UNLABELED) {
3282220deb96SPaul Moore *peer_sid = xfrm_sid;
3283220deb96SPaul Moore return 0;
3284220deb96SPaul Moore }
3285220deb96SPaul Moore
3286e67b7985SStephen Smalley if (!selinux_initialized())
328737ea433cSStephen Smalley return 0;
328837ea433cSStephen Smalley
32891b8b31a2SStephen Smalley rcu_read_lock();
3290e67b7985SStephen Smalley policy = rcu_dereference(selinux_state.policy);
32911b8b31a2SStephen Smalley policydb = &policy->policydb;
32921b8b31a2SStephen Smalley sidtab = policy->sidtab;
329346169802SStephen Smalley
3294aa8e712cSStephen Smalley /*
3295aa8e712cSStephen Smalley * We don't need to check initialized here since the only way both
3296220deb96SPaul Moore * nlbl_sid and xfrm_sid are not equal to SECSID_NULL would be if the
3297aa8e712cSStephen Smalley * security server was initialized and state->initialized was true.
3298aa8e712cSStephen Smalley */
329946169802SStephen Smalley if (!policydb->mls_enabled) {
330046169802SStephen Smalley rc = 0;
330146169802SStephen Smalley goto out;
330246169802SStephen Smalley }
3303220deb96SPaul Moore
33044b02b524SEric Paris rc = -EINVAL;
3305aa8e712cSStephen Smalley nlbl_ctx = sidtab_search(sidtab, nlbl_sid);
3306220deb96SPaul Moore if (!nlbl_ctx) {
3307b54c85c1Speter enderborg pr_err("SELinux: %s: unrecognized SID %d\n",
3308744ba35eSEric Paris __func__, nlbl_sid);
33094b02b524SEric Paris goto out;
3310220deb96SPaul Moore }
33114b02b524SEric Paris rc = -EINVAL;
3312aa8e712cSStephen Smalley xfrm_ctx = sidtab_search(sidtab, xfrm_sid);
3313220deb96SPaul Moore if (!xfrm_ctx) {
3314b54c85c1Speter enderborg pr_err("SELinux: %s: unrecognized SID %d\n",
3315744ba35eSEric Paris __func__, xfrm_sid);
33164b02b524SEric Paris goto out;
3317220deb96SPaul Moore }
3318220deb96SPaul Moore rc = (mls_context_cmp(nlbl_ctx, xfrm_ctx) ? 0 : -EACCES);
33194b02b524SEric Paris if (rc)
33204b02b524SEric Paris goto out;
3321220deb96SPaul Moore
3322220deb96SPaul Moore /* at present NetLabel SIDs/labels really only carry MLS
3323220deb96SPaul Moore * information so if the MLS portion of the NetLabel SID
3324220deb96SPaul Moore * matches the MLS portion of the labeled XFRM SID/label
3325220deb96SPaul Moore * then pass along the XFRM SID as it is the most
3326220deb96SPaul Moore * expressive */
3327220deb96SPaul Moore *peer_sid = xfrm_sid;
33284b02b524SEric Paris out:
33291b8b31a2SStephen Smalley rcu_read_unlock();
3330220deb96SPaul Moore return rc;
3331220deb96SPaul Moore }
3332220deb96SPaul Moore
get_classes_callback(void * k,void * d,void * args)333355fcf09bSChristopher J. PeBenito static int get_classes_callback(void *k, void *d, void *args)
333455fcf09bSChristopher J. PeBenito {
333555fcf09bSChristopher J. PeBenito struct class_datum *datum = d;
333655fcf09bSChristopher J. PeBenito char *name = k, **classes = args;
3337c50e125dSChristian Göttsche u32 value = datum->value - 1;
333855fcf09bSChristopher J. PeBenito
333955fcf09bSChristopher J. PeBenito classes[value] = kstrdup(name, GFP_ATOMIC);
334055fcf09bSChristopher J. PeBenito if (!classes[value])
334155fcf09bSChristopher J. PeBenito return -ENOMEM;
334255fcf09bSChristopher J. PeBenito
334355fcf09bSChristopher J. PeBenito return 0;
334455fcf09bSChristopher J. PeBenito }
334555fcf09bSChristopher J. PeBenito
security_get_classes(struct selinux_policy * policy,char *** classes,u32 * nclasses)334602a52c5cSStephen Smalley int security_get_classes(struct selinux_policy *policy,
3347c50e125dSChristian Göttsche char ***classes, u32 *nclasses)
334855fcf09bSChristopher J. PeBenito {
334946169802SStephen Smalley struct policydb *policydb;
33504b02b524SEric Paris int rc;
335155fcf09bSChristopher J. PeBenito
335202a52c5cSStephen Smalley policydb = &policy->policydb;
335346169802SStephen Smalley
33544b02b524SEric Paris rc = -ENOMEM;
3355aa8e712cSStephen Smalley *nclasses = policydb->p_classes.nprim;
33569f59f90bSJulia Lawall *classes = kcalloc(*nclasses, sizeof(**classes), GFP_ATOMIC);
335755fcf09bSChristopher J. PeBenito if (!*classes)
335855fcf09bSChristopher J. PeBenito goto out;
335955fcf09bSChristopher J. PeBenito
336003414a49SOndrej Mosnacek rc = hashtab_map(&policydb->p_classes.table, get_classes_callback,
336155fcf09bSChristopher J. PeBenito *classes);
33624b02b524SEric Paris if (rc) {
3363c50e125dSChristian Göttsche u32 i;
3364c50e125dSChristian Göttsche
336555fcf09bSChristopher J. PeBenito for (i = 0; i < *nclasses; i++)
336655fcf09bSChristopher J. PeBenito kfree((*classes)[i]);
336755fcf09bSChristopher J. PeBenito kfree(*classes);
336855fcf09bSChristopher J. PeBenito }
336955fcf09bSChristopher J. PeBenito
337055fcf09bSChristopher J. PeBenito out:
337155fcf09bSChristopher J. PeBenito return rc;
337255fcf09bSChristopher J. PeBenito }
337355fcf09bSChristopher J. PeBenito
get_permissions_callback(void * k,void * d,void * args)337455fcf09bSChristopher J. PeBenito static int get_permissions_callback(void *k, void *d, void *args)
337555fcf09bSChristopher J. PeBenito {
337655fcf09bSChristopher J. PeBenito struct perm_datum *datum = d;
337755fcf09bSChristopher J. PeBenito char *name = k, **perms = args;
3378c50e125dSChristian Göttsche u32 value = datum->value - 1;
337955fcf09bSChristopher J. PeBenito
338055fcf09bSChristopher J. PeBenito perms[value] = kstrdup(name, GFP_ATOMIC);
338155fcf09bSChristopher J. PeBenito if (!perms[value])
338255fcf09bSChristopher J. PeBenito return -ENOMEM;
338355fcf09bSChristopher J. PeBenito
338455fcf09bSChristopher J. PeBenito return 0;
338555fcf09bSChristopher J. PeBenito }
338655fcf09bSChristopher J. PeBenito
security_get_permissions(struct selinux_policy * policy,const char * class,char *** perms,u32 * nperms)338702a52c5cSStephen Smalley int security_get_permissions(struct selinux_policy *policy,
3388c50e125dSChristian Göttsche const char *class, char ***perms, u32 *nperms)
338955fcf09bSChristopher J. PeBenito {
339046169802SStephen Smalley struct policydb *policydb;
3391c50e125dSChristian Göttsche u32 i;
3392c50e125dSChristian Göttsche int rc;
339355fcf09bSChristopher J. PeBenito struct class_datum *match;
339455fcf09bSChristopher J. PeBenito
339502a52c5cSStephen Smalley policydb = &policy->policydb;
339646169802SStephen Smalley
33974b02b524SEric Paris rc = -EINVAL;
3398237389e3SOndrej Mosnacek match = symtab_search(&policydb->p_classes, class);
339955fcf09bSChristopher J. PeBenito if (!match) {
3400b54c85c1Speter enderborg pr_err("SELinux: %s: unrecognized class %s\n",
3401dd6f953aSHarvey Harrison __func__, class);
340255fcf09bSChristopher J. PeBenito goto out;
340355fcf09bSChristopher J. PeBenito }
340455fcf09bSChristopher J. PeBenito
34054b02b524SEric Paris rc = -ENOMEM;
340655fcf09bSChristopher J. PeBenito *nperms = match->permissions.nprim;
34079f59f90bSJulia Lawall *perms = kcalloc(*nperms, sizeof(**perms), GFP_ATOMIC);
340855fcf09bSChristopher J. PeBenito if (!*perms)
340955fcf09bSChristopher J. PeBenito goto out;
341055fcf09bSChristopher J. PeBenito
341155fcf09bSChristopher J. PeBenito if (match->comdatum) {
341203414a49SOndrej Mosnacek rc = hashtab_map(&match->comdatum->permissions.table,
341355fcf09bSChristopher J. PeBenito get_permissions_callback, *perms);
34144b02b524SEric Paris if (rc)
341555fcf09bSChristopher J. PeBenito goto err;
341655fcf09bSChristopher J. PeBenito }
341755fcf09bSChristopher J. PeBenito
341803414a49SOndrej Mosnacek rc = hashtab_map(&match->permissions.table, get_permissions_callback,
341955fcf09bSChristopher J. PeBenito *perms);
34204b02b524SEric Paris if (rc)
342155fcf09bSChristopher J. PeBenito goto err;
342255fcf09bSChristopher J. PeBenito
342355fcf09bSChristopher J. PeBenito out:
342455fcf09bSChristopher J. PeBenito return rc;
342555fcf09bSChristopher J. PeBenito
342655fcf09bSChristopher J. PeBenito err:
342755fcf09bSChristopher J. PeBenito for (i = 0; i < *nperms; i++)
342855fcf09bSChristopher J. PeBenito kfree((*perms)[i]);
342955fcf09bSChristopher J. PeBenito kfree(*perms);
343055fcf09bSChristopher J. PeBenito return rc;
343155fcf09bSChristopher J. PeBenito }
343255fcf09bSChristopher J. PeBenito
security_get_reject_unknown(void)3433e67b7985SStephen Smalley int security_get_reject_unknown(void)
34343f12070eSEric Paris {
34351b8b31a2SStephen Smalley struct selinux_policy *policy;
343646169802SStephen Smalley int value;
343746169802SStephen Smalley
3438e67b7985SStephen Smalley if (!selinux_initialized())
343937ea433cSStephen Smalley return 0;
344037ea433cSStephen Smalley
34411b8b31a2SStephen Smalley rcu_read_lock();
3442e67b7985SStephen Smalley policy = rcu_dereference(selinux_state.policy);
34431b8b31a2SStephen Smalley value = policy->policydb.reject_unknown;
34441b8b31a2SStephen Smalley rcu_read_unlock();
344546169802SStephen Smalley return value;
34463f12070eSEric Paris }
34473f12070eSEric Paris
security_get_allow_unknown(void)3448e67b7985SStephen Smalley int security_get_allow_unknown(void)
34493f12070eSEric Paris {
34501b8b31a2SStephen Smalley struct selinux_policy *policy;
345146169802SStephen Smalley int value;
345246169802SStephen Smalley
3453e67b7985SStephen Smalley if (!selinux_initialized())
345437ea433cSStephen Smalley return 0;
345537ea433cSStephen Smalley
34561b8b31a2SStephen Smalley rcu_read_lock();
3457e67b7985SStephen Smalley policy = rcu_dereference(selinux_state.policy);
34581b8b31a2SStephen Smalley value = policy->policydb.allow_unknown;
34591b8b31a2SStephen Smalley rcu_read_unlock();
346046169802SStephen Smalley return value;
34613f12070eSEric Paris }
34623f12070eSEric Paris
34633bb56b25SPaul Moore /**
34643bb56b25SPaul Moore * security_policycap_supported - Check for a specific policy capability
34653bb56b25SPaul Moore * @req_cap: capability
34663bb56b25SPaul Moore *
34673bb56b25SPaul Moore * Description:
34683bb56b25SPaul Moore * This function queries the currently loaded policy to see if it supports the
34693bb56b25SPaul Moore * capability specified by @req_cap. Returns true (1) if the capability is
34703bb56b25SPaul Moore * supported, false (0) if it isn't supported.
34713bb56b25SPaul Moore *
34723bb56b25SPaul Moore */
security_policycap_supported(unsigned int req_cap)3473e67b7985SStephen Smalley int security_policycap_supported(unsigned int req_cap)
34743bb56b25SPaul Moore {
34751b8b31a2SStephen Smalley struct selinux_policy *policy;
34763bb56b25SPaul Moore int rc;
34773bb56b25SPaul Moore
3478e67b7985SStephen Smalley if (!selinux_initialized())
347937ea433cSStephen Smalley return 0;
348037ea433cSStephen Smalley
34811b8b31a2SStephen Smalley rcu_read_lock();
3482e67b7985SStephen Smalley policy = rcu_dereference(selinux_state.policy);
34831b8b31a2SStephen Smalley rc = ebitmap_get_bit(&policy->policydb.policycaps, req_cap);
34841b8b31a2SStephen Smalley rcu_read_unlock();
34853bb56b25SPaul Moore
34863bb56b25SPaul Moore return rc;
34873bb56b25SPaul Moore }
34883bb56b25SPaul Moore
3489376bd9cbSDarrel Goeddel struct selinux_audit_rule {
3490376bd9cbSDarrel Goeddel u32 au_seqno;
3491376bd9cbSDarrel Goeddel struct context au_ctxt;
3492376bd9cbSDarrel Goeddel };
3493376bd9cbSDarrel Goeddel
selinux_audit_rule_free(void * vrule)34949d57a7f9SAhmed S. Darwish void selinux_audit_rule_free(void *vrule)
3495376bd9cbSDarrel Goeddel {
34969d57a7f9SAhmed S. Darwish struct selinux_audit_rule *rule = vrule;
34979d57a7f9SAhmed S. Darwish
3498376bd9cbSDarrel Goeddel if (rule) {
3499376bd9cbSDarrel Goeddel context_destroy(&rule->au_ctxt);
3500376bd9cbSDarrel Goeddel kfree(rule);
3501376bd9cbSDarrel Goeddel }
3502376bd9cbSDarrel Goeddel }
3503376bd9cbSDarrel Goeddel
selinux_audit_rule_init(u32 field,u32 op,char * rulestr,void ** vrule,gfp_t gfp)350428d0ecc5SGUO Zihua int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule,
350528d0ecc5SGUO Zihua gfp_t gfp)
3506376bd9cbSDarrel Goeddel {
3507aa8e712cSStephen Smalley struct selinux_state *state = &selinux_state;
35081b8b31a2SStephen Smalley struct selinux_policy *policy;
350946169802SStephen Smalley struct policydb *policydb;
3510376bd9cbSDarrel Goeddel struct selinux_audit_rule *tmprule;
3511376bd9cbSDarrel Goeddel struct role_datum *roledatum;
3512376bd9cbSDarrel Goeddel struct type_datum *typedatum;
3513376bd9cbSDarrel Goeddel struct user_datum *userdatum;
35149d57a7f9SAhmed S. Darwish struct selinux_audit_rule **rule = (struct selinux_audit_rule **)vrule;
3515376bd9cbSDarrel Goeddel int rc = 0;
3516376bd9cbSDarrel Goeddel
3517376bd9cbSDarrel Goeddel *rule = NULL;
3518376bd9cbSDarrel Goeddel
3519e67b7985SStephen Smalley if (!selinux_initialized())
35203ad40d64SSteve G return -EOPNOTSUPP;
3521376bd9cbSDarrel Goeddel
3522376bd9cbSDarrel Goeddel switch (field) {
35233a6b9f85SDarrel Goeddel case AUDIT_SUBJ_USER:
35243a6b9f85SDarrel Goeddel case AUDIT_SUBJ_ROLE:
35253a6b9f85SDarrel Goeddel case AUDIT_SUBJ_TYPE:
35266e5a2d1dSDarrel Goeddel case AUDIT_OBJ_USER:
35276e5a2d1dSDarrel Goeddel case AUDIT_OBJ_ROLE:
35286e5a2d1dSDarrel Goeddel case AUDIT_OBJ_TYPE:
3529376bd9cbSDarrel Goeddel /* only 'equals' and 'not equals' fit user, role, and type */
35305af75d8dSAl Viro if (op != Audit_equal && op != Audit_not_equal)
3531376bd9cbSDarrel Goeddel return -EINVAL;
3532376bd9cbSDarrel Goeddel break;
35333a6b9f85SDarrel Goeddel case AUDIT_SUBJ_SEN:
35343a6b9f85SDarrel Goeddel case AUDIT_SUBJ_CLR:
35356e5a2d1dSDarrel Goeddel case AUDIT_OBJ_LEV_LOW:
35366e5a2d1dSDarrel Goeddel case AUDIT_OBJ_LEV_HIGH:
353725985edcSLucas De Marchi /* we do not allow a range, indicated by the presence of '-' */
3538376bd9cbSDarrel Goeddel if (strchr(rulestr, '-'))
3539376bd9cbSDarrel Goeddel return -EINVAL;
3540376bd9cbSDarrel Goeddel break;
3541376bd9cbSDarrel Goeddel default:
3542376bd9cbSDarrel Goeddel /* only the above fields are valid */
3543376bd9cbSDarrel Goeddel return -EINVAL;
3544376bd9cbSDarrel Goeddel }
3545376bd9cbSDarrel Goeddel
354628d0ecc5SGUO Zihua tmprule = kzalloc(sizeof(struct selinux_audit_rule), gfp);
3547376bd9cbSDarrel Goeddel if (!tmprule)
3548376bd9cbSDarrel Goeddel return -ENOMEM;
3549376bd9cbSDarrel Goeddel context_init(&tmprule->au_ctxt);
3550376bd9cbSDarrel Goeddel
35511b8b31a2SStephen Smalley rcu_read_lock();
35521b8b31a2SStephen Smalley policy = rcu_dereference(state->policy);
35531b8b31a2SStephen Smalley policydb = &policy->policydb;
35541b8b31a2SStephen Smalley tmprule->au_seqno = policy->latest_granting;
3555376bd9cbSDarrel Goeddel switch (field) {
35563a6b9f85SDarrel Goeddel case AUDIT_SUBJ_USER:
35576e5a2d1dSDarrel Goeddel case AUDIT_OBJ_USER:
3558237389e3SOndrej Mosnacek userdatum = symtab_search(&policydb->p_users, rulestr);
3559c52df19eSPaul Moore if (!userdatum) {
3560c52df19eSPaul Moore rc = -EINVAL;
3561c52df19eSPaul Moore goto err;
3562c52df19eSPaul Moore }
3563376bd9cbSDarrel Goeddel tmprule->au_ctxt.user = userdatum->value;
3564376bd9cbSDarrel Goeddel break;
35653a6b9f85SDarrel Goeddel case AUDIT_SUBJ_ROLE:
35666e5a2d1dSDarrel Goeddel case AUDIT_OBJ_ROLE:
3567237389e3SOndrej Mosnacek roledatum = symtab_search(&policydb->p_roles, rulestr);
3568c52df19eSPaul Moore if (!roledatum) {
3569c52df19eSPaul Moore rc = -EINVAL;
3570c52df19eSPaul Moore goto err;
3571c52df19eSPaul Moore }
3572376bd9cbSDarrel Goeddel tmprule->au_ctxt.role = roledatum->value;
3573376bd9cbSDarrel Goeddel break;
35743a6b9f85SDarrel Goeddel case AUDIT_SUBJ_TYPE:
35756e5a2d1dSDarrel Goeddel case AUDIT_OBJ_TYPE:
3576237389e3SOndrej Mosnacek typedatum = symtab_search(&policydb->p_types, rulestr);
3577c52df19eSPaul Moore if (!typedatum) {
3578c52df19eSPaul Moore rc = -EINVAL;
3579c52df19eSPaul Moore goto err;
3580c52df19eSPaul Moore }
3581376bd9cbSDarrel Goeddel tmprule->au_ctxt.type = typedatum->value;
3582376bd9cbSDarrel Goeddel break;
35833a6b9f85SDarrel Goeddel case AUDIT_SUBJ_SEN:
35843a6b9f85SDarrel Goeddel case AUDIT_SUBJ_CLR:
35856e5a2d1dSDarrel Goeddel case AUDIT_OBJ_LEV_LOW:
35866e5a2d1dSDarrel Goeddel case AUDIT_OBJ_LEV_HIGH:
3587aa8e712cSStephen Smalley rc = mls_from_string(policydb, rulestr, &tmprule->au_ctxt,
3588aa8e712cSStephen Smalley GFP_ATOMIC);
35894b02b524SEric Paris if (rc)
3590c52df19eSPaul Moore goto err;
3591376bd9cbSDarrel Goeddel break;
3592376bd9cbSDarrel Goeddel }
35931b8b31a2SStephen Smalley rcu_read_unlock();
3594376bd9cbSDarrel Goeddel
3595376bd9cbSDarrel Goeddel *rule = tmprule;
3596c52df19eSPaul Moore return 0;
3597376bd9cbSDarrel Goeddel
3598c52df19eSPaul Moore err:
3599c52df19eSPaul Moore rcu_read_unlock();
3600c52df19eSPaul Moore selinux_audit_rule_free(tmprule);
3601c52df19eSPaul Moore *rule = NULL;
3602376bd9cbSDarrel Goeddel return rc;
3603376bd9cbSDarrel Goeddel }
3604376bd9cbSDarrel Goeddel
36059d57a7f9SAhmed S. Darwish /* Check to see if the rule contains any selinux fields */
selinux_audit_rule_known(struct audit_krule * rule)36069d57a7f9SAhmed S. Darwish int selinux_audit_rule_known(struct audit_krule *rule)
36079d57a7f9SAhmed S. Darwish {
3608c50e125dSChristian Göttsche u32 i;
36099d57a7f9SAhmed S. Darwish
36109d57a7f9SAhmed S. Darwish for (i = 0; i < rule->field_count; i++) {
36119d57a7f9SAhmed S. Darwish struct audit_field *f = &rule->fields[i];
36129d57a7f9SAhmed S. Darwish switch (f->type) {
36139d57a7f9SAhmed S. Darwish case AUDIT_SUBJ_USER:
36149d57a7f9SAhmed S. Darwish case AUDIT_SUBJ_ROLE:
36159d57a7f9SAhmed S. Darwish case AUDIT_SUBJ_TYPE:
36169d57a7f9SAhmed S. Darwish case AUDIT_SUBJ_SEN:
36179d57a7f9SAhmed S. Darwish case AUDIT_SUBJ_CLR:
36189d57a7f9SAhmed S. Darwish case AUDIT_OBJ_USER:
36199d57a7f9SAhmed S. Darwish case AUDIT_OBJ_ROLE:
36209d57a7f9SAhmed S. Darwish case AUDIT_OBJ_TYPE:
36219d57a7f9SAhmed S. Darwish case AUDIT_OBJ_LEV_LOW:
36229d57a7f9SAhmed S. Darwish case AUDIT_OBJ_LEV_HIGH:
36239d57a7f9SAhmed S. Darwish return 1;
36249d57a7f9SAhmed S. Darwish }
36259d57a7f9SAhmed S. Darwish }
36269d57a7f9SAhmed S. Darwish
36279d57a7f9SAhmed S. Darwish return 0;
36289d57a7f9SAhmed S. Darwish }
36299d57a7f9SAhmed S. Darwish
selinux_audit_rule_match(u32 sid,u32 field,u32 op,void * vrule)363090462a5bSRichard Guy Briggs int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule)
3631376bd9cbSDarrel Goeddel {
3632aa8e712cSStephen Smalley struct selinux_state *state = &selinux_state;
36331b8b31a2SStephen Smalley struct selinux_policy *policy;
3634376bd9cbSDarrel Goeddel struct context *ctxt;
3635376bd9cbSDarrel Goeddel struct mls_level *level;
36369d57a7f9SAhmed S. Darwish struct selinux_audit_rule *rule = vrule;
3637376bd9cbSDarrel Goeddel int match = 0;
3638376bd9cbSDarrel Goeddel
36399ad42a79SRichard Guy Briggs if (unlikely(!rule)) {
36409ad42a79SRichard Guy Briggs WARN_ONCE(1, "selinux_audit_rule_match: missing rule\n");
3641376bd9cbSDarrel Goeddel return -ENOENT;
3642376bd9cbSDarrel Goeddel }
3643376bd9cbSDarrel Goeddel
3644e67b7985SStephen Smalley if (!selinux_initialized())
364537ea433cSStephen Smalley return 0;
364637ea433cSStephen Smalley
36471b8b31a2SStephen Smalley rcu_read_lock();
3648376bd9cbSDarrel Goeddel
36491b8b31a2SStephen Smalley policy = rcu_dereference(state->policy);
36501b8b31a2SStephen Smalley
36511b8b31a2SStephen Smalley if (rule->au_seqno < policy->latest_granting) {
3652376bd9cbSDarrel Goeddel match = -ESTALE;
3653376bd9cbSDarrel Goeddel goto out;
3654376bd9cbSDarrel Goeddel }
3655376bd9cbSDarrel Goeddel
36561b8b31a2SStephen Smalley ctxt = sidtab_search(policy->sidtab, sid);
36579ad42a79SRichard Guy Briggs if (unlikely(!ctxt)) {
36589ad42a79SRichard Guy Briggs WARN_ONCE(1, "selinux_audit_rule_match: unrecognized SID %d\n",
36599a2f44f0SStephen Smalley sid);
3660376bd9cbSDarrel Goeddel match = -ENOENT;
3661376bd9cbSDarrel Goeddel goto out;
3662376bd9cbSDarrel Goeddel }
3663376bd9cbSDarrel Goeddel
3664376bd9cbSDarrel Goeddel /* a field/op pair that is not caught here will simply fall through
3665376bd9cbSDarrel Goeddel without a match */
3666376bd9cbSDarrel Goeddel switch (field) {
36673a6b9f85SDarrel Goeddel case AUDIT_SUBJ_USER:
36686e5a2d1dSDarrel Goeddel case AUDIT_OBJ_USER:
3669376bd9cbSDarrel Goeddel switch (op) {
36705af75d8dSAl Viro case Audit_equal:
3671376bd9cbSDarrel Goeddel match = (ctxt->user == rule->au_ctxt.user);
3672376bd9cbSDarrel Goeddel break;
36735af75d8dSAl Viro case Audit_not_equal:
3674376bd9cbSDarrel Goeddel match = (ctxt->user != rule->au_ctxt.user);
3675376bd9cbSDarrel Goeddel break;
3676376bd9cbSDarrel Goeddel }
3677376bd9cbSDarrel Goeddel break;
36783a6b9f85SDarrel Goeddel case AUDIT_SUBJ_ROLE:
36796e5a2d1dSDarrel Goeddel case AUDIT_OBJ_ROLE:
3680376bd9cbSDarrel Goeddel switch (op) {
36815af75d8dSAl Viro case Audit_equal:
3682376bd9cbSDarrel Goeddel match = (ctxt->role == rule->au_ctxt.role);
3683376bd9cbSDarrel Goeddel break;
36845af75d8dSAl Viro case Audit_not_equal:
3685376bd9cbSDarrel Goeddel match = (ctxt->role != rule->au_ctxt.role);
3686376bd9cbSDarrel Goeddel break;
3687376bd9cbSDarrel Goeddel }
3688376bd9cbSDarrel Goeddel break;
36893a6b9f85SDarrel Goeddel case AUDIT_SUBJ_TYPE:
36906e5a2d1dSDarrel Goeddel case AUDIT_OBJ_TYPE:
3691376bd9cbSDarrel Goeddel switch (op) {
36925af75d8dSAl Viro case Audit_equal:
3693376bd9cbSDarrel Goeddel match = (ctxt->type == rule->au_ctxt.type);
3694376bd9cbSDarrel Goeddel break;
36955af75d8dSAl Viro case Audit_not_equal:
3696376bd9cbSDarrel Goeddel match = (ctxt->type != rule->au_ctxt.type);
3697376bd9cbSDarrel Goeddel break;
3698376bd9cbSDarrel Goeddel }
3699376bd9cbSDarrel Goeddel break;
37003a6b9f85SDarrel Goeddel case AUDIT_SUBJ_SEN:
37013a6b9f85SDarrel Goeddel case AUDIT_SUBJ_CLR:
37026e5a2d1dSDarrel Goeddel case AUDIT_OBJ_LEV_LOW:
37036e5a2d1dSDarrel Goeddel case AUDIT_OBJ_LEV_HIGH:
37046e5a2d1dSDarrel Goeddel level = ((field == AUDIT_SUBJ_SEN ||
37056e5a2d1dSDarrel Goeddel field == AUDIT_OBJ_LEV_LOW) ?
3706376bd9cbSDarrel Goeddel &ctxt->range.level[0] : &ctxt->range.level[1]);
3707376bd9cbSDarrel Goeddel switch (op) {
37085af75d8dSAl Viro case Audit_equal:
3709376bd9cbSDarrel Goeddel match = mls_level_eq(&rule->au_ctxt.range.level[0],
3710376bd9cbSDarrel Goeddel level);
3711376bd9cbSDarrel Goeddel break;
37125af75d8dSAl Viro case Audit_not_equal:
3713376bd9cbSDarrel Goeddel match = !mls_level_eq(&rule->au_ctxt.range.level[0],
3714376bd9cbSDarrel Goeddel level);
3715376bd9cbSDarrel Goeddel break;
37165af75d8dSAl Viro case Audit_lt:
3717376bd9cbSDarrel Goeddel match = (mls_level_dom(&rule->au_ctxt.range.level[0],
3718376bd9cbSDarrel Goeddel level) &&
3719376bd9cbSDarrel Goeddel !mls_level_eq(&rule->au_ctxt.range.level[0],
3720376bd9cbSDarrel Goeddel level));
3721376bd9cbSDarrel Goeddel break;
37225af75d8dSAl Viro case Audit_le:
3723376bd9cbSDarrel Goeddel match = mls_level_dom(&rule->au_ctxt.range.level[0],
3724376bd9cbSDarrel Goeddel level);
3725376bd9cbSDarrel Goeddel break;
37265af75d8dSAl Viro case Audit_gt:
3727376bd9cbSDarrel Goeddel match = (mls_level_dom(level,
3728376bd9cbSDarrel Goeddel &rule->au_ctxt.range.level[0]) &&
3729376bd9cbSDarrel Goeddel !mls_level_eq(level,
3730376bd9cbSDarrel Goeddel &rule->au_ctxt.range.level[0]));
3731376bd9cbSDarrel Goeddel break;
37325af75d8dSAl Viro case Audit_ge:
3733376bd9cbSDarrel Goeddel match = mls_level_dom(level,
3734376bd9cbSDarrel Goeddel &rule->au_ctxt.range.level[0]);
3735376bd9cbSDarrel Goeddel break;
3736376bd9cbSDarrel Goeddel }
3737376bd9cbSDarrel Goeddel }
3738376bd9cbSDarrel Goeddel
3739376bd9cbSDarrel Goeddel out:
37401b8b31a2SStephen Smalley rcu_read_unlock();
3741376bd9cbSDarrel Goeddel return match;
3742376bd9cbSDarrel Goeddel }
3743376bd9cbSDarrel Goeddel
aurule_avc_callback(u32 event)3744562c99f2SWanlong Gao static int aurule_avc_callback(u32 event)
3745376bd9cbSDarrel Goeddel {
37463c797e51SOndrej Mosnacek if (event == AVC_CALLBACK_RESET)
37473c797e51SOndrej Mosnacek return audit_update_lsm_rules();
37483c797e51SOndrej Mosnacek return 0;
3749376bd9cbSDarrel Goeddel }
3750376bd9cbSDarrel Goeddel
aurule_init(void)3751376bd9cbSDarrel Goeddel static int __init aurule_init(void)
3752376bd9cbSDarrel Goeddel {
3753376bd9cbSDarrel Goeddel int err;
3754376bd9cbSDarrel Goeddel
3755562c99f2SWanlong Gao err = avc_add_callback(aurule_avc_callback, AVC_CALLBACK_RESET);
3756376bd9cbSDarrel Goeddel if (err)
3757376bd9cbSDarrel Goeddel panic("avc_add_callback() failed, error %d\n", err);
3758376bd9cbSDarrel Goeddel
3759376bd9cbSDarrel Goeddel return err;
3760376bd9cbSDarrel Goeddel }
3761376bd9cbSDarrel Goeddel __initcall(aurule_init);
3762376bd9cbSDarrel Goeddel
37637420ed23SVenkat Yekkirala #ifdef CONFIG_NETLABEL
37647420ed23SVenkat Yekkirala /**
37655778eabdSPaul Moore * security_netlbl_cache_add - Add an entry to the NetLabel cache
37665778eabdSPaul Moore * @secattr: the NetLabel packet security attributes
37675dbe1eb0SPaul Moore * @sid: the SELinux SID
37687420ed23SVenkat Yekkirala *
37697420ed23SVenkat Yekkirala * Description:
37707420ed23SVenkat Yekkirala * Attempt to cache the context in @ctx, which was derived from the packet in
37715778eabdSPaul Moore * @skb, in the NetLabel subsystem cache. This function assumes @secattr has
37725778eabdSPaul Moore * already been initialized.
37737420ed23SVenkat Yekkirala *
37747420ed23SVenkat Yekkirala */
security_netlbl_cache_add(struct netlbl_lsm_secattr * secattr,u32 sid)37755778eabdSPaul Moore static void security_netlbl_cache_add(struct netlbl_lsm_secattr *secattr,
37765dbe1eb0SPaul Moore u32 sid)
37777420ed23SVenkat Yekkirala {
37785dbe1eb0SPaul Moore u32 *sid_cache;
37797420ed23SVenkat Yekkirala
37805dbe1eb0SPaul Moore sid_cache = kmalloc(sizeof(*sid_cache), GFP_ATOMIC);
37815dbe1eb0SPaul Moore if (sid_cache == NULL)
37825dbe1eb0SPaul Moore return;
37835778eabdSPaul Moore secattr->cache = netlbl_secattr_cache_alloc(GFP_ATOMIC);
37845dbe1eb0SPaul Moore if (secattr->cache == NULL) {
37855dbe1eb0SPaul Moore kfree(sid_cache);
37865778eabdSPaul Moore return;
37870ec8abd7SJesper Juhl }
37887420ed23SVenkat Yekkirala
37895dbe1eb0SPaul Moore *sid_cache = sid;
37905dbe1eb0SPaul Moore secattr->cache->free = kfree;
37915dbe1eb0SPaul Moore secattr->cache->data = sid_cache;
37925778eabdSPaul Moore secattr->flags |= NETLBL_SECATTR_CACHE;
37937420ed23SVenkat Yekkirala }
37947420ed23SVenkat Yekkirala
37957420ed23SVenkat Yekkirala /**
37965778eabdSPaul Moore * security_netlbl_secattr_to_sid - Convert a NetLabel secattr to a SELinux SID
37977420ed23SVenkat Yekkirala * @secattr: the NetLabel packet security attributes
37987420ed23SVenkat Yekkirala * @sid: the SELinux SID
37997420ed23SVenkat Yekkirala *
38007420ed23SVenkat Yekkirala * Description:
38015778eabdSPaul Moore * Convert the given NetLabel security attributes in @secattr into a
38027420ed23SVenkat Yekkirala * SELinux SID. If the @secattr field does not contain a full SELinux
380325985edcSLucas De Marchi * SID/context then use SECINITSID_NETMSG as the foundation. If possible the
38045dbe1eb0SPaul Moore * 'cache' field of @secattr is set and the CACHE flag is set; this is to
38055dbe1eb0SPaul Moore * allow the @secattr to be used by NetLabel to cache the secattr to SID
38065dbe1eb0SPaul Moore * conversion for future lookups. Returns zero on success, negative values on
38075dbe1eb0SPaul Moore * failure.
38087420ed23SVenkat Yekkirala *
38097420ed23SVenkat Yekkirala */
security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr * secattr,u32 * sid)3810e67b7985SStephen Smalley int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr,
38117420ed23SVenkat Yekkirala u32 *sid)
38127420ed23SVenkat Yekkirala {
38131b8b31a2SStephen Smalley struct selinux_policy *policy;
381446169802SStephen Smalley struct policydb *policydb;
381546169802SStephen Smalley struct sidtab *sidtab;
38167ae9f23cSEric Paris int rc;
38177420ed23SVenkat Yekkirala struct context *ctx;
38187420ed23SVenkat Yekkirala struct context ctx_new;
38195778eabdSPaul Moore
3820e67b7985SStephen Smalley if (!selinux_initialized()) {
38215778eabdSPaul Moore *sid = SECSID_NULL;
38225778eabdSPaul Moore return 0;
38235778eabdSPaul Moore }
38247420ed23SVenkat Yekkirala
38259ad6e9cbSOndrej Mosnacek retry:
38269ad6e9cbSOndrej Mosnacek rc = 0;
38271b8b31a2SStephen Smalley rcu_read_lock();
3828e67b7985SStephen Smalley policy = rcu_dereference(selinux_state.policy);
38291b8b31a2SStephen Smalley policydb = &policy->policydb;
38301b8b31a2SStephen Smalley sidtab = policy->sidtab;
383146169802SStephen Smalley
38327ae9f23cSEric Paris if (secattr->flags & NETLBL_SECATTR_CACHE)
38335dbe1eb0SPaul Moore *sid = *(u32 *)secattr->cache->data;
38347ae9f23cSEric Paris else if (secattr->flags & NETLBL_SECATTR_SECID)
383516efd454SPaul Moore *sid = secattr->attr.secid;
38367ae9f23cSEric Paris else if (secattr->flags & NETLBL_SECATTR_MLS_LVL) {
38377ae9f23cSEric Paris rc = -EIDRM;
3838aa8e712cSStephen Smalley ctx = sidtab_search(sidtab, SECINITSID_NETMSG);
38397420ed23SVenkat Yekkirala if (ctx == NULL)
38407ae9f23cSEric Paris goto out;
38417420ed23SVenkat Yekkirala
384281990fbdSPaul Moore context_init(&ctx_new);
38437420ed23SVenkat Yekkirala ctx_new.user = ctx->user;
38447420ed23SVenkat Yekkirala ctx_new.role = ctx->role;
38457420ed23SVenkat Yekkirala ctx_new.type = ctx->type;
3846aa8e712cSStephen Smalley mls_import_netlbl_lvl(policydb, &ctx_new, secattr);
3847701a90baSPaul Moore if (secattr->flags & NETLBL_SECATTR_MLS_CAT) {
3848aa8e712cSStephen Smalley rc = mls_import_netlbl_cat(policydb, &ctx_new, secattr);
38497ae9f23cSEric Paris if (rc)
38507ae9f23cSEric Paris goto out;
38517420ed23SVenkat Yekkirala }
38527ae9f23cSEric Paris rc = -EIDRM;
38539ad6e9cbSOndrej Mosnacek if (!mls_context_isvalid(policydb, &ctx_new)) {
38549ad6e9cbSOndrej Mosnacek ebitmap_destroy(&ctx_new.range.level[0].cat);
38559ad6e9cbSOndrej Mosnacek goto out;
38569ad6e9cbSOndrej Mosnacek }
38577420ed23SVenkat Yekkirala
3858225621c9SOndrej Mosnacek rc = sidtab_context_to_sid(sidtab, &ctx_new, sid);
38599ad6e9cbSOndrej Mosnacek ebitmap_destroy(&ctx_new.range.level[0].cat);
38609ad6e9cbSOndrej Mosnacek if (rc == -ESTALE) {
38619ad6e9cbSOndrej Mosnacek rcu_read_unlock();
38629ad6e9cbSOndrej Mosnacek goto retry;
38639ad6e9cbSOndrej Mosnacek }
38647ae9f23cSEric Paris if (rc)
38659ad6e9cbSOndrej Mosnacek goto out;
38667420ed23SVenkat Yekkirala
38675dbe1eb0SPaul Moore security_netlbl_cache_add(secattr, *sid);
38687ae9f23cSEric Paris } else
3869388b2405Spaul.moore@hp.com *sid = SECSID_NULL;
38707420ed23SVenkat Yekkirala
38717ae9f23cSEric Paris out:
38721b8b31a2SStephen Smalley rcu_read_unlock();
38737420ed23SVenkat Yekkirala return rc;
38747420ed23SVenkat Yekkirala }
38757420ed23SVenkat Yekkirala
38767420ed23SVenkat Yekkirala /**
38775778eabdSPaul Moore * security_netlbl_sid_to_secattr - Convert a SELinux SID to a NetLabel secattr
38785778eabdSPaul Moore * @sid: the SELinux SID
38795778eabdSPaul Moore * @secattr: the NetLabel packet security attributes
38807420ed23SVenkat Yekkirala *
38817420ed23SVenkat Yekkirala * Description:
38825778eabdSPaul Moore * Convert the given SELinux SID in @sid into a NetLabel security attribute.
38835778eabdSPaul Moore * Returns zero on success, negative values on failure.
38847420ed23SVenkat Yekkirala *
38857420ed23SVenkat Yekkirala */
security_netlbl_sid_to_secattr(u32 sid,struct netlbl_lsm_secattr * secattr)3886e67b7985SStephen Smalley int security_netlbl_sid_to_secattr(u32 sid, struct netlbl_lsm_secattr *secattr)
38877420ed23SVenkat Yekkirala {
38881b8b31a2SStephen Smalley struct selinux_policy *policy;
388946169802SStephen Smalley struct policydb *policydb;
389099d854d2SPaul Moore int rc;
38917420ed23SVenkat Yekkirala struct context *ctx;
38927420ed23SVenkat Yekkirala
3893e67b7985SStephen Smalley if (!selinux_initialized())
38947420ed23SVenkat Yekkirala return 0;
38957420ed23SVenkat Yekkirala
38961b8b31a2SStephen Smalley rcu_read_lock();
3897e67b7985SStephen Smalley policy = rcu_dereference(selinux_state.policy);
38981b8b31a2SStephen Smalley policydb = &policy->policydb;
389946169802SStephen Smalley
390099d854d2SPaul Moore rc = -ENOENT;
39011b8b31a2SStephen Smalley ctx = sidtab_search(policy->sidtab, sid);
39024b02b524SEric Paris if (ctx == NULL)
39034b02b524SEric Paris goto out;
39044b02b524SEric Paris
39054b02b524SEric Paris rc = -ENOMEM;
3906aa8e712cSStephen Smalley secattr->domain = kstrdup(sym_name(policydb, SYM_TYPES, ctx->type - 1),
39077420ed23SVenkat Yekkirala GFP_ATOMIC);
39084b02b524SEric Paris if (secattr->domain == NULL)
39094b02b524SEric Paris goto out;
39104b02b524SEric Paris
39118d75899dSPaul Moore secattr->attr.secid = sid;
39128d75899dSPaul Moore secattr->flags |= NETLBL_SECATTR_DOMAIN_CPY | NETLBL_SECATTR_SECID;
3913aa8e712cSStephen Smalley mls_export_netlbl_lvl(policydb, ctx, secattr);
3914aa8e712cSStephen Smalley rc = mls_export_netlbl_cat(policydb, ctx, secattr);
39154b02b524SEric Paris out:
39161b8b31a2SStephen Smalley rcu_read_unlock();
3917f8687afeSPaul Moore return rc;
3918f8687afeSPaul Moore }
39197420ed23SVenkat Yekkirala #endif /* CONFIG_NETLABEL */
3920cee74f47SEric Paris
3921cee74f47SEric Paris /**
3922fdd1ffe8SLakshmi Ramasubramanian * __security_read_policy - read the policy.
3923fdd1ffe8SLakshmi Ramasubramanian * @policy: SELinux policy
3924fdd1ffe8SLakshmi Ramasubramanian * @data: binary policy data
3925fdd1ffe8SLakshmi Ramasubramanian * @len: length of data in bytes
3926fdd1ffe8SLakshmi Ramasubramanian *
3927fdd1ffe8SLakshmi Ramasubramanian */
__security_read_policy(struct selinux_policy * policy,void * data,size_t * len)3928fdd1ffe8SLakshmi Ramasubramanian static int __security_read_policy(struct selinux_policy *policy,
3929fdd1ffe8SLakshmi Ramasubramanian void *data, size_t *len)
3930fdd1ffe8SLakshmi Ramasubramanian {
3931fdd1ffe8SLakshmi Ramasubramanian int rc;
3932fdd1ffe8SLakshmi Ramasubramanian struct policy_file fp;
3933fdd1ffe8SLakshmi Ramasubramanian
3934fdd1ffe8SLakshmi Ramasubramanian fp.data = data;
3935fdd1ffe8SLakshmi Ramasubramanian fp.len = *len;
3936fdd1ffe8SLakshmi Ramasubramanian
3937fdd1ffe8SLakshmi Ramasubramanian rc = policydb_write(&policy->policydb, &fp);
3938fdd1ffe8SLakshmi Ramasubramanian if (rc)
3939fdd1ffe8SLakshmi Ramasubramanian return rc;
3940fdd1ffe8SLakshmi Ramasubramanian
3941fdd1ffe8SLakshmi Ramasubramanian *len = (unsigned long)fp.data - (unsigned long)data;
3942fdd1ffe8SLakshmi Ramasubramanian return 0;
3943fdd1ffe8SLakshmi Ramasubramanian }
3944fdd1ffe8SLakshmi Ramasubramanian
3945fdd1ffe8SLakshmi Ramasubramanian /**
3946cee74f47SEric Paris * security_read_policy - read the policy.
3947cee74f47SEric Paris * @data: binary policy data
3948cee74f47SEric Paris * @len: length of data in bytes
3949cee74f47SEric Paris *
3950cee74f47SEric Paris */
security_read_policy(void ** data,size_t * len)3951e67b7985SStephen Smalley int security_read_policy(void **data, size_t *len)
3952cee74f47SEric Paris {
3953e67b7985SStephen Smalley struct selinux_state *state = &selinux_state;
39541b8b31a2SStephen Smalley struct selinux_policy *policy;
3955cee74f47SEric Paris
395666ccd256SOndrej Mosnacek policy = rcu_dereference_protected(
395766ccd256SOndrej Mosnacek state->policy, lockdep_is_held(&state->policy_mutex));
395866ccd256SOndrej Mosnacek if (!policy)
3959cee74f47SEric Paris return -EINVAL;
3960cee74f47SEric Paris
396166ccd256SOndrej Mosnacek *len = policy->policydb.len;
3962845ca30fSEric Paris *data = vmalloc_user(*len);
3963cee74f47SEric Paris if (!*data)
3964cee74f47SEric Paris return -ENOMEM;
3965cee74f47SEric Paris
3966fdd1ffe8SLakshmi Ramasubramanian return __security_read_policy(policy, *data, len);
3967fdd1ffe8SLakshmi Ramasubramanian }
3968cee74f47SEric Paris
3969fdd1ffe8SLakshmi Ramasubramanian /**
3970fdd1ffe8SLakshmi Ramasubramanian * security_read_state_kernel - read the policy.
3971fdd1ffe8SLakshmi Ramasubramanian * @data: binary policy data
3972fdd1ffe8SLakshmi Ramasubramanian * @len: length of data in bytes
3973fdd1ffe8SLakshmi Ramasubramanian *
3974fdd1ffe8SLakshmi Ramasubramanian * Allocates kernel memory for reading SELinux policy.
3975fdd1ffe8SLakshmi Ramasubramanian * This function is for internal use only and should not
3976fdd1ffe8SLakshmi Ramasubramanian * be used for returning data to user space.
3977fdd1ffe8SLakshmi Ramasubramanian *
3978fdd1ffe8SLakshmi Ramasubramanian * This function must be called with policy_mutex held.
3979fdd1ffe8SLakshmi Ramasubramanian */
security_read_state_kernel(void ** data,size_t * len)3980e67b7985SStephen Smalley int security_read_state_kernel(void **data, size_t *len)
3981fdd1ffe8SLakshmi Ramasubramanian {
398273de1befSXiu Jianfeng int err;
3983e67b7985SStephen Smalley struct selinux_state *state = &selinux_state;
3984fdd1ffe8SLakshmi Ramasubramanian struct selinux_policy *policy;
3985cee74f47SEric Paris
3986fdd1ffe8SLakshmi Ramasubramanian policy = rcu_dereference_protected(
3987fdd1ffe8SLakshmi Ramasubramanian state->policy, lockdep_is_held(&state->policy_mutex));
3988fdd1ffe8SLakshmi Ramasubramanian if (!policy)
3989fdd1ffe8SLakshmi Ramasubramanian return -EINVAL;
3990cee74f47SEric Paris
3991fdd1ffe8SLakshmi Ramasubramanian *len = policy->policydb.len;
3992fdd1ffe8SLakshmi Ramasubramanian *data = vmalloc(*len);
3993fdd1ffe8SLakshmi Ramasubramanian if (!*data)
3994fdd1ffe8SLakshmi Ramasubramanian return -ENOMEM;
3995fdd1ffe8SLakshmi Ramasubramanian
399673de1befSXiu Jianfeng err = __security_read_policy(policy, *data, len);
399773de1befSXiu Jianfeng if (err) {
399873de1befSXiu Jianfeng vfree(*data);
399973de1befSXiu Jianfeng *data = NULL;
400073de1befSXiu Jianfeng *len = 0;
400173de1befSXiu Jianfeng }
400273de1befSXiu Jianfeng return err;
4003cee74f47SEric Paris }
4004