Skip to content

Commit 8d86c3a

Browse files
committed
selinux: restrict policy strings
Validate the characters and the lengths of strings parsed from binary policies. * Disallow control characters * Limit characters of identifiers to alphanumeric, underscore, dash, and dot * Limit identifiers in length to 64, expect types to 1024, sensitivities to 32 and categories to 16, characters (excluding NUL-terminator) Signed-off-by: Christian Göttsche <[email protected]> --- v3: - introduce a central limits.h header - add limits for all kinds of string: filesystem names, filetrans keys, genfs paths, infiniband device names v2: - add wrappers for str_read() to minimize the usage of magic numbers - limit sensitivities to a length of 32, to match categories, suggested by Daniel
1 parent deb1779 commit 8d86c3a

File tree

6 files changed

+196
-32
lines changed

6 files changed

+196
-32
lines changed

security/selinux/include/limits.h

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/* SPDX-License-Identifier: GPL-2.0-only */
2+
/*
3+
* Limits for various policy database elements.
4+
*/
5+
6+
/*
7+
* Maximum supported depth of conditional expressions.
8+
*/
9+
#define COND_EXPR_MAXDEPTH 10
10+
11+
/*
12+
* Maximum supported depth for constraint expressions.
13+
*/
14+
#define CEXPR_MAXDEPTH 5
15+
16+
/*
17+
* Maximum supported identifier value.
18+
*
19+
* Reasoning: The most used symbols are types and they need to fit into
20+
* an u16 for the avtab entries. Keep U16_MAX as special value
21+
* and U16_MAX-1 to avoid accidental overflows into U16_MAX.
22+
*/
23+
#define IDENTIFIER_MAXVALUE (U16_MAX - 2)
24+
25+
/*
26+
* Maximum supported length of security context strings.
27+
*
28+
* Reasoning: The string must fir into a PAGE_SIZE.
29+
*/
30+
#define CONTEXT_MAXLENGTH 4000
31+
32+
/*
33+
* Maximum supported boolean name length.
34+
*/
35+
#define BOOLEAN_NAME_MAXLENGTH 64
36+
37+
/*
38+
* Maximum supported security class and common class name length.
39+
*/
40+
#define CLASS_NAME_MAXLENGTH 64
41+
42+
/*
43+
* Maximum supported permission name length.
44+
*/
45+
#define PERMISSION_NAME_MAXLENGTH 64
46+
47+
/*
48+
* Maximum supported user name length.
49+
*/
50+
#define USER_NAME_MAXLENGTH 64
51+
52+
/*
53+
* Maximum supported role name length.
54+
*/
55+
#define ROLE_NAME_MAXLENGTH 64
56+
57+
/*
58+
* Maximum supported type name length.
59+
*/
60+
#define TYPE_NAME_MAXLENGTH 1024
61+
62+
/*
63+
* Maximum supported sensitivity name length.
64+
*/
65+
#define SENSITIVITY_NAME_MAXLENGTH 32
66+
67+
/*
68+
* Maximum supported category name length.
69+
*/
70+
#define CATEGORY_NAME_MAXLENGTH 16
71+
72+
/*
73+
* Maximum supported path name length for keys in filename transitions.
74+
*/
75+
#define FILETRANSKEY_NAME_MAXLENGTH 1024
76+
77+
/*
78+
* Maximum supported filesystem name length.
79+
*/
80+
#define FILESYSTEM_NAME_MAXLENGTH 128
81+
82+
/*
83+
* Maximum supported path prefix length for genfs statements.
84+
*/
85+
#define GENFS_PATH_MAXLENGTH 1024
86+
87+
/*
88+
* Maximum supported Infiniband device name length.
89+
*/
90+
#define INFINIBAND_DEVNAME_MAXLENGTH 256

security/selinux/ss/conditional.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,8 @@ int cond_index_bool(void *key, void *datum, void *datap)
245245
booldatum = datum;
246246
p = datap;
247247

248-
if (!booldatum->value || booldatum->value > p->p_bools.nprim)
248+
if (!booldatum->value || booldatum->value > p->p_bools.nprim ||
249+
booldatum->value > IDENTIFIER_MAXVALUE)
249250
return -EINVAL;
250251

251252
p->sym_val_to_name[SYM_BOOLS][booldatum->value - 1] = key;
@@ -280,7 +281,7 @@ int cond_read_bool(struct policydb *p, struct symtab *s, struct policy_file *fp)
280281

281282
len = le32_to_cpu(buf[2]);
282283

