Skip to content

Commit

Permalink
Move checked integer arithmetic to int_utils.h
Browse files Browse the repository at this point in the history
  • Loading branch information
randombit committed Apr 10, 2024
1 parent 846a6ae commit f1e8048
Show file tree
Hide file tree
Showing 7 changed files with 86 additions and 104 deletions.
14 changes: 8 additions & 6 deletions src/lib/asn1/ber_dec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
#include <botan/ber_dec.h>

#include <botan/bigint.h>
#include <botan/internal/int_utils.h>
#include <botan/internal/loadstor.h>
#include <botan/internal/safeint.h>
#include <memory>

namespace Botan {
Expand Down Expand Up @@ -128,18 +128,20 @@ size_t find_eoc(DataSource* ber, size_t allow_indef) {
while(true) {
ASN1_Type type_tag;
ASN1_Class class_tag;
size_t tag_size = decode_tag(&source, type_tag, class_tag);
const size_t tag_size = decode_tag(&source, type_tag, class_tag);
if(type_tag == ASN1_Type::NoObject) {
break;
}

size_t length_size = 0;
size_t item_size = decode_length(&source, length_size, allow_indef);
const size_t item_size = decode_length(&source, length_size, allow_indef);
source.discard_next(item_size);

length = BOTAN_CHECKED_ADD(length, item_size);
length = BOTAN_CHECKED_ADD(length, tag_size);
length = BOTAN_CHECKED_ADD(length, length_size);
if(auto new_len = checked_add(length, item_size, tag_size, length_size)) {
length = new_len.value();
} else {
throw Decoding_Error("Integer overflow while decoding DER");
}

if(type_tag == ASN1_Type::Eoc && class_tag == ASN1_Class::Universal) {
break;
Expand Down
7 changes: 5 additions & 2 deletions src/lib/compression/compress_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#include <botan/exceptn.h>
#include <botan/mem_ops.h>
#include <botan/internal/fmt.h>
#include <botan/internal/safeint.h>
#include <botan/internal/int_utils.h>
#include <cstdlib>

namespace Botan {
Expand All @@ -19,7 +19,10 @@ Compression_Error::Compression_Error(const char* func_name, ErrorType type, int
Exception(fmt("Compression API {} failed with return code {}", func_name, rc)), m_type(type), m_rc(rc) {}

void* Compression_Alloc_Info::do_malloc(size_t n, size_t size) {
if(!BOTAN_CHECKED_MUL(n, size).has_value()) [[unlikely]] {

// Precheck for integer overflow in the multiplication
// before passing to calloc, which may or may not check.
if(!checked_mul(n, size)) {
return nullptr;
}

Expand Down
5 changes: 2 additions & 3 deletions src/lib/utils/allocator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
#include <botan/allocator.h>

#include <botan/mem_ops.h>
#include <botan/internal/safeint.h>
#include <botan/internal/int_utils.h>
#include <cstdlib>
#include <new>

Expand All @@ -23,8 +23,7 @@ BOTAN_MALLOC_FN void* allocate_memory(size_t elems, size_t elem_size) {
}

// Some calloc implementations do not check for overflow (?!?)

if(!BOTAN_CHECKED_MUL(elems, elem_size).has_value()) {
if(!checked_mul(elems, elem_size).has_value()) {
throw std::bad_alloc();
}

Expand Down
2 changes: 1 addition & 1 deletion src/lib/utils/info.txt
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,14 @@ ct_utils.h
donna128.h
filesystem.h
fmt.h
int_utils.h
loadstor.h
mul128.h
os_utils.h
parsing.h
prefetch.h
rotate.h
rounding.h
safeint.h
scan_name.h
stl_util.h
timer.h
Expand Down
57 changes: 57 additions & 0 deletions src/lib/utils/int_utils.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
/*
* (C) 2024 Jack Lloyd
*
* Botan is released under the Simplified BSD License (see license.txt)
*/

#ifndef BOTAN_INT_UTILS_H_
#define BOTAN_INT_UTILS_H_

#include <botan/concepts.h>
#include <botan/types.h>
#include <optional>

namespace Botan {

template <std::unsigned_integral T>
constexpr inline std::optional<T> checked_add(T a, T b) {
const T r = a + b;
if(r - a != b) {
return {};
}
return r;
}

template <std::unsigned_integral T, std::unsigned_integral... Ts>
requires all_same_v<T, Ts...>
constexpr inline std::optional<T> checked_add(T a, T b, Ts... rest) {
if(auto r = checked_add(a, b)) {
return checked_add(r.value(), rest...);
} else {
return {};
}
}

template <std::unsigned_integral T>
constexpr inline std::optional<T> checked_mul(T a, T b) {
const T r = a * b;
// If a == 0 then the multiply certainly did not overflow
// Otherwise r / a == b unless overflow occured
if(a != 0 && r / a != b) {
return {};
}
return r;
}

template <std::unsigned_integral T, std::unsigned_integral RT>
std::optional<RT> checked_cast(T input) {
const RT cast = static_cast<RT>(input);
if(static_cast<T>(cast) != input) {
return {};
}
return cast;
}

} // namespace Botan

#endif
27 changes: 13 additions & 14 deletions src/lib/utils/locking_allocator/locking_allocator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@

#include <botan/internal/locking_allocator.h>

#include <botan/internal/int_utils.h>
#include <botan/internal/mem_pool.h>
#include <botan/internal/os_utils.h>
#include <botan/internal/safeint.h>

namespace Botan {

Expand All @@ -18,29 +18,28 @@ void* mlock_allocator::allocate(size_t num_elems, size_t elem_size) {
return nullptr;
}

const auto n = BOTAN_CHECKED_MUL(num_elems, elem_size);
if(!n.has_value()) {
return nullptr; // overflow!
if(auto n = checked_mul(num_elems, elem_size)) {
return m_pool->allocate(n.value());
} else {
// overflow!
return nullptr;
}

return m_pool->allocate(n.value());
}

bool mlock_allocator::deallocate(void* p, size_t num_elems, size_t elem_size) noexcept {
if(!m_pool) {
return false;
}

/*
We return nullptr in allocate if there was an overflow, so if an
overflow occurs here we know the pointer was not allocated by this pool.
*/
const auto n = BOTAN_CHECKED_MUL(num_elems, elem_size);
if(!n.has_value()) {
if(auto n = checked_mul(num_elems, elem_size)) {
return m_pool->deallocate(p, n.value());
} else {
/*
We return nullptr in allocate if there was an overflow, so if an
overflow occurs here we know the pointer was not allocated by this pool.
*/
return false;
}

return m_pool->deallocate(p, n.value());
}

mlock_allocator::mlock_allocator() {
Expand Down
78 changes: 0 additions & 78 deletions src/lib/utils/safeint.h

This file was deleted.

0 comments on commit f1e8048

Please sign in to comment.