Commit 07c9e4a4 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] SELinux leak fixes

From: Stephen Smalley <sds@epoch.ncsc.mil>

I believe that the patch below fixes the legitimate leaks in the SELinux
code.  In some cases, it rearranges the code (moving the allocation later
to reduce the need for further cleanup or linking the object into a
containing structure earlier so that the policydb_destroy will handle it
upon any subsequent errors).
parent b5ec6dea
...@@ -548,8 +548,10 @@ int mls_read_user(struct user_datum *usrdatum, void *fp) ...@@ -548,8 +548,10 @@ int mls_read_user(struct user_datum *usrdatum, void *fp)
memset(r, 0, sizeof(*r)); memset(r, 0, sizeof(*r));
rc = mls_read_range_helper(&r->range, fp); rc = mls_read_range_helper(&r->range, fp);
if (rc) if (rc) {
kfree(r);
goto out; goto out;
}
if (l) if (l)
l->next = r; l->next = r;
...@@ -581,10 +583,17 @@ int mls_read_trusted(struct policydb *p, void *fp) ...@@ -581,10 +583,17 @@ int mls_read_trusted(struct policydb *p, void *fp)
goto out; goto out;
rc = ebitmap_read(&p->trustedwriters, fp); rc = ebitmap_read(&p->trustedwriters, fp);
if (rc) if (rc)
goto out; goto bad;
rc = ebitmap_read(&p->trustedobjects, fp); rc = ebitmap_read(&p->trustedobjects, fp);
if (rc)
goto bad2;
out: out:
return rc; return rc;
bad2:
ebitmap_destroy(&p->trustedwriters);
bad:
ebitmap_destroy(&p->trustedreaders);
goto out;
} }
int sens_index(void *key, void *datum, void *datap) int sens_index(void *key, void *datum, void *datap)
......
...@@ -390,6 +390,16 @@ static int (*destroy_f[SYM_NUM]) (void *key, void *datum, void *datap) = ...@@ -390,6 +390,16 @@ static int (*destroy_f[SYM_NUM]) (void *key, void *datum, void *datap) =
mls_destroy_f mls_destroy_f
}; };
void ocontext_destroy(struct ocontext *c, int i)
{
context_destroy(&c->context[0]);
context_destroy(&c->context[1]);
if (i == OCON_ISID || i == OCON_FS ||
i == OCON_NETIF || i == OCON_FSUSE)
kfree(c->u.name);
kfree(c);
}
/* /*
* Free any memory allocated by a policy database structure. * Free any memory allocated by a policy database structure.
*/ */
...@@ -423,12 +433,7 @@ void policydb_destroy(struct policydb *p) ...@@ -423,12 +433,7 @@ void policydb_destroy(struct policydb *p)
while (c) { while (c) {
ctmp = c; ctmp = c;
c = c->next; c = c->next;
context_destroy(&ctmp->context[0]); ocontext_destroy(ctmp,i);
context_destroy(&ctmp->context[1]);
if (i == OCON_ISID || i == OCON_FS ||
i == OCON_NETIF || i == OCON_FSUSE)
kfree(ctmp->u.name);
kfree(ctmp);
} }
} }
...@@ -439,9 +444,7 @@ void policydb_destroy(struct policydb *p) ...@@ -439,9 +444,7 @@ void policydb_destroy(struct policydb *p)
while (c) { while (c) {
ctmp = c; ctmp = c;
c = c->next; c = c->next;
context_destroy(&ctmp->context[0]); ocontext_destroy(ctmp,OCON_FSUSE);
kfree(ctmp->u.name);
kfree(ctmp);
} }
gtmp = g; gtmp = g;
g = g->next; g = g->next;
...@@ -762,6 +765,13 @@ static int class_read(struct policydb *p, struct hashtab *h, void *fp) ...@@ -762,6 +765,13 @@ static int class_read(struct policydb *p, struct hashtab *h, void *fp)
goto bad; goto bad;
} }
memset(c, 0, sizeof(*c)); memset(c, 0, sizeof(*c));
if (lc) {
lc->next = c;
} else {
cladatum->constraints = c;
}
buf = next_entry(fp, sizeof(u32)*2); buf = next_entry(fp, sizeof(u32)*2);
if (!buf) if (!buf)
goto bad; goto bad;
...@@ -776,67 +786,50 @@ static int class_read(struct policydb *p, struct hashtab *h, void *fp) ...@@ -776,67 +786,50 @@ static int class_read(struct policydb *p, struct hashtab *h, void *fp)
goto bad; goto bad;
} }
memset(e, 0, sizeof(*e)); memset(e, 0, sizeof(*e));
if (le) {
le->next = e;
} else {
c->expr = e;
}
buf = next_entry(fp, sizeof(u32)*3); buf = next_entry(fp, sizeof(u32)*3);
if (!buf) { if (!buf)
kfree(e);
goto bad; goto bad;
}
e->expr_type = le32_to_cpu(buf[0]); e->expr_type = le32_to_cpu(buf[0]);
e->attr = le32_to_cpu(buf[1]); e->attr = le32_to_cpu(buf[1]);
e->op = le32_to_cpu(buf[2]); e->op = le32_to_cpu(buf[2]);
switch (e->expr_type) { switch (e->expr_type) {
case CEXPR_NOT: case CEXPR_NOT:
if (depth < 0) { if (depth < 0)
kfree(e);
goto bad; goto bad;
}
break; break;
case CEXPR_AND: case CEXPR_AND:
case CEXPR_OR: case CEXPR_OR:
if (depth < 1) { if (depth < 1)
kfree(e);
goto bad; goto bad;
}
depth--; depth--;
break; break;
case CEXPR_ATTR: case CEXPR_ATTR:
if (depth == (CEXPR_MAXDEPTH-1)) { if (depth == (CEXPR_MAXDEPTH-1))
kfree(e);
goto bad; goto bad;
}
depth++; depth++;
break; break;
case CEXPR_NAMES: case CEXPR_NAMES:
if (depth == (CEXPR_MAXDEPTH-1)) { if (depth == (CEXPR_MAXDEPTH-1))
kfree(e);
goto bad; goto bad;
}
depth++; depth++;
if (ebitmap_read(&e->names, fp)) { if (ebitmap_read(&e->names, fp))
kfree(e);
goto bad; goto bad;
}
break; break;
default: default:
kfree(e);
goto bad; goto bad;
break;
}
if (le) {
le->next = e;
} else {
c->expr = e;
} }
le = e; le = e;
} }
if (depth != 0) if (depth != 0)
goto bad; goto bad;
if (lc) {
lc->next = c;
} else {
cladatum->constraints = c;
}
lc = c; lc = c;
} }
...@@ -1331,12 +1324,6 @@ int policydb_read(struct policydb *p, void *fp) ...@@ -1331,12 +1324,6 @@ int policydb_read(struct policydb *p, void *fp)
genfs_p = NULL; genfs_p = NULL;
rc = -EINVAL; rc = -EINVAL;
for (i = 0; i < nel; i++) { for (i = 0; i < nel; i++) {
newgenfs = kmalloc(sizeof(*newgenfs), GFP_KERNEL);
if (!newgenfs) {
rc = -ENOMEM;
goto bad;
}
memset(newgenfs, 0, sizeof(*newgenfs));
buf = next_entry(fp, sizeof(u32)); buf = next_entry(fp, sizeof(u32));
if (!buf) if (!buf)
goto bad; goto bad;
...@@ -1344,9 +1331,17 @@ int policydb_read(struct policydb *p, void *fp) ...@@ -1344,9 +1331,17 @@ int policydb_read(struct policydb *p, void *fp)
buf = next_entry(fp, len); buf = next_entry(fp, len);
if (!buf) if (!buf)
goto bad; goto bad;
newgenfs = kmalloc(sizeof(*newgenfs), GFP_KERNEL);
if (!newgenfs) {
rc = -ENOMEM;
goto bad;
}
memset(newgenfs, 0, sizeof(*newgenfs));
newgenfs->fstype = kmalloc(len + 1,GFP_KERNEL); newgenfs->fstype = kmalloc(len + 1,GFP_KERNEL);
if (!newgenfs->fstype) { if (!newgenfs->fstype) {
rc = -ENOMEM; rc = -ENOMEM;
kfree(newgenfs);
goto bad; goto bad;
} }
memcpy(newgenfs->fstype, buf, len); memcpy(newgenfs->fstype, buf, len);
...@@ -1356,6 +1351,8 @@ int policydb_read(struct policydb *p, void *fp) ...@@ -1356,6 +1351,8 @@ int policydb_read(struct policydb *p, void *fp)
if (strcmp(newgenfs->fstype, genfs->fstype) == 0) { if (strcmp(newgenfs->fstype, genfs->fstype) == 0) {
printk(KERN_ERR "security: dup genfs " printk(KERN_ERR "security: dup genfs "
"fstype %s\n", newgenfs->fstype); "fstype %s\n", newgenfs->fstype);
kfree(newgenfs->fstype);
kfree(newgenfs);
goto bad; goto bad;
} }
if (strcmp(newgenfs->fstype, genfs->fstype) < 0) if (strcmp(newgenfs->fstype, genfs->fstype) < 0)
...@@ -1371,12 +1368,6 @@ int policydb_read(struct policydb *p, void *fp) ...@@ -1371,12 +1368,6 @@ int policydb_read(struct policydb *p, void *fp)
goto bad; goto bad;
nel2 = le32_to_cpu(buf[0]); nel2 = le32_to_cpu(buf[0]);
for (j = 0; j < nel2; j++) { for (j = 0; j < nel2; j++) {
newc = kmalloc(sizeof(*newc), GFP_KERNEL);
if (!newc) {
rc = -ENOMEM;
goto bad;
}
memset(newc, 0, sizeof(*newc));
buf = next_entry(fp, sizeof(u32)); buf = next_entry(fp, sizeof(u32));
if (!buf) if (!buf)
goto bad; goto bad;
...@@ -1384,19 +1375,27 @@ int policydb_read(struct policydb *p, void *fp) ...@@ -1384,19 +1375,27 @@ int policydb_read(struct policydb *p, void *fp)
buf = next_entry(fp, len); buf = next_entry(fp, len);
if (!buf) if (!buf)
goto bad; goto bad;
newc = kmalloc(sizeof(*newc), GFP_KERNEL);
if (!newc) {
rc = -ENOMEM;
goto bad;
}
memset(newc, 0, sizeof(*newc));
newc->u.name = kmalloc(len + 1,GFP_KERNEL); newc->u.name = kmalloc(len + 1,GFP_KERNEL);
if (!newc->u.name) { if (!newc->u.name) {
rc = -ENOMEM; rc = -ENOMEM;
goto bad; goto bad_newc;
} }
memcpy(newc->u.name, buf, len); memcpy(newc->u.name, buf, len);
newc->u.name[len] = 0; newc->u.name[len] = 0;
buf = next_entry(fp, sizeof(u32)); buf = next_entry(fp, sizeof(u32));
if (!buf) if (!buf)
goto bad; goto bad_newc;
newc->v.sclass = le32_to_cpu(buf[0]); newc->v.sclass = le32_to_cpu(buf[0]);
if (context_read_and_validate(&newc->context[0], p, fp)) if (context_read_and_validate(&newc->context[0], p, fp))
goto bad; goto bad_newc;
for (l = NULL, c = newgenfs->head; c; for (l = NULL, c = newgenfs->head; c;
l = c, c = c->next) { l = c, c = c->next) {
if (!strcmp(newc->u.name, c->u.name) && if (!strcmp(newc->u.name, c->u.name) &&
...@@ -1405,13 +1404,14 @@ int policydb_read(struct policydb *p, void *fp) ...@@ -1405,13 +1404,14 @@ int policydb_read(struct policydb *p, void *fp)
printk(KERN_ERR "security: dup genfs " printk(KERN_ERR "security: dup genfs "
"entry (%s,%s)\n", "entry (%s,%s)\n",
newgenfs->fstype, c->u.name); newgenfs->fstype, c->u.name);
goto bad; goto bad_newc;
} }
len = strlen(newc->u.name); len = strlen(newc->u.name);
len2 = strlen(c->u.name); len2 = strlen(c->u.name);
if (len > len2) if (len > len2)
break; break;
} }
newc->next = c; newc->next = c;
if (l) if (l)
l->next = newc; l->next = newc;
...@@ -1425,6 +1425,8 @@ int policydb_read(struct policydb *p, void *fp) ...@@ -1425,6 +1425,8 @@ int policydb_read(struct policydb *p, void *fp)
goto bad; goto bad;
out: out:
return rc; return rc;
bad_newc:
ocontext_destroy(newc,OCON_FSUSE);
bad: bad:
policydb_destroy(p); policydb_destroy(p);
goto out; goto out;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment