libselinux: rework selabel_subs_init() to avoid use-after-free

In selabel_subs_init(), when digest_add_specfile() fails, the returned
value is a pointer to data which has been freed (because label "err"
frees variable "sub" which is equals to the returned variable, "list").

Moreover since since commit fd56c5230c ("Separate out the calling of
local subs and dist subs in selabel_sub"), argument "list" of
selabel_subs_init() has always been NULL (rec->subs and rec->dist_subs
are both initialized to NULL in selabel_open() before
selabel_file_init() is called).

Drop selabel_file_init()'s "list" argument and free all the list items
which have been allocated in this function, when the code encounters an
error.

Signed-off-by: Nicolas Iooss <nicolas.iooss@m4x.org>
This commit is contained in:
Nicolas Iooss 2017-05-17 22:51:45 +02:00 committed by Stephen Smalley
parent 58962eb3d8
commit 55fe40ac77
3 changed files with 15 additions and 10 deletions

View File

@ -92,12 +92,11 @@ static char *selabel_sub(struct selabel_sub *ptr, const char *src)
}
struct selabel_sub *selabel_subs_init(const char *path,
struct selabel_sub *list,
struct selabel_digest *digest)
struct selabel_digest *digest)
{
char buf[1024];
FILE *cfg = fopen(path, "re");
struct selabel_sub *sub = NULL;
struct selabel_sub *list = NULL, *sub = NULL;
struct stat sb;
if (!cfg)
@ -146,6 +145,7 @@ struct selabel_sub *selabel_subs_init(const char *path,
sub->slen = strlen(src);
sub->next = list;
list = sub;
sub = NULL;
}
if (digest_add_specfile(digest, cfg, NULL, sb.st_size, path) < 0)
@ -158,6 +158,14 @@ err:
if (sub)
free(sub->src);
free(sub);
while (list) {
sub = list->next;
free(list->src);
free(list->dst);
free(list);
list = sub;
}
list = NULL;
goto out;
}

View File

@ -589,17 +589,15 @@ static int init(struct selabel_handle *rec, const struct selinux_opt *opts,
if (!path) {
rec->dist_subs =
selabel_subs_init(selinux_file_context_subs_dist_path(),
rec->dist_subs, rec->digest);
rec->digest);
rec->subs = selabel_subs_init(selinux_file_context_subs_path(),
rec->subs, rec->digest);
rec->digest);
path = selinux_file_context_path();
} else {
snprintf(subs_file, sizeof(subs_file), "%s.subs_dist", path);
rec->dist_subs = selabel_subs_init(subs_file, rec->dist_subs,
rec->digest);
rec->dist_subs = selabel_subs_init(subs_file, rec->digest);
snprintf(subs_file, sizeof(subs_file), "%s.subs", path);
rec->subs = selabel_subs_init(subs_file, rec->subs,
rec->digest);
rec->subs = selabel_subs_init(subs_file, rec->digest);
}
#endif

View File

@ -76,7 +76,6 @@ extern int digest_add_specfile(struct selabel_digest *digest, FILE *fp,
extern void digest_gen_hash(struct selabel_digest *digest);
extern struct selabel_sub *selabel_subs_init(const char *path,
struct selabel_sub *list,
struct selabel_digest *digest);
struct selabel_lookup_rec {