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])
210*aa4b6051SChristian Göttsche result |= (u32)1<<i;
211aa8e712cSStephen Smalley if (allow_unknown && !mapping->perms[i])
212*aa4b6051SChristian 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])
218*aa4b6051SChristian 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])
223*aa4b6051SChristian Göttsche result |= (u32)1<<i;
224aa8e712cSStephen Smalley if (!allow_unknown && !mapping->perms[i])
225*aa4b6051SChristian 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++)
233*aa4b6051SChristian 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 {
959fa1aa143SJeff Vander Stoep BUG();
960fa1aa143SJeff Vander Stoep }
961fa1aa143SJeff Vander Stoep
962fa1aa143SJeff Vander Stoep if (node->key.specified == AVTAB_XPERMS_ALLOWED) {
963fa1aa143SJeff Vander Stoep xpermd->used |= XPERMS_ALLOWED;
964fa1aa143SJeff Vander Stoep if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) {
965fa1aa143SJeff Vander Stoep memset(xpermd->allowed->p, 0xff,
966fa1aa143SJeff Vander Stoep sizeof(xpermd->allowed->p));
967fa1aa143SJeff Vander Stoep }
968fa1aa143SJeff Vander Stoep if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) {
969fa1aa143SJeff Vander Stoep for (i = 0; i < ARRAY_SIZE(xpermd->allowed->p); i++)
970fa1aa143SJeff Vander Stoep xpermd->allowed->p[i] |=
971fa1aa143SJeff Vander Stoep node->datum.u.xperms->perms.p[i];
972fa1aa143SJeff Vander Stoep }
973fa1aa143SJeff Vander Stoep } else if (node->key.specified == AVTAB_XPERMS_AUDITALLOW) {
974fa1aa143SJeff Vander Stoep xpermd->used |= XPERMS_AUDITALLOW;
975fa1aa143SJeff Vander Stoep if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) {
976fa1aa143SJeff Vander Stoep memset(xpermd->auditallow->p, 0xff,
977fa1aa143SJeff Vander Stoep sizeof(xpermd->auditallow->p));
978fa1aa143SJeff Vander Stoep }
979fa1aa143SJeff Vander Stoep if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) {
980fa1aa143SJeff Vander Stoep for (i = 0; i < ARRAY_SIZE(xpermd->auditallow->p); i++)
981fa1aa143SJeff Vander Stoep xpermd->auditallow->p[i] |=
982fa1aa143SJeff Vander Stoep node->datum.u.xperms->perms.p[i];
983fa1aa143SJeff Vander Stoep }
984fa1aa143SJeff Vander Stoep } else if (node->key.specified == AVTAB_XPERMS_DONTAUDIT) {
985fa1aa143SJeff Vander Stoep xpermd->used |= XPERMS_DONTAUDIT;
986fa1aa143SJeff Vander Stoep if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) {
987fa1aa143SJeff Vander Stoep memset(xpermd->dontaudit->p, 0xff,
988fa1aa143SJeff Vander Stoep sizeof(xpermd->dontaudit->p));
989fa1aa143SJeff Vander Stoep }
990fa1aa143SJeff Vander Stoep if (node->datum.u.xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION) {
991fa1aa143SJeff Vander Stoep for (i = 0; i < ARRAY_SIZE(xpermd->dontaudit->p); i++)
992fa1aa143SJeff Vander Stoep xpermd->dontaudit->p[i] |=
993fa1aa143SJeff Vander Stoep node->datum.u.xperms->perms.p[i];
994fa1aa143SJeff Vander Stoep }
995fa1aa143SJeff Vander Stoep } else {
996fa1aa143SJeff Vander Stoep BUG();
997fa1aa143SJeff Vander Stoep }
998fa1aa143SJeff Vander Stoep }
999fa1aa143SJeff Vander Stoep
security_compute_xperms_decision(u32 ssid,u32 tsid,u16 orig_tclass,u8 driver,struct extended_perms_decision * xpermd)1000e67b7985SStephen Smalley void security_compute_xperms_decision(u32 ssid,
1001fa1aa143SJeff Vander Stoep u32 tsid,
1002fa1aa143SJeff Vander Stoep u16 orig_tclass,
1003fa1aa143SJeff Vander Stoep u8 driver,
1004fa1aa143SJeff Vander Stoep struct extended_perms_decision *xpermd)
1005fa1aa143SJeff Vander Stoep {
10061b8b31a2SStephen Smalley struct selinux_policy *policy;
1007aa8e712cSStephen Smalley struct policydb *policydb;
1008aa8e712cSStephen Smalley struct sidtab *sidtab;
1009fa1aa143SJeff Vander Stoep u16 tclass;
1010fa1aa143SJeff Vander Stoep struct context *scontext, *tcontext;
1011fa1aa143SJeff Vander Stoep struct avtab_key avkey;
1012fa1aa143SJeff Vander Stoep struct avtab_node *node;
1013fa1aa143SJeff Vander Stoep struct ebitmap *sattr, *tattr;
1014fa1aa143SJeff Vander Stoep struct ebitmap_node *snode, *tnode;
1015fa1aa143SJeff Vander Stoep unsigned int i, j;
1016fa1aa143SJeff Vander Stoep
1017fa1aa143SJeff Vander Stoep xpermd->driver = driver;
1018fa1aa143SJeff Vander Stoep xpermd->used = 0;
1019fa1aa143SJeff Vander Stoep memset(xpermd->allowed->p, 0, sizeof(xpermd->allowed->p));
1020fa1aa143SJeff Vander Stoep memset(xpermd->auditallow->p, 0, sizeof(xpermd->auditallow->p));
1021fa1aa143SJeff Vander Stoep memset(xpermd->dontaudit->p, 0, sizeof(xpermd->dontaudit->p));
1022fa1aa143SJeff Vander Stoep
10231b8b31a2SStephen Smalley rcu_read_lock();
1024e67b7985SStephen Smalley if (!selinux_initialized())
1025fa1aa143SJeff Vander Stoep goto allow;
1026fa1aa143SJeff Vander Stoep
1027e67b7985SStephen Smalley policy = rcu_dereference(selinux_state.policy);
10281b8b31a2SStephen Smalley policydb = &policy->policydb;
10291b8b31a2SStephen Smalley sidtab = policy->sidtab;
1030aa8e712cSStephen Smalley
1031aa8e712cSStephen Smalley scontext = sidtab_search(sidtab, ssid);
1032fa1aa143SJeff Vander Stoep if (!scontext) {
1033b54c85c1Speter enderborg pr_err("SELinux: %s: unrecognized SID %d\n",
1034fa1aa143SJeff Vander Stoep __func__, ssid);
1035fa1aa143SJeff Vander Stoep goto out;
1036fa1aa143SJeff Vander Stoep }
1037fa1aa143SJeff Vander Stoep
1038aa8e712cSStephen Smalley tcontext = sidtab_search(sidtab, tsid);
1039fa1aa143SJeff Vander Stoep if (!tcontext) {
1040b54c85c1Speter enderborg pr_err("SELinux: %s: unrecognized SID %d\n",
1041fa1aa143SJeff Vander Stoep __func__, tsid);
1042fa1aa143SJeff Vander Stoep goto out;
1043fa1aa143SJeff Vander Stoep }
1044fa1aa143SJeff Vander Stoep
10451b8b31a2SStephen Smalley tclass = unmap_class(&policy->map, orig_tclass);
1046fa1aa143SJeff Vander Stoep if (unlikely(orig_tclass && !tclass)) {
1047aa8e712cSStephen Smalley if (policydb->allow_unknown)
1048fa1aa143SJeff Vander Stoep goto allow;
1049fa1aa143SJeff Vander Stoep goto out;
1050fa1aa143SJeff Vander Stoep }
1051fa1aa143SJeff Vander Stoep
1052fa1aa143SJeff Vander Stoep
1053aa8e712cSStephen Smalley if (unlikely(!tclass || tclass > policydb->p_classes.nprim)) {
1054fa1aa143SJeff Vander Stoep pr_warn_ratelimited("SELinux: Invalid class %hu\n", tclass);
1055fa1aa143SJeff Vander Stoep goto out;
1056fa1aa143SJeff Vander Stoep }
1057fa1aa143SJeff Vander Stoep
1058fa1aa143SJeff Vander Stoep avkey.target_class = tclass;
1059fa1aa143SJeff Vander Stoep avkey.specified = AVTAB_XPERMS;
1060acdf52d9SKent Overstreet sattr = &policydb->type_attr_map_array[scontext->type - 1];
1061acdf52d9SKent Overstreet tattr = &policydb->type_attr_map_array[tcontext->type - 1];
1062fa1aa143SJeff Vander Stoep ebitmap_for_each_positive_bit(sattr, snode, i) {
1063fa1aa143SJeff Vander Stoep ebitmap_for_each_positive_bit(tattr, tnode, j) {
1064fa1aa143SJeff Vander Stoep avkey.source_type = i + 1;
1065fa1aa143SJeff Vander Stoep avkey.target_type = j + 1;
1066aa8e712cSStephen Smalley for (node = avtab_search_node(&policydb->te_avtab,
1067aa8e712cSStephen Smalley &avkey);
1068fa1aa143SJeff Vander Stoep node;
1069fa1aa143SJeff Vander Stoep node = avtab_search_node_next(node, avkey.specified))
1070fa1aa143SJeff Vander Stoep services_compute_xperms_decision(xpermd, node);
1071fa1aa143SJeff Vander Stoep
1072aa8e712cSStephen Smalley cond_compute_xperms(&policydb->te_cond_avtab,
1073fa1aa143SJeff Vander Stoep &avkey, xpermd);
1074fa1aa143SJeff Vander Stoep }
1075fa1aa143SJeff Vander Stoep }
1076fa1aa143SJeff Vander Stoep out:
10771b8b31a2SStephen Smalley rcu_read_unlock();
1078fa1aa143SJeff Vander Stoep return;
1079fa1aa143SJeff Vander Stoep allow:
1080fa1aa143SJeff Vander Stoep memset(xpermd->allowed->p, 0xff, sizeof(xpermd->allowed->p));
1081fa1aa143SJeff Vander Stoep goto out;
1082fa1aa143SJeff Vander Stoep }
1083c6d3aaa4SStephen Smalley
10841da177e4SLinus Torvalds /**
10851da177e4SLinus Torvalds * security_compute_av - Compute access vector decisions.
10861da177e4SLinus Torvalds * @ssid: source security identifier
10871da177e4SLinus Torvalds * @tsid: target security identifier
1088e9fd7292SPaul Moore * @orig_tclass: target security class
10891da177e4SLinus Torvalds * @avd: access vector decisions
1090fa1aa143SJeff Vander Stoep * @xperms: extended permissions
10911da177e4SLinus Torvalds *
10921da177e4SLinus Torvalds * Compute a set of access vector decisions based on the
10931da177e4SLinus Torvalds * SID pair (@ssid, @tsid) for the permissions in @tclass.
10941da177e4SLinus Torvalds */
security_compute_av(u32 ssid,u32 tsid,u16 orig_tclass,struct av_decision * avd,struct extended_perms * xperms)1095e67b7985SStephen Smalley void security_compute_av(u32 ssid,
10961da177e4SLinus Torvalds u32 tsid,
1097c6d3aaa4SStephen Smalley u16 orig_tclass,
1098fa1aa143SJeff Vander Stoep struct av_decision *avd,
1099fa1aa143SJeff Vander Stoep struct extended_perms *xperms)
1100c6d3aaa4SStephen Smalley {
11011b8b31a2SStephen Smalley struct selinux_policy *policy;
1102aa8e712cSStephen Smalley struct policydb *policydb;
1103aa8e712cSStephen Smalley struct sidtab *sidtab;
1104c6d3aaa4SStephen Smalley u16 tclass;
110519439d05SStephen Smalley struct context *scontext = NULL, *tcontext = NULL;
1106c6d3aaa4SStephen Smalley
11071b8b31a2SStephen Smalley rcu_read_lock();
1108e67b7985SStephen Smalley policy = rcu_dereference(selinux_state.policy);
11091b8b31a2SStephen Smalley avd_init(policy, avd);
1110fa1aa143SJeff Vander Stoep xperms->len = 0;
1111e67b7985SStephen Smalley if (!selinux_initialized())
1112c6d3aaa4SStephen Smalley goto allow;
1113c6d3aaa4SStephen Smalley
11141b8b31a2SStephen Smalley policydb = &policy->policydb;
11151b8b31a2SStephen Smalley sidtab = policy->sidtab;
1116aa8e712cSStephen Smalley
1117aa8e712cSStephen Smalley scontext = sidtab_search(sidtab, ssid);
111819439d05SStephen Smalley if (!scontext) {
1119b54c85c1Speter enderborg pr_err("SELinux: %s: unrecognized SID %d\n",
112019439d05SStephen Smalley __func__, ssid);
112119439d05SStephen Smalley goto out;
112219439d05SStephen Smalley }
112319439d05SStephen Smalley
112419439d05SStephen Smalley /* permissive domain? */
1125aa8e712cSStephen Smalley if (ebitmap_get_bit(&policydb->permissive_map, scontext->type))
112619439d05SStephen Smalley avd->flags |= AVD_FLAGS_PERMISSIVE;
112719439d05SStephen Smalley
1128aa8e712cSStephen Smalley tcontext = sidtab_search(sidtab, tsid);
112919439d05SStephen Smalley if (!tcontext) {
1130b54c85c1Speter enderborg pr_err("SELinux: %s: unrecognized SID %d\n",
113119439d05SStephen Smalley __func__, tsid);
113219439d05SStephen Smalley goto out;
113319439d05SStephen Smalley }
113419439d05SStephen Smalley
11351b8b31a2SStephen Smalley tclass = unmap_class(&policy->map, orig_tclass);
1136c6d3aaa4SStephen Smalley if (unlikely(orig_tclass && !tclass)) {
1137aa8e712cSStephen Smalley if (policydb->allow_unknown)
1138c6d3aaa4SStephen Smalley goto allow;
1139b7f3008aSStephen Smalley goto out;
1140c6d3aaa4SStephen Smalley }
1141aa8e712cSStephen Smalley context_struct_compute_av(policydb, scontext, tcontext, tclass, avd,
1142aa8e712cSStephen Smalley xperms);
11431b8b31a2SStephen Smalley map_decision(&policy->map, orig_tclass, avd,
1144aa8e712cSStephen Smalley policydb->allow_unknown);
1145b7f3008aSStephen Smalley out:
11461b8b31a2SStephen Smalley rcu_read_unlock();
114719439d05SStephen Smalley return;
1148c6d3aaa4SStephen Smalley allow:
1149c6d3aaa4SStephen Smalley avd->allowed = 0xffffffff;
1150b7f3008aSStephen Smalley goto out;
1151c6d3aaa4SStephen Smalley }
1152c6d3aaa4SStephen Smalley
security_compute_av_user(u32 ssid,u32 tsid,u16 tclass,struct av_decision * avd)1153e67b7985SStephen Smalley void security_compute_av_user(u32 ssid,
1154c6d3aaa4SStephen Smalley u32 tsid,
11551da177e4SLinus Torvalds u16 tclass,
11561da177e4SLinus Torvalds struct av_decision *avd)
11571da177e4SLinus Torvalds {
11581b8b31a2SStephen Smalley struct selinux_policy *policy;
1159aa8e712cSStephen Smalley struct policydb *policydb;
1160aa8e712cSStephen Smalley struct sidtab *sidtab;
116119439d05SStephen Smalley struct context *scontext = NULL, *tcontext = NULL;
11621da177e4SLinus Torvalds
11631b8b31a2SStephen Smalley rcu_read_lock();
1164e67b7985SStephen Smalley policy = rcu_dereference(selinux_state.policy);
11651b8b31a2SStephen Smalley avd_init(policy, avd);
1166e67b7985SStephen Smalley if (!selinux_initialized())
116719439d05SStephen Smalley goto allow;
116819439d05SStephen Smalley
11691b8b31a2SStephen Smalley policydb = &policy->policydb;
11701b8b31a2SStephen Smalley sidtab = policy->sidtab;
1171aa8e712cSStephen Smalley
1172aa8e712cSStephen Smalley scontext = sidtab_search(sidtab, ssid);
117319439d05SStephen Smalley if (!scontext) {
1174b54c85c1Speter enderborg pr_err("SELinux: %s: unrecognized SID %d\n",
117519439d05SStephen Smalley __func__, ssid);
117619439d05SStephen Smalley goto out;
117719439d05SStephen Smalley }
117819439d05SStephen Smalley
117919439d05SStephen Smalley /* permissive domain? */
1180aa8e712cSStephen Smalley if (ebitmap_get_bit(&policydb->permissive_map, scontext->type))
118119439d05SStephen Smalley avd->flags |= AVD_FLAGS_PERMISSIVE;
118219439d05SStephen Smalley
1183aa8e712cSStephen Smalley tcontext = sidtab_search(sidtab, tsid);
118419439d05SStephen Smalley if (!tcontext) {
1185b54c85c1Speter enderborg pr_err("SELinux: %s: unrecognized SID %d\n",
118619439d05SStephen Smalley __func__, tsid);
118719439d05SStephen Smalley goto out;
118819439d05SStephen Smalley }
118919439d05SStephen Smalley
119019439d05SStephen Smalley if (unlikely(!tclass)) {
1191aa8e712cSStephen Smalley if (policydb->allow_unknown)
119219439d05SStephen Smalley goto allow;
119319439d05SStephen Smalley goto out;
119419439d05SStephen Smalley }
119519439d05SStephen Smalley
1196aa8e712cSStephen Smalley context_struct_compute_av(policydb, scontext, tcontext, tclass, avd,
1197aa8e712cSStephen Smalley NULL);
119819439d05SStephen Smalley out:
11991b8b31a2SStephen Smalley rcu_read_unlock();
120019439d05SStephen Smalley return;
120119439d05SStephen Smalley allow:
120219439d05SStephen Smalley avd->allowed = 0xffffffff;
120319439d05SStephen Smalley goto out;
12041da177e4SLinus Torvalds }
12051da177e4SLinus Torvalds
12061da177e4SLinus Torvalds /*
12071da177e4SLinus Torvalds * Write the security context string representation of
12081da177e4SLinus Torvalds * the context structure `context' into a dynamically
12091da177e4SLinus Torvalds * allocated string of the correct size. Set `*scontext'
12101da177e4SLinus Torvalds * to point to this string and set `*scontext_len' to
12111da177e4SLinus Torvalds * the length of the string.
12121da177e4SLinus Torvalds */
context_struct_to_string(struct policydb * p,struct context * context,char ** scontext,u32 * scontext_len)1213aa8e712cSStephen Smalley static int context_struct_to_string(struct policydb *p,
1214aa8e712cSStephen Smalley struct context *context,
1215aa8e712cSStephen Smalley char **scontext, u32 *scontext_len)
12161da177e4SLinus Torvalds {
12171da177e4SLinus Torvalds char *scontextp;
12181da177e4SLinus Torvalds
1219d5630b9dSEric Paris if (scontext)
12201da177e4SLinus Torvalds *scontext = NULL;
12211da177e4SLinus Torvalds *scontext_len = 0;
12221da177e4SLinus Torvalds
122312b29f34SStephen Smalley if (context->len) {
122412b29f34SStephen Smalley *scontext_len = context->len;
1225bb7081abSEric Paris if (scontext) {
122612b29f34SStephen Smalley *scontext = kstrdup(context->str, GFP_ATOMIC);
122712b29f34SStephen Smalley if (!(*scontext))
122812b29f34SStephen Smalley return -ENOMEM;
1229bb7081abSEric Paris }
123012b29f34SStephen Smalley return 0;
123112b29f34SStephen Smalley }
123212b29f34SStephen Smalley
12331da177e4SLinus Torvalds /* Compute the size of the context. */
1234aa8e712cSStephen Smalley *scontext_len += strlen(sym_name(p, SYM_USERS, context->user - 1)) + 1;
1235aa8e712cSStephen Smalley *scontext_len += strlen(sym_name(p, SYM_ROLES, context->role - 1)) + 1;
1236aa8e712cSStephen Smalley *scontext_len += strlen(sym_name(p, SYM_TYPES, context->type - 1)) + 1;
1237aa8e712cSStephen Smalley *scontext_len += mls_compute_context_len(p, context);
12381da177e4SLinus Torvalds
1239d5630b9dSEric Paris if (!scontext)
1240d5630b9dSEric Paris return 0;
1241d5630b9dSEric Paris
12421da177e4SLinus Torvalds /* Allocate space for the context; caller must free this space. */
12431da177e4SLinus Torvalds scontextp = kmalloc(*scontext_len, GFP_ATOMIC);
12445d55a345SEric Paris if (!scontextp)
12451da177e4SLinus Torvalds return -ENOMEM;
12461da177e4SLinus Torvalds *scontext = scontextp;
12471da177e4SLinus Torvalds
12481da177e4SLinus Torvalds /*
12491da177e4SLinus Torvalds * Copy the user name, role name and type name into the context.
12501da177e4SLinus Torvalds */
12519529c788SRasmus Villemoes scontextp += sprintf(scontextp, "%s:%s:%s",
1252aa8e712cSStephen Smalley sym_name(p, SYM_USERS, context->user - 1),
1253aa8e712cSStephen Smalley sym_name(p, SYM_ROLES, context->role - 1),
1254aa8e712cSStephen Smalley sym_name(p, SYM_TYPES, context->type - 1));
12551da177e4SLinus Torvalds
1256aa8e712cSStephen Smalley mls_sid_to_context(p, context, &scontextp);
12571da177e4SLinus Torvalds
12581da177e4SLinus Torvalds *scontextp = 0;
12591da177e4SLinus Torvalds
12601da177e4SLinus Torvalds return 0;
12611da177e4SLinus Torvalds }
12621da177e4SLinus Torvalds
sidtab_entry_to_string(struct policydb * p,struct sidtab * sidtab,struct sidtab_entry * entry,char ** scontext,u32 * scontext_len)1263d97bd23cSOndrej Mosnacek static int sidtab_entry_to_string(struct policydb *p,
1264d97bd23cSOndrej Mosnacek struct sidtab *sidtab,
1265d97bd23cSOndrej Mosnacek struct sidtab_entry *entry,
1266d97bd23cSOndrej Mosnacek char **scontext, u32 *scontext_len)
1267d97bd23cSOndrej Mosnacek {
1268d97bd23cSOndrej Mosnacek int rc = sidtab_sid2str_get(sidtab, entry, scontext, scontext_len);
1269d97bd23cSOndrej Mosnacek
1270d97bd23cSOndrej Mosnacek if (rc != -ENOENT)
1271d97bd23cSOndrej Mosnacek return rc;
1272d97bd23cSOndrej Mosnacek
1273d97bd23cSOndrej Mosnacek rc = context_struct_to_string(p, &entry->context, scontext,
1274d97bd23cSOndrej Mosnacek scontext_len);
1275d97bd23cSOndrej Mosnacek if (!rc && scontext)
1276d97bd23cSOndrej Mosnacek sidtab_sid2str_put(sidtab, entry, *scontext, *scontext_len);
1277d97bd23cSOndrej Mosnacek return rc;
1278d97bd23cSOndrej Mosnacek }
1279d97bd23cSOndrej Mosnacek
12801da177e4SLinus Torvalds #include "initial_sid_to_string.h"
12811da177e4SLinus Torvalds
security_sidtab_hash_stats(char * page)1282e67b7985SStephen Smalley int security_sidtab_hash_stats(char *page)
128366f8e2f0SJeff Vander Stoep {
12841b8b31a2SStephen Smalley struct selinux_policy *policy;
128566f8e2f0SJeff Vander Stoep int rc;
128666f8e2f0SJeff Vander Stoep
1287e67b7985SStephen Smalley if (!selinux_initialized()) {
128815b590a8SPaul Moore pr_err("SELinux: %s: called before initial load_policy\n",
128915b590a8SPaul Moore __func__);
129015b590a8SPaul Moore return -EINVAL;
129115b590a8SPaul Moore }
129215b590a8SPaul Moore
12931b8b31a2SStephen Smalley rcu_read_lock();
1294e67b7985SStephen Smalley policy = rcu_dereference(selinux_state.policy);
12951b8b31a2SStephen Smalley rc = sidtab_hash_stats(policy->sidtab, page);
12961b8b31a2SStephen Smalley rcu_read_unlock();
129766f8e2f0SJeff Vander Stoep
129866f8e2f0SJeff Vander Stoep return rc;
129966f8e2f0SJeff Vander Stoep }
130066f8e2f0SJeff Vander Stoep
security_get_initial_sid_context(u32 sid)1301f0ee2e46SJames Carter const char *security_get_initial_sid_context(u32 sid)
1302f0ee2e46SJames Carter {
1303f0ee2e46SJames Carter if (unlikely(sid > SECINITSID_NUM))
1304f0ee2e46SJames Carter return NULL;
1305f0ee2e46SJames Carter return initial_sid_to_string[sid];
1306f0ee2e46SJames Carter }
1307f0ee2e46SJames Carter
security_sid_to_context_core(u32 sid,char ** scontext,u32 * scontext_len,int force,int only_invalid)1308e67b7985SStephen Smalley static int security_sid_to_context_core(u32 sid, char **scontext,
1309fede1483SOndrej Mosnacek u32 *scontext_len, int force,
1310fede1483SOndrej Mosnacek int only_invalid)
13111da177e4SLinus Torvalds {
13121b8b31a2SStephen Smalley struct selinux_policy *policy;
1313aa8e712cSStephen Smalley struct policydb *policydb;
1314aa8e712cSStephen Smalley struct sidtab *sidtab;
1315d97bd23cSOndrej Mosnacek struct sidtab_entry *entry;
13161da177e4SLinus Torvalds int rc = 0;
13171da177e4SLinus Torvalds
1318d5630b9dSEric Paris if (scontext)
13194f4acf3aSStephen Smalley *scontext = NULL;
13204f4acf3aSStephen Smalley *scontext_len = 0;
13214f4acf3aSStephen Smalley
1322e67b7985SStephen Smalley if (!selinux_initialized()) {
13231da177e4SLinus Torvalds if (sid <= SECINITSID_NUM) {
13241da177e4SLinus Torvalds char *scontextp;
1325e3e0b582SStephen Smalley const char *s = initial_sid_to_string[sid];
13261da177e4SLinus Torvalds
1327e3e0b582SStephen Smalley if (!s)
1328e3e0b582SStephen Smalley return -EINVAL;
1329e3e0b582SStephen Smalley *scontext_len = strlen(s) + 1;
1330d5630b9dSEric Paris if (!scontext)
1331e3e0b582SStephen Smalley return 0;
1332e3e0b582SStephen Smalley scontextp = kmemdup(s, *scontext_len, GFP_ATOMIC);
1333e3e0b582SStephen Smalley if (!scontextp)
1334e3e0b582SStephen Smalley return -ENOMEM;
13351da177e4SLinus Torvalds *scontext = scontextp;
1336e3e0b582SStephen Smalley return 0;
13371da177e4SLinus Torvalds }
1338b54c85c1Speter enderborg pr_err("SELinux: %s: called before initial "
1339744ba35eSEric Paris "load_policy on unknown SID %d\n", __func__, sid);
1340e3e0b582SStephen Smalley return -EINVAL;
13411da177e4SLinus Torvalds }
13421b8b31a2SStephen Smalley rcu_read_lock();
1343e67b7985SStephen Smalley policy = rcu_dereference(selinux_state.policy);
13441b8b31a2SStephen Smalley policydb = &policy->policydb;
13451b8b31a2SStephen Smalley sidtab = policy->sidtab;
1346d97bd23cSOndrej Mosnacek
134712b29f34SStephen Smalley if (force)
1348d97bd23cSOndrej Mosnacek entry = sidtab_search_entry_force(sidtab, sid);
134912b29f34SStephen Smalley else
1350d97bd23cSOndrej Mosnacek entry = sidtab_search_entry(sidtab, sid);
1351d97bd23cSOndrej Mosnacek if (!entry) {
1352b54c85c1Speter enderborg pr_err("SELinux: %s: unrecognized SID %d\n",
1353744ba35eSEric Paris __func__, sid);
13541da177e4SLinus Torvalds rc = -EINVAL;
13551da177e4SLinus Torvalds goto out_unlock;
13561da177e4SLinus Torvalds }
1357d97bd23cSOndrej Mosnacek if (only_invalid && !entry->context.len)
1358d97bd23cSOndrej Mosnacek goto out_unlock;
1359d97bd23cSOndrej Mosnacek
1360d97bd23cSOndrej Mosnacek rc = sidtab_entry_to_string(policydb, sidtab, entry, scontext,
1361aa8e712cSStephen Smalley scontext_len);
1362d97bd23cSOndrej Mosnacek
13631da177e4SLinus Torvalds out_unlock:
13641b8b31a2SStephen Smalley rcu_read_unlock();
13651da177e4SLinus Torvalds return rc;
13661da177e4SLinus Torvalds
13671da177e4SLinus Torvalds }
13681da177e4SLinus Torvalds
136912b29f34SStephen Smalley /**
137012b29f34SStephen Smalley * security_sid_to_context - Obtain a context for a given SID.
137112b29f34SStephen Smalley * @sid: security identifier, SID
137212b29f34SStephen Smalley * @scontext: security context
137312b29f34SStephen Smalley * @scontext_len: length in bytes
137412b29f34SStephen Smalley *
137512b29f34SStephen Smalley * Write the string representation of the context associated with @sid
137612b29f34SStephen Smalley * into a dynamically allocated string of the correct size. Set @scontext
137712b29f34SStephen Smalley * to point to this string and set @scontext_len to the length of the string.
137812b29f34SStephen Smalley */
security_sid_to_context(u32 sid,char ** scontext,u32 * scontext_len)1379e67b7985SStephen Smalley int security_sid_to_context(u32 sid, char **scontext, u32 *scontext_len)
13801da177e4SLinus Torvalds {
1381e67b7985SStephen Smalley return security_sid_to_context_core(sid, scontext,
1382fede1483SOndrej Mosnacek scontext_len, 0, 0);
138312b29f34SStephen Smalley }
138412b29f34SStephen Smalley
security_sid_to_context_force(u32 sid,char ** scontext,u32 * scontext_len)1385e67b7985SStephen Smalley int security_sid_to_context_force(u32 sid,
1386aa8e712cSStephen Smalley char **scontext, u32 *scontext_len)
138712b29f34SStephen Smalley {
1388e67b7985SStephen Smalley return security_sid_to_context_core(sid, scontext,
1389fede1483SOndrej Mosnacek scontext_len, 1, 0);
1390fede1483SOndrej Mosnacek }
1391fede1483SOndrej Mosnacek
1392fede1483SOndrej Mosnacek /**
1393fede1483SOndrej Mosnacek * security_sid_to_context_inval - Obtain a context for a given SID if it
1394fede1483SOndrej Mosnacek * is invalid.
1395fede1483SOndrej Mosnacek * @sid: security identifier, SID
1396fede1483SOndrej Mosnacek * @scontext: security context
1397fede1483SOndrej Mosnacek * @scontext_len: length in bytes
1398fede1483SOndrej Mosnacek *
1399fede1483SOndrej Mosnacek * Write the string representation of the context associated with @sid
1400fede1483SOndrej Mosnacek * into a dynamically allocated string of the correct size, but only if the
1401fede1483SOndrej Mosnacek * context is invalid in the current policy. Set @scontext to point to
1402fede1483SOndrej Mosnacek * this string (or NULL if the context is valid) and set @scontext_len to
1403fede1483SOndrej Mosnacek * the length of the string (or 0 if the context is valid).
1404fede1483SOndrej Mosnacek */
security_sid_to_context_inval(u32 sid,char ** scontext,u32 * scontext_len)1405e67b7985SStephen Smalley int security_sid_to_context_inval(u32 sid,
1406fede1483SOndrej Mosnacek char **scontext, u32 *scontext_len)
1407fede1483SOndrej Mosnacek {
1408e67b7985SStephen Smalley return security_sid_to_context_core(sid, scontext,
1409fede1483SOndrej Mosnacek scontext_len, 1, 1);
141012b29f34SStephen Smalley }
141112b29f34SStephen Smalley
14129a59daa0SStephen Smalley /*
14139a59daa0SStephen Smalley * Caveat: Mutates scontext.
14149a59daa0SStephen Smalley */
string_to_context_struct(struct policydb * pol,struct sidtab * sidtabp,char * scontext,struct context * ctx,u32 def_sid)141512b29f34SStephen Smalley static int string_to_context_struct(struct policydb *pol,
141612b29f34SStephen Smalley struct sidtab *sidtabp,
14179a59daa0SStephen Smalley char *scontext,
141812b29f34SStephen Smalley struct context *ctx,
14199a59daa0SStephen Smalley u32 def_sid)
142012b29f34SStephen Smalley {
14211da177e4SLinus Torvalds struct role_datum *role;
14221da177e4SLinus Torvalds struct type_datum *typdatum;
14231da177e4SLinus Torvalds struct user_datum *usrdatum;
14241da177e4SLinus Torvalds char *scontextp, *p, oldc;
14251da177e4SLinus Torvalds int rc = 0;
14261da177e4SLinus Torvalds
142712b29f34SStephen Smalley context_init(ctx);
142812b29f34SStephen Smalley
142912b29f34SStephen Smalley /* Parse the security context. */
143012b29f34SStephen Smalley
143112b29f34SStephen Smalley rc = -EINVAL;
14320b3c2b3dSChristian Göttsche scontextp = scontext;
143312b29f34SStephen Smalley
143412b29f34SStephen Smalley /* Extract the user. */
143512b29f34SStephen Smalley p = scontextp;
143612b29f34SStephen Smalley while (*p && *p != ':')
143712b29f34SStephen Smalley p++;
143812b29f34SStephen Smalley
143912b29f34SStephen Smalley if (*p == 0)
144012b29f34SStephen Smalley goto out;
144112b29f34SStephen Smalley
144212b29f34SStephen Smalley *p++ = 0;
144312b29f34SStephen Smalley
1444237389e3SOndrej Mosnacek usrdatum = symtab_search(&pol->p_users, scontextp);
144512b29f34SStephen Smalley if (!usrdatum)
144612b29f34SStephen Smalley goto out;
144712b29f34SStephen Smalley
144812b29f34SStephen Smalley ctx->user = usrdatum->value;
144912b29f34SStephen Smalley
145012b29f34SStephen Smalley /* Extract role. */
145112b29f34SStephen Smalley scontextp = p;
145212b29f34SStephen Smalley while (*p && *p != ':')
145312b29f34SStephen Smalley p++;
145412b29f34SStephen Smalley
145512b29f34SStephen Smalley if (*p == 0)
145612b29f34SStephen Smalley goto out;
145712b29f34SStephen Smalley
145812b29f34SStephen Smalley *p++ = 0;
145912b29f34SStephen Smalley
1460237389e3SOndrej Mosnacek role = symtab_search(&pol->p_roles, scontextp);
146112b29f34SStephen Smalley if (!role)
146212b29f34SStephen Smalley goto out;
146312b29f34SStephen Smalley ctx->role = role->value;
146412b29f34SStephen Smalley
146512b29f34SStephen Smalley /* Extract type. */
146612b29f34SStephen Smalley scontextp = p;
146712b29f34SStephen Smalley while (*p && *p != ':')
146812b29f34SStephen Smalley p++;
146912b29f34SStephen Smalley oldc = *p;
147012b29f34SStephen Smalley *p++ = 0;
147112b29f34SStephen Smalley
1472237389e3SOndrej Mosnacek typdatum = symtab_search(&pol->p_types, scontextp);
1473d9250deaSKaiGai Kohei if (!typdatum || typdatum->attribute)
147412b29f34SStephen Smalley goto out;
147512b29f34SStephen Smalley
147612b29f34SStephen Smalley ctx->type = typdatum->value;
147712b29f34SStephen Smalley
147895ffe194SJann Horn rc = mls_context_to_sid(pol, oldc, p, ctx, sidtabp, def_sid);
147912b29f34SStephen Smalley if (rc)
148012b29f34SStephen Smalley goto out;
148112b29f34SStephen Smalley
148212b29f34SStephen Smalley /* Check the validity of the new context. */
148395ffe194SJann Horn rc = -EINVAL;
14844b02b524SEric Paris if (!policydb_context_isvalid(pol, ctx))
148512b29f34SStephen Smalley goto out;
148612b29f34SStephen Smalley rc = 0;
148712b29f34SStephen Smalley out:
14888e531af9SEric Paris if (rc)
14898e531af9SEric Paris context_destroy(ctx);
149012b29f34SStephen Smalley return rc;
149112b29f34SStephen Smalley }
149212b29f34SStephen Smalley
security_context_to_sid_core(const char * scontext,u32 scontext_len,u32 * sid,u32 def_sid,gfp_t gfp_flags,int force)1493e67b7985SStephen Smalley static int security_context_to_sid_core(const char *scontext, u32 scontext_len,
149412b29f34SStephen Smalley u32 *sid, u32 def_sid, gfp_t gfp_flags,
149512b29f34SStephen Smalley int force)
149612b29f34SStephen Smalley {
14971b8b31a2SStephen Smalley struct selinux_policy *policy;
1498aa8e712cSStephen Smalley struct policydb *policydb;
1499aa8e712cSStephen Smalley struct sidtab *sidtab;
15009a59daa0SStephen Smalley char *scontext2, *str = NULL;
150112b29f34SStephen Smalley struct context context;
150212b29f34SStephen Smalley int rc = 0;
150312b29f34SStephen Smalley
15042172fa70SStephen Smalley /* An empty security context is never valid. */
15052172fa70SStephen Smalley if (!scontext_len)
15062172fa70SStephen Smalley return -EINVAL;
15072172fa70SStephen Smalley
1508ef28df55SPaul Moore /* Copy the string to allow changes and ensure a NUL terminator */
1509ef28df55SPaul Moore scontext2 = kmemdup_nul(scontext, scontext_len, gfp_flags);
1510ef28df55SPaul Moore if (!scontext2)
1511ef28df55SPaul Moore return -ENOMEM;
1512ef28df55SPaul Moore
1513e67b7985SStephen Smalley if (!selinux_initialized()) {
1514c50e125dSChristian Göttsche u32 i;
15151da177e4SLinus Torvalds
15161da177e4SLinus Torvalds for (i = 1; i < SECINITSID_NUM; i++) {
1517e3e0b582SStephen Smalley const char *s = initial_sid_to_string[i];
1518e3e0b582SStephen Smalley
1519e3e0b582SStephen Smalley if (s && !strcmp(s, scontext2)) {
15201da177e4SLinus Torvalds *sid = i;
1521ef28df55SPaul Moore goto out;
15221da177e4SLinus Torvalds }
15231da177e4SLinus Torvalds }
15241da177e4SLinus Torvalds *sid = SECINITSID_KERNEL;
1525ef28df55SPaul Moore goto out;
15261da177e4SLinus Torvalds }
15271da177e4SLinus Torvalds *sid = SECSID_NULL;
15281da177e4SLinus Torvalds
15299a59daa0SStephen Smalley if (force) {
15309a59daa0SStephen Smalley /* Save another copy for storing in uninterpreted form */
15314b02b524SEric Paris rc = -ENOMEM;
15329a59daa0SStephen Smalley str = kstrdup(scontext2, gfp_flags);
15334b02b524SEric Paris if (!str)
15344b02b524SEric Paris goto out;
15359a59daa0SStephen Smalley }
15369ad6e9cbSOndrej Mosnacek retry:
15371b8b31a2SStephen Smalley rcu_read_lock();
1538e67b7985SStephen Smalley policy = rcu_dereference(selinux_state.policy);
15391b8b31a2SStephen Smalley policydb = &policy->policydb;
15401b8b31a2SStephen Smalley sidtab = policy->sidtab;
1541aa8e712cSStephen Smalley rc = string_to_context_struct(policydb, sidtab, scontext2,
154295ffe194SJann Horn &context, def_sid);
154312b29f34SStephen Smalley if (rc == -EINVAL && force) {
15449a59daa0SStephen Smalley context.str = str;
1545efe3de79SSachin Grover context.len = strlen(str) + 1;
15469a59daa0SStephen Smalley str = NULL;
154712b29f34SStephen Smalley } else if (rc)
15484b02b524SEric Paris goto out_unlock;
1549225621c9SOndrej Mosnacek rc = sidtab_context_to_sid(sidtab, &context, sid);
15509ad6e9cbSOndrej Mosnacek if (rc == -ESTALE) {
15519ad6e9cbSOndrej Mosnacek rcu_read_unlock();
15529ad6e9cbSOndrej Mosnacek if (context.str) {
15539ad6e9cbSOndrej Mosnacek str = context.str;
15549ad6e9cbSOndrej Mosnacek context.str = NULL;
15559ad6e9cbSOndrej Mosnacek }
15569ad6e9cbSOndrej Mosnacek context_destroy(&context);
15579ad6e9cbSOndrej Mosnacek goto retry;
15589ad6e9cbSOndrej Mosnacek }
15591da177e4SLinus Torvalds context_destroy(&context);
15604b02b524SEric Paris out_unlock:
15611b8b31a2SStephen Smalley rcu_read_unlock();
15624b02b524SEric Paris out:
15639a59daa0SStephen Smalley kfree(scontext2);
15649a59daa0SStephen Smalley kfree(str);
15651da177e4SLinus Torvalds return rc;
15661da177e4SLinus Torvalds }
15671da177e4SLinus Torvalds
1568f5c1d5b2SJames Morris /**
1569f5c1d5b2SJames Morris * security_context_to_sid - Obtain a SID for a given security context.
1570f5c1d5b2SJames Morris * @scontext: security context
1571f5c1d5b2SJames Morris * @scontext_len: length in bytes
1572f5c1d5b2SJames Morris * @sid: security identifier, SID
157352a4c640SNikolay Aleksandrov * @gfp: context for the allocation
1574f5c1d5b2SJames Morris *
1575f5c1d5b2SJames Morris * Obtains a SID associated with the security context that
1576f5c1d5b2SJames Morris * has the string representation specified by @scontext.
1577f5c1d5b2SJames Morris * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient
1578f5c1d5b2SJames Morris * memory is available, or 0 on success.
1579f5c1d5b2SJames Morris */
security_context_to_sid(const char * scontext,u32 scontext_len,u32 * sid,gfp_t gfp)1580e67b7985SStephen Smalley int security_context_to_sid(const char *scontext, u32 scontext_len, u32 *sid,
158152a4c640SNikolay Aleksandrov gfp_t gfp)
1582f5c1d5b2SJames Morris {
1583e67b7985SStephen Smalley return security_context_to_sid_core(scontext, scontext_len,
158452a4c640SNikolay Aleksandrov sid, SECSID_NULL, gfp, 0);
1585f5c1d5b2SJames Morris }
1586f5c1d5b2SJames Morris
security_context_str_to_sid(const char * scontext,u32 * sid,gfp_t gfp)1587e67b7985SStephen Smalley int security_context_str_to_sid(const char *scontext, u32 *sid, gfp_t gfp)
158844be2f65SRasmus Villemoes {
1589e67b7985SStephen Smalley return security_context_to_sid(scontext, strlen(scontext),
1590aa8e712cSStephen Smalley sid, gfp);
159144be2f65SRasmus Villemoes }
159244be2f65SRasmus Villemoes
1593f5c1d5b2SJames Morris /**
1594f5c1d5b2SJames Morris * security_context_to_sid_default - Obtain a SID for a given security context,
1595f5c1d5b2SJames Morris * falling back to specified default if needed.
1596f5c1d5b2SJames Morris *
1597f5c1d5b2SJames Morris * @scontext: security context
1598f5c1d5b2SJames Morris * @scontext_len: length in bytes
1599f5c1d5b2SJames Morris * @sid: security identifier, SID
1600d133a960SGabriel Craciunescu * @def_sid: default SID to assign on error
1601e9fd7292SPaul Moore * @gfp_flags: the allocator get-free-page (GFP) flags
1602f5c1d5b2SJames Morris *
1603f5c1d5b2SJames Morris * Obtains a SID associated with the security context that
1604f5c1d5b2SJames Morris * has the string representation specified by @scontext.
1605f5c1d5b2SJames Morris * The default SID is passed to the MLS layer to be used to allow
1606f5c1d5b2SJames Morris * kernel labeling of the MLS field if the MLS field is not present
1607f5c1d5b2SJames Morris * (for upgrading to MLS without full relabel).
160812b29f34SStephen Smalley * Implicitly forces adding of the context even if it cannot be mapped yet.
1609f5c1d5b2SJames Morris * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient
1610f5c1d5b2SJames Morris * memory is available, or 0 on success.
1611f5c1d5b2SJames Morris */
security_context_to_sid_default(const char * scontext,u32 scontext_len,u32 * sid,u32 def_sid,gfp_t gfp_flags)1612e67b7985SStephen Smalley int security_context_to_sid_default(const char *scontext, u32 scontext_len,
16137bf570dcSDavid Howells u32 *sid, u32 def_sid, gfp_t gfp_flags)
1614f5c1d5b2SJames Morris {
1615e67b7985SStephen Smalley return security_context_to_sid_core(scontext, scontext_len,
161612b29f34SStephen Smalley sid, def_sid, gfp_flags, 1);
161712b29f34SStephen Smalley }
161812b29f34SStephen Smalley
security_context_to_sid_force(const char * scontext,u32 scontext_len,u32 * sid)1619e67b7985SStephen Smalley int security_context_to_sid_force(const char *scontext, u32 scontext_len,
162012b29f34SStephen Smalley u32 *sid)
162112b29f34SStephen Smalley {
1622e67b7985SStephen Smalley return security_context_to_sid_core(scontext, scontext_len,
162312b29f34SStephen Smalley sid, SECSID_NULL, GFP_KERNEL, 1);
1624f5c1d5b2SJames Morris }
1625f5c1d5b2SJames Morris
compute_sid_handle_invalid_context(struct selinux_policy * policy,struct sidtab_entry * sentry,struct sidtab_entry * tentry,u16 tclass,struct context * newcontext)16261da177e4SLinus Torvalds static int compute_sid_handle_invalid_context(
16271b8b31a2SStephen Smalley struct selinux_policy *policy,
1628d97bd23cSOndrej Mosnacek struct sidtab_entry *sentry,
1629d97bd23cSOndrej Mosnacek struct sidtab_entry *tentry,
16301da177e4SLinus Torvalds u16 tclass,
16311da177e4SLinus Torvalds struct context *newcontext)
16321da177e4SLinus Torvalds {
16331b8b31a2SStephen Smalley struct policydb *policydb = &policy->policydb;
16341b8b31a2SStephen Smalley struct sidtab *sidtab = policy->sidtab;
16351da177e4SLinus Torvalds char *s = NULL, *t = NULL, *n = NULL;
16361da177e4SLinus Torvalds u32 slen, tlen, nlen;
1637ea74a685SRichard Guy Briggs struct audit_buffer *ab;
16381da177e4SLinus Torvalds
1639d97bd23cSOndrej Mosnacek if (sidtab_entry_to_string(policydb, sidtab, sentry, &s, &slen))
16401da177e4SLinus Torvalds goto out;
1641d97bd23cSOndrej Mosnacek if (sidtab_entry_to_string(policydb, sidtab, tentry, &t, &tlen))
16421da177e4SLinus Torvalds goto out;
1643aa8e712cSStephen Smalley if (context_struct_to_string(policydb, newcontext, &n, &nlen))
16441da177e4SLinus Torvalds goto out;
1645ea74a685SRichard Guy Briggs ab = audit_log_start(audit_context(), GFP_ATOMIC, AUDIT_SELINUX_ERR);
1646893c47d1SAustin Kim if (!ab)
1647893c47d1SAustin Kim goto out;
1648ea74a685SRichard Guy Briggs audit_log_format(ab,
1649ea74a685SRichard Guy Briggs "op=security_compute_sid invalid_context=");
1650ea74a685SRichard Guy Briggs /* no need to record the NUL with untrusted strings */
1651ea74a685SRichard Guy Briggs audit_log_n_untrustedstring(ab, n, nlen - 1);
1652ea74a685SRichard Guy Briggs audit_log_format(ab, " scontext=%s tcontext=%s tclass=%s",
1653ea74a685SRichard Guy Briggs s, t, sym_name(policydb, SYM_CLASSES, tclass-1));
1654ea74a685SRichard Guy Briggs audit_log_end(ab);
16551da177e4SLinus Torvalds out:
16561da177e4SLinus Torvalds kfree(s);
16571da177e4SLinus Torvalds kfree(t);
16581da177e4SLinus Torvalds kfree(n);
1659e67b7985SStephen Smalley if (!enforcing_enabled())
16601da177e4SLinus Torvalds return 0;
16611da177e4SLinus Torvalds return -EACCES;
16621da177e4SLinus Torvalds }
16631da177e4SLinus Torvalds
filename_compute_type(struct policydb * policydb,struct context * newcontext,u32 stype,u32 ttype,u16 tclass,const char * objname)1664aa8e712cSStephen Smalley static void filename_compute_type(struct policydb *policydb,
1665aa8e712cSStephen Smalley struct context *newcontext,
16662667991fSEric Paris u32 stype, u32 ttype, u16 tclass,
1667f50a3ec9SKohei Kaigai const char *objname)
1668652bb9b0SEric Paris {
1669c3a27611SOndrej Mosnacek struct filename_trans_key ft;
1670c3a27611SOndrej Mosnacek struct filename_trans_datum *datum;
167103a4c018SEric Paris
167203a4c018SEric Paris /*
167303a4c018SEric Paris * Most filename trans rules are going to live in specific directories
167403a4c018SEric Paris * like /dev or /var/run. This bitmap will quickly skip rule searches
167503a4c018SEric Paris * if the ttype does not contain any rules.
167603a4c018SEric Paris */
1677aa8e712cSStephen Smalley if (!ebitmap_get_bit(&policydb->filename_trans_ttypes, ttype))
1678652bb9b0SEric Paris return;
167903a4c018SEric Paris
16802463c26dSEric Paris ft.ttype = ttype;
16812463c26dSEric Paris ft.tclass = tclass;
16822463c26dSEric Paris ft.name = objname;
16832463c26dSEric Paris
168424def7bbSOndrej Mosnacek datum = policydb_filenametr_search(policydb, &ft);
1685c3a27611SOndrej Mosnacek while (datum) {
1686c3a27611SOndrej Mosnacek if (ebitmap_get_bit(&datum->stypes, stype - 1)) {
1687c3a27611SOndrej Mosnacek newcontext->type = datum->otype;
1688c3a27611SOndrej Mosnacek return;
1689c3a27611SOndrej Mosnacek }
1690c3a27611SOndrej Mosnacek datum = datum->next;
1691c3a27611SOndrej Mosnacek }
1692652bb9b0SEric Paris }
1693652bb9b0SEric Paris
security_compute_sid(u32 ssid,u32 tsid,u16 orig_tclass,u16 specified,const char * objname,u32 * out_sid,bool kern)1694e67b7985SStephen Smalley static int security_compute_sid(u32 ssid,
16951da177e4SLinus Torvalds u32 tsid,
1696c6d3aaa4SStephen Smalley u16 orig_tclass,
16977128578cSChristian Göttsche u16 specified,
1698f50a3ec9SKohei Kaigai const char *objname,
1699c6d3aaa4SStephen Smalley u32 *out_sid,
1700c6d3aaa4SStephen Smalley bool kern)
17011da177e4SLinus Torvalds {
17021b8b31a2SStephen Smalley struct selinux_policy *policy;
1703aa8e712cSStephen Smalley struct policydb *policydb;
1704aa8e712cSStephen Smalley struct sidtab *sidtab;
17059ad6e9cbSOndrej Mosnacek struct class_datum *cladatum;
1706d97bd23cSOndrej Mosnacek struct context *scontext, *tcontext, newcontext;
1707d97bd23cSOndrej Mosnacek struct sidtab_entry *sentry, *tentry;
17081da177e4SLinus Torvalds struct avtab_key avkey;
170908a12b39SChristian Göttsche struct avtab_node *avnode, *node;
1710c6d3aaa4SStephen Smalley u16 tclass;
17111da177e4SLinus Torvalds int rc = 0;
17126f5317e7SHarry Ciao bool sock;
17131da177e4SLinus Torvalds
1714e67b7985SStephen Smalley if (!selinux_initialized()) {
1715c6d3aaa4SStephen Smalley switch (orig_tclass) {
1716c6d3aaa4SStephen Smalley case SECCLASS_PROCESS: /* kernel value */
17171da177e4SLinus Torvalds *out_sid = ssid;
17181da177e4SLinus Torvalds break;
17191da177e4SLinus Torvalds default:
17201da177e4SLinus Torvalds *out_sid = tsid;
17211da177e4SLinus Torvalds break;
17221da177e4SLinus Torvalds }
17231da177e4SLinus Torvalds goto out;
17241da177e4SLinus Torvalds }
17251da177e4SLinus Torvalds
17269ad6e9cbSOndrej Mosnacek retry:
17279ad6e9cbSOndrej Mosnacek cladatum = NULL;
1728851f8a69SVenkat Yekkirala context_init(&newcontext);
1729851f8a69SVenkat Yekkirala
17301b8b31a2SStephen Smalley rcu_read_lock();
17311b8b31a2SStephen Smalley
1732e67b7985SStephen Smalley policy = rcu_dereference(selinux_state.policy);
17331da177e4SLinus Torvalds
17346f5317e7SHarry Ciao if (kern) {
17351b8b31a2SStephen Smalley tclass = unmap_class(&policy->map, orig_tclass);
17366f5317e7SHarry Ciao sock = security_is_socket_class(orig_tclass);
17376f5317e7SHarry Ciao } else {
1738c6d3aaa4SStephen Smalley tclass = orig_tclass;
17391b8b31a2SStephen Smalley sock = security_is_socket_class(map_class(&policy->map,
1740aa8e712cSStephen Smalley tclass));
17416f5317e7SHarry Ciao }
1742c6d3aaa4SStephen Smalley
17431b8b31a2SStephen Smalley policydb = &policy->policydb;
17441b8b31a2SStephen Smalley sidtab = policy->sidtab;
1745aa8e712cSStephen Smalley
1746d97bd23cSOndrej Mosnacek sentry = sidtab_search_entry(sidtab, ssid);
1747d97bd23cSOndrej Mosnacek if (!sentry) {
1748b54c85c1Speter enderborg pr_err("SELinux: %s: unrecognized SID %d\n",
1749744ba35eSEric Paris __func__, ssid);
17501da177e4SLinus Torvalds rc = -EINVAL;
17511da177e4SLinus Torvalds goto out_unlock;
17521da177e4SLinus Torvalds }
1753d97bd23cSOndrej Mosnacek tentry = sidtab_search_entry(sidtab, tsid);
1754d97bd23cSOndrej Mosnacek if (!tentry) {
1755b54c85c1Speter enderborg pr_err("SELinux: %s: unrecognized SID %d\n",
1756744ba35eSEric Paris __func__, tsid);
17571da177e4SLinus Torvalds rc = -EINVAL;
17581da177e4SLinus Torvalds goto out_unlock;
17591da177e4SLinus Torvalds }
17601da177e4SLinus Torvalds
1761d97bd23cSOndrej Mosnacek scontext = &sentry->context;
1762d97bd23cSOndrej Mosnacek tcontext = &tentry->context;
1763d97bd23cSOndrej Mosnacek
1764aa8e712cSStephen Smalley if (tclass && tclass <= policydb->p_classes.nprim)
1765aa8e712cSStephen Smalley cladatum = policydb->class_val_to_struct[tclass - 1];
1766aa893269SEric Paris
17671da177e4SLinus Torvalds /* Set the user identity. */
17681da177e4SLinus Torvalds switch (specified) {
17691da177e4SLinus Torvalds case AVTAB_TRANSITION:
17701da177e4SLinus Torvalds case AVTAB_CHANGE:
1771aa893269SEric Paris if (cladatum && cladatum->default_user == DEFAULT_TARGET) {
1772aa893269SEric Paris newcontext.user = tcontext->user;
1773aa893269SEric Paris } else {
1774aa893269SEric Paris /* notice this gets both DEFAULT_SOURCE and unset */
17751da177e4SLinus Torvalds /* Use the process user identity. */
17761da177e4SLinus Torvalds newcontext.user = scontext->user;
1777aa893269SEric Paris }
17781da177e4SLinus Torvalds break;
17791da177e4SLinus Torvalds case AVTAB_MEMBER:
17801da177e4SLinus Torvalds /* Use the related object owner. */
17811da177e4SLinus Torvalds newcontext.user = tcontext->user;
17821da177e4SLinus Torvalds break;
17831da177e4SLinus Torvalds }
17841da177e4SLinus Torvalds
1785aa893269SEric Paris /* Set the role to default values. */
1786aa893269SEric Paris if (cladatum && cladatum->default_role == DEFAULT_SOURCE) {
17871da177e4SLinus Torvalds newcontext.role = scontext->role;
1788aa893269SEric Paris } else if (cladatum && cladatum->default_role == DEFAULT_TARGET) {
1789aa893269SEric Paris newcontext.role = tcontext->role;
1790aa893269SEric Paris } else {
17914b850396SZou Wei if ((tclass == policydb->process_class) || sock)
1792aa893269SEric Paris newcontext.role = scontext->role;
1793aa893269SEric Paris else
1794aa893269SEric Paris newcontext.role = OBJECT_R_VAL;
1795aa893269SEric Paris }
1796aa893269SEric Paris
1797aa893269SEric Paris /* Set the type to default values. */
1798eed7795dSEric Paris if (cladatum && cladatum->default_type == DEFAULT_SOURCE) {
1799eed7795dSEric Paris newcontext.type = scontext->type;
1800eed7795dSEric Paris } else if (cladatum && cladatum->default_type == DEFAULT_TARGET) {
1801eed7795dSEric Paris newcontext.type = tcontext->type;
1802eed7795dSEric Paris } else {
18034b850396SZou Wei if ((tclass == policydb->process_class) || sock) {
1804aa893269SEric Paris /* Use the type of process. */
18051da177e4SLinus Torvalds newcontext.type = scontext->type;
1806c6d3aaa4SStephen Smalley } else {
18071da177e4SLinus Torvalds /* Use the type of the related object. */
18081da177e4SLinus Torvalds newcontext.type = tcontext->type;
18091da177e4SLinus Torvalds }
1810eed7795dSEric Paris }
18111da177e4SLinus Torvalds
18121da177e4SLinus Torvalds /* Look for a type transition/member/change rule. */
18131da177e4SLinus Torvalds avkey.source_type = scontext->type;
18141da177e4SLinus Torvalds avkey.target_type = tcontext->type;
18151da177e4SLinus Torvalds avkey.target_class = tclass;
1816782ebb99SStephen Smalley avkey.specified = specified;
181708a12b39SChristian Göttsche avnode = avtab_search_node(&policydb->te_avtab, &avkey);
18181da177e4SLinus Torvalds
18191da177e4SLinus Torvalds /* If no permanent rule, also check for enabled conditional rules */
182008a12b39SChristian Göttsche if (!avnode) {
1821aa8e712cSStephen Smalley node = avtab_search_node(&policydb->te_cond_avtab, &avkey);
1822dbc74c65SVesa-Matti Kari for (; node; node = avtab_search_node_next(node, specified)) {
1823782ebb99SStephen Smalley if (node->key.specified & AVTAB_ENABLED) {
182408a12b39SChristian Göttsche avnode = node;
18251da177e4SLinus Torvalds break;
18261da177e4SLinus Torvalds }
18271da177e4SLinus Torvalds }
18281da177e4SLinus Torvalds }
18291da177e4SLinus Torvalds
183008a12b39SChristian Göttsche if (avnode) {
18311da177e4SLinus Torvalds /* Use the type from the type transition/member/change rule. */
183208a12b39SChristian Göttsche newcontext.type = avnode->datum.u.data;
18331da177e4SLinus Torvalds }
18341da177e4SLinus Torvalds
18354742600cSEric Paris /* if we have a objname this is a file trans check so check those rules */
1836f50a3ec9SKohei Kaigai if (objname)
1837aa8e712cSStephen Smalley filename_compute_type(policydb, &newcontext, scontext->type,
1838f50a3ec9SKohei Kaigai tcontext->type, tclass, objname);
1839652bb9b0SEric Paris
18401da177e4SLinus Torvalds /* Check for class-specific changes. */
18411da177e4SLinus Torvalds if (specified & AVTAB_TRANSITION) {
18421da177e4SLinus Torvalds /* Look for a role transition rule. */
1843e67b2ec9SOndrej Mosnacek struct role_trans_datum *rtd;
1844e67b2ec9SOndrej Mosnacek struct role_trans_key rtk = {
1845e67b2ec9SOndrej Mosnacek .role = scontext->role,
1846e67b2ec9SOndrej Mosnacek .type = tcontext->type,
1847e67b2ec9SOndrej Mosnacek .tclass = tclass,
1848e67b2ec9SOndrej Mosnacek };
1849e67b2ec9SOndrej Mosnacek
185024def7bbSOndrej Mosnacek rtd = policydb_roletr_search(policydb, &rtk);
1851e67b2ec9SOndrej Mosnacek if (rtd)
1852e67b2ec9SOndrej Mosnacek newcontext.role = rtd->new_role;
18531da177e4SLinus Torvalds }
18541da177e4SLinus Torvalds
18551da177e4SLinus Torvalds /* Set the MLS attributes.
18561da177e4SLinus Torvalds This is done last because it may allocate memory. */
1857aa8e712cSStephen Smalley rc = mls_compute_sid(policydb, scontext, tcontext, tclass, specified,
18586f5317e7SHarry Ciao &newcontext, sock);
18591da177e4SLinus Torvalds if (rc)
18601da177e4SLinus Torvalds goto out_unlock;
18611da177e4SLinus Torvalds
18621da177e4SLinus Torvalds /* Check the validity of the context. */
1863aa8e712cSStephen Smalley if (!policydb_context_isvalid(policydb, &newcontext)) {
1864e67b7985SStephen Smalley rc = compute_sid_handle_invalid_context(policy, sentry,
18651b8b31a2SStephen Smalley tentry, tclass,
18661b8b31a2SStephen Smalley &newcontext);
18671da177e4SLinus Torvalds if (rc)
18681da177e4SLinus Torvalds goto out_unlock;
18691da177e4SLinus Torvalds }
18701da177e4SLinus Torvalds /* Obtain the sid for the context. */
1871225621c9SOndrej Mosnacek rc = sidtab_context_to_sid(sidtab, &newcontext, out_sid);
18729ad6e9cbSOndrej Mosnacek if (rc == -ESTALE) {
18739ad6e9cbSOndrej Mosnacek rcu_read_unlock();
18749ad6e9cbSOndrej Mosnacek context_destroy(&newcontext);
18759ad6e9cbSOndrej Mosnacek goto retry;
18769ad6e9cbSOndrej Mosnacek }
18771da177e4SLinus Torvalds out_unlock:
18781b8b31a2SStephen Smalley rcu_read_unlock();
18791da177e4SLinus Torvalds context_destroy(&newcontext);
18801da177e4SLinus Torvalds out:
18811da177e4SLinus Torvalds return rc;
18821da177e4SLinus Torvalds }
18831da177e4SLinus Torvalds
18841da177e4SLinus Torvalds /**
18851da177e4SLinus Torvalds * security_transition_sid - Compute the SID for a new subject/object.
18861da177e4SLinus Torvalds * @ssid: source security identifier
18871da177e4SLinus Torvalds * @tsid: target security identifier
18881da177e4SLinus Torvalds * @tclass: target security class
1889e9fd7292SPaul Moore * @qstr: object name
18901da177e4SLinus Torvalds * @out_sid: security identifier for new subject/object
18911da177e4SLinus Torvalds *
18921da177e4SLinus Torvalds * Compute a SID to use for labeling a new subject or object in the
18931da177e4SLinus Torvalds * class @tclass based on a SID pair (@ssid, @tsid).
18941da177e4SLinus Torvalds * Return -%EINVAL if any of the parameters are invalid, -%ENOMEM
18951da177e4SLinus Torvalds * if insufficient memory is available, or %0 if the new SID was
18961da177e4SLinus Torvalds * computed successfully.
18971da177e4SLinus Torvalds */
security_transition_sid(u32 ssid,u32 tsid,u16 tclass,const struct qstr * qstr,u32 * out_sid)1898e67b7985SStephen Smalley int security_transition_sid(u32 ssid, u32 tsid, u16 tclass,
1899652bb9b0SEric Paris const struct qstr *qstr, u32 *out_sid)
19001da177e4SLinus Torvalds {
1901e67b7985SStephen Smalley return security_compute_sid(ssid, tsid, tclass,
1902aa8e712cSStephen Smalley AVTAB_TRANSITION,
1903f50a3ec9SKohei Kaigai qstr ? qstr->name : NULL, out_sid, true);
1904c6d3aaa4SStephen Smalley }
1905c6d3aaa4SStephen Smalley
security_transition_sid_user(u32 ssid,u32 tsid,u16 tclass,const char * objname,u32 * out_sid)1906e67b7985SStephen Smalley int security_transition_sid_user(u32 ssid, u32 tsid, u16 tclass,
1907f50a3ec9SKohei Kaigai const char *objname, u32 *out_sid)
1908c6d3aaa4SStephen Smalley {
1909e67b7985SStephen Smalley return security_compute_sid(ssid, tsid, tclass,
1910aa8e712cSStephen Smalley AVTAB_TRANSITION,
1911f50a3ec9SKohei Kaigai objname, out_sid, false);
19121da177e4SLinus Torvalds }
19131da177e4SLinus Torvalds
19141da177e4SLinus Torvalds /**
19151da177e4SLinus Torvalds * security_member_sid - Compute the SID for member selection.
19161da177e4SLinus Torvalds * @ssid: source security identifier
19171da177e4SLinus Torvalds * @tsid: target security identifier
19181da177e4SLinus Torvalds * @tclass: target security class
19191da177e4SLinus Torvalds * @out_sid: security identifier for selected member
19201da177e4SLinus Torvalds *
19211da177e4SLinus Torvalds * Compute a SID to use when selecting a member of a polyinstantiated
19221da177e4SLinus Torvalds * object of class @tclass based on a SID pair (@ssid, @tsid).
19231da177e4SLinus Torvalds * Return -%EINVAL if any of the parameters are invalid, -%ENOMEM
19241da177e4SLinus Torvalds * if insufficient memory is available, or %0 if the SID was
19251da177e4SLinus Torvalds * computed successfully.
19261da177e4SLinus Torvalds */
security_member_sid(u32 ssid,u32 tsid,u16 tclass,u32 * out_sid)1927e67b7985SStephen Smalley int security_member_sid(u32 ssid,
19281da177e4SLinus Torvalds u32 tsid,
19291da177e4SLinus Torvalds u16 tclass,
19301da177e4SLinus Torvalds u32 *out_sid)
19311da177e4SLinus Torvalds {
1932e67b7985SStephen Smalley return security_compute_sid(ssid, tsid, tclass,
1933aa8e712cSStephen Smalley AVTAB_MEMBER, NULL,
1934652bb9b0SEric Paris out_sid, false);
19351da177e4SLinus Torvalds }
19361da177e4SLinus Torvalds
19371da177e4SLinus Torvalds /**
19381da177e4SLinus Torvalds * security_change_sid - Compute the SID for object relabeling.
19391da177e4SLinus Torvalds * @ssid: source security identifier
19401da177e4SLinus Torvalds * @tsid: target security identifier
19411da177e4SLinus Torvalds * @tclass: target security class
19421da177e4SLinus Torvalds * @out_sid: security identifier for selected member
19431da177e4SLinus Torvalds *
19441da177e4SLinus Torvalds * Compute a SID to use for relabeling an object of class @tclass
19451da177e4SLinus Torvalds * based on a SID pair (@ssid, @tsid).
19461da177e4SLinus Torvalds * Return -%EINVAL if any of the parameters are invalid, -%ENOMEM
19471da177e4SLinus Torvalds * if insufficient memory is available, or %0 if the SID was
19481da177e4SLinus Torvalds * computed successfully.
19491da177e4SLinus Torvalds */
security_change_sid(u32 ssid,u32 tsid,u16 tclass,u32 * out_sid)1950e67b7985SStephen Smalley int security_change_sid(u32 ssid,
19511da177e4SLinus Torvalds u32 tsid,
19521da177e4SLinus Torvalds u16 tclass,
19531da177e4SLinus Torvalds u32 *out_sid)
19541da177e4SLinus Torvalds {
1955e67b7985SStephen Smalley return security_compute_sid(ssid, tsid, tclass, AVTAB_CHANGE, NULL,
1956652bb9b0SEric Paris out_sid, false);
1957b94c7e67SChad Sellers }
1958b94c7e67SChad Sellers
convert_context_handle_invalid_context(struct policydb * policydb,struct context * context)1959aa8e712cSStephen Smalley static inline int convert_context_handle_invalid_context(
19601b8b31a2SStephen Smalley struct policydb *policydb,
1961aa8e712cSStephen Smalley struct context *context)
19621da177e4SLinus Torvalds {
19631da177e4SLinus Torvalds char *s;
19641da177e4SLinus Torvalds u32 len;
19651da177e4SLinus Torvalds
1966e67b7985SStephen Smalley if (enforcing_enabled())
19674b02b524SEric Paris return -EINVAL;
19684b02b524SEric Paris
1969aa8e712cSStephen Smalley if (!context_struct_to_string(policydb, context, &s, &len)) {
1970b54c85c1Speter enderborg pr_warn("SELinux: Context %s would be invalid if enforcing\n",
1971b54c85c1Speter enderborg s);
19721da177e4SLinus Torvalds kfree(s);
19731da177e4SLinus Torvalds }
19744b02b524SEric Paris return 0;
19751da177e4SLinus Torvalds }
19761da177e4SLinus Torvalds
1977048be156SPaul Moore /**
1978048be156SPaul Moore * services_convert_context - Convert a security context across policies.
1979048be156SPaul Moore * @args: populated convert_context_args struct
1980048be156SPaul Moore * @oldc: original context
1981048be156SPaul Moore * @newc: converted context
198257888f7bSLinus Torvalds * @gfp_flags: allocation flags
1983048be156SPaul Moore *
1984048be156SPaul Moore * Convert the values in the security context structure @oldc from the values
1985048be156SPaul Moore * specified in the policy @args->oldp to the values specified in the policy
1986048be156SPaul Moore * @args->newp, storing the new context in @newc, and verifying that the
1987048be156SPaul Moore * context is valid under the new policy.
19881da177e4SLinus Torvalds */
services_convert_context(struct convert_context_args * args,struct context * oldc,struct context * newc,gfp_t gfp_flags)1989048be156SPaul Moore int services_convert_context(struct convert_context_args *args,
199057888f7bSLinus Torvalds struct context *oldc, struct context *newc,
1991abe3c631SGONG, Ruiqi gfp_t gfp_flags)
19921da177e4SLinus Torvalds {
19930719aaf5SGuido Trentalancia struct ocontext *oc;
19941da177e4SLinus Torvalds struct role_datum *role;
19951da177e4SLinus Torvalds struct type_datum *typdatum;
19961da177e4SLinus Torvalds struct user_datum *usrdatum;
19971da177e4SLinus Torvalds char *s;
19981da177e4SLinus Torvalds u32 len;
199924ed7fdaSOndrej Mosnacek int rc;
20001da177e4SLinus Torvalds
2001ee1a84fdSOndrej Mosnacek if (oldc->str) {
2002abe3c631SGONG, Ruiqi s = kstrdup(oldc->str, gfp_flags);
20034b02b524SEric Paris if (!s)
2004ee1a84fdSOndrej Mosnacek return -ENOMEM;
20054b02b524SEric Paris
2006048be156SPaul Moore rc = string_to_context_struct(args->newp, NULL, s, newc, SECSID_NULL);
2007ee1a84fdSOndrej Mosnacek if (rc == -EINVAL) {
20082a524393SOndrej Mosnacek /*
20092a524393SOndrej Mosnacek * Retain string representation for later mapping.
20102a524393SOndrej Mosnacek *
20112a524393SOndrej Mosnacek * IMPORTANT: We need to copy the contents of oldc->str
20122a524393SOndrej Mosnacek * back into s again because string_to_context_struct()
20132a524393SOndrej Mosnacek * may have garbled it.
20142a524393SOndrej Mosnacek */
20152a524393SOndrej Mosnacek memcpy(s, oldc->str, oldc->len);
2016ee1a84fdSOndrej Mosnacek context_init(newc);
2017ee1a84fdSOndrej Mosnacek newc->str = s;
2018ee1a84fdSOndrej Mosnacek newc->len = oldc->len;
2019ee1a84fdSOndrej Mosnacek return 0;
2020ee1a84fdSOndrej Mosnacek }
2021ee1a84fdSOndrej Mosnacek kfree(s);
2022ee1a84fdSOndrej Mosnacek if (rc) {
202312b29f34SStephen Smalley /* Other error condition, e.g. ENOMEM. */
2024b54c85c1Speter enderborg pr_err("SELinux: Unable to map context %s, rc = %d.\n",
2025ee1a84fdSOndrej Mosnacek oldc->str, -rc);
2026ee1a84fdSOndrej Mosnacek return rc;
202712b29f34SStephen Smalley }
2028ee1a84fdSOndrej Mosnacek pr_info("SELinux: Context %s became valid (mapped).\n",
2029ee1a84fdSOndrej Mosnacek oldc->str);
2030ee1a84fdSOndrej Mosnacek return 0;
203112b29f34SStephen Smalley }
203212b29f34SStephen Smalley
2033ee1a84fdSOndrej Mosnacek context_init(newc);
20341da177e4SLinus Torvalds
20351da177e4SLinus Torvalds /* Convert the user. */
2036237389e3SOndrej Mosnacek usrdatum = symtab_search(&args->newp->p_users,
2037048be156SPaul Moore sym_name(args->oldp, SYM_USERS, oldc->user - 1));
20385d55a345SEric Paris if (!usrdatum)
20391da177e4SLinus Torvalds goto bad;
2040ee1a84fdSOndrej Mosnacek newc->user = usrdatum->value;
20411da177e4SLinus Torvalds
20421da177e4SLinus Torvalds /* Convert the role. */
2043237389e3SOndrej Mosnacek role = symtab_search(&args->newp->p_roles,
2044ee1a84fdSOndrej Mosnacek sym_name(args->oldp, SYM_ROLES, oldc->role - 1));
20455d55a345SEric Paris if (!role)
20461da177e4SLinus Torvalds goto bad;
2047ee1a84fdSOndrej Mosnacek newc->role = role->value;
20481da177e4SLinus Torvalds
20491da177e4SLinus Torvalds /* Convert the type. */
2050237389e3SOndrej Mosnacek typdatum = symtab_search(&args->newp->p_types,
2051048be156SPaul Moore sym_name(args->oldp, SYM_TYPES, oldc->type - 1));
20525d55a345SEric Paris if (!typdatum)
20531da177e4SLinus Torvalds goto bad;
2054ee1a84fdSOndrej Mosnacek newc->type = typdatum->value;
20551da177e4SLinus Torvalds
20560719aaf5SGuido Trentalancia /* Convert the MLS fields if dealing with MLS policies */
20570719aaf5SGuido Trentalancia if (args->oldp->mls_enabled && args->newp->mls_enabled) {
2058ee1a84fdSOndrej Mosnacek rc = mls_convert_context(args->oldp, args->newp, oldc, newc);
20591da177e4SLinus Torvalds if (rc)
20601da177e4SLinus Torvalds goto bad;
20610719aaf5SGuido Trentalancia } else if (!args->oldp->mls_enabled && args->newp->mls_enabled) {
20620719aaf5SGuido Trentalancia /*
20630719aaf5SGuido Trentalancia * Switching between non-MLS and MLS policy:
20640719aaf5SGuido Trentalancia * ensure that the MLS fields of the context for all
20650719aaf5SGuido Trentalancia * existing entries in the sidtab are filled in with a
20660719aaf5SGuido Trentalancia * suitable default value, likely taken from one of the
20670719aaf5SGuido Trentalancia * initial SIDs.
20680719aaf5SGuido Trentalancia */
20690719aaf5SGuido Trentalancia oc = args->newp->ocontexts[OCON_ISID];
20700719aaf5SGuido Trentalancia while (oc && oc->sid[0] != SECINITSID_UNLABELED)
20710719aaf5SGuido Trentalancia oc = oc->next;
20720719aaf5SGuido Trentalancia if (!oc) {
2073b54c85c1Speter enderborg pr_err("SELinux: unable to look up"
20740719aaf5SGuido Trentalancia " the initial SIDs list\n");
20750719aaf5SGuido Trentalancia goto bad;
20760719aaf5SGuido Trentalancia }
2077ee1a84fdSOndrej Mosnacek rc = mls_range_set(newc, &oc->context[0].range);
20780719aaf5SGuido Trentalancia if (rc)
20790719aaf5SGuido Trentalancia goto bad;
20800719aaf5SGuido Trentalancia }
20811da177e4SLinus Torvalds
20821da177e4SLinus Torvalds /* Check the validity of the new context. */
2083ee1a84fdSOndrej Mosnacek if (!policydb_context_isvalid(args->newp, newc)) {
2084e67b7985SStephen Smalley rc = convert_context_handle_invalid_context(args->oldp, oldc);
20851da177e4SLinus Torvalds if (rc)
20861da177e4SLinus Torvalds goto bad;
20871da177e4SLinus Torvalds }
20881da177e4SLinus Torvalds
2089ee1a84fdSOndrej Mosnacek return 0;
20901da177e4SLinus Torvalds bad:
209112b29f34SStephen Smalley /* Map old representation to string and save it. */
2092ee1a84fdSOndrej Mosnacek rc = context_struct_to_string(args->oldp, oldc, &s, &len);
20934b02b524SEric Paris if (rc)
20944b02b524SEric Paris return rc;
2095ee1a84fdSOndrej Mosnacek context_destroy(newc);
2096ee1a84fdSOndrej Mosnacek newc->str = s;
2097ee1a84fdSOndrej Mosnacek newc->len = len;
2098b54c85c1Speter enderborg pr_info("SELinux: Context %s became invalid (unmapped).\n",
2099ee1a84fdSOndrej Mosnacek newc->str);
2100ee1a84fdSOndrej Mosnacek return 0;
21011da177e4SLinus Torvalds }
21021da177e4SLinus Torvalds
security_load_policycaps(struct selinux_policy * policy)2103e67b7985SStephen Smalley static void security_load_policycaps(struct selinux_policy *policy)
21043bb56b25SPaul Moore {
210546169802SStephen Smalley struct policydb *p;
21064dc2fce3SStephen Smalley unsigned int i;
21074dc2fce3SStephen Smalley struct ebitmap_node *node;
21084dc2fce3SStephen Smalley
21091b8b31a2SStephen Smalley p = &policy->policydb;
211046169802SStephen Smalley
2111e67b7985SStephen Smalley for (i = 0; i < ARRAY_SIZE(selinux_state.policycap); i++)
2112e67b7985SStephen Smalley WRITE_ONCE(selinux_state.policycap[i],
2113e8ba53d0SStephen Smalley ebitmap_get_bit(&p->policycaps, i));
21144dc2fce3SStephen Smalley
21154dc2fce3SStephen Smalley for (i = 0; i < ARRAY_SIZE(selinux_policycap_names); i++)
21164dc2fce3SStephen Smalley pr_info("SELinux: policy capability %s=%d\n",
21174dc2fce3SStephen Smalley selinux_policycap_names[i],
2118aa8e712cSStephen Smalley ebitmap_get_bit(&p->policycaps, i));
21194dc2fce3SStephen Smalley
2120aa8e712cSStephen Smalley ebitmap_for_each_positive_bit(&p->policycaps, node, i) {
21214dc2fce3SStephen Smalley if (i >= ARRAY_SIZE(selinux_policycap_names))
21224dc2fce3SStephen Smalley pr_info("SELinux: unknown policy capability %u\n",
21234dc2fce3SStephen Smalley i);
21244dc2fce3SStephen Smalley }
21253bb56b25SPaul Moore }
21263bb56b25SPaul Moore
21271b8b31a2SStephen Smalley static int security_preserve_bools(struct selinux_policy *oldpolicy,
21281b8b31a2SStephen Smalley struct selinux_policy *newpolicy);
21291da177e4SLinus Torvalds
selinux_policy_free(struct selinux_policy * policy)213046169802SStephen Smalley static void selinux_policy_free(struct selinux_policy *policy)
213146169802SStephen Smalley {
213246169802SStephen Smalley if (!policy)
213346169802SStephen Smalley return;
213446169802SStephen Smalley
2135c7c556f1SStephen Smalley sidtab_destroy(policy->sidtab);
213646169802SStephen Smalley kfree(policy->map.mapping);
21370256b0aaSDan Carpenter policydb_destroy(&policy->policydb);
21380256b0aaSDan Carpenter kfree(policy->sidtab);
213946169802SStephen Smalley kfree(policy);
214046169802SStephen Smalley }
214146169802SStephen Smalley
selinux_policy_cond_free(struct selinux_policy * policy)21421b8b31a2SStephen Smalley static void selinux_policy_cond_free(struct selinux_policy *policy)
21431b8b31a2SStephen Smalley {
21441b8b31a2SStephen Smalley cond_policydb_destroy_dup(&policy->policydb);
21451b8b31a2SStephen Smalley kfree(policy);
21461b8b31a2SStephen Smalley }
21471b8b31a2SStephen Smalley
selinux_policy_cancel(struct selinux_load_state * load_state)2148e67b7985SStephen Smalley void selinux_policy_cancel(struct selinux_load_state *load_state)
214902a52c5cSStephen Smalley {
2150e67b7985SStephen Smalley struct selinux_state *state = &selinux_state;
21511b8b31a2SStephen Smalley struct selinux_policy *oldpolicy;
21521b8b31a2SStephen Smalley
21539ff9abc4SStephen Smalley oldpolicy = rcu_dereference_protected(state->policy,
21549ff9abc4SStephen Smalley lockdep_is_held(&state->policy_mutex));
21551b8b31a2SStephen Smalley
21561b8b31a2SStephen Smalley sidtab_cancel_convert(oldpolicy->sidtab);
21576406887aSOndrej Mosnacek selinux_policy_free(load_state->policy);
21586406887aSOndrej Mosnacek kfree(load_state->convert_data);
215902a52c5cSStephen Smalley }
216002a52c5cSStephen Smalley
selinux_notify_policy_change(u32 seqno)2161e67b7985SStephen Smalley static void selinux_notify_policy_change(u32 seqno)
2162c7c556f1SStephen Smalley {
2163c7c556f1SStephen Smalley /* Flush external caches and notify userspace of policy load */
2164e67b7985SStephen Smalley avc_ss_reset(seqno);
2165c7c556f1SStephen Smalley selnl_notify_policyload(seqno);
2166e67b7985SStephen Smalley selinux_status_update_policyload(seqno);
2167c7c556f1SStephen Smalley selinux_netlbl_cache_invalidate();
2168c7c556f1SStephen Smalley selinux_xfrm_notify_policyload();
2169e67b7985SStephen Smalley selinux_ima_measure_state_locked();
2170c7c556f1SStephen Smalley }
2171c7c556f1SStephen Smalley
selinux_policy_commit(struct selinux_load_state * load_state)2172e67b7985SStephen Smalley void selinux_policy_commit(struct selinux_load_state *load_state)
217346169802SStephen Smalley {
2174e67b7985SStephen Smalley struct selinux_state *state = &selinux_state;
21756406887aSOndrej Mosnacek struct selinux_policy *oldpolicy, *newpolicy = load_state->policy;
21769ad6e9cbSOndrej Mosnacek unsigned long flags;
217746169802SStephen Smalley u32 seqno;
217846169802SStephen Smalley
21799ff9abc4SStephen Smalley oldpolicy = rcu_dereference_protected(state->policy,
21809ff9abc4SStephen Smalley lockdep_is_held(&state->policy_mutex));
218146169802SStephen Smalley
218246169802SStephen Smalley /* If switching between different policy types, log MLS status */
218346169802SStephen Smalley if (oldpolicy) {
218446169802SStephen Smalley if (oldpolicy->policydb.mls_enabled && !newpolicy->policydb.mls_enabled)
218546169802SStephen Smalley pr_info("SELinux: Disabling MLS support...\n");
218646169802SStephen Smalley else if (!oldpolicy->policydb.mls_enabled && newpolicy->policydb.mls_enabled)
218746169802SStephen Smalley pr_info("SELinux: Enabling MLS support...\n");
218846169802SStephen Smalley }
218946169802SStephen Smalley
21901b8b31a2SStephen Smalley /* Set latest granting seqno for new policy. */
21911b8b31a2SStephen Smalley if (oldpolicy)
21921b8b31a2SStephen Smalley newpolicy->latest_granting = oldpolicy->latest_granting + 1;
21931b8b31a2SStephen Smalley else
21941b8b31a2SStephen Smalley newpolicy->latest_granting = 1;
21951b8b31a2SStephen Smalley seqno = newpolicy->latest_granting;
21961b8b31a2SStephen Smalley
219746169802SStephen Smalley /* Install the new policy. */
21989ad6e9cbSOndrej Mosnacek if (oldpolicy) {
21999ad6e9cbSOndrej Mosnacek sidtab_freeze_begin(oldpolicy->sidtab, &flags);
22001b8b31a2SStephen Smalley rcu_assign_pointer(state->policy, newpolicy);
22019ad6e9cbSOndrej Mosnacek sidtab_freeze_end(oldpolicy->sidtab, &flags);
22029ad6e9cbSOndrej Mosnacek } else {
22039ad6e9cbSOndrej Mosnacek rcu_assign_pointer(state->policy, newpolicy);
22049ad6e9cbSOndrej Mosnacek }
220546169802SStephen Smalley
220646169802SStephen Smalley /* Load the policycaps from the new policy */
2207e67b7985SStephen Smalley security_load_policycaps(newpolicy);
220846169802SStephen Smalley
2209e67b7985SStephen Smalley if (!selinux_initialized()) {
221046169802SStephen Smalley /*
221146169802SStephen Smalley * After first policy load, the security server is
221246169802SStephen Smalley * marked as initialized and ready to handle requests and
221346169802SStephen Smalley * any objects created prior to policy load are then labeled.
221446169802SStephen Smalley */
2215e67b7985SStephen Smalley selinux_mark_initialized();
221646169802SStephen Smalley selinux_complete_init();
221746169802SStephen Smalley }
221846169802SStephen Smalley
221946169802SStephen Smalley /* Free the old policy */
22201b8b31a2SStephen Smalley synchronize_rcu();
222146169802SStephen Smalley selinux_policy_free(oldpolicy);
22226406887aSOndrej Mosnacek kfree(load_state->convert_data);
222346169802SStephen Smalley
2224c7c556f1SStephen Smalley /* Notify others of the policy change */
2225e67b7985SStephen Smalley selinux_notify_policy_change(seqno);
222646169802SStephen Smalley }
222746169802SStephen Smalley
22281da177e4SLinus Torvalds /**
22291da177e4SLinus Torvalds * security_load_policy - Load a security policy configuration.
22301da177e4SLinus Torvalds * @data: binary policy data
22311da177e4SLinus Torvalds * @len: length of data in bytes
2232e9fd7292SPaul Moore * @load_state: policy load state
22331da177e4SLinus Torvalds *
22341da177e4SLinus Torvalds * Load a new set of security policy configuration data,
22351da177e4SLinus Torvalds * validate it and convert the SID table as necessary.
22361da177e4SLinus Torvalds * This function will flush the access vector cache after
22371da177e4SLinus Torvalds * loading the new policy.
22381da177e4SLinus Torvalds */
security_load_policy(void * data,size_t len,struct selinux_load_state * load_state)2239e67b7985SStephen Smalley int security_load_policy(void *data, size_t len,
22406406887aSOndrej Mosnacek struct selinux_load_state *load_state)
22411da177e4SLinus Torvalds {
2242e67b7985SStephen Smalley struct selinux_state *state = &selinux_state;
22431b8b31a2SStephen Smalley struct selinux_policy *newpolicy, *oldpolicy;
22446406887aSOndrej Mosnacek struct selinux_policy_convert_data *convert_data;
22451da177e4SLinus Torvalds int rc = 0;
22461da177e4SLinus Torvalds struct policy_file file = { data, len }, *fp = &file;
22471da177e4SLinus Torvalds
224846169802SStephen Smalley newpolicy = kzalloc(sizeof(*newpolicy), GFP_KERNEL);
224946169802SStephen Smalley if (!newpolicy)
2250dd89b9d9SOndrej Mosnacek return -ENOMEM;
2251aa8e712cSStephen Smalley
2252c7c556f1SStephen Smalley newpolicy->sidtab = kzalloc(sizeof(*newpolicy->sidtab), GFP_KERNEL);
22530256b0aaSDan Carpenter if (!newpolicy->sidtab) {
22540256b0aaSDan Carpenter rc = -ENOMEM;
22550256b0aaSDan Carpenter goto err_policy;
22560256b0aaSDan Carpenter }
2257c7c556f1SStephen Smalley
225846169802SStephen Smalley rc = policydb_read(&newpolicy->policydb, fp);
2259a2000050SEric Paris if (rc)
22600256b0aaSDan Carpenter goto err_sidtab;
2261b94c7e67SChad Sellers
226246169802SStephen Smalley newpolicy->policydb.len = len;
226346169802SStephen Smalley rc = selinux_set_mapping(&newpolicy->policydb, secclass_map,
226446169802SStephen Smalley &newpolicy->map);
226546169802SStephen Smalley if (rc)
22660256b0aaSDan Carpenter goto err_policydb;
226746169802SStephen Smalley
2268c7c556f1SStephen Smalley rc = policydb_load_isids(&newpolicy->policydb, newpolicy->sidtab);
226946169802SStephen Smalley if (rc) {
227046169802SStephen Smalley pr_err("SELinux: unable to load the initial SIDs\n");
22710256b0aaSDan Carpenter goto err_mapping;
227246169802SStephen Smalley }
227346169802SStephen Smalley
2274e67b7985SStephen Smalley if (!selinux_initialized()) {
227546169802SStephen Smalley /* First policy load, so no need to preserve state from old policy */
22766406887aSOndrej Mosnacek load_state->policy = newpolicy;
22776406887aSOndrej Mosnacek load_state->convert_data = NULL;
227846169802SStephen Smalley return 0;
227946169802SStephen Smalley }
228046169802SStephen Smalley
22819ff9abc4SStephen Smalley oldpolicy = rcu_dereference_protected(state->policy,
22829ff9abc4SStephen Smalley lockdep_is_held(&state->policy_mutex));
22831b8b31a2SStephen Smalley
228446169802SStephen Smalley /* Preserve active boolean values from the old policy */
22851b8b31a2SStephen Smalley rc = security_preserve_bools(oldpolicy, newpolicy);
2286e900a7d9SStephen Smalley if (rc) {
2287b54c85c1Speter enderborg pr_err("SELinux: unable to preserve booleans\n");
22880256b0aaSDan Carpenter goto err_free_isids;
2289e900a7d9SStephen Smalley }
2290e900a7d9SStephen Smalley
2291048be156SPaul Moore /*
2292048be156SPaul Moore * Convert the internal representations of contexts
2293048be156SPaul Moore * in the new SID table.
2294048be156SPaul Moore */
2295048be156SPaul Moore
22966406887aSOndrej Mosnacek convert_data = kmalloc(sizeof(*convert_data), GFP_KERNEL);
22976406887aSOndrej Mosnacek if (!convert_data) {
22986406887aSOndrej Mosnacek rc = -ENOMEM;
22996406887aSOndrej Mosnacek goto err_free_isids;
23006406887aSOndrej Mosnacek }
23016406887aSOndrej Mosnacek
23026406887aSOndrej Mosnacek convert_data->args.oldp = &oldpolicy->policydb;
23036406887aSOndrej Mosnacek convert_data->args.newp = &newpolicy->policydb;
2304ee1a84fdSOndrej Mosnacek
23056406887aSOndrej Mosnacek convert_data->sidtab_params.args = &convert_data->args;
23066406887aSOndrej Mosnacek convert_data->sidtab_params.target = newpolicy->sidtab;
2307ee1a84fdSOndrej Mosnacek
23086406887aSOndrej Mosnacek rc = sidtab_convert(oldpolicy->sidtab, &convert_data->sidtab_params);
23090719aaf5SGuido Trentalancia if (rc) {
2310b54c85c1Speter enderborg pr_err("SELinux: unable to convert the internal"
23110719aaf5SGuido Trentalancia " representation of contexts in the new SID"
23120719aaf5SGuido Trentalancia " table\n");
23136406887aSOndrej Mosnacek goto err_free_convert_data;
23140719aaf5SGuido Trentalancia }
23151da177e4SLinus Torvalds
23166406887aSOndrej Mosnacek load_state->policy = newpolicy;
23176406887aSOndrej Mosnacek load_state->convert_data = convert_data;
231846169802SStephen Smalley return 0;
23190256b0aaSDan Carpenter
23206406887aSOndrej Mosnacek err_free_convert_data:
23216406887aSOndrej Mosnacek kfree(convert_data);
23220256b0aaSDan Carpenter err_free_isids:
23230256b0aaSDan Carpenter sidtab_destroy(newpolicy->sidtab);
23240256b0aaSDan Carpenter err_mapping:
23250256b0aaSDan Carpenter kfree(newpolicy->map.mapping);
23260256b0aaSDan Carpenter err_policydb:
23270256b0aaSDan Carpenter policydb_destroy(&newpolicy->policydb);
23280256b0aaSDan Carpenter err_sidtab:
23290256b0aaSDan Carpenter kfree(newpolicy->sidtab);
23300256b0aaSDan Carpenter err_policy:
23310256b0aaSDan Carpenter kfree(newpolicy);
23320256b0aaSDan Carpenter
2333b5495b42STim Gardner return rc;
23341da177e4SLinus Torvalds }
23351da177e4SLinus Torvalds
23361da177e4SLinus Torvalds /**
2337cbfcd13bSOndrej Mosnacek * ocontext_to_sid - Helper to safely get sid for an ocontext
2338cbfcd13bSOndrej Mosnacek * @sidtab: SID table
2339cbfcd13bSOndrej Mosnacek * @c: ocontext structure
2340cbfcd13bSOndrej Mosnacek * @index: index of the context entry (0 or 1)
2341cbfcd13bSOndrej Mosnacek * @out_sid: pointer to the resulting SID value
2342cbfcd13bSOndrej Mosnacek *
2343cbfcd13bSOndrej Mosnacek * For all ocontexts except OCON_ISID the SID fields are populated
2344cbfcd13bSOndrej Mosnacek * on-demand when needed. Since updating the SID value is an SMP-sensitive
2345cbfcd13bSOndrej Mosnacek * operation, this helper must be used to do that safely.
2346cbfcd13bSOndrej Mosnacek *
2347cbfcd13bSOndrej Mosnacek * WARNING: This function may return -ESTALE, indicating that the caller
2348cbfcd13bSOndrej Mosnacek * must retry the operation after re-acquiring the policy pointer!
2349cbfcd13bSOndrej Mosnacek */
ocontext_to_sid(struct sidtab * sidtab,struct ocontext * c,size_t index,u32 * out_sid)2350cbfcd13bSOndrej Mosnacek static int ocontext_to_sid(struct sidtab *sidtab, struct ocontext *c,
2351cbfcd13bSOndrej Mosnacek size_t index, u32 *out_sid)
2352cbfcd13bSOndrej Mosnacek {
2353cbfcd13bSOndrej Mosnacek int rc;
2354cbfcd13bSOndrej Mosnacek u32 sid;
2355cbfcd13bSOndrej Mosnacek
2356cbfcd13bSOndrej Mosnacek /* Ensure the associated sidtab entry is visible to this thread. */
2357cbfcd13bSOndrej Mosnacek sid = smp_load_acquire(&c->sid[index]);
2358cbfcd13bSOndrej Mosnacek if (!sid) {
2359cbfcd13bSOndrej Mosnacek rc = sidtab_context_to_sid(sidtab, &c->context[index], &sid);
2360cbfcd13bSOndrej Mosnacek if (rc)
2361cbfcd13bSOndrej Mosnacek return rc;
2362cbfcd13bSOndrej Mosnacek
2363cbfcd13bSOndrej Mosnacek /*
2364cbfcd13bSOndrej Mosnacek * Ensure the new sidtab entry is visible to other threads
2365cbfcd13bSOndrej Mosnacek * when they see the SID.
2366cbfcd13bSOndrej Mosnacek */
2367cbfcd13bSOndrej Mosnacek smp_store_release(&c->sid[index], sid);
2368cbfcd13bSOndrej Mosnacek }
2369cbfcd13bSOndrej Mosnacek *out_sid = sid;
2370cbfcd13bSOndrej Mosnacek return 0;
2371cbfcd13bSOndrej Mosnacek }
2372cbfcd13bSOndrej Mosnacek
2373cbfcd13bSOndrej Mosnacek /**
23741da177e4SLinus Torvalds * security_port_sid - Obtain the SID for a port.
23751da177e4SLinus Torvalds * @protocol: protocol number
23761da177e4SLinus Torvalds * @port: port number
23771da177e4SLinus Torvalds * @out_sid: security identifier
23781da177e4SLinus Torvalds */
security_port_sid(u8 protocol,u16 port,u32 * out_sid)2379e67b7985SStephen Smalley int security_port_sid(u8 protocol, u16 port, u32 *out_sid)
23801da177e4SLinus Torvalds {
23811b8b31a2SStephen Smalley struct selinux_policy *policy;
2382aa8e712cSStephen Smalley struct policydb *policydb;
2383225621c9SOndrej Mosnacek struct sidtab *sidtab;
23841da177e4SLinus Torvalds struct ocontext *c;
23859ad6e9cbSOndrej Mosnacek int rc;
23861da177e4SLinus Torvalds
2387e67b7985SStephen Smalley if (!selinux_initialized()) {
238837ea433cSStephen Smalley *out_sid = SECINITSID_PORT;
238937ea433cSStephen Smalley return 0;
239037ea433cSStephen Smalley }
239137ea433cSStephen Smalley
23929ad6e9cbSOndrej Mosnacek retry:
23939ad6e9cbSOndrej Mosnacek rc = 0;
23941b8b31a2SStephen Smalley rcu_read_lock();
2395e67b7985SStephen Smalley policy = rcu_dereference(selinux_state.policy);
23961b8b31a2SStephen Smalley policydb = &policy->policydb;
23971b8b31a2SStephen Smalley sidtab = policy->sidtab;
2398aa8e712cSStephen Smalley
2399aa8e712cSStephen Smalley c = policydb->ocontexts[OCON_PORT];
24001da177e4SLinus Torvalds while (c) {
24011da177e4SLinus Torvalds if (c->u.port.protocol == protocol &&
24021da177e4SLinus Torvalds c->u.port.low_port <= port &&
24031da177e4SLinus Torvalds c->u.port.high_port >= port)
24041da177e4SLinus Torvalds break;
24051da177e4SLinus Torvalds c = c->next;
24061da177e4SLinus Torvalds }
24071da177e4SLinus Torvalds
24081da177e4SLinus Torvalds if (c) {
2409cbfcd13bSOndrej Mosnacek rc = ocontext_to_sid(sidtab, c, 0, out_sid);
24109ad6e9cbSOndrej Mosnacek if (rc == -ESTALE) {
24119ad6e9cbSOndrej Mosnacek rcu_read_unlock();
24129ad6e9cbSOndrej Mosnacek goto retry;
24139ad6e9cbSOndrej Mosnacek }
24141da177e4SLinus Torvalds if (rc)
24151da177e4SLinus Torvalds goto out;
24161da177e4SLinus Torvalds } else {
24171da177e4SLinus Torvalds *out_sid = SECINITSID_PORT;
24181da177e4SLinus Torvalds }
24191da177e4SLinus Torvalds
24201da177e4SLinus Torvalds out:
24211b8b31a2SStephen Smalley rcu_read_unlock();
24221da177e4SLinus Torvalds return rc;
24231da177e4SLinus Torvalds }
24241da177e4SLinus Torvalds
24251da177e4SLinus Torvalds /**
2426d0a83314SYang Li * security_ib_pkey_sid - Obtain the SID for a pkey.
2427cfc4d882SDaniel Jurgens * @subnet_prefix: Subnet Prefix
2428cfc4d882SDaniel Jurgens * @pkey_num: pkey number
2429cfc4d882SDaniel Jurgens * @out_sid: security identifier
2430cfc4d882SDaniel Jurgens */
security_ib_pkey_sid(u64 subnet_prefix,u16 pkey_num,u32 * out_sid)2431e67b7985SStephen Smalley int security_ib_pkey_sid(u64 subnet_prefix, u16 pkey_num, u32 *out_sid)
2432cfc4d882SDaniel Jurgens {
24331b8b31a2SStephen Smalley struct selinux_policy *policy;
2434aa8e712cSStephen Smalley struct policydb *policydb;
2435225621c9SOndrej Mosnacek struct sidtab *sidtab;
2436cfc4d882SDaniel Jurgens struct ocontext *c;
24379ad6e9cbSOndrej Mosnacek int rc;
2438cfc4d882SDaniel Jurgens
2439e67b7985SStephen Smalley if (!selinux_initialized()) {
244037ea433cSStephen Smalley *out_sid = SECINITSID_UNLABELED;
244137ea433cSStephen Smalley return 0;
244237ea433cSStephen Smalley }
244337ea433cSStephen Smalley
24449ad6e9cbSOndrej Mosnacek retry:
24459ad6e9cbSOndrej Mosnacek rc = 0;
24461b8b31a2SStephen Smalley rcu_read_lock();
2447e67b7985SStephen Smalley policy = rcu_dereference(selinux_state.policy);
24481b8b31a2SStephen Smalley policydb = &policy->policydb;
24491b8b31a2SStephen Smalley sidtab = policy->sidtab;
2450aa8e712cSStephen Smalley
2451aa8e712cSStephen Smalley c = policydb->ocontexts[OCON_IBPKEY];
2452cfc4d882SDaniel Jurgens while (c) {
2453cfc4d882SDaniel Jurgens if (c->u.ibpkey.low_pkey <= pkey_num &&
2454cfc4d882SDaniel Jurgens c->u.ibpkey.high_pkey >= pkey_num &&
2455cfc4d882SDaniel Jurgens c->u.ibpkey.subnet_prefix == subnet_prefix)
2456cfc4d882SDaniel Jurgens break;
2457cfc4d882SDaniel Jurgens
2458cfc4d882SDaniel Jurgens c = c->next;
2459cfc4d882SDaniel Jurgens }
2460cfc4d882SDaniel Jurgens
2461cfc4d882SDaniel Jurgens if (c) {
2462cbfcd13bSOndrej Mosnacek rc = ocontext_to_sid(sidtab, c, 0, out_sid);
24639ad6e9cbSOndrej Mosnacek if (rc == -ESTALE) {
24649ad6e9cbSOndrej Mosnacek rcu_read_unlock();
24659ad6e9cbSOndrej Mosnacek goto retry;
24669ad6e9cbSOndrej Mosnacek }
2467cfc4d882SDaniel Jurgens if (rc)
2468cfc4d882SDaniel Jurgens goto out;
2469cfc4d882SDaniel Jurgens } else
2470cfc4d882SDaniel Jurgens *out_sid = SECINITSID_UNLABELED;
2471cfc4d882SDaniel Jurgens
2472cfc4d882SDaniel Jurgens out:
24731b8b31a2SStephen Smalley rcu_read_unlock();
2474cfc4d882SDaniel Jurgens return rc;
2475cfc4d882SDaniel Jurgens }
2476cfc4d882SDaniel Jurgens
2477cfc4d882SDaniel Jurgens /**
2478ab861dfcSDaniel Jurgens * security_ib_endport_sid - Obtain the SID for a subnet management interface.
2479ab861dfcSDaniel Jurgens * @dev_name: device name
2480e9fd7292SPaul Moore * @port_num: port number
2481ab861dfcSDaniel Jurgens * @out_sid: security identifier
2482ab861dfcSDaniel Jurgens */
security_ib_endport_sid(const char * dev_name,u8 port_num,u32 * out_sid)2483e67b7985SStephen Smalley int security_ib_endport_sid(const char *dev_name, u8 port_num, u32 *out_sid)
2484ab861dfcSDaniel Jurgens {
24851b8b31a2SStephen Smalley struct selinux_policy *policy;
2486aa8e712cSStephen Smalley struct policydb *policydb;
2487225621c9SOndrej Mosnacek struct sidtab *sidtab;
2488ab861dfcSDaniel Jurgens struct ocontext *c;
24899ad6e9cbSOndrej Mosnacek int rc;
2490ab861dfcSDaniel Jurgens
2491e67b7985SStephen Smalley if (!selinux_initialized()) {
249237ea433cSStephen Smalley *out_sid = SECINITSID_UNLABELED;
249337ea433cSStephen Smalley return 0;
249437ea433cSStephen Smalley }
249537ea433cSStephen Smalley
24969ad6e9cbSOndrej Mosnacek retry:
24979ad6e9cbSOndrej Mosnacek rc = 0;
24981b8b31a2SStephen Smalley rcu_read_lock();
2499e67b7985SStephen Smalley policy = rcu_dereference(selinux_state.policy);
25001b8b31a2SStephen Smalley policydb = &policy->policydb;
25011b8b31a2SStephen Smalley sidtab = policy->sidtab;
2502aa8e712cSStephen Smalley
2503aa8e712cSStephen Smalley c = policydb->ocontexts[OCON_IBENDPORT];
2504ab861dfcSDaniel Jurgens while (c) {
2505ab861dfcSDaniel Jurgens if (c->u.ibendport.port == port_num &&
2506ab861dfcSDaniel Jurgens !strncmp(c->u.ibendport.dev_name,
2507ab861dfcSDaniel Jurgens dev_name,
2508ab861dfcSDaniel Jurgens IB_DEVICE_NAME_MAX))
2509ab861dfcSDaniel Jurgens break;
2510ab861dfcSDaniel Jurgens
2511ab861dfcSDaniel Jurgens c = c->next;
2512ab861dfcSDaniel Jurgens }
2513ab861dfcSDaniel Jurgens
2514ab861dfcSDaniel Jurgens if (c) {
2515cbfcd13bSOndrej Mosnacek rc = ocontext_to_sid(sidtab, c, 0, out_sid);
25169ad6e9cbSOndrej Mosnacek if (rc == -ESTALE) {
25179ad6e9cbSOndrej Mosnacek rcu_read_unlock();
25189ad6e9cbSOndrej Mosnacek goto retry;
25199ad6e9cbSOndrej Mosnacek }
2520ab861dfcSDaniel Jurgens if (rc)
2521ab861dfcSDaniel Jurgens goto out;
2522ab861dfcSDaniel Jurgens } else
2523ab861dfcSDaniel Jurgens *out_sid = SECINITSID_UNLABELED;
2524ab861dfcSDaniel Jurgens
2525ab861dfcSDaniel Jurgens out:
25261b8b31a2SStephen Smalley rcu_read_unlock();
2527ab861dfcSDaniel Jurgens return rc;
2528ab861dfcSDaniel Jurgens }
2529ab861dfcSDaniel Jurgens
2530ab861dfcSDaniel Jurgens /**
25311da177e4SLinus Torvalds * security_netif_sid - Obtain the SID for a network interface.
25321da177e4SLinus Torvalds * @name: interface name
25331da177e4SLinus Torvalds * @if_sid: interface SID
25341da177e4SLinus Torvalds */
security_netif_sid(char * name,u32 * if_sid)2535e67b7985SStephen Smalley int security_netif_sid(char *name, u32 *if_sid)
25361da177e4SLinus Torvalds {
25371b8b31a2SStephen Smalley struct selinux_policy *policy;
2538aa8e712cSStephen Smalley struct policydb *policydb;
2539225621c9SOndrej Mosnacek struct sidtab *sidtab;
25409ad6e9cbSOndrej Mosnacek int rc;
25411da177e4SLinus Torvalds struct ocontext *c;
25421da177e4SLinus Torvalds
2543e67b7985SStephen Smalley if (!selinux_initialized()) {
254437ea433cSStephen Smalley *if_sid = SECINITSID_NETIF;
254537ea433cSStephen Smalley return 0;
254637ea433cSStephen Smalley }
254737ea433cSStephen Smalley
25489ad6e9cbSOndrej Mosnacek retry:
25499ad6e9cbSOndrej Mosnacek rc = 0;
25501b8b31a2SStephen Smalley rcu_read_lock();
2551e67b7985SStephen Smalley policy = rcu_dereference(selinux_state.policy);
25521b8b31a2SStephen Smalley policydb = &policy->policydb;
25531b8b31a2SStephen Smalley sidtab = policy->sidtab;
2554aa8e712cSStephen Smalley
2555aa8e712cSStephen Smalley c = policydb->ocontexts[OCON_NETIF];
25561da177e4SLinus Torvalds while (c) {
25571da177e4SLinus Torvalds if (strcmp(name, c->u.name) == 0)
25581da177e4SLinus Torvalds break;
25591da177e4SLinus Torvalds c = c->next;
25601da177e4SLinus Torvalds }
25611da177e4SLinus Torvalds
25621da177e4SLinus Torvalds if (c) {
2563cbfcd13bSOndrej Mosnacek rc = ocontext_to_sid(sidtab, c, 0, if_sid);
25649ad6e9cbSOndrej Mosnacek if (rc == -ESTALE) {
25659ad6e9cbSOndrej Mosnacek rcu_read_unlock();
25669ad6e9cbSOndrej Mosnacek goto retry;
25679ad6e9cbSOndrej Mosnacek }
25681da177e4SLinus Torvalds if (rc)
25691da177e4SLinus Torvalds goto out;
2570e8bfdb9dSPaul Moore } else
25711da177e4SLinus Torvalds *if_sid = SECINITSID_NETIF;
25721da177e4SLinus Torvalds
25731da177e4SLinus Torvalds out:
25741b8b31a2SStephen Smalley rcu_read_unlock();
25751da177e4SLinus Torvalds return rc;
25761da177e4SLinus Torvalds }
25771da177e4SLinus Torvalds
match_ipv6_addrmask(u32 * input,u32 * addr,u32 * mask)25781da177e4SLinus Torvalds static int match_ipv6_addrmask(u32 *input, u32 *addr, u32 *mask)
25791da177e4SLinus Torvalds {
25801da177e4SLinus Torvalds int i, fail = 0;
25811da177e4SLinus Torvalds
25821da177e4SLinus Torvalds for (i = 0; i < 4; i++)
25831da177e4SLinus Torvalds if (addr[i] != (input[i] & mask[i])) {
25841da177e4SLinus Torvalds fail = 1;
25851da177e4SLinus Torvalds break;
25861da177e4SLinus Torvalds }
25871da177e4SLinus Torvalds
25881da177e4SLinus Torvalds return !fail;
25891da177e4SLinus Torvalds }
25901da177e4SLinus Torvalds
25911da177e4SLinus Torvalds /**
25921da177e4SLinus Torvalds * security_node_sid - Obtain the SID for a node (host).
25931da177e4SLinus Torvalds * @domain: communication domain aka address family
25941da177e4SLinus Torvalds * @addrp: address
25951da177e4SLinus Torvalds * @addrlen: address length in bytes
25961da177e4SLinus Torvalds * @out_sid: security identifier
25971da177e4SLinus Torvalds */
security_node_sid(u16 domain,void * addrp,u32 addrlen,u32 * out_sid)2598e67b7985SStephen Smalley int security_node_sid(u16 domain,
25991da177e4SLinus Torvalds void *addrp,
26001da177e4SLinus Torvalds u32 addrlen,
26011da177e4SLinus Torvalds u32 *out_sid)
26021da177e4SLinus Torvalds {
26031b8b31a2SStephen Smalley struct selinux_policy *policy;
2604aa8e712cSStephen Smalley struct policydb *policydb;
2605225621c9SOndrej Mosnacek struct sidtab *sidtab;
26064b02b524SEric Paris int rc;
26071da177e4SLinus Torvalds struct ocontext *c;
26081da177e4SLinus Torvalds
2609e67b7985SStephen Smalley if (!selinux_initialized()) {
261037ea433cSStephen Smalley *out_sid = SECINITSID_NODE;
261137ea433cSStephen Smalley return 0;
261237ea433cSStephen Smalley }
261337ea433cSStephen Smalley
26149ad6e9cbSOndrej Mosnacek retry:
26151b8b31a2SStephen Smalley rcu_read_lock();
2616e67b7985SStephen Smalley policy = rcu_dereference(selinux_state.policy);
26171b8b31a2SStephen Smalley policydb = &policy->policydb;
26181b8b31a2SStephen Smalley sidtab = policy->sidtab;
26191da177e4SLinus Torvalds
26201da177e4SLinus Torvalds switch (domain) {
26211da177e4SLinus Torvalds case AF_INET: {
26221da177e4SLinus Torvalds u32 addr;
26231da177e4SLinus Torvalds
26241da177e4SLinus Torvalds rc = -EINVAL;
26254b02b524SEric Paris if (addrlen != sizeof(u32))
26261da177e4SLinus Torvalds goto out;
26271da177e4SLinus Torvalds
26281da177e4SLinus Torvalds addr = *((u32 *)addrp);
26291da177e4SLinus Torvalds
2630aa8e712cSStephen Smalley c = policydb->ocontexts[OCON_NODE];
26311da177e4SLinus Torvalds while (c) {
26321da177e4SLinus Torvalds if (c->u.node.addr == (addr & c->u.node.mask))
26331da177e4SLinus Torvalds break;
26341da177e4SLinus Torvalds c = c->next;
26351da177e4SLinus Torvalds }
26361da177e4SLinus Torvalds break;
26371da177e4SLinus Torvalds }
26381da177e4SLinus Torvalds
26391da177e4SLinus Torvalds case AF_INET6:
26401da177e4SLinus Torvalds rc = -EINVAL;
26414b02b524SEric Paris if (addrlen != sizeof(u64) * 2)
26421da177e4SLinus Torvalds goto out;
2643aa8e712cSStephen Smalley c = policydb->ocontexts[OCON_NODE6];
26441da177e4SLinus Torvalds while (c) {
26451da177e4SLinus Torvalds if (match_ipv6_addrmask(addrp, c->u.node6.addr,
26461da177e4SLinus Torvalds c->u.node6.mask))
26471da177e4SLinus Torvalds break;
26481da177e4SLinus Torvalds c = c->next;
26491da177e4SLinus Torvalds }
26501da177e4SLinus Torvalds break;
26511da177e4SLinus Torvalds
26521da177e4SLinus Torvalds default:
26534b02b524SEric Paris rc = 0;
26541da177e4SLinus Torvalds *out_sid = SECINITSID_NODE;
26551da177e4SLinus Torvalds goto out;
26561da177e4SLinus Torvalds }
26571da177e4SLinus Torvalds
26581da177e4SLinus Torvalds if (c) {
2659cbfcd13bSOndrej Mosnacek rc = ocontext_to_sid(sidtab, c, 0, out_sid);
26609ad6e9cbSOndrej Mosnacek if (rc == -ESTALE) {
26619ad6e9cbSOndrej Mosnacek rcu_read_unlock();
26629ad6e9cbSOndrej Mosnacek goto retry;
26639ad6e9cbSOndrej Mosnacek }
26641da177e4SLinus Torvalds if (rc)
26651da177e4SLinus Torvalds goto out;
26661da177e4SLinus Torvalds } else {
26671da177e4SLinus Torvalds *out_sid = SECINITSID_NODE;
26681da177e4SLinus Torvalds }
26691da177e4SLinus Torvalds
26704b02b524SEric Paris rc = 0;
26711da177e4SLinus Torvalds out:
26721b8b31a2SStephen Smalley rcu_read_unlock();
26731da177e4SLinus Torvalds return rc;
26741da177e4SLinus Torvalds }
26751da177e4SLinus Torvalds
26761da177e4SLinus Torvalds #define SIDS_NEL 25
26771da177e4SLinus Torvalds
26781da177e4SLinus Torvalds /**
26791da177e4SLinus Torvalds * security_get_user_sids - Obtain reachable SIDs for a user.
26801da177e4SLinus Torvalds * @fromsid: starting SID
26811da177e4SLinus Torvalds * @username: username
26821da177e4SLinus Torvalds * @sids: array of reachable SIDs for user
26831da177e4SLinus Torvalds * @nel: number of elements in @sids
26841da177e4SLinus Torvalds *
26851da177e4SLinus Torvalds * Generate the set of SIDs for legal security contexts
26861da177e4SLinus Torvalds * for a given user that can be reached by @fromsid.
26871da177e4SLinus Torvalds * Set *@sids to point to a dynamically allocated
26881da177e4SLinus Torvalds * array containing the set of SIDs. Set *@nel to the
26891da177e4SLinus Torvalds * number of elements in the array.
26901da177e4SLinus Torvalds */
26911da177e4SLinus Torvalds
security_get_user_sids(u32 fromsid,char * username,u32 ** sids,u32 * nel)2692e67b7985SStephen Smalley int security_get_user_sids(u32 fromsid,
26931da177e4SLinus Torvalds char *username,
26941da177e4SLinus Torvalds u32 **sids,
26951da177e4SLinus Torvalds u32 *nel)
26961da177e4SLinus Torvalds {
26971b8b31a2SStephen Smalley struct selinux_policy *policy;
2698aa8e712cSStephen Smalley struct policydb *policydb;
2699aa8e712cSStephen Smalley struct sidtab *sidtab;
27001da177e4SLinus Torvalds struct context *fromcon, usercon;
27012c3c05dbSStephen Smalley u32 *mysids = NULL, *mysids2, sid;
27029ad6e9cbSOndrej Mosnacek u32 i, j, mynel, maxnel = SIDS_NEL;
27031da177e4SLinus Torvalds struct user_datum *user;
27041da177e4SLinus Torvalds struct role_datum *role;
2705782ebb99SStephen Smalley struct ebitmap_node *rnode, *tnode;
27069ad6e9cbSOndrej Mosnacek int rc;
27071da177e4SLinus Torvalds
27081da177e4SLinus Torvalds *sids = NULL;
27091da177e4SLinus Torvalds *nel = 0;
27102c3c05dbSStephen Smalley
2711e67b7985SStephen Smalley if (!selinux_initialized())
27129ad6e9cbSOndrej Mosnacek return 0;
27131da177e4SLinus Torvalds
27149ad6e9cbSOndrej Mosnacek mysids = kcalloc(maxnel, sizeof(*mysids), GFP_KERNEL);
27159ad6e9cbSOndrej Mosnacek if (!mysids)
27169ad6e9cbSOndrej Mosnacek return -ENOMEM;
27179ad6e9cbSOndrej Mosnacek
27189ad6e9cbSOndrej Mosnacek retry:
27199ad6e9cbSOndrej Mosnacek mynel = 0;
27201b8b31a2SStephen Smalley rcu_read_lock();
2721e67b7985SStephen Smalley policy = rcu_dereference(selinux_state.policy);
27221b8b31a2SStephen Smalley policydb = &policy->policydb;
27231b8b31a2SStephen Smalley sidtab = policy->sidtab;
27241da177e4SLinus Torvalds
272512b29f34SStephen Smalley context_init(&usercon);
272612b29f34SStephen Smalley
27274b02b524SEric Paris rc = -EINVAL;
2728aa8e712cSStephen Smalley fromcon = sidtab_search(sidtab, fromsid);
27294b02b524SEric Paris if (!fromcon)
27301da177e4SLinus Torvalds goto out_unlock;
27311da177e4SLinus Torvalds
27321da177e4SLinus Torvalds rc = -EINVAL;
2733237389e3SOndrej Mosnacek user = symtab_search(&policydb->p_users, username);
27344b02b524SEric Paris if (!user)
27351da177e4SLinus Torvalds goto out_unlock;
27364b02b524SEric Paris
27371da177e4SLinus Torvalds usercon.user = user->value;
27381da177e4SLinus Torvalds
27399fe79ad1SKaiGai Kohei ebitmap_for_each_positive_bit(&user->roles, rnode, i) {
2740aa8e712cSStephen Smalley role = policydb->role_val_to_struct[i];
27411da177e4SLinus Torvalds usercon.role = i + 1;
27429fe79ad1SKaiGai Kohei ebitmap_for_each_positive_bit(&role->types, tnode, j) {
27431da177e4SLinus Torvalds usercon.type = j + 1;
27441da177e4SLinus Torvalds
2745aa8e712cSStephen Smalley if (mls_setup_user_range(policydb, fromcon, user,
2746aa8e712cSStephen Smalley &usercon))
27471da177e4SLinus Torvalds continue;
27481da177e4SLinus Torvalds
2749225621c9SOndrej Mosnacek rc = sidtab_context_to_sid(sidtab, &usercon, &sid);
27509ad6e9cbSOndrej Mosnacek if (rc == -ESTALE) {
27519ad6e9cbSOndrej Mosnacek rcu_read_unlock();
27529ad6e9cbSOndrej Mosnacek goto retry;
27539ad6e9cbSOndrej Mosnacek }
27542c3c05dbSStephen Smalley if (rc)
27551da177e4SLinus Torvalds goto out_unlock;
27561da177e4SLinus Torvalds if (mynel < maxnel) {
27571da177e4SLinus Torvalds mysids[mynel++] = sid;
27581da177e4SLinus Torvalds } else {
27594b02b524SEric Paris rc = -ENOMEM;
27601da177e4SLinus Torvalds maxnel += SIDS_NEL;
276189d155efSJames Morris mysids2 = kcalloc(maxnel, sizeof(*mysids2), GFP_ATOMIC);
27624b02b524SEric Paris if (!mysids2)
27631da177e4SLinus Torvalds goto out_unlock;
27641da177e4SLinus Torvalds memcpy(mysids2, mysids, mynel * sizeof(*mysids2));
27651da177e4SLinus Torvalds kfree(mysids);
27661da177e4SLinus Torvalds mysids = mysids2;
27671da177e4SLinus Torvalds mysids[mynel++] = sid;
27681da177e4SLinus Torvalds }
27691da177e4SLinus Torvalds }
27701da177e4SLinus Torvalds }
27714b02b524SEric Paris rc = 0;
27721da177e4SLinus Torvalds out_unlock:
27731b8b31a2SStephen Smalley rcu_read_unlock();
27742c3c05dbSStephen Smalley if (rc || !mynel) {
27752c3c05dbSStephen Smalley kfree(mysids);
27769ad6e9cbSOndrej Mosnacek return rc;
27772c3c05dbSStephen Smalley }
27782c3c05dbSStephen Smalley
27794b02b524SEric Paris rc = -ENOMEM;
27802c3c05dbSStephen Smalley mysids2 = kcalloc(mynel, sizeof(*mysids2), GFP_KERNEL);
27812c3c05dbSStephen Smalley if (!mysids2) {
27822c3c05dbSStephen Smalley kfree(mysids);
27839ad6e9cbSOndrej Mosnacek return rc;
27842c3c05dbSStephen Smalley }
27852c3c05dbSStephen Smalley for (i = 0, j = 0; i < mynel; i++) {
2786f01e1af4SLinus Torvalds struct av_decision dummy_avd;
2787e67b7985SStephen Smalley rc = avc_has_perm_noaudit(fromsid, mysids[i],
2788c6d3aaa4SStephen Smalley SECCLASS_PROCESS, /* kernel value */
27892c3c05dbSStephen Smalley PROCESS__TRANSITION, AVC_STRICT,
2790f01e1af4SLinus Torvalds &dummy_avd);
27912c3c05dbSStephen Smalley if (!rc)
27922c3c05dbSStephen Smalley mysids2[j++] = mysids[i];
27932c3c05dbSStephen Smalley cond_resched();
27942c3c05dbSStephen Smalley }
27952c3c05dbSStephen Smalley kfree(mysids);
27962c3c05dbSStephen Smalley *sids = mysids2;
27972c3c05dbSStephen Smalley *nel = j;
27989ad6e9cbSOndrej Mosnacek return 0;
27991da177e4SLinus Torvalds }
28001da177e4SLinus Torvalds
28011da177e4SLinus Torvalds /**
2802f31e7994SWaiman Long * __security_genfs_sid - Helper to obtain a SID for a file in a filesystem
2803e9fd7292SPaul Moore * @policy: policy
28041da177e4SLinus Torvalds * @fstype: filesystem type
28051da177e4SLinus Torvalds * @path: path from root of mount
2806e9fd7292SPaul Moore * @orig_sclass: file security class
28071da177e4SLinus Torvalds * @sid: SID for path
28081da177e4SLinus Torvalds *
28091da177e4SLinus Torvalds * Obtain a SID to use for a file in a filesystem that
28101da177e4SLinus Torvalds * cannot support xattr or use a fixed labeling behavior like
28111da177e4SLinus Torvalds * transition SIDs or task SIDs.
28129ad6e9cbSOndrej Mosnacek *
28139ad6e9cbSOndrej Mosnacek * WARNING: This function may return -ESTALE, indicating that the caller
28149ad6e9cbSOndrej Mosnacek * must retry the operation after re-acquiring the policy pointer!
28151da177e4SLinus Torvalds */
__security_genfs_sid(struct selinux_policy * policy,const char * fstype,const char * path,u16 orig_sclass,u32 * sid)281602a52c5cSStephen Smalley static inline int __security_genfs_sid(struct selinux_policy *policy,
2817aa8e712cSStephen Smalley const char *fstype,
281808df4905SChristian Göttsche const char *path,
2819c6d3aaa4SStephen Smalley u16 orig_sclass,
28201da177e4SLinus Torvalds u32 *sid)
28211da177e4SLinus Torvalds {
282202a52c5cSStephen Smalley struct policydb *policydb = &policy->policydb;
2823c7c556f1SStephen Smalley struct sidtab *sidtab = policy->sidtab;
2824c6d3aaa4SStephen Smalley u16 sclass;
28251da177e4SLinus Torvalds struct genfs *genfs;
28261da177e4SLinus Torvalds struct ocontext *c;
2827cbfcd13bSOndrej Mosnacek int cmp = 0;
28281da177e4SLinus Torvalds
2829b1aa5301SStephen Smalley while (path[0] == '/' && path[1] == '/')
2830b1aa5301SStephen Smalley path++;
2831b1aa5301SStephen Smalley
283202a52c5cSStephen Smalley sclass = unmap_class(&policy->map, orig_sclass);
28334b02b524SEric Paris *sid = SECINITSID_UNLABELED;
2834c6d3aaa4SStephen Smalley
2835aa8e712cSStephen Smalley for (genfs = policydb->genfs; genfs; genfs = genfs->next) {
28361da177e4SLinus Torvalds cmp = strcmp(fstype, genfs->fstype);
28371da177e4SLinus Torvalds if (cmp <= 0)
28381da177e4SLinus Torvalds break;
28391da177e4SLinus Torvalds }
28401da177e4SLinus Torvalds
28414b02b524SEric Paris if (!genfs || cmp)
2842cbfcd13bSOndrej Mosnacek return -ENOENT;
28431da177e4SLinus Torvalds
28441da177e4SLinus Torvalds for (c = genfs->head; c; c = c->next) {
2845c50e125dSChristian Göttsche size_t len = strlen(c->u.name);
28461da177e4SLinus Torvalds if ((!c->v.sclass || sclass == c->v.sclass) &&
28471da177e4SLinus Torvalds (strncmp(c->u.name, path, len) == 0))
28481da177e4SLinus Torvalds break;
28491da177e4SLinus Torvalds }
28501da177e4SLinus Torvalds
28514b02b524SEric Paris if (!c)
2852cbfcd13bSOndrej Mosnacek return -ENOENT;
28531da177e4SLinus Torvalds
2854cbfcd13bSOndrej Mosnacek return ocontext_to_sid(sidtab, c, 0, sid);
28551da177e4SLinus Torvalds }
28561da177e4SLinus Torvalds
28571da177e4SLinus Torvalds /**
2858f31e7994SWaiman Long * security_genfs_sid - Obtain a SID for a file in a filesystem
2859f31e7994SWaiman Long * @fstype: filesystem type
2860f31e7994SWaiman Long * @path: path from root of mount
2861e9fd7292SPaul Moore * @orig_sclass: file security class
2862f31e7994SWaiman Long * @sid: SID for path
2863f31e7994SWaiman Long *
2864f31e7994SWaiman Long * Acquire policy_rwlock before calling __security_genfs_sid() and release
2865f31e7994SWaiman Long * it afterward.
2866f31e7994SWaiman Long */
security_genfs_sid(const char * fstype,const char * path,u16 orig_sclass,u32 * sid)2867e67b7985SStephen Smalley int security_genfs_sid(const char *fstype,
286808df4905SChristian Göttsche const char *path,
2869f31e7994SWaiman Long u16 orig_sclass,
2870f31e7994SWaiman Long u32 *sid)
2871f31e7994SWaiman Long {
28721b8b31a2SStephen Smalley struct selinux_policy *policy;
2873f31e7994SWaiman Long int retval;
2874f31e7994SWaiman Long
2875e67b7985SStephen Smalley if (!selinux_initialized()) {
287637ea433cSStephen Smalley *sid = SECINITSID_UNLABELED;
287737ea433cSStephen Smalley return 0;
287837ea433cSStephen Smalley }
287937ea433cSStephen Smalley
28809ad6e9cbSOndrej Mosnacek do {
28811b8b31a2SStephen Smalley rcu_read_lock();
2882e67b7985SStephen Smalley policy = rcu_dereference(selinux_state.policy);
28839ad6e9cbSOndrej Mosnacek retval = __security_genfs_sid(policy, fstype, path,
28849ad6e9cbSOndrej Mosnacek orig_sclass, sid);
28851b8b31a2SStephen Smalley rcu_read_unlock();
28869ad6e9cbSOndrej Mosnacek } while (retval == -ESTALE);
2887f31e7994SWaiman Long return retval;
2888f31e7994SWaiman Long }
2889f31e7994SWaiman Long
selinux_policy_genfs_sid(struct selinux_policy * policy,const char * fstype,const char * path,u16 orig_sclass,u32 * sid)289002a52c5cSStephen Smalley int selinux_policy_genfs_sid(struct selinux_policy *policy,
289102a52c5cSStephen Smalley const char *fstype,
289208df4905SChristian Göttsche const char *path,
289302a52c5cSStephen Smalley u16 orig_sclass,
289402a52c5cSStephen Smalley u32 *sid)
289502a52c5cSStephen Smalley {
289602a52c5cSStephen Smalley /* no lock required, policy is not yet accessible by other threads */
289702a52c5cSStephen Smalley return __security_genfs_sid(policy, fstype, path, orig_sclass, sid);
289802a52c5cSStephen Smalley }
289902a52c5cSStephen Smalley
2900f31e7994SWaiman Long /**
29011da177e4SLinus Torvalds * security_fs_use - Determine how to handle labeling for a filesystem.
2902a64c54cfSEric Paris * @sb: superblock in question
29031da177e4SLinus Torvalds */
security_fs_use(struct super_block * sb)2904e67b7985SStephen Smalley int security_fs_use(struct super_block *sb)
29051da177e4SLinus Torvalds {
29061b8b31a2SStephen Smalley struct selinux_policy *policy;
2907aa8e712cSStephen Smalley struct policydb *policydb;
2908225621c9SOndrej Mosnacek struct sidtab *sidtab;
29099ad6e9cbSOndrej Mosnacek int rc;
29101da177e4SLinus Torvalds struct ocontext *c;
29111aea7808SCasey Schaufler struct superblock_security_struct *sbsec = selinux_superblock(sb);
2912a64c54cfSEric Paris const char *fstype = sb->s_type->name;
29131da177e4SLinus Torvalds
2914e67b7985SStephen Smalley if (!selinux_initialized()) {
291537ea433cSStephen Smalley sbsec->behavior = SECURITY_FS_USE_NONE;
291637ea433cSStephen Smalley sbsec->sid = SECINITSID_UNLABELED;
291737ea433cSStephen Smalley return 0;
291837ea433cSStephen Smalley }
291937ea433cSStephen Smalley
29209ad6e9cbSOndrej Mosnacek retry:
29211b8b31a2SStephen Smalley rcu_read_lock();
2922e67b7985SStephen Smalley policy = rcu_dereference(selinux_state.policy);
29231b8b31a2SStephen Smalley policydb = &policy->policydb;
29241b8b31a2SStephen Smalley sidtab = policy->sidtab;
2925aa8e712cSStephen Smalley
2926aa8e712cSStephen Smalley c = policydb->ocontexts[OCON_FSUSE];
29274d546f81SPaul Moore while (c) {
29284d546f81SPaul Moore if (strcmp(fstype, c->u.name) == 0)
29291da177e4SLinus Torvalds break;
29304d546f81SPaul Moore c = c->next;
29311da177e4SLinus Torvalds }
29321da177e4SLinus Torvalds
29331da177e4SLinus Torvalds if (c) {
2934a64c54cfSEric Paris sbsec->behavior = c->v.behavior;
2935cbfcd13bSOndrej Mosnacek rc = ocontext_to_sid(sidtab, c, 0, &sbsec->sid);
29369ad6e9cbSOndrej Mosnacek if (rc == -ESTALE) {
29379ad6e9cbSOndrej Mosnacek rcu_read_unlock();
29389ad6e9cbSOndrej Mosnacek goto retry;
29399ad6e9cbSOndrej Mosnacek }
29401da177e4SLinus Torvalds if (rc)
29411da177e4SLinus Torvalds goto out;
2942089be43eSJames Morris } else {
29431b8b31a2SStephen Smalley rc = __security_genfs_sid(policy, fstype, "/",
294402a52c5cSStephen Smalley SECCLASS_DIR, &sbsec->sid);
29459ad6e9cbSOndrej Mosnacek if (rc == -ESTALE) {
29469ad6e9cbSOndrej Mosnacek rcu_read_unlock();
29479ad6e9cbSOndrej Mosnacek goto retry;
29489ad6e9cbSOndrej Mosnacek }
29491da177e4SLinus Torvalds if (rc) {
2950a64c54cfSEric Paris sbsec->behavior = SECURITY_FS_USE_NONE;
29511da177e4SLinus Torvalds rc = 0;
29521da177e4SLinus Torvalds } else {
2953a64c54cfSEric Paris sbsec->behavior = SECURITY_FS_USE_GENFS;
29541da177e4SLinus Torvalds }
2955089be43eSJames Morris }
29561da177e4SLinus Torvalds
29571da177e4SLinus Torvalds out:
29581b8b31a2SStephen Smalley rcu_read_unlock();
29591da177e4SLinus Torvalds return rc;
29601da177e4SLinus Torvalds }
29611da177e4SLinus Torvalds
security_get_bools(struct selinux_policy * policy,u32 * len,char *** names,int ** values)296202a52c5cSStephen Smalley int security_get_bools(struct selinux_policy *policy,
296360abd318SOndrej Mosnacek u32 *len, char ***names, int **values)
29641da177e4SLinus Torvalds {
2965aa8e712cSStephen Smalley struct policydb *policydb;
296660abd318SOndrej Mosnacek u32 i;
296760abd318SOndrej Mosnacek int rc;
29681da177e4SLinus Torvalds
296902a52c5cSStephen Smalley policydb = &policy->policydb;
2970aa8e712cSStephen Smalley
29711da177e4SLinus Torvalds *names = NULL;
29721da177e4SLinus Torvalds *values = NULL;
29731da177e4SLinus Torvalds
29741da177e4SLinus Torvalds rc = 0;
2975aa8e712cSStephen Smalley *len = policydb->p_bools.nprim;
29764b02b524SEric Paris if (!*len)
29771da177e4SLinus Torvalds goto out;
29781da177e4SLinus Torvalds
29794b02b524SEric Paris rc = -ENOMEM;
2980e0795cf4SJesper Juhl *names = kcalloc(*len, sizeof(char *), GFP_ATOMIC);
29811da177e4SLinus Torvalds if (!*names)
29821da177e4SLinus Torvalds goto err;
29831da177e4SLinus Torvalds
29844b02b524SEric Paris rc = -ENOMEM;
2985e0795cf4SJesper Juhl *values = kcalloc(*len, sizeof(int), GFP_ATOMIC);
29861da177e4SLinus Torvalds if (!*values)
29871da177e4SLinus Torvalds goto err;
29881da177e4SLinus Torvalds
29891da177e4SLinus Torvalds for (i = 0; i < *len; i++) {
2990aa8e712cSStephen Smalley (*values)[i] = policydb->bool_val_to_struct[i]->state;
29914b02b524SEric Paris
29924b02b524SEric Paris rc = -ENOMEM;
2993aa8e712cSStephen Smalley (*names)[i] = kstrdup(sym_name(policydb, SYM_BOOLS, i),
2994aa8e712cSStephen Smalley GFP_ATOMIC);
29951da177e4SLinus Torvalds if (!(*names)[i])
29961da177e4SLinus Torvalds goto err;
29971da177e4SLinus Torvalds }
29981da177e4SLinus Torvalds rc = 0;
29991da177e4SLinus Torvalds out:
30001da177e4SLinus Torvalds return rc;
30011da177e4SLinus Torvalds err:
30021da177e4SLinus Torvalds if (*names) {
30031da177e4SLinus Torvalds for (i = 0; i < *len; i++)
30041da177e4SLinus Torvalds kfree((*names)[i]);
300565de5096STom Rix kfree(*names);
30061da177e4SLinus Torvalds }
30071da177e4SLinus Torvalds kfree(*values);
300865de5096STom Rix *len = 0;
300965de5096STom Rix *names = NULL;
301065de5096STom Rix *values = NULL;
30111da177e4SLinus Torvalds goto out;
30121da177e4SLinus Torvalds }
30131da177e4SLinus Torvalds
30141da177e4SLinus Torvalds
security_set_bools(u32 len,int * values)3015e67b7985SStephen Smalley int security_set_bools(u32 len, int *values)
30161da177e4SLinus Torvalds {
3017e67b7985SStephen Smalley struct selinux_state *state = &selinux_state;
3018c7c556f1SStephen Smalley struct selinux_policy *newpolicy, *oldpolicy;
301960abd318SOndrej Mosnacek int rc;
3020c7c556f1SStephen Smalley u32 i, seqno = 0;
30211da177e4SLinus Torvalds
3022e67b7985SStephen Smalley if (!selinux_initialized())
302337ea433cSStephen Smalley return -EINVAL;
302437ea433cSStephen Smalley
30259ff9abc4SStephen Smalley oldpolicy = rcu_dereference_protected(state->policy,
30269ff9abc4SStephen Smalley lockdep_is_held(&state->policy_mutex));
30271b8b31a2SStephen Smalley
3028c7c556f1SStephen Smalley /* Consistency check on number of booleans, should never fail */
30291b8b31a2SStephen Smalley if (WARN_ON(len != oldpolicy->policydb.p_bools.nprim))
3030c7c556f1SStephen Smalley return -EINVAL;
30311da177e4SLinus Torvalds
30321b8b31a2SStephen Smalley newpolicy = kmemdup(oldpolicy, sizeof(*newpolicy), GFP_KERNEL);
3033c7c556f1SStephen Smalley if (!newpolicy)
3034c7c556f1SStephen Smalley return -ENOMEM;
30351da177e4SLinus Torvalds
3036c7c556f1SStephen Smalley /*
3037c7c556f1SStephen Smalley * Deep copy only the parts of the policydb that might be
3038c7c556f1SStephen Smalley * modified as a result of changing booleans.
3039c7c556f1SStephen Smalley */
3040c7c556f1SStephen Smalley rc = cond_policydb_dup(&newpolicy->policydb, &oldpolicy->policydb);
3041c7c556f1SStephen Smalley if (rc) {
3042c7c556f1SStephen Smalley kfree(newpolicy);
3043c7c556f1SStephen Smalley return -ENOMEM;
3044c7c556f1SStephen Smalley }
3045c7c556f1SStephen Smalley
3046c7c556f1SStephen Smalley /* Update the boolean states in the copy */
30471da177e4SLinus Torvalds for (i = 0; i < len; i++) {
3048c7c556f1SStephen Smalley int new_state = !!values[i];
3049c7c556f1SStephen Smalley int old_state = newpolicy->policydb.bool_val_to_struct[i]->state;
3050c7c556f1SStephen Smalley
3051c7c556f1SStephen Smalley if (new_state != old_state) {
3052cdfb6b34SRichard Guy Briggs audit_log(audit_context(), GFP_ATOMIC,
3053af601e46SSteve Grubb AUDIT_MAC_CONFIG_CHANGE,
30544746ec5bSEric Paris "bool=%s val=%d old_val=%d auid=%u ses=%u",
3055c7c556f1SStephen Smalley sym_name(&newpolicy->policydb, SYM_BOOLS, i),
3056c7c556f1SStephen Smalley new_state,
3057c7c556f1SStephen Smalley old_state,
3058581abc09SEric W. Biederman from_kuid(&init_user_ns, audit_get_loginuid(current)),
30594746ec5bSEric Paris audit_get_sessionid(current));
3060c7c556f1SStephen Smalley newpolicy->policydb.bool_val_to_struct[i]->state = new_state;
3061af601e46SSteve Grubb }
30621da177e4SLinus Torvalds }
30631da177e4SLinus Torvalds
3064c7c556f1SStephen Smalley /* Re-evaluate the conditional rules in the copy */
3065c7c556f1SStephen Smalley evaluate_cond_nodes(&newpolicy->policydb);
30661da177e4SLinus Torvalds
30671b8b31a2SStephen Smalley /* Set latest granting seqno for new policy */
30681b8b31a2SStephen Smalley newpolicy->latest_granting = oldpolicy->latest_granting + 1;
30691b8b31a2SStephen Smalley seqno = newpolicy->latest_granting;
30701b8b31a2SStephen Smalley
3071c7c556f1SStephen Smalley /* Install the new policy */
30721b8b31a2SStephen Smalley rcu_assign_pointer(state->policy, newpolicy);
3073c7c556f1SStephen Smalley
3074c7c556f1SStephen Smalley /*
3075c7c556f1SStephen Smalley * Free the conditional portions of the old policydb
30761b8b31a2SStephen Smalley * that were copied for the new policy, and the oldpolicy
30771b8b31a2SStephen Smalley * structure itself but not what it references.
3078c7c556f1SStephen Smalley */
30791b8b31a2SStephen Smalley synchronize_rcu();
30801b8b31a2SStephen Smalley selinux_policy_cond_free(oldpolicy);
3081c7c556f1SStephen Smalley
3082c7c556f1SStephen Smalley /* Notify others of the policy change */
3083e67b7985SStephen Smalley selinux_notify_policy_change(seqno);
3084c7c556f1SStephen Smalley return 0;
30851da177e4SLinus Torvalds }
30861da177e4SLinus Torvalds
security_get_bool_value(u32 index)3087e67b7985SStephen Smalley int security_get_bool_value(u32 index)
30881da177e4SLinus Torvalds {
30891b8b31a2SStephen Smalley struct selinux_policy *policy;
3090aa8e712cSStephen Smalley struct policydb *policydb;
30914b02b524SEric Paris int rc;
309260abd318SOndrej Mosnacek u32 len;
30931da177e4SLinus Torvalds
3094e67b7985SStephen Smalley if (!selinux_initialized())
309537ea433cSStephen Smalley return 0;
309637ea433cSStephen Smalley
30971b8b31a2SStephen Smalley rcu_read_lock();
3098e67b7985SStephen Smalley policy = rcu_dereference(selinux_state.policy);
30991b8b31a2SStephen Smalley policydb = &policy->policydb;
31001da177e4SLinus Torvalds
31011da177e4SLinus Torvalds rc = -EFAULT;
3102aa8e712cSStephen Smalley len = policydb->p_bools.nprim;
31030fd71a62SPrarit Bhargava if (index >= len)
31041da177e4SLinus Torvalds goto out;
31051da177e4SLinus Torvalds
3106aa8e712cSStephen Smalley rc = policydb->bool_val_to_struct[index]->state;
31071da177e4SLinus Torvalds out:
31081b8b31a2SStephen Smalley rcu_read_unlock();
31091da177e4SLinus Torvalds return rc;
31101da177e4SLinus Torvalds }
3111376bd9cbSDarrel Goeddel
security_preserve_bools(struct selinux_policy * oldpolicy,struct selinux_policy * newpolicy)31121b8b31a2SStephen Smalley static int security_preserve_bools(struct selinux_policy *oldpolicy,
31131b8b31a2SStephen Smalley struct selinux_policy *newpolicy)
3114e900a7d9SStephen Smalley {
311560abd318SOndrej Mosnacek int rc, *bvalues = NULL;
3116e900a7d9SStephen Smalley char **bnames = NULL;
3117e900a7d9SStephen Smalley struct cond_bool_datum *booldatum;
311860abd318SOndrej Mosnacek u32 i, nbools = 0;
3119e900a7d9SStephen Smalley
31201b8b31a2SStephen Smalley rc = security_get_bools(oldpolicy, &nbools, &bnames, &bvalues);
3121e900a7d9SStephen Smalley if (rc)
3122e900a7d9SStephen Smalley goto out;
3123e900a7d9SStephen Smalley for (i = 0; i < nbools; i++) {
31241b8b31a2SStephen Smalley booldatum = symtab_search(&newpolicy->policydb.p_bools,
31251b8b31a2SStephen Smalley bnames[i]);
3126e900a7d9SStephen Smalley if (booldatum)
3127e900a7d9SStephen Smalley booldatum->state = bvalues[i];
3128e900a7d9SStephen Smalley }
31291b8b31a2SStephen Smalley evaluate_cond_nodes(&newpolicy->policydb);
3130e900a7d9SStephen Smalley
3131e900a7d9SStephen Smalley out:
3132e900a7d9SStephen Smalley if (bnames) {
3133e900a7d9SStephen Smalley for (i = 0; i < nbools; i++)
3134e900a7d9SStephen Smalley kfree(bnames[i]);
3135e900a7d9SStephen Smalley }
3136e900a7d9SStephen Smalley kfree(bnames);
3137e900a7d9SStephen Smalley kfree(bvalues);
3138e900a7d9SStephen Smalley return rc;
3139e900a7d9SStephen Smalley }
3140e900a7d9SStephen Smalley
314108554d6bSVenkat Yekkirala /*
314208554d6bSVenkat Yekkirala * security_sid_mls_copy() - computes a new sid based on the given
314308554d6bSVenkat Yekkirala * sid and the mls portion of mls_sid.
314408554d6bSVenkat Yekkirala */
security_sid_mls_copy(u32 sid,u32 mls_sid,u32 * new_sid)3145e67b7985SStephen Smalley int security_sid_mls_copy(u32 sid, u32 mls_sid, u32 *new_sid)
314608554d6bSVenkat Yekkirala {
31471b8b31a2SStephen Smalley struct selinux_policy *policy;
314846169802SStephen Smalley struct policydb *policydb;
314946169802SStephen Smalley struct sidtab *sidtab;
315008554d6bSVenkat Yekkirala struct context *context1;
315108554d6bSVenkat Yekkirala struct context *context2;
315208554d6bSVenkat Yekkirala struct context newcon;
315308554d6bSVenkat Yekkirala char *s;
315408554d6bSVenkat Yekkirala u32 len;
31554b02b524SEric Paris int rc;
315608554d6bSVenkat Yekkirala
3157e67b7985SStephen Smalley if (!selinux_initialized()) {
315808554d6bSVenkat Yekkirala *new_sid = sid;
31599ad6e9cbSOndrej Mosnacek return 0;
316008554d6bSVenkat Yekkirala }
316108554d6bSVenkat Yekkirala
31629ad6e9cbSOndrej Mosnacek retry:
31639ad6e9cbSOndrej Mosnacek rc = 0;
316408554d6bSVenkat Yekkirala context_init(&newcon);
316508554d6bSVenkat Yekkirala
31661b8b31a2SStephen Smalley rcu_read_lock();
3167e67b7985SStephen Smalley policy = rcu_dereference(selinux_state.policy);
31681b8b31a2SStephen Smalley policydb = &policy->policydb;
31691b8b31a2SStephen Smalley sidtab = policy->sidtab;
317046169802SStephen Smalley
317146169802SStephen Smalley if (!policydb->mls_enabled) {
317246169802SStephen Smalley *new_sid = sid;
317346169802SStephen Smalley goto out_unlock;
317446169802SStephen Smalley }
317546169802SStephen Smalley
31764b02b524SEric Paris rc = -EINVAL;
3177aa8e712cSStephen Smalley context1 = sidtab_search(sidtab, sid);
317808554d6bSVenkat Yekkirala if (!context1) {
3179b54c85c1Speter enderborg pr_err("SELinux: %s: unrecognized SID %d\n",
3180744ba35eSEric Paris __func__, sid);
318108554d6bSVenkat Yekkirala goto out_unlock;
318208554d6bSVenkat Yekkirala }
318308554d6bSVenkat Yekkirala
31844b02b524SEric Paris rc = -EINVAL;
3185aa8e712cSStephen Smalley context2 = sidtab_search(sidtab, mls_sid);
318608554d6bSVenkat Yekkirala if (!context2) {
3187b54c85c1Speter enderborg pr_err("SELinux: %s: unrecognized SID %d\n",
3188744ba35eSEric Paris __func__, mls_sid);
318908554d6bSVenkat Yekkirala goto out_unlock;
319008554d6bSVenkat Yekkirala }
319108554d6bSVenkat Yekkirala
319208554d6bSVenkat Yekkirala newcon.user = context1->user;
319308554d6bSVenkat Yekkirala newcon.role = context1->role;
319408554d6bSVenkat Yekkirala newcon.type = context1->type;
31950efc61eaSVenkat Yekkirala rc = mls_context_cpy(&newcon, context2);
319608554d6bSVenkat Yekkirala if (rc)
319708554d6bSVenkat Yekkirala goto out_unlock;
319808554d6bSVenkat Yekkirala
319908554d6bSVenkat Yekkirala /* Check the validity of the new context. */
3200aa8e712cSStephen Smalley if (!policydb_context_isvalid(policydb, &newcon)) {
3201e67b7985SStephen Smalley rc = convert_context_handle_invalid_context(policydb,
32021b8b31a2SStephen Smalley &newcon);
32034b02b524SEric Paris if (rc) {
3204aa8e712cSStephen Smalley if (!context_struct_to_string(policydb, &newcon, &s,
3205aa8e712cSStephen Smalley &len)) {
3206ea74a685SRichard Guy Briggs struct audit_buffer *ab;
3207ea74a685SRichard Guy Briggs
3208ea74a685SRichard Guy Briggs ab = audit_log_start(audit_context(),
3209ea74a685SRichard Guy Briggs GFP_ATOMIC,
3210ea74a685SRichard Guy Briggs AUDIT_SELINUX_ERR);
3211ea74a685SRichard Guy Briggs audit_log_format(ab,
3212ea74a685SRichard Guy Briggs "op=security_sid_mls_copy invalid_context=");
3213ea74a685SRichard Guy Briggs /* don't record NUL with untrusted strings */
3214ea74a685SRichard Guy Briggs audit_log_n_untrustedstring(ab, s, len - 1);
3215ea74a685SRichard Guy Briggs audit_log_end(ab);
321608554d6bSVenkat Yekkirala kfree(s);
321708554d6bSVenkat Yekkirala }
32184b02b524SEric Paris goto out_unlock;
32194b02b524SEric Paris }
32204b02b524SEric Paris }
3221225621c9SOndrej Mosnacek rc = sidtab_context_to_sid(sidtab, &newcon, new_sid);
32229ad6e9cbSOndrej Mosnacek if (rc == -ESTALE) {
32239ad6e9cbSOndrej Mosnacek rcu_read_unlock();
32249ad6e9cbSOndrej Mosnacek context_destroy(&newcon);
32259ad6e9cbSOndrej Mosnacek goto retry;
32269ad6e9cbSOndrej Mosnacek }
322708554d6bSVenkat Yekkirala out_unlock:
32281b8b31a2SStephen Smalley rcu_read_unlock();
322908554d6bSVenkat Yekkirala context_destroy(&newcon);
323008554d6bSVenkat Yekkirala return rc;
323108554d6bSVenkat Yekkirala }
323208554d6bSVenkat Yekkirala
3233220deb96SPaul Moore /**
3234220deb96SPaul Moore * security_net_peersid_resolve - Compare and resolve two network peer SIDs
3235220deb96SPaul Moore * @nlbl_sid: NetLabel SID
3236220deb96SPaul Moore * @nlbl_type: NetLabel labeling protocol type
3237220deb96SPaul Moore * @xfrm_sid: XFRM SID
3238e9fd7292SPaul Moore * @peer_sid: network peer sid
3239220deb96SPaul Moore *
3240220deb96SPaul Moore * Description:
3241220deb96SPaul Moore * Compare the @nlbl_sid and @xfrm_sid values and if the two SIDs can be
3242220deb96SPaul Moore * resolved into a single SID it is returned via @peer_sid and the function
3243220deb96SPaul Moore * returns zero. Otherwise @peer_sid is set to SECSID_NULL and the function
3244220deb96SPaul Moore * returns a negative value. A table summarizing the behavior is below:
3245220deb96SPaul Moore *
3246220deb96SPaul Moore * | function return | @sid
3247220deb96SPaul Moore * ------------------------------+-----------------+-----------------
3248220deb96SPaul Moore * no peer labels | 0 | SECSID_NULL
3249220deb96SPaul Moore * single peer label | 0 | <peer_label>
3250220deb96SPaul Moore * multiple, consistent labels | 0 | <peer_label>
3251220deb96SPaul Moore * multiple, inconsistent labels | -<errno> | SECSID_NULL
3252220deb96SPaul Moore *
3253220deb96SPaul Moore */
security_net_peersid_resolve(u32 nlbl_sid,u32 nlbl_type,u32 xfrm_sid,u32 * peer_sid)3254e67b7985SStephen Smalley int security_net_peersid_resolve(u32 nlbl_sid, u32 nlbl_type,
3255220deb96SPaul Moore u32 xfrm_sid,
3256220deb96SPaul Moore u32 *peer_sid)
3257220deb96SPaul Moore {
32581b8b31a2SStephen Smalley struct selinux_policy *policy;
325946169802SStephen Smalley struct policydb *policydb;
326046169802SStephen Smalley struct sidtab *sidtab;
3261220deb96SPaul Moore int rc;
3262220deb96SPaul Moore struct context *nlbl_ctx;
3263220deb96SPaul Moore struct context *xfrm_ctx;
3264220deb96SPaul Moore
32654b02b524SEric Paris *peer_sid = SECSID_NULL;
32664b02b524SEric Paris
3267220deb96SPaul Moore /* handle the common (which also happens to be the set of easy) cases
3268220deb96SPaul Moore * right away, these two if statements catch everything involving a
3269220deb96SPaul Moore * single or absent peer SID/label */
3270220deb96SPaul Moore if (xfrm_sid == SECSID_NULL) {
3271220deb96SPaul Moore *peer_sid = nlbl_sid;
3272220deb96SPaul Moore return 0;
3273220deb96SPaul Moore }
3274220deb96SPaul Moore /* NOTE: an nlbl_type == NETLBL_NLTYPE_UNLABELED is a "fallback" label
3275220deb96SPaul Moore * and is treated as if nlbl_sid == SECSID_NULL when a XFRM SID/label
3276220deb96SPaul Moore * is present */
3277220deb96SPaul Moore if (nlbl_sid == SECSID_NULL || nlbl_type == NETLBL_NLTYPE_UNLABELED) {
3278220deb96SPaul Moore *peer_sid = xfrm_sid;
3279220deb96SPaul Moore return 0;
3280220deb96SPaul Moore }
3281220deb96SPaul Moore
3282e67b7985SStephen Smalley if (!selinux_initialized())
328337ea433cSStephen Smalley return 0;
328437ea433cSStephen Smalley
32851b8b31a2SStephen Smalley rcu_read_lock();
3286e67b7985SStephen Smalley policy = rcu_dereference(selinux_state.policy);
32871b8b31a2SStephen Smalley policydb = &policy->policydb;
32881b8b31a2SStephen Smalley sidtab = policy->sidtab;
328946169802SStephen Smalley
3290aa8e712cSStephen Smalley /*
3291aa8e712cSStephen Smalley * We don't need to check initialized here since the only way both
3292220deb96SPaul Moore * nlbl_sid and xfrm_sid are not equal to SECSID_NULL would be if the
3293aa8e712cSStephen Smalley * security server was initialized and state->initialized was true.
3294aa8e712cSStephen Smalley */
329546169802SStephen Smalley if (!policydb->mls_enabled) {
329646169802SStephen Smalley rc = 0;
329746169802SStephen Smalley goto out;
329846169802SStephen Smalley }
3299220deb96SPaul Moore
33004b02b524SEric Paris rc = -EINVAL;
3301aa8e712cSStephen Smalley nlbl_ctx = sidtab_search(sidtab, nlbl_sid);
3302220deb96SPaul Moore if (!nlbl_ctx) {
3303b54c85c1Speter enderborg pr_err("SELinux: %s: unrecognized SID %d\n",
3304744ba35eSEric Paris __func__, nlbl_sid);
33054b02b524SEric Paris goto out;
3306220deb96SPaul Moore }
33074b02b524SEric Paris rc = -EINVAL;
3308aa8e712cSStephen Smalley xfrm_ctx = sidtab_search(sidtab, xfrm_sid);
3309220deb96SPaul Moore if (!xfrm_ctx) {
3310b54c85c1Speter enderborg pr_err("SELinux: %s: unrecognized SID %d\n",
3311744ba35eSEric Paris __func__, xfrm_sid);
33124b02b524SEric Paris goto out;
3313220deb96SPaul Moore }
3314220deb96SPaul Moore rc = (mls_context_cmp(nlbl_ctx, xfrm_ctx) ? 0 : -EACCES);
33154b02b524SEric Paris if (rc)
33164b02b524SEric Paris goto out;
3317220deb96SPaul Moore
3318220deb96SPaul Moore /* at present NetLabel SIDs/labels really only carry MLS
3319220deb96SPaul Moore * information so if the MLS portion of the NetLabel SID
3320220deb96SPaul Moore * matches the MLS portion of the labeled XFRM SID/label
3321220deb96SPaul Moore * then pass along the XFRM SID as it is the most
3322220deb96SPaul Moore * expressive */
3323220deb96SPaul Moore *peer_sid = xfrm_sid;
33244b02b524SEric Paris out:
33251b8b31a2SStephen Smalley rcu_read_unlock();
3326220deb96SPaul Moore return rc;
3327220deb96SPaul Moore }
3328220deb96SPaul Moore
get_classes_callback(void * k,void * d,void * args)332955fcf09bSChristopher J. PeBenito static int get_classes_callback(void *k, void *d, void *args)
333055fcf09bSChristopher J. PeBenito {
333155fcf09bSChristopher J. PeBenito struct class_datum *datum = d;
333255fcf09bSChristopher J. PeBenito char *name = k, **classes = args;
3333c50e125dSChristian Göttsche u32 value = datum->value - 1;
333455fcf09bSChristopher J. PeBenito
333555fcf09bSChristopher J. PeBenito classes[value] = kstrdup(name, GFP_ATOMIC);
333655fcf09bSChristopher J. PeBenito if (!classes[value])
333755fcf09bSChristopher J. PeBenito return -ENOMEM;
333855fcf09bSChristopher J. PeBenito
333955fcf09bSChristopher J. PeBenito return 0;
334055fcf09bSChristopher J. PeBenito }
334155fcf09bSChristopher J. PeBenito
security_get_classes(struct selinux_policy * policy,char *** classes,u32 * nclasses)334202a52c5cSStephen Smalley int security_get_classes(struct selinux_policy *policy,
3343c50e125dSChristian Göttsche char ***classes, u32 *nclasses)
334455fcf09bSChristopher J. PeBenito {
334546169802SStephen Smalley struct policydb *policydb;
33464b02b524SEric Paris int rc;
334755fcf09bSChristopher J. PeBenito
334802a52c5cSStephen Smalley policydb = &policy->policydb;
334946169802SStephen Smalley
33504b02b524SEric Paris rc = -ENOMEM;
3351aa8e712cSStephen Smalley *nclasses = policydb->p_classes.nprim;
33529f59f90bSJulia Lawall *classes = kcalloc(*nclasses, sizeof(**classes), GFP_ATOMIC);
335355fcf09bSChristopher J. PeBenito if (!*classes)
335455fcf09bSChristopher J. PeBenito goto out;
335555fcf09bSChristopher J. PeBenito
335603414a49SOndrej Mosnacek rc = hashtab_map(&policydb->p_classes.table, get_classes_callback,
335755fcf09bSChristopher J. PeBenito *classes);
33584b02b524SEric Paris if (rc) {
3359c50e125dSChristian Göttsche u32 i;
3360c50e125dSChristian Göttsche
336155fcf09bSChristopher J. PeBenito for (i = 0; i < *nclasses; i++)
336255fcf09bSChristopher J. PeBenito kfree((*classes)[i]);
336355fcf09bSChristopher J. PeBenito kfree(*classes);
336455fcf09bSChristopher J. PeBenito }
336555fcf09bSChristopher J. PeBenito
336655fcf09bSChristopher J. PeBenito out:
336755fcf09bSChristopher J. PeBenito return rc;
336855fcf09bSChristopher J. PeBenito }
336955fcf09bSChristopher J. PeBenito
get_permissions_callback(void * k,void * d,void * args)337055fcf09bSChristopher J. PeBenito static int get_permissions_callback(void *k, void *d, void *args)
337155fcf09bSChristopher J. PeBenito {
337255fcf09bSChristopher J. PeBenito struct perm_datum *datum = d;
337355fcf09bSChristopher J. PeBenito char *name = k, **perms = args;
3374c50e125dSChristian Göttsche u32 value = datum->value - 1;
337555fcf09bSChristopher J. PeBenito
337655fcf09bSChristopher J. PeBenito perms[value] = kstrdup(name, GFP_ATOMIC);
337755fcf09bSChristopher J. PeBenito if (!perms[value])
337855fcf09bSChristopher J. PeBenito return -ENOMEM;
337955fcf09bSChristopher J. PeBenito
338055fcf09bSChristopher J. PeBenito return 0;
338155fcf09bSChristopher J. PeBenito }
338255fcf09bSChristopher J. PeBenito
security_get_permissions(struct selinux_policy * policy,const char * class,char *** perms,u32 * nperms)338302a52c5cSStephen Smalley int security_get_permissions(struct selinux_policy *policy,
3384c50e125dSChristian Göttsche const char *class, char ***perms, u32 *nperms)
338555fcf09bSChristopher J. PeBenito {
338646169802SStephen Smalley struct policydb *policydb;
3387c50e125dSChristian Göttsche u32 i;
3388c50e125dSChristian Göttsche int rc;
338955fcf09bSChristopher J. PeBenito struct class_datum *match;
339055fcf09bSChristopher J. PeBenito
339102a52c5cSStephen Smalley policydb = &policy->policydb;
339246169802SStephen Smalley
33934b02b524SEric Paris rc = -EINVAL;
3394237389e3SOndrej Mosnacek match = symtab_search(&policydb->p_classes, class);
339555fcf09bSChristopher J. PeBenito if (!match) {
3396b54c85c1Speter enderborg pr_err("SELinux: %s: unrecognized class %s\n",
3397dd6f953aSHarvey Harrison __func__, class);
339855fcf09bSChristopher J. PeBenito goto out;
339955fcf09bSChristopher J. PeBenito }
340055fcf09bSChristopher J. PeBenito
34014b02b524SEric Paris rc = -ENOMEM;
340255fcf09bSChristopher J. PeBenito *nperms = match->permissions.nprim;
34039f59f90bSJulia Lawall *perms = kcalloc(*nperms, sizeof(**perms), GFP_ATOMIC);
340455fcf09bSChristopher J. PeBenito if (!*perms)
340555fcf09bSChristopher J. PeBenito goto out;
340655fcf09bSChristopher J. PeBenito
340755fcf09bSChristopher J. PeBenito if (match->comdatum) {
340803414a49SOndrej Mosnacek rc = hashtab_map(&match->comdatum->permissions.table,
340955fcf09bSChristopher J. PeBenito get_permissions_callback, *perms);
34104b02b524SEric Paris if (rc)
341155fcf09bSChristopher J. PeBenito goto err;
341255fcf09bSChristopher J. PeBenito }
341355fcf09bSChristopher J. PeBenito
341403414a49SOndrej Mosnacek rc = hashtab_map(&match->permissions.table, get_permissions_callback,
341555fcf09bSChristopher J. PeBenito *perms);
34164b02b524SEric Paris if (rc)
341755fcf09bSChristopher J. PeBenito goto err;
341855fcf09bSChristopher J. PeBenito
341955fcf09bSChristopher J. PeBenito out:
342055fcf09bSChristopher J. PeBenito return rc;
342155fcf09bSChristopher J. PeBenito
342255fcf09bSChristopher J. PeBenito err:
342355fcf09bSChristopher J. PeBenito for (i = 0; i < *nperms; i++)
342455fcf09bSChristopher J. PeBenito kfree((*perms)[i]);
342555fcf09bSChristopher J. PeBenito kfree(*perms);
342655fcf09bSChristopher J. PeBenito return rc;
342755fcf09bSChristopher J. PeBenito }
342855fcf09bSChristopher J. PeBenito
security_get_reject_unknown(void)3429e67b7985SStephen Smalley int security_get_reject_unknown(void)
34303f12070eSEric Paris {
34311b8b31a2SStephen Smalley struct selinux_policy *policy;
343246169802SStephen Smalley int value;
343346169802SStephen Smalley
3434e67b7985SStephen Smalley if (!selinux_initialized())
343537ea433cSStephen Smalley return 0;
343637ea433cSStephen Smalley
34371b8b31a2SStephen Smalley rcu_read_lock();
3438e67b7985SStephen Smalley policy = rcu_dereference(selinux_state.policy);
34391b8b31a2SStephen Smalley value = policy->policydb.reject_unknown;
34401b8b31a2SStephen Smalley rcu_read_unlock();
344146169802SStephen Smalley return value;
34423f12070eSEric Paris }
34433f12070eSEric Paris
security_get_allow_unknown(void)3444e67b7985SStephen Smalley int security_get_allow_unknown(void)
34453f12070eSEric Paris {
34461b8b31a2SStephen Smalley struct selinux_policy *policy;
344746169802SStephen Smalley int value;
344846169802SStephen Smalley
3449e67b7985SStephen Smalley if (!selinux_initialized())
345037ea433cSStephen Smalley return 0;
345137ea433cSStephen Smalley
34521b8b31a2SStephen Smalley rcu_read_lock();
3453e67b7985SStephen Smalley policy = rcu_dereference(selinux_state.policy);
34541b8b31a2SStephen Smalley value = policy->policydb.allow_unknown;
34551b8b31a2SStephen Smalley rcu_read_unlock();
345646169802SStephen Smalley return value;
34573f12070eSEric Paris }
34583f12070eSEric Paris
34593bb56b25SPaul Moore /**
34603bb56b25SPaul Moore * security_policycap_supported - Check for a specific policy capability
34613bb56b25SPaul Moore * @req_cap: capability
34623bb56b25SPaul Moore *
34633bb56b25SPaul Moore * Description:
34643bb56b25SPaul Moore * This function queries the currently loaded policy to see if it supports the
34653bb56b25SPaul Moore * capability specified by @req_cap. Returns true (1) if the capability is
34663bb56b25SPaul Moore * supported, false (0) if it isn't supported.
34673bb56b25SPaul Moore *
34683bb56b25SPaul Moore */
security_policycap_supported(unsigned int req_cap)3469e67b7985SStephen Smalley int security_policycap_supported(unsigned int req_cap)
34703bb56b25SPaul Moore {
34711b8b31a2SStephen Smalley struct selinux_policy *policy;
34723bb56b25SPaul Moore int rc;
34733bb56b25SPaul Moore
3474e67b7985SStephen Smalley if (!selinux_initialized())
347537ea433cSStephen Smalley return 0;
347637ea433cSStephen Smalley
34771b8b31a2SStephen Smalley rcu_read_lock();
3478e67b7985SStephen Smalley policy = rcu_dereference(selinux_state.policy);
34791b8b31a2SStephen Smalley rc = ebitmap_get_bit(&policy->policydb.policycaps, req_cap);
34801b8b31a2SStephen Smalley rcu_read_unlock();
34813bb56b25SPaul Moore
34823bb56b25SPaul Moore return rc;
34833bb56b25SPaul Moore }
34843bb56b25SPaul Moore
3485376bd9cbSDarrel Goeddel struct selinux_audit_rule {
3486376bd9cbSDarrel Goeddel u32 au_seqno;
3487376bd9cbSDarrel Goeddel struct context au_ctxt;
3488376bd9cbSDarrel Goeddel };
3489376bd9cbSDarrel Goeddel
selinux_audit_rule_free(void * vrule)34909d57a7f9SAhmed S. Darwish void selinux_audit_rule_free(void *vrule)
3491376bd9cbSDarrel Goeddel {
34929d57a7f9SAhmed S. Darwish struct selinux_audit_rule *rule = vrule;
34939d57a7f9SAhmed S. Darwish
3494376bd9cbSDarrel Goeddel if (rule) {
3495376bd9cbSDarrel Goeddel context_destroy(&rule->au_ctxt);
3496376bd9cbSDarrel Goeddel kfree(rule);
3497376bd9cbSDarrel Goeddel }
3498376bd9cbSDarrel Goeddel }
3499376bd9cbSDarrel Goeddel
selinux_audit_rule_init(u32 field,u32 op,char * rulestr,void ** vrule)35009d57a7f9SAhmed S. Darwish int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
3501376bd9cbSDarrel Goeddel {
3502aa8e712cSStephen Smalley struct selinux_state *state = &selinux_state;
35031b8b31a2SStephen Smalley struct selinux_policy *policy;
350446169802SStephen Smalley struct policydb *policydb;
3505376bd9cbSDarrel Goeddel struct selinux_audit_rule *tmprule;
3506376bd9cbSDarrel Goeddel struct role_datum *roledatum;
3507376bd9cbSDarrel Goeddel struct type_datum *typedatum;
3508376bd9cbSDarrel Goeddel struct user_datum *userdatum;
35099d57a7f9SAhmed S. Darwish struct selinux_audit_rule **rule = (struct selinux_audit_rule **)vrule;
3510376bd9cbSDarrel Goeddel int rc = 0;
3511376bd9cbSDarrel Goeddel
3512376bd9cbSDarrel Goeddel *rule = NULL;
3513376bd9cbSDarrel Goeddel
3514e67b7985SStephen Smalley if (!selinux_initialized())
35153ad40d64SSteve G return -EOPNOTSUPP;
3516376bd9cbSDarrel Goeddel
3517376bd9cbSDarrel Goeddel switch (field) {
35183a6b9f85SDarrel Goeddel case AUDIT_SUBJ_USER:
35193a6b9f85SDarrel Goeddel case AUDIT_SUBJ_ROLE:
35203a6b9f85SDarrel Goeddel case AUDIT_SUBJ_TYPE:
35216e5a2d1dSDarrel Goeddel case AUDIT_OBJ_USER:
35226e5a2d1dSDarrel Goeddel case AUDIT_OBJ_ROLE:
35236e5a2d1dSDarrel Goeddel case AUDIT_OBJ_TYPE:
3524376bd9cbSDarrel Goeddel /* only 'equals' and 'not equals' fit user, role, and type */
35255af75d8dSAl Viro if (op != Audit_equal && op != Audit_not_equal)
3526376bd9cbSDarrel Goeddel return -EINVAL;
3527376bd9cbSDarrel Goeddel break;
35283a6b9f85SDarrel Goeddel case AUDIT_SUBJ_SEN:
35293a6b9f85SDarrel Goeddel case AUDIT_SUBJ_CLR:
35306e5a2d1dSDarrel Goeddel case AUDIT_OBJ_LEV_LOW:
35316e5a2d1dSDarrel Goeddel case AUDIT_OBJ_LEV_HIGH:
353225985edcSLucas De Marchi /* we do not allow a range, indicated by the presence of '-' */
3533376bd9cbSDarrel Goeddel if (strchr(rulestr, '-'))
3534376bd9cbSDarrel Goeddel return -EINVAL;
3535376bd9cbSDarrel Goeddel break;
3536376bd9cbSDarrel Goeddel default:
3537376bd9cbSDarrel Goeddel /* only the above fields are valid */
3538376bd9cbSDarrel Goeddel return -EINVAL;
3539376bd9cbSDarrel Goeddel }
3540376bd9cbSDarrel Goeddel
3541376bd9cbSDarrel Goeddel tmprule = kzalloc(sizeof(struct selinux_audit_rule), GFP_KERNEL);
3542376bd9cbSDarrel Goeddel if (!tmprule)
3543376bd9cbSDarrel Goeddel return -ENOMEM;
3544376bd9cbSDarrel Goeddel context_init(&tmprule->au_ctxt);
3545376bd9cbSDarrel Goeddel
35461b8b31a2SStephen Smalley rcu_read_lock();
35471b8b31a2SStephen Smalley policy = rcu_dereference(state->policy);
35481b8b31a2SStephen Smalley policydb = &policy->policydb;
35491b8b31a2SStephen Smalley tmprule->au_seqno = policy->latest_granting;
3550376bd9cbSDarrel Goeddel switch (field) {
35513a6b9f85SDarrel Goeddel case AUDIT_SUBJ_USER:
35526e5a2d1dSDarrel Goeddel case AUDIT_OBJ_USER:
3553237389e3SOndrej Mosnacek userdatum = symtab_search(&policydb->p_users, rulestr);
3554c52df19eSPaul Moore if (!userdatum) {
3555c52df19eSPaul Moore rc = -EINVAL;
3556c52df19eSPaul Moore goto err;
3557c52df19eSPaul Moore }
3558376bd9cbSDarrel Goeddel tmprule->au_ctxt.user = userdatum->value;
3559376bd9cbSDarrel Goeddel break;
35603a6b9f85SDarrel Goeddel case AUDIT_SUBJ_ROLE:
35616e5a2d1dSDarrel Goeddel case AUDIT_OBJ_ROLE:
3562237389e3SOndrej Mosnacek roledatum = symtab_search(&policydb->p_roles, rulestr);
3563c52df19eSPaul Moore if (!roledatum) {
3564c52df19eSPaul Moore rc = -EINVAL;
3565c52df19eSPaul Moore goto err;
3566c52df19eSPaul Moore }
3567376bd9cbSDarrel Goeddel tmprule->au_ctxt.role = roledatum->value;
3568376bd9cbSDarrel Goeddel break;
35693a6b9f85SDarrel Goeddel case AUDIT_SUBJ_TYPE:
35706e5a2d1dSDarrel Goeddel case AUDIT_OBJ_TYPE:
3571237389e3SOndrej Mosnacek typedatum = symtab_search(&policydb->p_types, rulestr);
3572c52df19eSPaul Moore if (!typedatum) {
3573c52df19eSPaul Moore rc = -EINVAL;
3574c52df19eSPaul Moore goto err;
3575c52df19eSPaul Moore }
3576376bd9cbSDarrel Goeddel tmprule->au_ctxt.type = typedatum->value;
3577376bd9cbSDarrel Goeddel break;
35783a6b9f85SDarrel Goeddel case AUDIT_SUBJ_SEN:
35793a6b9f85SDarrel Goeddel case AUDIT_SUBJ_CLR:
35806e5a2d1dSDarrel Goeddel case AUDIT_OBJ_LEV_LOW:
35816e5a2d1dSDarrel Goeddel case AUDIT_OBJ_LEV_HIGH:
3582aa8e712cSStephen Smalley rc = mls_from_string(policydb, rulestr, &tmprule->au_ctxt,
3583aa8e712cSStephen Smalley GFP_ATOMIC);
35844b02b524SEric Paris if (rc)
3585c52df19eSPaul Moore goto err;
3586376bd9cbSDarrel Goeddel break;
3587376bd9cbSDarrel Goeddel }
35881b8b31a2SStephen Smalley rcu_read_unlock();
3589376bd9cbSDarrel Goeddel
3590376bd9cbSDarrel Goeddel *rule = tmprule;
3591c52df19eSPaul Moore return 0;
3592376bd9cbSDarrel Goeddel
3593c52df19eSPaul Moore err:
3594c52df19eSPaul Moore rcu_read_unlock();
3595c52df19eSPaul Moore selinux_audit_rule_free(tmprule);
3596c52df19eSPaul Moore *rule = NULL;
3597376bd9cbSDarrel Goeddel return rc;
3598376bd9cbSDarrel Goeddel }
3599376bd9cbSDarrel Goeddel
36009d57a7f9SAhmed S. Darwish /* Check to see if the rule contains any selinux fields */
selinux_audit_rule_known(struct audit_krule * rule)36019d57a7f9SAhmed S. Darwish int selinux_audit_rule_known(struct audit_krule *rule)
36029d57a7f9SAhmed S. Darwish {
3603c50e125dSChristian Göttsche u32 i;
36049d57a7f9SAhmed S. Darwish
36059d57a7f9SAhmed S. Darwish for (i = 0; i < rule->field_count; i++) {
36069d57a7f9SAhmed S. Darwish struct audit_field *f = &rule->fields[i];
36079d57a7f9SAhmed S. Darwish switch (f->type) {
36089d57a7f9SAhmed S. Darwish case AUDIT_SUBJ_USER:
36099d57a7f9SAhmed S. Darwish case AUDIT_SUBJ_ROLE:
36109d57a7f9SAhmed S. Darwish case AUDIT_SUBJ_TYPE:
36119d57a7f9SAhmed S. Darwish case AUDIT_SUBJ_SEN:
36129d57a7f9SAhmed S. Darwish case AUDIT_SUBJ_CLR:
36139d57a7f9SAhmed S. Darwish case AUDIT_OBJ_USER:
36149d57a7f9SAhmed S. Darwish case AUDIT_OBJ_ROLE:
36159d57a7f9SAhmed S. Darwish case AUDIT_OBJ_TYPE:
36169d57a7f9SAhmed S. Darwish case AUDIT_OBJ_LEV_LOW:
36179d57a7f9SAhmed S. Darwish case AUDIT_OBJ_LEV_HIGH:
36189d57a7f9SAhmed S. Darwish return 1;
36199d57a7f9SAhmed S. Darwish }
36209d57a7f9SAhmed S. Darwish }
36219d57a7f9SAhmed S. Darwish
36229d57a7f9SAhmed S. Darwish return 0;
36239d57a7f9SAhmed S. Darwish }
36249d57a7f9SAhmed S. Darwish
selinux_audit_rule_match(u32 sid,u32 field,u32 op,void * vrule)362590462a5bSRichard Guy Briggs int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule)
3626376bd9cbSDarrel Goeddel {
3627aa8e712cSStephen Smalley struct selinux_state *state = &selinux_state;
36281b8b31a2SStephen Smalley struct selinux_policy *policy;
3629376bd9cbSDarrel Goeddel struct context *ctxt;
3630376bd9cbSDarrel Goeddel struct mls_level *level;
36319d57a7f9SAhmed S. Darwish struct selinux_audit_rule *rule = vrule;
3632376bd9cbSDarrel Goeddel int match = 0;
3633376bd9cbSDarrel Goeddel
36349ad42a79SRichard Guy Briggs if (unlikely(!rule)) {
36359ad42a79SRichard Guy Briggs WARN_ONCE(1, "selinux_audit_rule_match: missing rule\n");
3636376bd9cbSDarrel Goeddel return -ENOENT;
3637376bd9cbSDarrel Goeddel }
3638376bd9cbSDarrel Goeddel
3639e67b7985SStephen Smalley if (!selinux_initialized())
364037ea433cSStephen Smalley return 0;
364137ea433cSStephen Smalley
36421b8b31a2SStephen Smalley rcu_read_lock();
3643376bd9cbSDarrel Goeddel
36441b8b31a2SStephen Smalley policy = rcu_dereference(state->policy);
36451b8b31a2SStephen Smalley
36461b8b31a2SStephen Smalley if (rule->au_seqno < policy->latest_granting) {
3647376bd9cbSDarrel Goeddel match = -ESTALE;
3648376bd9cbSDarrel Goeddel goto out;
3649376bd9cbSDarrel Goeddel }
3650376bd9cbSDarrel Goeddel
36511b8b31a2SStephen Smalley ctxt = sidtab_search(policy->sidtab, sid);
36529ad42a79SRichard Guy Briggs if (unlikely(!ctxt)) {
36539ad42a79SRichard Guy Briggs WARN_ONCE(1, "selinux_audit_rule_match: unrecognized SID %d\n",
36549a2f44f0SStephen Smalley sid);
3655376bd9cbSDarrel Goeddel match = -ENOENT;
3656376bd9cbSDarrel Goeddel goto out;
3657376bd9cbSDarrel Goeddel }
3658376bd9cbSDarrel Goeddel
3659376bd9cbSDarrel Goeddel /* a field/op pair that is not caught here will simply fall through
3660376bd9cbSDarrel Goeddel without a match */
3661376bd9cbSDarrel Goeddel switch (field) {
36623a6b9f85SDarrel Goeddel case AUDIT_SUBJ_USER:
36636e5a2d1dSDarrel Goeddel case AUDIT_OBJ_USER:
3664376bd9cbSDarrel Goeddel switch (op) {
36655af75d8dSAl Viro case Audit_equal:
3666376bd9cbSDarrel Goeddel match = (ctxt->user == rule->au_ctxt.user);
3667376bd9cbSDarrel Goeddel break;
36685af75d8dSAl Viro case Audit_not_equal:
3669376bd9cbSDarrel Goeddel match = (ctxt->user != rule->au_ctxt.user);
3670376bd9cbSDarrel Goeddel break;
3671376bd9cbSDarrel Goeddel }
3672376bd9cbSDarrel Goeddel break;
36733a6b9f85SDarrel Goeddel case AUDIT_SUBJ_ROLE:
36746e5a2d1dSDarrel Goeddel case AUDIT_OBJ_ROLE:
3675376bd9cbSDarrel Goeddel switch (op) {
36765af75d8dSAl Viro case Audit_equal:
3677376bd9cbSDarrel Goeddel match = (ctxt->role == rule->au_ctxt.role);
3678376bd9cbSDarrel Goeddel break;
36795af75d8dSAl Viro case Audit_not_equal:
3680376bd9cbSDarrel Goeddel match = (ctxt->role != rule->au_ctxt.role);
3681376bd9cbSDarrel Goeddel break;
3682376bd9cbSDarrel Goeddel }
3683376bd9cbSDarrel Goeddel break;
36843a6b9f85SDarrel Goeddel case AUDIT_SUBJ_TYPE:
36856e5a2d1dSDarrel Goeddel case AUDIT_OBJ_TYPE:
3686376bd9cbSDarrel Goeddel switch (op) {
36875af75d8dSAl Viro case Audit_equal:
3688376bd9cbSDarrel Goeddel match = (ctxt->type == rule->au_ctxt.type);
3689376bd9cbSDarrel Goeddel break;
36905af75d8dSAl Viro case Audit_not_equal:
3691376bd9cbSDarrel Goeddel match = (ctxt->type != rule->au_ctxt.type);
3692376bd9cbSDarrel Goeddel break;
3693376bd9cbSDarrel Goeddel }
3694376bd9cbSDarrel Goeddel break;
36953a6b9f85SDarrel Goeddel case AUDIT_SUBJ_SEN:
36963a6b9f85SDarrel Goeddel case AUDIT_SUBJ_CLR:
36976e5a2d1dSDarrel Goeddel case AUDIT_OBJ_LEV_LOW:
36986e5a2d1dSDarrel Goeddel case AUDIT_OBJ_LEV_HIGH:
36996e5a2d1dSDarrel Goeddel level = ((field == AUDIT_SUBJ_SEN ||
37006e5a2d1dSDarrel Goeddel field == AUDIT_OBJ_LEV_LOW) ?
3701376bd9cbSDarrel Goeddel &ctxt->range.level[0] : &ctxt->range.level[1]);
3702376bd9cbSDarrel Goeddel switch (op) {
37035af75d8dSAl Viro case Audit_equal:
3704376bd9cbSDarrel Goeddel match = mls_level_eq(&rule->au_ctxt.range.level[0],
3705376bd9cbSDarrel Goeddel level);
3706376bd9cbSDarrel Goeddel break;
37075af75d8dSAl Viro case Audit_not_equal:
3708376bd9cbSDarrel Goeddel match = !mls_level_eq(&rule->au_ctxt.range.level[0],
3709376bd9cbSDarrel Goeddel level);
3710376bd9cbSDarrel Goeddel break;
37115af75d8dSAl Viro case Audit_lt:
3712376bd9cbSDarrel Goeddel match = (mls_level_dom(&rule->au_ctxt.range.level[0],
3713376bd9cbSDarrel Goeddel level) &&
3714376bd9cbSDarrel Goeddel !mls_level_eq(&rule->au_ctxt.range.level[0],
3715376bd9cbSDarrel Goeddel level));
3716376bd9cbSDarrel Goeddel break;
37175af75d8dSAl Viro case Audit_le:
3718376bd9cbSDarrel Goeddel match = mls_level_dom(&rule->au_ctxt.range.level[0],
3719376bd9cbSDarrel Goeddel level);
3720376bd9cbSDarrel Goeddel break;
37215af75d8dSAl Viro case Audit_gt:
3722376bd9cbSDarrel Goeddel match = (mls_level_dom(level,
3723376bd9cbSDarrel Goeddel &rule->au_ctxt.range.level[0]) &&
3724376bd9cbSDarrel Goeddel !mls_level_eq(level,
3725376bd9cbSDarrel Goeddel &rule->au_ctxt.range.level[0]));
3726376bd9cbSDarrel Goeddel break;
37275af75d8dSAl Viro case Audit_ge:
3728376bd9cbSDarrel Goeddel match = mls_level_dom(level,
3729376bd9cbSDarrel Goeddel &rule->au_ctxt.range.level[0]);
3730376bd9cbSDarrel Goeddel break;
3731376bd9cbSDarrel Goeddel }
3732376bd9cbSDarrel Goeddel }
3733376bd9cbSDarrel Goeddel
3734376bd9cbSDarrel Goeddel out:
37351b8b31a2SStephen Smalley rcu_read_unlock();
3736376bd9cbSDarrel Goeddel return match;
3737376bd9cbSDarrel Goeddel }
3738376bd9cbSDarrel Goeddel
aurule_avc_callback(u32 event)3739562c99f2SWanlong Gao static int aurule_avc_callback(u32 event)
3740376bd9cbSDarrel Goeddel {
37413c797e51SOndrej Mosnacek if (event == AVC_CALLBACK_RESET)
37423c797e51SOndrej Mosnacek return audit_update_lsm_rules();
37433c797e51SOndrej Mosnacek return 0;
3744376bd9cbSDarrel Goeddel }
3745376bd9cbSDarrel Goeddel
aurule_init(void)3746376bd9cbSDarrel Goeddel static int __init aurule_init(void)
3747376bd9cbSDarrel Goeddel {
3748376bd9cbSDarrel Goeddel int err;
3749376bd9cbSDarrel Goeddel
3750562c99f2SWanlong Gao err = avc_add_callback(aurule_avc_callback, AVC_CALLBACK_RESET);
3751376bd9cbSDarrel Goeddel if (err)
3752376bd9cbSDarrel Goeddel panic("avc_add_callback() failed, error %d\n", err);
3753376bd9cbSDarrel Goeddel
3754376bd9cbSDarrel Goeddel return err;
3755376bd9cbSDarrel Goeddel }
3756376bd9cbSDarrel Goeddel __initcall(aurule_init);
3757376bd9cbSDarrel Goeddel
37587420ed23SVenkat Yekkirala #ifdef CONFIG_NETLABEL
37597420ed23SVenkat Yekkirala /**
37605778eabdSPaul Moore * security_netlbl_cache_add - Add an entry to the NetLabel cache
37615778eabdSPaul Moore * @secattr: the NetLabel packet security attributes
37625dbe1eb0SPaul Moore * @sid: the SELinux SID
37637420ed23SVenkat Yekkirala *
37647420ed23SVenkat Yekkirala * Description:
37657420ed23SVenkat Yekkirala * Attempt to cache the context in @ctx, which was derived from the packet in
37665778eabdSPaul Moore * @skb, in the NetLabel subsystem cache. This function assumes @secattr has
37675778eabdSPaul Moore * already been initialized.
37687420ed23SVenkat Yekkirala *
37697420ed23SVenkat Yekkirala */
security_netlbl_cache_add(struct netlbl_lsm_secattr * secattr,u32 sid)37705778eabdSPaul Moore static void security_netlbl_cache_add(struct netlbl_lsm_secattr *secattr,
37715dbe1eb0SPaul Moore u32 sid)
37727420ed23SVenkat Yekkirala {
37735dbe1eb0SPaul Moore u32 *sid_cache;
37747420ed23SVenkat Yekkirala
37755dbe1eb0SPaul Moore sid_cache = kmalloc(sizeof(*sid_cache), GFP_ATOMIC);
37765dbe1eb0SPaul Moore if (sid_cache == NULL)
37775dbe1eb0SPaul Moore return;
37785778eabdSPaul Moore secattr->cache = netlbl_secattr_cache_alloc(GFP_ATOMIC);
37795dbe1eb0SPaul Moore if (secattr->cache == NULL) {
37805dbe1eb0SPaul Moore kfree(sid_cache);
37815778eabdSPaul Moore return;
37820ec8abd7SJesper Juhl }
37837420ed23SVenkat Yekkirala
37845dbe1eb0SPaul Moore *sid_cache = sid;
37855dbe1eb0SPaul Moore secattr->cache->free = kfree;
37865dbe1eb0SPaul Moore secattr->cache->data = sid_cache;
37875778eabdSPaul Moore secattr->flags |= NETLBL_SECATTR_CACHE;
37887420ed23SVenkat Yekkirala }
37897420ed23SVenkat Yekkirala
37907420ed23SVenkat Yekkirala /**
37915778eabdSPaul Moore * security_netlbl_secattr_to_sid - Convert a NetLabel secattr to a SELinux SID
37927420ed23SVenkat Yekkirala * @secattr: the NetLabel packet security attributes
37937420ed23SVenkat Yekkirala * @sid: the SELinux SID
37947420ed23SVenkat Yekkirala *
37957420ed23SVenkat Yekkirala * Description:
37965778eabdSPaul Moore * Convert the given NetLabel security attributes in @secattr into a
37977420ed23SVenkat Yekkirala * SELinux SID. If the @secattr field does not contain a full SELinux
379825985edcSLucas De Marchi * SID/context then use SECINITSID_NETMSG as the foundation. If possible the
37995dbe1eb0SPaul Moore * 'cache' field of @secattr is set and the CACHE flag is set; this is to
38005dbe1eb0SPaul Moore * allow the @secattr to be used by NetLabel to cache the secattr to SID
38015dbe1eb0SPaul Moore * conversion for future lookups. Returns zero on success, negative values on
38025dbe1eb0SPaul Moore * failure.
38037420ed23SVenkat Yekkirala *
38047420ed23SVenkat Yekkirala */
security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr * secattr,u32 * sid)3805e67b7985SStephen Smalley int security_netlbl_secattr_to_sid(struct netlbl_lsm_secattr *secattr,
38067420ed23SVenkat Yekkirala u32 *sid)
38077420ed23SVenkat Yekkirala {
38081b8b31a2SStephen Smalley struct selinux_policy *policy;
380946169802SStephen Smalley struct policydb *policydb;
381046169802SStephen Smalley struct sidtab *sidtab;
38117ae9f23cSEric Paris int rc;
38127420ed23SVenkat Yekkirala struct context *ctx;
38137420ed23SVenkat Yekkirala struct context ctx_new;
38145778eabdSPaul Moore
3815e67b7985SStephen Smalley if (!selinux_initialized()) {
38165778eabdSPaul Moore *sid = SECSID_NULL;
38175778eabdSPaul Moore return 0;
38185778eabdSPaul Moore }
38197420ed23SVenkat Yekkirala
38209ad6e9cbSOndrej Mosnacek retry:
38219ad6e9cbSOndrej Mosnacek rc = 0;
38221b8b31a2SStephen Smalley rcu_read_lock();
3823e67b7985SStephen Smalley policy = rcu_dereference(selinux_state.policy);
38241b8b31a2SStephen Smalley policydb = &policy->policydb;
38251b8b31a2SStephen Smalley sidtab = policy->sidtab;
382646169802SStephen Smalley
38277ae9f23cSEric Paris if (secattr->flags & NETLBL_SECATTR_CACHE)
38285dbe1eb0SPaul Moore *sid = *(u32 *)secattr->cache->data;
38297ae9f23cSEric Paris else if (secattr->flags & NETLBL_SECATTR_SECID)
383016efd454SPaul Moore *sid = secattr->attr.secid;
38317ae9f23cSEric Paris else if (secattr->flags & NETLBL_SECATTR_MLS_LVL) {
38327ae9f23cSEric Paris rc = -EIDRM;
3833aa8e712cSStephen Smalley ctx = sidtab_search(sidtab, SECINITSID_NETMSG);
38347420ed23SVenkat Yekkirala if (ctx == NULL)
38357ae9f23cSEric Paris goto out;
38367420ed23SVenkat Yekkirala
383781990fbdSPaul Moore context_init(&ctx_new);
38387420ed23SVenkat Yekkirala ctx_new.user = ctx->user;
38397420ed23SVenkat Yekkirala ctx_new.role = ctx->role;
38407420ed23SVenkat Yekkirala ctx_new.type = ctx->type;
3841aa8e712cSStephen Smalley mls_import_netlbl_lvl(policydb, &ctx_new, secattr);
3842701a90baSPaul Moore if (secattr->flags & NETLBL_SECATTR_MLS_CAT) {
3843aa8e712cSStephen Smalley rc = mls_import_netlbl_cat(policydb, &ctx_new, secattr);
38447ae9f23cSEric Paris if (rc)
38457ae9f23cSEric Paris goto out;
38467420ed23SVenkat Yekkirala }
38477ae9f23cSEric Paris rc = -EIDRM;
38489ad6e9cbSOndrej Mosnacek if (!mls_context_isvalid(policydb, &ctx_new)) {
38499ad6e9cbSOndrej Mosnacek ebitmap_destroy(&ctx_new.range.level[0].cat);
38509ad6e9cbSOndrej Mosnacek goto out;
38519ad6e9cbSOndrej Mosnacek }
38527420ed23SVenkat Yekkirala
3853225621c9SOndrej Mosnacek rc = sidtab_context_to_sid(sidtab, &ctx_new, sid);
38549ad6e9cbSOndrej Mosnacek ebitmap_destroy(&ctx_new.range.level[0].cat);
38559ad6e9cbSOndrej Mosnacek if (rc == -ESTALE) {
38569ad6e9cbSOndrej Mosnacek rcu_read_unlock();
38579ad6e9cbSOndrej Mosnacek goto retry;
38589ad6e9cbSOndrej Mosnacek }
38597ae9f23cSEric Paris if (rc)
38609ad6e9cbSOndrej Mosnacek goto out;
38617420ed23SVenkat Yekkirala
38625dbe1eb0SPaul Moore security_netlbl_cache_add(secattr, *sid);
38637ae9f23cSEric Paris } else
3864388b2405Spaul.moore@hp.com *sid = SECSID_NULL;
38657420ed23SVenkat Yekkirala
38667ae9f23cSEric Paris out:
38671b8b31a2SStephen Smalley rcu_read_unlock();
38687420ed23SVenkat Yekkirala return rc;
38697420ed23SVenkat Yekkirala }
38707420ed23SVenkat Yekkirala
38717420ed23SVenkat Yekkirala /**
38725778eabdSPaul Moore * security_netlbl_sid_to_secattr - Convert a SELinux SID to a NetLabel secattr
38735778eabdSPaul Moore * @sid: the SELinux SID
38745778eabdSPaul Moore * @secattr: the NetLabel packet security attributes
38757420ed23SVenkat Yekkirala *
38767420ed23SVenkat Yekkirala * Description:
38775778eabdSPaul Moore * Convert the given SELinux SID in @sid into a NetLabel security attribute.
38785778eabdSPaul Moore * Returns zero on success, negative values on failure.
38797420ed23SVenkat Yekkirala *
38807420ed23SVenkat Yekkirala */
security_netlbl_sid_to_secattr(u32 sid,struct netlbl_lsm_secattr * secattr)3881e67b7985SStephen Smalley int security_netlbl_sid_to_secattr(u32 sid, struct netlbl_lsm_secattr *secattr)
38827420ed23SVenkat Yekkirala {
38831b8b31a2SStephen Smalley struct selinux_policy *policy;
388446169802SStephen Smalley struct policydb *policydb;
388599d854d2SPaul Moore int rc;
38867420ed23SVenkat Yekkirala struct context *ctx;
38877420ed23SVenkat Yekkirala
3888e67b7985SStephen Smalley if (!selinux_initialized())
38897420ed23SVenkat Yekkirala return 0;
38907420ed23SVenkat Yekkirala
38911b8b31a2SStephen Smalley rcu_read_lock();
3892e67b7985SStephen Smalley policy = rcu_dereference(selinux_state.policy);
38931b8b31a2SStephen Smalley policydb = &policy->policydb;
389446169802SStephen Smalley
389599d854d2SPaul Moore rc = -ENOENT;
38961b8b31a2SStephen Smalley ctx = sidtab_search(policy->sidtab, sid);
38974b02b524SEric Paris if (ctx == NULL)
38984b02b524SEric Paris goto out;
38994b02b524SEric Paris
39004b02b524SEric Paris rc = -ENOMEM;
3901aa8e712cSStephen Smalley secattr->domain = kstrdup(sym_name(policydb, SYM_TYPES, ctx->type - 1),
39027420ed23SVenkat Yekkirala GFP_ATOMIC);
39034b02b524SEric Paris if (secattr->domain == NULL)
39044b02b524SEric Paris goto out;
39054b02b524SEric Paris
39068d75899dSPaul Moore secattr->attr.secid = sid;
39078d75899dSPaul Moore secattr->flags |= NETLBL_SECATTR_DOMAIN_CPY | NETLBL_SECATTR_SECID;
3908aa8e712cSStephen Smalley mls_export_netlbl_lvl(policydb, ctx, secattr);
3909aa8e712cSStephen Smalley rc = mls_export_netlbl_cat(policydb, ctx, secattr);
39104b02b524SEric Paris out:
39111b8b31a2SStephen Smalley rcu_read_unlock();
3912f8687afeSPaul Moore return rc;
3913f8687afeSPaul Moore }
39147420ed23SVenkat Yekkirala #endif /* CONFIG_NETLABEL */
3915cee74f47SEric Paris
3916cee74f47SEric Paris /**
3917fdd1ffe8SLakshmi Ramasubramanian * __security_read_policy - read the policy.
3918fdd1ffe8SLakshmi Ramasubramanian * @policy: SELinux policy
3919fdd1ffe8SLakshmi Ramasubramanian * @data: binary policy data
3920fdd1ffe8SLakshmi Ramasubramanian * @len: length of data in bytes
3921fdd1ffe8SLakshmi Ramasubramanian *
3922fdd1ffe8SLakshmi Ramasubramanian */
__security_read_policy(struct selinux_policy * policy,void * data,size_t * len)3923fdd1ffe8SLakshmi Ramasubramanian static int __security_read_policy(struct selinux_policy *policy,
3924fdd1ffe8SLakshmi Ramasubramanian void *data, size_t *len)
3925fdd1ffe8SLakshmi Ramasubramanian {
3926fdd1ffe8SLakshmi Ramasubramanian int rc;
3927fdd1ffe8SLakshmi Ramasubramanian struct policy_file fp;
3928fdd1ffe8SLakshmi Ramasubramanian
3929fdd1ffe8SLakshmi Ramasubramanian fp.data = data;
3930fdd1ffe8SLakshmi Ramasubramanian fp.len = *len;
3931fdd1ffe8SLakshmi Ramasubramanian
3932fdd1ffe8SLakshmi Ramasubramanian rc = policydb_write(&policy->policydb, &fp);
3933fdd1ffe8SLakshmi Ramasubramanian if (rc)
3934fdd1ffe8SLakshmi Ramasubramanian return rc;
3935fdd1ffe8SLakshmi Ramasubramanian
3936fdd1ffe8SLakshmi Ramasubramanian *len = (unsigned long)fp.data - (unsigned long)data;
3937fdd1ffe8SLakshmi Ramasubramanian return 0;
3938fdd1ffe8SLakshmi Ramasubramanian }
3939fdd1ffe8SLakshmi Ramasubramanian
3940fdd1ffe8SLakshmi Ramasubramanian /**
3941cee74f47SEric Paris * security_read_policy - read the policy.
3942cee74f47SEric Paris * @data: binary policy data
3943cee74f47SEric Paris * @len: length of data in bytes
3944cee74f47SEric Paris *
3945cee74f47SEric Paris */
security_read_policy(void ** data,size_t * len)3946e67b7985SStephen Smalley int security_read_policy(void **data, size_t *len)
3947cee74f47SEric Paris {
3948e67b7985SStephen Smalley struct selinux_state *state = &selinux_state;
39491b8b31a2SStephen Smalley struct selinux_policy *policy;
3950cee74f47SEric Paris
395166ccd256SOndrej Mosnacek policy = rcu_dereference_protected(
395266ccd256SOndrej Mosnacek state->policy, lockdep_is_held(&state->policy_mutex));
395366ccd256SOndrej Mosnacek if (!policy)
3954cee74f47SEric Paris return -EINVAL;
3955cee74f47SEric Paris
395666ccd256SOndrej Mosnacek *len = policy->policydb.len;
3957845ca30fSEric Paris *data = vmalloc_user(*len);
3958cee74f47SEric Paris if (!*data)
3959cee74f47SEric Paris return -ENOMEM;
3960cee74f47SEric Paris
3961fdd1ffe8SLakshmi Ramasubramanian return __security_read_policy(policy, *data, len);
3962fdd1ffe8SLakshmi Ramasubramanian }
3963cee74f47SEric Paris
3964fdd1ffe8SLakshmi Ramasubramanian /**
3965fdd1ffe8SLakshmi Ramasubramanian * security_read_state_kernel - read the policy.
3966fdd1ffe8SLakshmi Ramasubramanian * @data: binary policy data
3967fdd1ffe8SLakshmi Ramasubramanian * @len: length of data in bytes
3968fdd1ffe8SLakshmi Ramasubramanian *
3969fdd1ffe8SLakshmi Ramasubramanian * Allocates kernel memory for reading SELinux policy.
3970fdd1ffe8SLakshmi Ramasubramanian * This function is for internal use only and should not
3971fdd1ffe8SLakshmi Ramasubramanian * be used for returning data to user space.
3972fdd1ffe8SLakshmi Ramasubramanian *
3973fdd1ffe8SLakshmi Ramasubramanian * This function must be called with policy_mutex held.
3974fdd1ffe8SLakshmi Ramasubramanian */
security_read_state_kernel(void ** data,size_t * len)3975e67b7985SStephen Smalley int security_read_state_kernel(void **data, size_t *len)
3976fdd1ffe8SLakshmi Ramasubramanian {
397773de1befSXiu Jianfeng int err;
3978e67b7985SStephen Smalley struct selinux_state *state = &selinux_state;
3979fdd1ffe8SLakshmi Ramasubramanian struct selinux_policy *policy;
3980cee74f47SEric Paris
3981fdd1ffe8SLakshmi Ramasubramanian policy = rcu_dereference_protected(
3982fdd1ffe8SLakshmi Ramasubramanian state->policy, lockdep_is_held(&state->policy_mutex));
3983fdd1ffe8SLakshmi Ramasubramanian if (!policy)
3984fdd1ffe8SLakshmi Ramasubramanian return -EINVAL;
3985cee74f47SEric Paris
3986fdd1ffe8SLakshmi Ramasubramanian *len = policy->policydb.len;
3987fdd1ffe8SLakshmi Ramasubramanian *data = vmalloc(*len);
3988fdd1ffe8SLakshmi Ramasubramanian if (!*data)
3989fdd1ffe8SLakshmi Ramasubramanian return -ENOMEM;
3990fdd1ffe8SLakshmi Ramasubramanian
399173de1befSXiu Jianfeng err = __security_read_policy(policy, *data, len);
399273de1befSXiu Jianfeng if (err) {
399373de1befSXiu Jianfeng vfree(*data);
399473de1befSXiu Jianfeng *data = NULL;
399573de1befSXiu Jianfeng *len = 0;
399673de1befSXiu Jianfeng }
399773de1befSXiu Jianfeng return err;
3998cee74f47SEric Paris }
3999