283-
rc = str_read(&key, GFP_KERNEL, fp, len);
284+
rc = str_read_bool(&key, GFP_KERNEL, fp, len);
284285
if (rc)
285286
goto err;
286287

security/selinux/ss/conditional.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,6 @@
1212
#include "policydb.h"
1313
#include "../include/conditional.h"
1414

15-
#define COND_EXPR_MAXDEPTH 10
16-
1715
/*
1816
* A conditional expression is a list of operators and operands
1917
* in reverse polish notation.

security/selinux/ss/constraint.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@
1919

2020
#include "ebitmap.h"
2121

22-
#define CEXPR_MAXDEPTH 5
23-
2422
struct constraint_expr {
2523
#define CEXPR_NOT 1 /* not expr */
2624
#define CEXPR_AND 2 /* expr and expr */

security/selinux/ss/policydb.c

Lines changed: 53 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -552,7 +552,8 @@ static int common_index(void *key, void *datum, void *datap)
552552

553553
comdatum = datum;
554554
p = datap;
555-
if (!comdatum->value || comdatum->value > p->p_commons.nprim)
555+
if (!comdatum->value || comdatum->value > p->p_commons.nprim ||
556+
comdatum->value > IDENTIFIER_MAXVALUE)
556557
return -EINVAL;
557558

558559
p->sym_val_to_name[SYM_COMMONS][comdatum->value - 1] = key;
@@ -567,7 +568,8 @@ static int class_index(void *key, void *datum, void *datap)
567568

568569
cladatum = datum;
569570
p = datap;
570-
if (!cladatum->value || cladatum->value > p->p_classes.nprim)
571+
if (!cladatum->value || cladatum->value > p->p_classes.nprim ||
572+
cladatum->value > IDENTIFIER_MAXVALUE)
571573
return -EINVAL;
572574

573575
p->sym_val_to_name[SYM_CLASSES][cladatum->value - 1] = key;
@@ -583,6 +585,7 @@ static int role_index(void *key, void *datum, void *datap)
583585
role = datum;
584586
p = datap;
585587
if (!role->value || role->value > p->p_roles.nprim ||
588+
role->value > IDENTIFIER_MAXVALUE ||
586589
role->bounds > p->p_roles.nprim)
587590
return -EINVAL;
588591

@@ -601,6 +604,7 @@ static int type_index(void *key, void *datum, void *datap)
601604

