diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c4a6dbc..d43941a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -49,7 +49,6 @@ jobs: uses: actions/setup-go@v5 with: go-version: 1.24.0 - check-latest: true - name: Test Cross-Language env: TEST_DB_NAME: ${{ env.MYSQL_DATABASE }} @@ -62,7 +61,7 @@ jobs: ASHERAH_KMS_MODE: static run: scripts/integration-test.sh - name: Publish (dry-run) - run: npm publish --dry-run + run: npm publish --dry-run --tag dev test-multi-arch: runs-on: ubuntu-latest strategy: diff --git a/scripts/integration-test.sh b/scripts/integration-test.sh index 57e58fb..e0c2932 100755 --- a/scripts/integration-test.sh +++ b/scripts/integration-test.sh @@ -9,6 +9,7 @@ GO_DIR="${ORIG_DIR}/integration/go" mkdir -p "${GO_DIR}/bin" export GOPATH=${GO_DIR} export GOBIN=${GO_DIR}/bin +export GOTOOLCHAIN=local PATH=$GOPATH/bin:$GOROOT/bin:$PATH ### Encrypt with Go diff --git a/src/asherah.cc b/src/asherah.cc index 04ad56f..e4c63aa 100644 --- a/src/asherah.cc +++ b/src/asherah.cc @@ -433,9 +433,13 @@ class Asherah : public Napi::Addon { NapiUtils::RequireParameterCount(info, 1); Napi::Number item_size = info[0].ToNumber(); - auto new_size = (size_t)item_size.Int32Value(); - - maximum_stack_alloc_size = new_size; + int32_t value = item_size.Int32Value(); + + // Clamp to reasonable range without branching + constexpr int32_t MAX_STACK_SIZE = 1048576; // 1MB max + value = std::max(0, std::min(value, MAX_STACK_SIZE)); + + maximum_stack_alloc_size = static_cast(value); } catch (Napi::Error &e) { e.ThrowAsJavaScriptException(); return; @@ -734,6 +738,13 @@ class Asherah : public Napi::Addon { const size_t est_envelope_overhead = 185; const double base64_overhead = 1.34; + // Only check for overflow if suspiciously large (> 1TB) + if (unlikely(data_byte_len > 1099511627776ULL)) { + if (data_byte_len > SIZE_MAX / 2) { + throw std::invalid_argument("Data size too large for encryption"); + } + } + // Add one rather than using std::ceil to round up size_t est_data_byte_len = size_t(double(data_byte_len + est_encryption_overhead) * diff --git a/src/cobhan_buffer.h b/src/cobhan_buffer.h index 720e203..34bc233 100644 --- a/src/cobhan_buffer.h +++ b/src/cobhan_buffer.h @@ -8,6 +8,7 @@ #include // for std::ostringstream #include // for std::runtime_error, std::invalid_argument #include // for std::string +#include "hints.h" // for unlikely class CobhanBuffer { public: @@ -94,6 +95,12 @@ class CobhanBuffer { } static size_t AllocationSizeToMaxDataSize(size_t allocation_len_bytes) { + // Check for buffer underflow with unlikely hint + constexpr size_t min_size = cobhan_header_size_bytes + canary_size_bytes + safety_padding_bytes; + if (unlikely(allocation_len_bytes < min_size)) { + throw std::invalid_argument("Buffer allocation size too small"); + } + size_t data_len_bytes = allocation_len_bytes - cobhan_header_size_bytes - canary_size_bytes - safety_padding_bytes; if (data_len_bytes > max_int32_size) { diff --git a/src/scoped_allocate.h b/src/scoped_allocate.h index ce94cfe..73aef82 100644 --- a/src/scoped_allocate.h +++ b/src/scoped_allocate.h @@ -3,6 +3,8 @@ #ifdef USE_SCOPED_ALLOCATE_BUFFER +#include "hints.h" // for unlikely macro + /* This macro allows us to allocate a buffer either on the stack or on the heap. If the requested buffer size is less than max_stack_alloc_size, we create the