From: "Kinney, Michael D" <michael.d.kinney@intel.com>
To: Laszlo Ersek <lersek@redhat.com>,
Sean Brogan <sean.brogan@microsoft.com>,
Bret Barkelew <Bret.Barkelew@microsoft.com>
Cc: "edk2-devel@lists.01.org" <edk2-devel@lists.01.org>,
"Gao, Liming" <liming.gao@intel.com>
Subject: Re: [Patch] MdePkg/BaseSafeIntLib: Add SafeIntLib class and instance
Date: Tue, 13 Feb 2018 16:17:48 +0000 [thread overview]
Message-ID: <E92EE9817A31E24EB0585FDF735412F5B89665C5@ORSMSX113.amr.corp.intel.com> (raw)
In-Reply-To: <868954f3-f368-073c-9e62-d11440e719c9@redhat.com>
+Bret
Mike
> -----Original Message-----
> From: edk2-devel [mailto:edk2-devel-bounces@lists.01.org]
> On Behalf Of Laszlo Ersek
> Sent: Tuesday, February 13, 2018 4:24 AM
> To: Kinney, Michael D <michael.d.kinney@intel.com>; Sean
> Brogan <sean.brogan@microsoft.com>
> Cc: edk2-devel@lists.01.org; Gao, Liming
> <liming.gao@intel.com>
> Subject: Re: [edk2] [Patch] MdePkg/BaseSafeIntLib: Add
> SafeIntLib class and instance
>
> Sean, Michael,
>
> can you please follow up on this?
>
> To clarify, I think this is a serious bug in SafeIntLib,
> dependent on
> what we want to use this library for. As far as I
> understand, SafeIntLib
> intends to centralize integer manipulation / arithmetic,
> so that client
> code need not concern itself with overflow checking and
> such (on the C
> expression level -- it still has to check return
> statuses, of course).
> In other words, undefined behavior related to integer
> arithmetic is
> supposed to be prevented in various modules by moving all
> such
> operations into SafeIntLib, and letting client code use
> SafeIntLib APIs.
>
> However, for this to work, SafeIntLib itself must be 100%
> free of
> undefined behavior. And that's not the case (unless we
> define additional
> guarantees -- on top of ISO C -- for edk2 target
> architectures). Should
> I file a TianoCore BZ? Or is someone already (re)auditing
> the library?
> Or else, is my concern unjustified? Please comment.
>
> Thanks,
> Laszlo
>
> On 02/08/18 01:45, Laszlo Ersek wrote:
> > On 02/08/18 01:32, Laszlo Ersek wrote:
> >> On 12/19/17 20:36, Kinney, Michael D wrote:
> >>> From: Sean Brogan <sean.brogan@microsoft.com>
> >>>
> >>> SafeIntLib provides helper functions to prevent
> integer overflow
> >>> during type conversion, addition, subtraction, and
> multiplication.
> >>
> >> I clearly cannot review such a huge patch, but I've
> noticed something
> >> and would like to ask for clarification:
> >>
> >>> +/**
> >>> + INT64 Subtraction
> >>> +
> >>> + Performs the requested operation using the input
> parameters into a value
> >>> + specified by Result type and stores the converted
> value into the caller
> >>> + allocated output buffer specified by Result. The
> caller must pass in a
> >>> + Result buffer that is at least as large as the
> Result type.
> >>> +
> >>> + If Result is NULL, RETURN_INVALID_PARAMETER is
> returned.
> >>> +
> >>> + If the requested operation results in an overflow
> or an underflow condition,
> >>> + then Result is set to INT64_ERROR and
> RETURN_BUFFER_TOO_SMALL is returned.
> >>> +
> >>> + @param[in] Minuend A number from which
> another is to be subtracted.
> >>> + @param[in] Subtrahend A number to be subtracted
> from another
> >>> + @param[out] Result Pointer to the result of
> subtraction
> >>> +
> >>> + @retval RETURN_SUCCESS Successful
> subtraction
> >>> + @retval RETURN_BUFFER_TOO_SMALL Underflow
> >>> + @retval RETURN_INVALID_PARAMETER Result is NULL
> >>> +**/
> >>> +RETURN_STATUS
> >>> +EFIAPI
> >>> +SafeInt64Sub (
> >>> + IN INT64 Minuend,
> >>> + IN INT64 Subtrahend,
> >>> + OUT INT64 *Result
> >>> + )
> >>> +{
> >>> + RETURN_STATUS Status;
> >>> + INT64 SignedResult;
> >>> +
> >>> + if (Result == NULL) {
> >>> + return RETURN_INVALID_PARAMETER;
> >>> + }
> >>> +
> >>> + SignedResult = Minuend - Subtrahend;
> >>> +
> >>> + //
> >>> + // Subtracting a positive number from a positive
> number never overflows.
> >>> + // Subtracting a negative number from a negative
> number never overflows.
> >>> + // If you subtract a negative number from a
> positive number, you expect a positive result.
> >>> + // If you subtract a positive number from a
> negative number, you expect a negative result.
> >>> + // Overflow if inputs vary in sign and the output
> does not have the same sign as the first input.
> >>> + //
> >>> + if (((Minuend < 0) != (Subtrahend < 0)) &&
> >>> + ((Minuend < 0) != (SignedResult < 0))) {
> >>> + *Result = INT64_ERROR;
> >>> + Status = RETURN_BUFFER_TOO_SMALL;
> >>> + } else {
> >>> + *Result = SignedResult;
> >>> + Status = RETURN_SUCCESS;
> >>> + }
> >>> +
> >>> + return Status;
> >>> +}
> >>
> >> Is our goal to
> >>
> >> (a) catch overflows before the caller goes wrong due
> to them, or
> >> (b) completely prevent undefined behavior from
> happening, even inside
> >> SafeInt64Sub()?
> >>
> >> The above implementation may be good for (a), but it's
> not correct for
> >> (b). The
> >>
> >> SignedResult = Minuend - Subtrahend;
> >>
> >> subtraction invokes undefined behavior if the result
> cannot be
> >> represented [*]; the rest of the code cannot help.
> >>
> >> Now if we say that such subtractions always occur
> according to the
> >> "usual two's complement definition", on all
> architectures that edk2
> >> targets, and we're sure that no compiler or analysis
> tool will flag --
> >> or exploit -- the UB either, then the code is fine;
> meaning our choice
> >> is (a).
> >>
> >> But, if (b) is our goal, I would replace the current
> error condition with:
> >>
> >> (((Subtrahend > 0) && (Minuend < MIN_INT64 +
> Subtrahend)) ||
> >> ((Subtrahend < 0) && (Minuend > MAX_INT64 +
> Subtrahend)))
> >
> > To clarify, I wouldn't just replace the error
> condition. In addition to
> > that, I would remove the SignedResult helper variable
> (together with the
> > current subtraction), and calculate & assign
> >
> > *Result = Minuend - Subtrahend;
> >
> > only after the error condition fails (i.e. the
> subtraction is safe).
> >
> > Thanks,
> > Laszlo
> >
> >
> >> Justification:
> >>
> >> * Subtrahend==0 can never cause overflow
> >>
> >> * Subtrahend>0 can only cause overflow at the negative
> end, so check
> >> that: (Minuend - Subtrahend < MIN_INT64),
> mathematically speaking.
> >> In order to write that down in C, add Subtrahend (a
> positive value)
> >> to both sides, yielding (Minuend < MIN_INT64 +
> Subtrahend). Here,
> >> (MIN_INT64 + Subtrahend) will never go out of range,
> because
> >> Subtrahend is positive, and (MIN_INT64 + MAX_INT64)
> is representable.
> >>
> >> * Subtrahend<0 can only cause overflow at the positive
> end, so check
> >> that: (Minuend - Subtrahend > MAX_INT64),
> mathematically speaking.
> >> In order to write that down in C, add Subtrahend (a
> negative value)
> >> to both sides, yielding (Minuend > MAX_INT64 +
> Subtrahend). Here,
> >> (MAX_INT64 + Subtrahend) will never go out of range,
> because
> >> Subtrahend is negative, and (MAX_INT64 + MIN_INT64)
> is representable.
> >>
> >> (
> >>
> >> [*] ISO C99 section 6.5 Expressions, p5: "If an
> exceptional condition
> >> occurs during the evaluation of an expression (that
> is, if the result is
> >> not mathematically defined or not in the range of
> representable values
> >> for its type), the behavior is undefined."
> >>
> >> Section 6.2.5 Types, p9 only exempts unsigned
> integers, "A computation
> >> involving unsigned operands can never overflow,
> because a result that
> >> cannot be represented by the resulting unsigned
> integer type is reduced
> >> modulo the number that is one greater than the largest
> value that can be
> >> represented by the resulting type."
> >>
> >> Note that this is different from conversion, where the
> computation first
> >> succeeds (= we have a value), and then the value is
> converted to a type
> >> that causes truncation: section 6.3.1.3 Signed and
> unsigned integers,
> >> p3: "Otherwise, the new type is signed and the value
> cannot be
> >> represented in it; either the result is
> implementation-defined or an
> >> implementation-defined signal is raised."
> >>
> >> In the code above, the expression (Minuend -
> Subtrahend) can invoke
> >> undefined behavior, there is no conversion (not even
> as part of the
> >> assignment to SignedResult).
> >>
> >> )
> >>
> >> Thanks,
> >> Laszlo
> >> _______________________________________________
> >> edk2-devel mailing list
> >> edk2-devel@lists.01.org
> >> https://lists.01.org/mailman/listinfo/edk2-devel
> >>
> >
> > _______________________________________________
> > edk2-devel mailing list
> > edk2-devel@lists.01.org
> > https://lists.01.org/mailman/listinfo/edk2-devel
> >
>
> _______________________________________________
> edk2-devel mailing list
> edk2-devel@lists.01.org
> https://lists.01.org/mailman/listinfo/edk2-devel
next prev parent reply other threads:[~2018-02-13 16:11 UTC|newest]
Thread overview: 16+ messages / expand[flat|nested] mbox.gz Atom feed top
2017-12-19 19:36 [Patch] MdePkg/BaseSafeIntLib: Add SafeIntLib class and instance Kinney, Michael D
2018-01-18 8:09 ` Sean Brogan
2018-01-19 7:48 ` Gao, Liming
2018-02-08 0:32 ` Laszlo Ersek
2018-02-08 0:45 ` Laszlo Ersek
2018-02-13 12:23 ` Laszlo Ersek
2018-02-13 16:17 ` Kinney, Michael D [this message]
2018-02-13 16:56 ` Bret Barkelew
2018-02-13 17:15 ` Andrew Fish
2018-02-13 17:55 ` Laszlo Ersek
2018-02-13 17:29 ` Laszlo Ersek
2018-02-13 18:19 ` Bret Barkelew
2018-02-13 17:18 ` Ard Biesheuvel
2018-02-13 17:51 ` Laszlo Ersek
2018-02-13 17:55 ` Ard Biesheuvel
2018-02-13 18:03 ` Laszlo Ersek
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-list from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=E92EE9817A31E24EB0585FDF735412F5B89665C5@ORSMSX113.amr.corp.intel.com \
--to=devel@edk2.groups.io \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox