Re: [PATCH 1/6] libsepol/cil: fix out-of-bound read of a file context pattern ending with "\"

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Tue, Mar 16, 2021 at 2:34 PM James Carter <jwcart2@xxxxxxxxx> wrote:
>
> On Mon, Mar 15, 2021 at 5:34 PM Nicolas Iooss <nicolas.iooss@xxxxxxx> wrote:
> >
> > On Mon, Mar 15, 2021 at 10:02 PM James Carter <jwcart2@xxxxxxxxx> wrote:
> > >
> > > On Sun, Mar 14, 2021 at 4:23 PM Nicolas Iooss <nicolas.iooss@xxxxxxx> wrote:
> > > >
> > > > OSS-Fuzz found a Heap-buffer-overflow in the CIL compiler when trying to
> > > > compile the following policy:
> > > >
> > > >     (sid SID)
> > > >     (sidorder(SID))
> > > >     (filecon "\" any ())
> > > >     (filecon "" any ())
> > > >
> > > > When cil_post_fc_fill_data() processes "\", it goes beyond the NUL
> > > > terminator of the string. Fix this by returning when '\0' is read after
> > > > a backslash.
> > > >
> > > > Fixes: https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=28484
> > > > Signed-off-by: Nicolas Iooss <nicolas.iooss@xxxxxxx>
> > > > ---
> > > >  libsepol/cil/src/cil_post.c | 6 ++++++
> > > >  1 file changed, 6 insertions(+)
> > > >
> > > > diff --git a/libsepol/cil/src/cil_post.c b/libsepol/cil/src/cil_post.c
> > > > index a55df1ea5bb0..5f9cf4efd242 100644
> > > > --- a/libsepol/cil/src/cil_post.c
> > > > +++ b/libsepol/cil/src/cil_post.c
> > > > @@ -179,6 +179,12 @@ void cil_post_fc_fill_data(struct fc_data *fc, char *path)
> > > >                         break;
> > > >                 case '\\':
> > > >                         c++;
> > >
> > > The patch below is fine, but I can't figure out the reason for the
> > > line above. I guess it means that fc->str_len++ will be skipped, but
> > > if that is the purpose, it is not very clear. Does anyone know if this
> > > is correct?
> >
> > Which line? "break;" ? In case you and/or other people are confused
> > about the code in cil_post_fc_fill_data, this "break;" exits the
> > switch(path[c]) block but still executes the lines right after
> > ("fc->str_len++;" and "c++;"):
> >
>
> Sorry, I wasn't very clear. I am wondering what the "c++" is doing
> here because after the switch statement there is another "c++" (after
> "fc->str_length++"), so this skips the character after the "/". Why
> would one do that? My only thought is that maybe "/" is not supposed
> to count towards the string length and the author thought not counting
> the next character works just as well? Except, of course, it doesn't
> if there is no next character.

The matched character is a backslash ("\"), not a slash ("/"). I
understand that this implementation of "c++; without fc->str_len++;
nor fc->stem_len++;" is there in order to count sequences such as
"\(", "\.", "\["... as a single character. More precisely, when for
example the two-character sequence "\." is encountered in a path
(which happens often, as it is the way to escape dots in file context
patterns):

* c is increased twice ("c++;" in present twice in the while loop), in
order to go to the character next to the sequence ;
* fc->str_len is increased once (this sequence counts as a single
non-special character) ;
* if fc->meta is false (i.e. if no meta character such as ".", "(",
"["... has been encountered yet), fc->stem_len is increased once (this
sequence counts as a single non-special character in the "stem" of the
path)

The code I added in my patch made fc->stem_len increase when a path
ends with "\" (the character after the backslash character is a NUL
string terminator), before exiting cil_post_fc_fill_data. Now I am
wondering whether fc->str_len should also be increased, in order to
"count the backslash". In fact, finishing a path pattern with an
incomplete escape sequence is weird and I do not precisely know the
semantic of the length counters in such a case. What do you think?

Nicolas

> > while (path[c] != '\0') {
> >     switch (path[c]) {
> >     case '.':
> >     /* ... */
> >     case '{':
> >         fc->meta = 1;
> >         break;
> >     case '\\':
> >         c++;
> >         /* FALLTHRU */
> >     default:
> > // This code is executed for every character before a special one
> > // (while "meta" is false)
> > // and "\c" counts as a single character, for c being anything.
> >         if (!fc->meta) {
> >             fc->stem_len++;
> >         }
> >         break;
> >     }
> > // These lines are executed for every character.
> > // "str_len" counts the number of unescaped characters
> > // ("\c" counts as a single character)
> >     fc->str_len++;
> >     c++;
> > }
> >
> > In my opinion, the code looks correct, but this could be verified with
> > a new unit test which could computes str_len and stem_len for some
> > strings.
> >
> > Cheers,
> > Nicolas
> >




[Index of Archives]     [Selinux Refpolicy]     [Linux SGX]     [Fedora Users]     [Fedora Desktop]     [Yosemite Photos]     [Yosemite Camping]     [Yosemite Campsites]     [KDE Users]     [Gnome Users]

  Powered by Linux