/** @file This library provides helper functions to prevent integer overflow during type conversion, addition, subtraction, and multiplication. Copyright (c) 2017, Microsoft Corporation All rights reserved. SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include <Base.h> #include <Library/SafeIntLib.h> /** INT32 -> UINTN conversion Converts the value specified by Operand to 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 conversion results in an overflow or an underflow condition, then Result is set to UINTN_ERROR and RETURN_BUFFER_TOO_SMALL is returned. @param[in] Operand Operand to be converted to new type @param[out] Result Pointer to the result of conversion @retval RETURN_SUCCESS Successful conversion @retval RETURN_BUFFER_TOO_SMALL Overflow @retval RETURN_INVALID_PARAMETER Result is NULL **/ RETURN_STATUS EFIAPI SafeInt32ToUintn ( IN INT32 Operand, OUT UINTN *Result ) { if (sizeof (UINTN) == sizeof (UINT32)) { return SafeInt32ToUint32 (Operand, (UINT32 *)Result); } return SafeInt32ToUint64 (Operand, (UINT64 *) Result); } /** UINT32 -> INTN conversion Converts the value specified by Operand to 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 conversion results in an overflow or an underflow condition, then Result is set to INTN_ERROR and RETURN_BUFFER_TOO_SMALL is returned. @param[in] Operand Operand to be converted to new type @param[out] Result Pointer to the result of conversion @retval RETURN_SUCCESS Successful conversion @retval RETURN_BUFFER_TOO_SMALL Overflow @retval RETURN_INVALID_PARAMETER Result is NULL **/ RETURN_STATUS EFIAPI SafeUint32ToIntn ( IN UINT32 Operand, OUT INTN *Result ) { if (Result == NULL) { return RETURN_INVALID_PARAMETER; } if (sizeof (UINTN) == sizeof (UINT32)) { return SafeUint32ToInt32 (Operand, (INT32 *)Result); } *Result = Operand; return RETURN_SUCCESS; } /** INTN -> INT32 conversion Converts the value specified by Operand to 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 conversion results in an overflow or an underflow condition, then Result is set to INT32_ERROR and RETURN_BUFFER_TOO_SMALL is returned. @param[in] Operand Operand to be converted to new type @param[out] Result Pointer to the result of conversion @retval RETURN_SUCCESS Successful conversion @retval RETURN_BUFFER_TOO_SMALL Overflow @retval RETURN_INVALID_PARAMETER Result is NULL **/ RETURN_STATUS EFIAPI SafeIntnToInt32 ( IN INTN Operand, OUT INT32 *Result ) { if (Result == NULL) { return RETURN_INVALID_PARAMETER; } if (sizeof (UINTN) == sizeof (UINT32)) { *Result = (INT32)Operand; return RETURN_SUCCESS; } return SafeInt64ToInt32 ((INT64) Operand, Result); } /** INTN -> UINT32 conversion Converts the value specified by Operand to 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 conversion results in an overflow or an underflow condition, then Result is set to UINT32_ERROR and RETURN_BUFFER_TOO_SMALL is returned. @param[in] Operand Operand to be converted to new type @param[out] Result Pointer to the result of conversion @retval RETURN_SUCCESS Successful conversion @retval RETURN_BUFFER_TOO_SMALL Overflow @retval RETURN_INVALID_PARAMETER Result is NULL **/ RETURN_STATUS EFIAPI SafeIntnToUint32 ( IN INTN Operand, OUT UINT32 *Result ) { RETURN_STATUS Status; if (Result == NULL) { return RETURN_INVALID_PARAMETER; } if (sizeof (UINTN) == sizeof (UINT32)) { if (Operand >= 0) { *Result = (UINT32)Operand; Status = RETURN_SUCCESS; } else { *Result = UINT32_ERROR; Status = RETURN_BUFFER_TOO_SMALL; } return Status; } return SafeInt64ToUint32 ((INT64)Operand, Result); } /** UINTN -> UINT32 conversion Converts the value specified by Operand to 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 conversion results in an overflow or an underflow condition, then Result is set to UINT32_ERROR and RETURN_BUFFER_TOO_SMALL is returned. @param[in] Operand Operand to be converted to new type @param[out] Result Pointer to the result of conversion @retval RETURN_SUCCESS Successful conversion @retval RETURN_BUFFER_TOO_SMALL Overflow @retval RETURN_INVALID_PARAMETER Result is NULL **/ RETURN_STATUS EFIAPI SafeUintnToUint32 ( IN UINTN Operand, OUT UINT32 *Result ) { if (Result == NULL) { return RETURN_INVALID_PARAMETER; } if (sizeof (UINTN) == sizeof (UINT32)) { *Result = (UINT32)Operand; return RETURN_SUCCESS; } return SafeUint64ToUint32 ((UINT64)Operand, Result); } /** UINTN -> INT64 conversion Converts the value specified by Operand to 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 conversion results in an overflow or an underflow condition, then Result is set to INT64_ERROR and RETURN_BUFFER_TOO_SMALL is returned. @param[in] Operand Operand to be converted to new type @param[out] Result Pointer to the result of conversion @retval RETURN_SUCCESS Successful conversion @retval RETURN_BUFFER_TOO_SMALL Overflow @retval RETURN_INVALID_PARAMETER Result is NULL **/ RETURN_STATUS EFIAPI SafeUintnToInt64 ( IN UINTN Operand, OUT INT64 *Result ) { if (Result == NULL) { return RETURN_INVALID_PARAMETER; } if (sizeof (UINTN) == sizeof (UINT32)) { *Result = (INT64)Operand; return RETURN_SUCCESS; } return SafeUint64ToInt64 ((UINT64)Operand, Result); } /** INT64 -> INTN conversion Converts the value specified by Operand to 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 conversion results in an overflow or an underflow condition, then Result is set to INTN_ERROR and RETURN_BUFFER_TOO_SMALL is returned. @param[in] Operand Operand to be converted to new type @param[out] Result Pointer to the result of conversion @retval RETURN_SUCCESS Successful conversion @retval RETURN_BUFFER_TOO_SMALL Overflow @retval RETURN_INVALID_PARAMETER Result is NULL **/ RETURN_STATUS EFIAPI SafeInt64ToIntn ( IN INT64 Operand, OUT INTN *Result ) { if (Result == NULL) { return RETURN_INVALID_PARAMETER; } if (sizeof (UINTN) == sizeof (UINT32)) { return SafeInt64ToInt32 (Operand, (INT32 *)Result); } *Result = (INTN)Operand; return RETURN_SUCCESS; } /** INT64 -> UINTN conversion Converts the value specified by Operand to 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 conversion results in an overflow or an underflow condition, then Result is set to UINTN_ERROR and RETURN_BUFFER_TOO_SMALL is returned. @param[in] Operand Operand to be converted to new type @param[out] Result Pointer to the result of conversion @retval RETURN_SUCCESS Successful conversion @retval RETURN_BUFFER_TOO_SMALL Overflow @retval RETURN_INVALID_PARAMETER Result is NULL **/ RETURN_STATUS EFIAPI SafeInt64ToUintn ( IN INT64 Operand, OUT UINTN *Result ) { if (sizeof (UINTN) == sizeof (UINT32)) { return SafeInt64ToUint32 (Operand, (UINT32 *)Result); } return SafeInt64ToUint64 (Operand, (UINT64 *)Result); } /** UINT64 -> UINTN conversion Converts the value specified by Operand to 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 conversion results in an overflow or an underflow condition, then Result is set to UINTN_ERROR and RETURN_BUFFER_TOO_SMALL is returned. @param[in] Operand Operand to be converted to new type @param[out] Result Pointer to the result of conversion @retval RETURN_SUCCESS Successful conversion @retval RETURN_BUFFER_TOO_SMALL Overflow @retval RETURN_INVALID_PARAMETER Result is NULL **/ RETURN_STATUS EFIAPI SafeUint64ToUintn ( IN UINT64 Operand, OUT UINTN *Result ) { if (Result == NULL) { return RETURN_INVALID_PARAMETER; } if (sizeof (UINTN) == sizeof (UINT32)) { return SafeUint64ToUint32 ((UINT64) Operand, (UINT32 *)Result); } *Result = Operand; return RETURN_SUCCESS; } /** UINTN addition 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 UINTN_ERROR and RETURN_BUFFER_TOO_SMALL is returned. @param[in] Augend A number to which addend will be added @param[in] Addend A number to be added to another @param[out] Result Pointer to the result of addition @retval RETURN_SUCCESS Successful addition @retval RETURN_BUFFER_TOO_SMALL Overflow @retval RETURN_INVALID_PARAMETER Result is NULL **/ RETURN_STATUS EFIAPI SafeUintnAdd ( IN UINTN Augend, IN UINTN Addend, OUT UINTN *Result ) { RETURN_STATUS Status; if (Result == NULL) { return RETURN_INVALID_PARAMETER; } if (sizeof (UINTN) == sizeof (UINT32)) { if ((UINT32)(Augend + Addend) >= Augend) { *Result = (Augend + Addend); Status = RETURN_SUCCESS; } else { *Result = UINTN_ERROR; Status = RETURN_BUFFER_TOO_SMALL; } return Status; } return SafeUint64Add ((UINT64)Augend, (UINT64)Addend, (UINT64 *)Result); } /** UINTN 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 UINTN_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 SafeUintnSub ( IN UINTN Minuend, IN UINTN Subtrahend, OUT UINTN *Result ) { RETURN_STATUS Status; if (Result == NULL) { return RETURN_INVALID_PARAMETER; } if (sizeof (UINTN) == sizeof (UINT32)) { if (Minuend >= Subtrahend) { *Result = (Minuend - Subtrahend); Status = RETURN_SUCCESS; } else { *Result = UINTN_ERROR; Status = RETURN_BUFFER_TOO_SMALL; } return Status; } return SafeUint64Sub ((UINT64)Minuend, (UINT64)Subtrahend, (UINT64 *)Result); } /** UINTN multiplication 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 UINTN_ERROR and RETURN_BUFFER_TOO_SMALL is returned. @param[in] Multiplicand A number that is to be multiplied by another @param[in] Multiplier A number by which the multiplicand is to be multiplied @param[out] Result Pointer to the result of multiplication @retval RETURN_SUCCESS Successful multiplication @retval RETURN_BUFFER_TOO_SMALL Overflow @retval RETURN_INVALID_PARAMETER Result is NULL **/ RETURN_STATUS EFIAPI SafeUintnMult ( IN UINTN Multiplicand, IN UINTN Multiplier, OUT UINTN *Result ) { UINT64 IntermediateResult; if (sizeof (UINTN) == sizeof (UINT32)) { IntermediateResult = ((UINT64) Multiplicand) *((UINT64) Multiplier); return SafeUint64ToUintn (IntermediateResult, Result); } return SafeUint64Mult ((UINT64)Multiplicand, (UINT64)Multiplier, (UINT64 *)Result); } /** INTN Addition 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 INTN_ERROR and RETURN_BUFFER_TOO_SMALL is returned. @param[in] Augend A number to which addend will be added @param[in] Addend A number to be added to another @param[out] Result Pointer to the result of addition @retval RETURN_SUCCESS Successful addition @retval RETURN_BUFFER_TOO_SMALL Overflow @retval RETURN_INVALID_PARAMETER Result is NULL **/ RETURN_STATUS EFIAPI SafeIntnAdd ( IN INTN Augend, IN INTN Addend, OUT INTN *Result ) { if (sizeof (UINTN) == sizeof (UINT32)) { return SafeInt64ToIntn (((INT64)Augend) + ((INT64)Addend), Result); } return SafeInt64Add ((INT64)Augend, (INT64)Addend, (INT64 *)Result); } /** INTN 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 INTN_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 SafeIntnSub ( IN INTN Minuend, IN INTN Subtrahend, OUT INTN *Result ) { if (sizeof (UINTN) == sizeof (UINT32)) { return SafeInt64ToIntn (((INT64)Minuend) - ((INT64)Subtrahend), Result); } return SafeInt64Sub ((INT64)Minuend, (INT64)Subtrahend, (INT64 *)Result); } /** INTN multiplication 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 INTN_ERROR and RETURN_BUFFER_TOO_SMALL is returned. @param[in] Multiplicand A number that is to be multiplied by another @param[in] Multiplier A number by which the multiplicand is to be multiplied @param[out] Result Pointer to the result of multiplication @retval RETURN_SUCCESS Successful multiplication @retval RETURN_BUFFER_TOO_SMALL Overflow @retval RETURN_INVALID_PARAMETER Result is NULL **/ RETURN_STATUS EFIAPI SafeIntnMult ( IN INTN Multiplicand, IN INTN Multiplier, OUT INTN *Result ) { if (sizeof (UINTN) == sizeof (UINT32)) { return SafeInt64ToIntn (((INT64)Multiplicand) *((INT64)Multiplier), Result); } return SafeInt64Mult ((INT64)Multiplicand, (INT64)Multiplier, (INT64 *)Result); }