Skip to content

Commit 2463c26

Browse files
committed
SELinux: put name based create rules in a hashtable
To shorten the list we need to run if filename trans rules exist for the type of the given parent directory I put them in a hashtable. Given the policy we are expecting to use in Fedora this takes the worst case list run from about 5,000 entries to 17. Signed-off-by: Eric Paris <[email protected]> Reviewed-by: James Morris <[email protected]>
1 parent 3f058ef commit 2463c26

File tree

3 files changed

+135
-61
lines changed

3 files changed

+135
-61
lines changed

security/selinux/ss/policydb.c

Lines changed: 119 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,43 @@ static int roles_init(struct policydb *p)
184184
return rc;
185185
}
186186

187+
static u32 filenametr_hash(struct hashtab *h, const void *k)
188+
{
189+
const struct filename_trans *ft = k;
190+
unsigned long hash;
191+
unsigned int byte_num;
192+
unsigned char focus;
193+
194+
hash = ft->stype ^ ft->ttype ^ ft->tclass;
195+
196+
byte_num = 0;
197+
while ((focus = ft->name[byte_num++]))
198+
hash = partial_name_hash(focus, hash);
199+
return hash & (h->size - 1);
200+
}
201+
202+
static int filenametr_cmp(struct hashtab *h, const void *k1, const void *k2)
203+
{
204+
const struct filename_trans *ft1 = k1;
205+
const struct filename_trans *ft2 = k2;
206+
int v;
207+
208+
v = ft1->stype - ft2->stype;
209+
if (v)
210+
return v;
211+
212+
v = ft1->ttype - ft2->ttype;
213+
if (v)
214+
return v;
215+
216+
v = ft1->tclass - ft2->tclass;
217+
if (v)
218+
return v;
219+
220+
return strcmp(ft1->name, ft2->name);
221+
222+
}
223+
187224
static u32 rangetr_hash(struct hashtab *h, const void *k)
188225
{
189226
const struct range_trans *key = k;
@@ -236,6 +273,10 @@ static int policydb_init(struct policydb *p)
236273
if (rc)
237274
goto out;
238275

276+
p->filename_trans = hashtab_create(filenametr_hash, filenametr_cmp, (1 << 10));
277+
if (!p->filename_trans)
278+
goto out;
279+
239280
p->range_tr = hashtab_create(rangetr_hash, rangetr_cmp, 256);
240281
if (!p->range_tr)
241282
goto out;
@@ -246,6 +287,8 @@ static int policydb_init(struct policydb *p)
246287

247288
return 0;
248289
out:
290+
hashtab_destroy(p->filename_trans);
291+
hashtab_destroy(p->range_tr);
249292
for (i = 0; i < SYM_NUM; i++)
250293
hashtab_destroy(p->symtab[i].table);
251294
return rc;
@@ -675,6 +718,16 @@ static int (*destroy_f[SYM_NUM]) (void *key, void *datum, void *datap) =
675718
cat_destroy,
676719
};
677720

721+
static int filenametr_destroy(void *key, void *datum, void *p)
722+
{
723+
struct filename_trans *ft = key;
724+
kfree(ft->name);
725+
kfree(key);
726+
kfree(datum);
727+
cond_resched();
728+
return 0;
729+
}
730+
678731
static int range_tr_destroy(void *key, void *datum, void *p)
679732
{
680733
struct mls_range *rt = datum;
@@ -709,7 +762,6 @@ void policydb_destroy(struct policydb *p)
709762
int i;
710763
struct role_allow *ra, *lra = NULL;
711764
struct role_trans *tr, *ltr = NULL;
712-
struct filename_trans *ft, *nft;
713765

714766
for (i = 0; i < SYM_NUM; i++) {
715767
cond_resched();
@@ -773,6 +825,9 @@ void policydb_destroy(struct policydb *p)
773825
}
774826
kfree(lra);
775827

828+
hashtab_map(p->filename_trans, filenametr_destroy, NULL);
829+
hashtab_destroy(p->filename_trans);
830+
776831
hashtab_map(p->range_tr, range_tr_destroy, NULL);
777832
hashtab_destroy(p->range_tr);
778833

@@ -788,14 +843,6 @@ void policydb_destroy(struct policydb *p)
788843
flex_array_free(p->type_attr_map_array);
789844
}
790845

