Re: [PATCH] libsepol: Prevent OOB access of array when copying scope information
Stephen Smalley <[email protected]>
| Newsgroups | org.kernel.vger.selinux |
|---|---|
| Message-ID | <CAEjxPJ5Mcz8ECLWS6mmjfbx+YsBF2tPNZVVyeGRjhQFMN-VN4w@mail.gmail.com> |
On Fri, Jul 17, 2026 at 1:35 PM James Carter <[email protected]> wrote: > > The function copy_scope_index() in link.c copies information about > what declarations are in scope for the current block. This is tracked > in the "scope" field of the scope_index struct in an array of ebitmaps. > A second field called "class_perms_map" is used to track which > permissions are in scope for each class. The "class_perms_len" field is > the length of the permissions array. As the function is copying scoping > information from the module to the base policy, the index values are > translated as well. When the information for classes is translated and > copied the largest new index value for a class is determined. This value > is used to allocate the class_perms_map array. For each source class in > that array, the bits in the source ebitmap are translated and set in the > destination bitmap. > > A maliciously crafted policy could set permissions in the module's > class_perms_map for a class that is not in scope. If that class has > a new index that is greater than the largest index of a valid class, > then there will be an OOB write when copying the class_perms_map. > > When copying the class_perms_map, check that the index is not going to > result in an OOB write when converting. In addition, if there were no > classes, then just set class_perms_map to NULL and return. Also, don't > bother trying to copy permissions if the ebitmap is empty. Finally, > just use array notation when copying the scope and class_perms_map > data since they are both arrays of ebitmaps. > > Signed-off-by: James Carter <[email protected]> Acked-by: Stephen Smalley <[email protected]> > --- > libsepol/src/link.c | 27 +++++++++++++++++++-------- > 1 file changed, 19 insertions(+), 8 deletions(-) > > diff --git a/libsepol/src/link.c b/libsepol/src/link.c > index 70742fc8..868e0a7a 100644 > --- a/libsepol/src/link.c > +++ b/libsepol/src/link.c > @@ -1652,8 +1652,9 @@ static int copy_scope_index(scope_index_t *src, scope_index_t *dest, > ebitmap_node_t *node; > /* copy the scoping information for this avrule decl block */ > for (i = 0; i < SYM_NUM; i++) { > - ebitmap_t *srcmap = src->scope + i; > - ebitmap_t *destmap = dest->scope + i; > + ebitmap_t *srcmap = &src->scope[i]; > + ebitmap_t *destmap = &dest->scope[i]; > + > if (copy_callback_f[i] == NULL) { > continue; > } > @@ -1672,18 +1673,28 @@ static int copy_scope_index(scope_index_t *src, scope_index_t *dest, > } > } > > + dest->class_perms_len = largest_mapped_class_value; > + if (largest_mapped_class_value == 0) { > + dest->class_perms_map = NULL; > + return 0; > + } > + > /* next copy the enabled permissions data */ > if ((dest->class_perms_map = calloc(largest_mapped_class_value, > sizeof(*dest->class_perms_map))) == > NULL) { > goto cleanup; > } > - dest->class_perms_len = largest_mapped_class_value; > - for (i = 0; i < src->class_perms_len; i++) { > - const ebitmap_t *srcmap = src->class_perms_map + i; > - ebitmap_t *destmap = > - dest->class_perms_map + module->map[SYM_CLASSES][i] - 1; > > + for (i = 0; i < src->class_perms_len; i++) { > + const ebitmap_t *srcmap = &src->class_perms_map[i]; > + ebitmap_t *destmap; > + if (ebitmap_is_empty(srcmap)) > + continue; > + j = module->map[SYM_CLASSES][i] - 1; > + if (j >= largest_mapped_class_value) > + goto cleanup; > + destmap = &dest->class_perms_map[j]; > if (ebitmap_convert(srcmap, destmap, module->perm_map[i])) > goto cleanup; > } > @@ -1691,7 +1702,7 @@ static int copy_scope_index(scope_index_t *src, scope_index_t *dest, > return 0; > > cleanup: > - ERR(state->handle, "Out of memory!"); > + ERR(state->handle, "Error copying scope index"); > return -1; > } > > -- > 2.55.0 >