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 Wed, Mar 17, 2021 at 3:45 AM Nicolas Iooss <nicolas.iooss@xxxxxxx> wrote:
>
> 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

I am an idiot. The code makes a lot more sense now. You only want to
count an escaped character as one character.

> 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?
>

I think that it is an invalid path, so maybe I need to add some sort
of verification to the path at some point.

I finally found the source of this code in
refpolicy/support/fc_sort.py where the function compute_diffdata() is
very similar. That function would increment str_len in this case, so
to be consistent with that fc->str_len should also be incremented.

Jim


> 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