791-
ft = p->filename_trans;
792-
while (ft) {
793-
nft = ft->next;
794-
kfree(ft->name);
795-
kfree(ft);
796-
ft = nft;
797-
}
798-
799846
ebitmap_destroy(&p->filename_trans_ttypes);
800847
ebitmap_destroy(&p->policycaps);
801848
ebitmap_destroy(&p->permissive_map);
@@ -1806,9 +1853,10 @@ static int range_read(struct policydb *p, void *fp)
18061853

18071854
static int filename_trans_read(struct policydb *p, void *fp)
18081855
{
1809-
struct filename_trans *ft, *last;
1810-
u32 nel, len;
1856+
struct filename_trans *ft;
1857+
struct filename_trans_datum *otype;
18111858
char *name;
1859+
u32 nel, len;
18121860
__le32 buf[4];
18131861
int rc, i;
18141862

@@ -1817,25 +1865,23 @@ static int filename_trans_read(struct policydb *p, void *fp)
18171865

18181866
rc = next_entry(buf, fp, sizeof(u32));
18191867
if (rc)
1820-
goto out;
1868+
return rc;
18211869
nel = le32_to_cpu(buf[0]);
18221870

1823-
last = p->filename_trans;
1824-
while (last && last->next)
1825-
last = last->next;
1826-
18271871
for (i = 0; i < nel; i++) {
1872+
ft = NULL;
1873+
otype = NULL;
1874+
name = NULL;
1875+
18281876
rc = -ENOMEM;
18291877
ft = kzalloc(sizeof(*ft), GFP_KERNEL);
18301878
if (!ft)
18311879
goto out;
18321880

1833-
/* add it to the tail of the list */
1834-
if (!last)
1835-
p->filename_trans = ft;
1836-
else
1837-
last->next = ft;
1838-
last = ft;
1881+
rc = -ENOMEM;
1882+
otype = kmalloc(sizeof(*otype), GFP_KERNEL);
1883+
if (!otype)
1884+
goto out;
18391885

18401886
/* length of the path component string */
18411887
rc = next_entry(buf, fp, sizeof(u32));
@@ -1863,14 +1909,22 @@ static int filename_trans_read(struct policydb *p, void *fp)
18631909
ft->stype = le32_to_cpu(buf[0]);
18641910
ft->ttype = le32_to_cpu(buf[1]);
18651911
ft->tclass = le32_to_cpu(buf[2]);
1866-
ft->otype = le32_to_cpu(buf[3]);
1912+
1913+
otype->otype = le32_to_cpu(buf[3]);
18671914

18681915
rc = ebitmap_set_bit(&p->filename_trans_ttypes, ft->ttype, 1);
18691916
if (rc)
18701917
goto out;
1918+
1919+
hashtab_insert(p->filename_trans, ft, otype);
18711920
}
1872-
rc = 0;
1921+
hash_eval(p->filename_trans, "filenametr");
1922+
return 0;
18731923
out:
1924+
kfree(ft);
1925+
kfree(name);
1926+
kfree(otype);
1927+
18741928
return rc;
18751929
}
18761930

@@ -3131,43 +3185,60 @@ static int range_write(struct policydb *p, void *fp)
31313185
return 0;
31323186
}
31333187