602605
if (typdatum->primary) {
603606
if (!typdatum->value || typdatum->value > p->p_types.nprim ||
607+
typdatum->value > IDENTIFIER_MAXVALUE ||
604608
typdatum->bounds > p->p_types.nprim)
605609
return -EINVAL;
606610
p->sym_val_to_name[SYM_TYPES][typdatum->value - 1] = key;
@@ -618,6 +622,7 @@ static int user_index(void *key, void *datum, void *datap)
618622
usrdatum = datum;
619623
p = datap;
620624
if (!usrdatum->value || usrdatum->value > p->p_users.nprim ||
625+
usrdatum->value > IDENTIFIER_MAXVALUE ||
621626
usrdatum->bounds > p->p_users.nprim)
622627
return -EINVAL;
623628

@@ -634,7 +639,8 @@ static int sens_index(void *key, void *datum, void *datap)
634639
levdatum = datum;
635640
p = datap;
636641

637-
if (!levdatum->level.sens || levdatum->level.sens > p->p_levels.nprim)
642+
if (!levdatum->level.sens || levdatum->level.sens > p->p_levels.nprim ||
643+
levdatum->level.sens > IDENTIFIER_MAXVALUE)
638644
return -EINVAL;
639645

640646
if (!levdatum->isalias)
@@ -651,7 +657,8 @@ static int cat_index(void *key, void *datum, void *datap)
651657
catdatum = datum;
652658
p = datap;
653659

654-
if (!catdatum->value || catdatum->value > p->p_cats.nprim)
660+
if (!catdatum->value || catdatum->value > p->p_cats.nprim ||
661+
catdatum->value > IDENTIFIER_MAXVALUE)
655662
return -EINVAL;
656663

657664
if (!catdatum->isalias)
@@ -1226,8 +1233,9 @@ static int context_read_and_validate(struct context *c, struct policydb *p,
12261233
* binary representation file.
12271234
*/
12281235

1229-
int str_read(char **strp, gfp_t flags, struct policy_file *fp, u32 len)
1236+
int str_read(char **strp, gfp_t flags, struct policy_file *fp, u32 len, int kind, u32 max_len)
12301237
{
1238+
u32 i;
12311239
int rc;
12321240
char *str;
12331241

@@ -1237,19 +1245,35 @@ int str_read(char **strp, gfp_t flags, struct policy_file *fp, u32 len)
12371245
if (size_check(sizeof(char), len, fp))
12381246
return -EINVAL;
12391247

1248+
if (len > max_len)
1249+
return -EINVAL;
1250+
12401251
str = kmalloc(len + 1, flags | __GFP_NOWARN);
12411252
if (!str)
12421253
return -ENOMEM;
12431254

12441255
rc = next_entry(str, fp, len);
1245-
if (rc) {
1246-
kfree(str);
1247-
return rc;
1256+
if (rc)
1257+
goto bad_str;
1258+
1259+
rc = -EINVAL;
1260+
for (i = 0; i < len; i++) {
1261+
if (iscntrl(str[i]))
1262+
goto bad_str;
1263+
1264+
if (kind == STR_IDENTIFIER &&
1265+
!(isalnum(str[i]) || str[i] == '_' || str[i] == '-' || str[i] == '.'))
1266+
goto bad_str;
1267+
12481268
}
12491269

12501270
str[len] = '\0';
12511271
*strp = str;
12521272
return 0;
1273+
1274+
bad_str:
1275+
kfree(str);
1276+
return rc;
12531277
}
12541278

12551279
static int perm_read(struct policydb *p, struct symtab *s, struct policy_file *fp)
@@ -1274,7 +1298,7 @@ static int perm_read(struct policydb *p, struct symtab *s, struct policy_file *f
12741298
if (perdatum->value < 1 || perdatum->value > SEL_VEC_MAX)
12751299
goto bad;
12761300

1277-
rc = str_read(&key, GFP_KERNEL, fp, len);
1301+
rc = str_read_perm(&key, GFP_KERNEL, fp, len);
12781302
if (rc)
12791303
goto bad;
12801304

@@ -1321,7 +1345,7 @@ static int common_read(struct policydb *p, struct symtab *s, struct policy_file
13211345
goto bad;
13221346
comdatum->permissions.nprim = le32_to_cpu(buf[2]);
13231347

1324-
rc = str_read(&key, GFP_KERNEL, fp, len);
1348+
rc = str_read_class(&key, GFP_KERNEL, fp, len);
13251349
if (rc)
13261350
goto bad;
13271351

@@ -1559,12 +1583,12 @@ static int class_read(struct policydb *p, struct symtab *s, struct policy_file *
15591583

15601584
ncons = le32_to_cpu(buf[5]);
15611585

1562-
rc = str_read(&key, GFP_KERNEL, fp, len);
1586+
rc = str_read_class(&key, GFP_KERNEL, fp, len);
15631587
if (rc)
15641588
goto bad;
15651589

15661590
if (len2) {
1567-
rc = str_read(&cladatum->comkey, GFP_KERNEL, fp, len2);
1591+
rc = str_read_class(&cladatum->comkey, GFP_KERNEL, fp, len2);
15681592
if (rc)
15691593
goto bad;
15701594

@@ -1698,7 +1722,7 @@ static int role_read(struct policydb *p, struct symtab *s, struct policy_file *f
16981722
if (p->policyvers >= POLICYDB_VERSION_BOUNDARY)
16991723
role->bounds = le32_to_cpu(buf[2]);
17001724

1701-
rc = str_read(&key, GFP_KERNEL, fp, len);
1725+
rc = str_read_role(&key, GFP_KERNEL, fp, len);
17021726
if (rc)
17031727
goto bad;
17041728

@@ -1765,7 +1789,7 @@ static int type_read(struct policydb *p, struct symtab *s, struct policy_file *f
17651789
typdatum->primary = le32_to_cpu(buf[2]);
17661790
}
17671791

1768-
rc = str_read(&key, GFP_KERNEL, fp, len);
1792+
rc = str_read_type(&key, GFP_KERNEL, fp, len);
17691793
if (rc)
17701794
goto bad;
17711795

@@ -1829,7 +1853,7 @@ static int user_read(struct policydb *p, struct symtab *s, struct policy_file *f
18291853
if (p->policyvers >= POLICYDB_VERSION_BOUNDARY)
18301854
usrdatum->bounds = le32_to_cpu(buf[2]);
18311855

1832-
rc = str_read(&key, GFP_KERNEL, fp, len);
1856+
rc = str_read_user(&key, GFP_KERNEL, fp, len);
18331857
if (rc)
18341858
goto bad;
18351859

@@ -1878,7 +1902,7 @@ static int sens_read(struct policydb *p, struct symtab *s, struct policy_file *f
18781902
goto bad;
18791903
levdatum->isalias = val;
18801904

1881-
rc = str_read(&key, GFP_KERNEL, fp, len);
1905+
rc = str_read_sens(&key, GFP_KERNEL, fp, len);
18821906
if (rc)
18831907
goto bad;
18841908

@@ -1921,7 +1945,7 @@ static int cat_read(struct policydb *p, struct symtab *s, struct policy_file *fp
19211945
goto bad;
19221946
catdatum->isalias = val;
19231947

1924-
rc = str_read(&key, GFP_KERNEL, fp, len);
1948+
rc = str_read_cat(&key, GFP_KERNEL, fp, len);
19251949
if (rc)
19261950
goto bad;
19271951

@@ -2230,7 +2254,7 @@ static int filename_trans_read_helper_compat(struct policydb *p, struct policy_f
22302254
len = le32_to_cpu(buf[0]);
22312255

22322256
/* path component string */
2233-
rc = str_read(&name, GFP_KERNEL, fp, len);
2257+
rc = str_read(&name, GFP_KERNEL, fp, len, STR_UNCONSTRAINT, FILETRANSKEY_NAME_MAXLENGTH);
22342258
if (rc)
22352259
return rc;
22362260

@@ -2329,7 +2353,7 @@ static int filename_trans_read_helper(struct policydb *p, struct policy_file *fp
23292353
len = le32_to_cpu(buf[0]);
23302354

23312355
/* path component string */
2332-
rc = str_read(&name, GFP_KERNEL, fp, len);
2356+
rc = str_read(&name, GFP_KERNEL, fp, len, STR_UNCONSTRAINT, FILETRANSKEY_NAME_MAXLENGTH);
23332357
if (rc)
23342358
return rc;
23352359

@@ -2483,7 +2507,7 @@ static int genfs_read(struct policydb *p, struct policy_file *fp)
24832507
if (!newgenfs)
24842508
goto out;
24852509

2486-
rc = str_read(&newgenfs->fstype, GFP_KERNEL, fp, len);
2510+
rc = str_read_fsname(&newgenfs->fstype, GFP_KERNEL, fp, len);
24872511
if (rc)
24882512
goto out;
24892513

@@ -2522,7 +2546,8 @@ static int genfs_read(struct policydb *p, struct policy_file *fp)
25222546
if (!newc)
25232547
goto out;
25242548

2525-
rc = str_read(&newc->u.name, GFP_KERNEL, fp, len);
2549+
rc = str_read(&newc->u.name, GFP_KERNEL, fp, len,
2550+
STR_UNCONSTRAINT, GENFS_PATH_MAXLENGTH);
25262551
if (rc)
25272552
goto out;
25282553

@@ -2625,7 +2650,7 @@ static int ocontext_read(struct policydb *p,
26252650
goto out;
26262651
len = le32_to_cpu(buf[0]);
26272652

2628-
rc = str_read(&c->u.name, GFP_KERNEL, fp, len);
2653+
rc = str_read_fsname(&c->u.name, GFP_KERNEL, fp, len);
26292654
if (rc)
26302655
goto out;
26312656

@@ -2693,7 +2718,7 @@ static int ocontext_read(struct policydb *p,
26932718
goto out;
26942719

26952720
len = le32_to_cpu(buf[1]);
2696-
rc = str_read(&c->u.name, GFP_KERNEL, fp, len);
2721+
rc = str_read_fsname(&c->u.name, GFP_KERNEL, fp, len);
26972722
if (rc)
26982723
goto out;
26992724

@@ -2759,7 +2784,9 @@ static int ocontext_read(struct policydb *p,
27592784
len = le32_to_cpu(buf[0]);
27602785

27612786
rc = str_read(&c->u.ibendport.dev_name,
2762-
GFP_KERNEL, fp, len);
2787+
GFP_KERNEL, fp, len,
2788+
STR_UNCONSTRAINT,
2789+
INFINIBAND_DEVNAME_MAXLENGTH);
27632790
if (rc)
27642791
goto out;
27652792

@@ -2827,7 +2854,8 @@ int policydb_read(struct policydb *p, struct policy_file *fp)
28272854
goto bad;
28282855
}
28292856

2830-
rc = str_read(&policydb_str, GFP_KERNEL, fp, len);
2857+
rc = str_read(&policydb_str, GFP_KERNEL, fp, len,
2858+
STR_UNCONSTRAINT, strlen(POLICYDB_STRING));
28312859
if (rc) {
28322860
if (rc == -ENOMEM) {
28332861
pr_err("SELinux: unable to allocate memory for policydb string of length %d\n",

0 commit comments

Comments
 (0)