public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: Laszlo Ersek <lersek@redhat.com>
To: edk2-devel-01 <edk2-devel@lists.01.org>
Cc: Bret Barkelew <Bret.Barkelew@microsoft.com>,
	Liming Gao <liming.gao@intel.com>,
	Michael D Kinney <michael.d.kinney@intel.com>,
	Sean Brogan <sean.brogan@microsoft.com>
Subject: [PATCH 1/4] MdePkg/BaseSafeIntLib: fix undefined behavior in SafeInt64Sub()
Date: Thu, 15 Feb 2018 19:36:35 +0100	[thread overview]
Message-ID: <20180215183638.18578-2-lersek@redhat.com> (raw)
In-Reply-To: <20180215183638.18578-1-lersek@redhat.com>

The subtraction in the assignment

  SignedResult = Minuend - Subtrahend;

is performed with unchecked INT64 operands. According to ISO C, if the
mathematical result of signed integer subtraction cannot be represented in
the result type, the behavior is undefined. (Refer to ISO C99 6.5p5.
6.2.5p9 only exempts unsigned integers, and 6.3.1.3p3 does not apply
because it treats the conversion of integers that have been successfully
evaluated first.)

Replace the after-the-fact result checking with checks on the operands,
and only perform the subtraction if it is safe.

Cc: Bret Barkelew <Bret.Barkelew@microsoft.com>
Cc: Liming Gao <liming.gao@intel.com>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Sean Brogan <sean.brogan@microsoft.com>
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Laszlo Ersek <lersek@redhat.com>
---
 MdePkg/Library/BaseSafeIntLib/SafeIntLib.c | 50 +++++++++++++++-----
 1 file changed, 39 insertions(+), 11 deletions(-)

diff --git a/MdePkg/Library/BaseSafeIntLib/SafeIntLib.c b/MdePkg/Library/BaseSafeIntLib/SafeIntLib.c
index d846160ba0d1..8e857927b067 100644
--- a/MdePkg/Library/BaseSafeIntLib/SafeIntLib.c
+++ b/MdePkg/Library/BaseSafeIntLib/SafeIntLib.c
@@ -3837,27 +3837,55 @@ SafeInt64Sub (
   )
 {
   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.
+  // * A Subtrahend of zero can never cause underflow or overflow.
   //
-  if (((Minuend < 0) != (Subtrahend < 0)) &&
-      ((Minuend < 0) != (SignedResult < 0))) {
+  // * A positive Subtrahend can only cause underflow. The underflow condition
+  //   is:
+  //
+  //     (Minuend - Subtrahend) < MIN_INT64
+  //
+  //   Adding Subtrahend to both sides yields
+  //
+  //     Minuend < (MIN_INT64 + Subtrahend)
+  //
+  //   This condition can be coded directly in C because the RHS will neither
+  //   underflow nor overflow. That is due to the starting condition:
+  //
+  //     0 < Subtrahend <= MAX_INT64
+  //
+  //   Adding MIN_INT64 to all three sides yields
+  //
+  //     MIN_INT64 < (MIN_INT64 + Subtrahend) <= (MIN_INT64 + MAX_INT64) = -1
+  //
+  // * A negative Subtrahend can only cause overflow. The overflow condition is
+  //
+  //     (Minuend - Subtrahend) > MAX_INT64
+  //
+  //   Adding Subtrahend to both sides yields
+  //
+  //     Minuend > (MAX_INT64 + Subtrahend)
+  //
+  //   This condition can be coded directly in C because the RHS will neither
+  //   underflow nor overflow. That is due to the starting condition:
+  //
+  //     MIN_INT64 <= Subtrahend < 0
+  //
+  //   Adding MAX_INT64 to all three sides yields
+  //
+  //     -1 = (MAX_INT64 + MIN_INT64) <= (MAX_INT64 + Subtrahend) < MAX_INT64
+  //
+  if (((Subtrahend > 0) && (Minuend < (MIN_INT64 + Subtrahend))) ||
+      ((Subtrahend < 0) && (Minuend > (MAX_INT64 + Subtrahend)))) {
     *Result = INT64_ERROR;
     Status = RETURN_BUFFER_TOO_SMALL;
   } else {
-    *Result = SignedResult;
+    *Result = Minuend - Subtrahend;
     Status = RETURN_SUCCESS;
   }
 
-- 
2.14.1.3.gb7cf6e02401b




  reply	other threads:[~2018-02-15 18:30 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-02-15 18:36 [PATCH 0/4] MdePkg/BaseSafeIntLib: fix undefined behavior in INT64 Sub/Add/Mult Laszlo Ersek
2018-02-15 18:36 ` Laszlo Ersek [this message]
2018-02-15 18:36 ` [PATCH 2/4] MdePkg/BaseSafeIntLib: fix undefined behavior in SafeInt64Add() Laszlo Ersek
2018-02-15 18:36 ` [PATCH 3/4] MdePkg/BaseSafeIntLib: clean up parentheses in MIN_INT64_MAGNITUDE Laszlo Ersek
2018-02-15 18:36 ` [PATCH 4/4] MdePkg/BaseSafeIntLib: fix undefined behavior in SafeInt64Mult() Laszlo Ersek
2018-02-16 11:28 ` [PATCH 0/4] MdePkg/BaseSafeIntLib: fix undefined behavior in INT64 Sub/Add/Mult Ard Biesheuvel
2018-02-16 20:44   ` Laszlo Ersek
2018-02-16 18:11 ` Kinney, Michael D
2018-02-16 20:49   ` Laszlo Ersek
2018-02-17  3:07     ` Kinney, Michael D
2018-02-21 11:00       ` Laszlo Ersek
2018-02-21 18:10         ` Ard Biesheuvel

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=20180215183638.18578-2-lersek@redhat.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