3134-
static int filename_trans_write(struct policydb *p, void *fp)
3188+
static int filename_write_helper(void *key, void *data, void *ptr)
31353189
{
3136-
struct filename_trans *ft;
3137-
u32 len, nel = 0;
31383190
__le32 buf[4];
3191+
struct filename_trans *ft = key;
3192+
struct filename_trans_datum *otype = data;
3193+
void *fp = ptr;
31393194
int rc;
3195+
u32 len;
31403196

3141-
for (ft = p->filename_trans; ft; ft = ft->next)
3142-
nel++;
3143-
3144-
buf[0] = cpu_to_le32(nel);
3197+
len = strlen(ft->name);
3198+
buf[0] = cpu_to_le32(len);
31453199
rc = put_entry(buf, sizeof(u32), 1, fp);
31463200
if (rc)
31473201
return rc;
31483202

3149-
for (ft = p->filename_trans; ft; ft = ft->next) {
3150-
len = strlen(ft->name);
3151-
buf[0] = cpu_to_le32(len);
3152-
rc = put_entry(buf, sizeof(u32), 1, fp);
3153-
if (rc)
3154-
return rc;
3203+
rc = put_entry(ft->name, sizeof(char), len, fp);
3204+
if (rc)
3205+
return rc;
31553206

3156-
rc = put_entry(ft->name, sizeof(char), len, fp);
3157-
if (rc)
3158-
return rc;
3207+
buf[0] = ft->stype;
3208+
buf[1] = ft->ttype;
3209+
buf[2] = ft->tclass;
3210+
buf[3] = otype->otype;
31593211

3160-
buf[0] = ft->stype;
3161-
buf[1] = ft->ttype;
3162-
buf[2] = ft->tclass;
3163-
buf[3] = ft->otype;
3212+
rc = put_entry(buf, sizeof(u32), 4, fp);
3213+
if (rc)
3214+
return rc;
31643215

3165-
rc = put_entry(buf, sizeof(u32), 4, fp);
3166-
if (rc)
3167-
return rc;
3168-
}
31693216
return 0;
31703217
}
3218+
3219+
static int filename_trans_write(struct policydb *p, void *fp)
3220+
{
3221+
u32 nel;
3222+
__le32 buf[1];
3223+
int rc;
3224+
3225+
nel = 0;
3226+
rc = hashtab_map(p->filename_trans, hashtab_cnt, &nel);
3227+
if (rc)
3228+
return rc;
3229+
3230+
buf[0] = cpu_to_le32(nel);
3231+
rc = put_entry(buf, sizeof(u32), 1, fp);
3232+
if (rc)
3233+
return rc;
3234+
3235+
rc = hashtab_map(p->filename_trans, filename_write_helper, fp);
3236+
if (rc)
3237+
return rc;
3238+
3239+
return 0;
3240+
}
3241+
31713242
/*
31723243
* Write the configuration data in a policy database
31733244
* structure to a policy database binary representation

security/selinux/ss/policydb.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,11 +79,13 @@ struct role_trans {
7979
};
8080

8181
struct filename_trans {
82-
struct filename_trans *next;
8382
u32 stype; /* current process */
8483
u32 ttype; /* parent dir context */
8584
u16 tclass; /* class of new object */
8685
const char *name; /* last path component */
86+
};
87+
88+
struct filename_trans_datum {
8789
u32 otype; /* expected of new object */
8890
};
8991

@@ -227,10 +229,11 @@ struct policydb {
227229
/* role transitions */
228230
struct role_trans *role_tr;
229231

232+
/* file transitions with the last path component */
230233
/* quickly exclude lookups when parent ttype has no rules */
231234
struct ebitmap filename_trans_ttypes;
232-
/* file transitions with the last path component */
233-
struct filename_trans *filename_trans;
235+
/* actual set of filename_trans rules */
236+
struct hashtab *filename_trans;
234237

235238
/* bools indexed by (value - 1) */
236239
struct cond_bool_datum **bool_val_to_struct;

security/selinux/ss/services.c

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1362,7 +1362,8 @@ static void filename_compute_type(struct policydb *p, struct context *newcontext
13621362
u32 stype, u32 ttype, u16 tclass,
13631363
const char *objname)
13641364
{
1365-
struct filename_trans *ft;
1365+
struct filename_trans ft;
1366+
struct filename_trans_datum *otype;
13661367

13671368
/*
13681369
* Most filename trans rules are going to live in specific directories
@@ -1372,15 +1373,14 @@ static void filename_compute_type(struct policydb *p, struct context *newcontext
13721373
if (!ebitmap_get_bit(&p->filename_trans_ttypes, ttype))
13731374
return;
13741375

1375-
for (ft = p->filename_trans; ft; ft = ft->next) {
1376-
if (ft->stype == stype &&
1377-
ft->ttype == ttype &&
1378-
ft->tclass == tclass &&
1379-
!strcmp(ft->name, objname)) {
1380-
newcontext->type = ft->otype;
1381-
return;
1382-
}
1383-
}
1376+
ft.stype = stype;
1377+
ft.ttype = ttype;
1378+
ft.tclass = tclass;
1379+
ft.name = objname;
1380+
1381+
otype = hashtab_search(p->filename_trans, &ft);
1382+
if (otype)
1383+
newcontext->type = otype->otype;
13841384
}
13851385

13861386
static int security_compute_sid(u32 ssid,

0 commit comments

Comments
 (0)