From: Ard Biesheuvel <ard.biesheuvel@linaro.org>
To: "Kinney, Michael D" <michael.d.kinney@intel.com>
Cc: Laszlo Ersek <lersek@redhat.com>,
Sean Brogan <sean.brogan@microsoft.com>,
Bret Barkelew <Bret.Barkelew@microsoft.com>,
"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 17:18:34 +0000 [thread overview]
Message-ID: <CAKv+Gu9UByvGi_T+64c=GSHUQuT9x8XHw+AQWrF1Coruwr7W6w@mail.gmail.com> (raw)
In-Reply-To: <E92EE9817A31E24EB0585FDF735412F5B89665C5@ORSMSX113.amr.corp.intel.com>
On 13 February 2018 at 16:17, Kinney, Michael D
<michael.d.kinney@intel.com> wrote:
> +Bret
>
> Mike
>
Why has this patch been submitted if there are unanswered questions of
such a fundamental nature?
Could someone please revert it until there is agreement about its
inclusion (and in which form)?
>> -----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
> _______________________________________________
> 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 17:12 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
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 [this message]
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='CAKv+Gu9UByvGi_T+64c=GSHUQuT9x8XHw+AQWrF1Coruwr7W6w@mail.gmail.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