Skip to content

Integrating LIEF parser for SHARED builds #2534

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged

Conversation

prikhap
Copy link

@prikhap prikhap commented Jul 10, 2025

Title: Add CI workflow for C++ inject_hash implementation

Description:
This PR adds CI workflow and testing infrastructure for the C++ inject_hash implementation.

Changes:

  • Add GitHub Actions workflow for testing
  • Add test script for building and verifying functionality
  • Test on both Ubuntu and macOS environments

Testing:

  • Verified workflow locally
  • Tests build process
  • Tests FIPS integrity verification

prikhap added 2 commits July 10, 2025 01:20
- Add LIEF version 0.13.0 as git submodule
- Configure CMake to build LIEF from source
- Update inject_hash implementation to use LIEF
- Remove pre-built LIEF binaries
- Add initial C++ implementation and tests

This change improves portability and maintainability by using
LIEF as a submodule instead of pre-built binaries.
@prikhap prikhap requested a review from a team as a code owner July 10, 2025 21:26
Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clang-tidy made some suggestions

@@ -0,0 +1,37 @@
#include <LIEF/LIEF.hpp>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: 'LIEF/LIEF.hpp' file not found [clang-diagnostic-error]

#include <LIEF/LIEF.hpp>
         ^

- Add GitHub Actions workflow for Ubuntu and macOS
- Add test script with detailed logging
- Handle OS-specific library names
- Add environment verification
- Disable fail-fast to test both environments
@codecov-commenter
Copy link

codecov-commenter commented Jul 10, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 78.76%. Comparing base (274e9e6) to head (68c042d).
⚠️ Report is 3 commits behind head on inject-hash-cpp-experiment.

Additional details and impacted files
@@                      Coverage Diff                       @@
##           inject-hash-cpp-experiment    #2534      +/-   ##
==============================================================
- Coverage                       78.90%   78.76%   -0.14%     
==============================================================
  Files                             640      642       +2     
  Lines                          109766   110242     +476     
  Branches                        15526    15603      +77     
==============================================================
+ Hits                            86612    86834     +222     
- Misses                          22457    22711     +254     
  Partials                          697      697              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this file used right now? I understand that it might come up in later implementations, but we can leave until then to pull this in.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed it!

Comment on lines 42 to 45
# Test inject_hash_cpp basic functionality
echo "Testing inject_hash_cpp basic functionality..."
./util/fipstools/inject_hash_cpp/inject_hash_cpp --version || echo "Version check failed"
./util/fipstools/inject_hash_cpp/inject_hash_cpp --help || echo "Help check failed"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't seem to be used, could we remove this?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed it!

CMakeLists.txt Outdated
@@ -1,5 +1,31 @@
cmake_minimum_required(VERSION 3.5..3.31)


####################
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment/text here is redundant.

echo "Building full project..."
ninja

# Test actual FIPS injection
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Redundant comment here as well.

Comment on lines 30 to 32
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DFIPS=1 \
-DFIPS_SHARED=1 \
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should also be testing the shared build with ubuntu. And we should use -DCMAKE_BUILD_TYPE=Release since that's what we validate for FIPS :)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

static *

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tried handling static files, which require creating an archive file parser (left it for some other PR)


# First try to build just inject_hash_cpp
echo "Building inject_hash_cpp..."
ninja inject_hash_cpp
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think inject_hash_cpp is necessarily used here. Calling ninja with the build flags you've set up should be sufficient enough.

We could also probably drop the ninja call on L49 below in favor of this line.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Comment on lines 29 to 32
std::cout << "\nReceived arguments:" << std::endl;
for (int i = 1; i < argc; i++) {
std::cout << " Arg " << i << ": " << argv[i] << std::endl;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is probably useful for debugging, but we should drop it since we don't want debugging prints in most production code.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the inject_hash.cpp currently is just a test file, added some test functionalities and std:cout to see if the file was actually called.

# Test actual FIPS injection
echo "Testing FIPS injection..."
if [[ "$OSTYPE" == "darwin"* ]]; then
./util/fipstools/inject_hash_cpp/inject_hash_cpp -o ./crypto/libcrypto.dylib -in-object ./crypto/libcrypto.dylib -apple
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

-o ./crypto/libcrypto.dylib and -apple don't seem to actually be used here. Same for below.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Modified according to the CMake compiler flags

Comment on lines 10 to 15
for (int i = 1; i < argc - 1; i++) {
if (strcmp(argv[i], "-in-object") == 0) {
binary_path = argv[i + 1];
break;
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's probably a more graceful way to handle this. Could you look into pulling in the argument parsing functions in tool/internal.h?

ParseKeyValueArguments should help you parse what you need in a cleaner and more easily extendable fashion.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just kept this for testing purpose. will keep this in mind while making the final file

Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clang-tidy made some suggestions

}
std::vector<uint8_t> calculate_hash(HMAC_size(&ctx));

unsigned int calculate_hash_len;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: variable 'calculate_hash_len' is not initialized [cppcoreguidelines-init-variables]

Suggested change
unsigned int calculate_hash_len;
unsigned int calculate_hash_len = 0;

@samuel40791765 samuel40791765 requested a review from andrewhop July 17, 2025 18:55
@prikhap prikhap force-pushed the implement-inject-hash-clean branch from a29cda3 to a11e97a Compare July 17, 2025 23:28
mkdir -p build
cd build

# Configure based on build type and OS
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nothing is actually building aws-lc, this is only running CMake to configure the build.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missed adding the ninja command.

Comment on lines 21 to 28
cmake -GNinja \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DFIPS=1 \
-DFIPS_SHARED=1 \
-DBUILD_SHARED_LIBS=1 \
-DUSE_CPP_INJECT_HASH=ON \
-DCMAKE_OSX_SYSROOT=/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk \
..
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are existing helper functions defined in common_posix_setup.sh to help simplify this.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

included in the recent commit.

Comment on lines 25 to 28
set_target_properties(inject_hash_cpp PROPERTIES
CXX_STANDARD 17
CXX_STANDARD_REQUIRED ON
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why 17?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Had kept it since LIEF requires this version of C++. However, we don't have to bother about the version while building aws-lc, hence deleted the properties from CMake.

Comment on lines 46 to 47
chmod +x tests/ci/run_inject_hash_cpp.sh
./tests/ci/run_inject_hash_cpp.sh
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not check the bash script in with the correct file permissions?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

…or inject_hash.cpp and made .sh locally executable
@prikhap prikhap force-pushed the implement-inject-hash-clean branch from 9f4fa5d to 62d0cb0 Compare July 18, 2025 22:36
Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clang-tidy made some suggestions


if (is_archive) {
// Create temporary directory
std::string temp_dir = std::filesystem::temp_directory_path().string() +
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: variable 'temp_dir' is not initialized [cppcoreguidelines-init-variables]

Suggested change
std::string temp_dir = std::filesystem::temp_directory_path().string() +
y = 0

}

// There should be only one object file
std::string object_file;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: variable 'object_file' is not initialized [cppcoreguidelines-init-variables]

util/fipstools/inject_hash_cpp/inject_hash.cpp:57:

- le;
+ le = 0;

Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clang-tidy made some suggestions

}

// Find extracted file
std::string extracted_file;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: variable 'extracted_file' is not initialized [cppcoreguidelines-init-variables]

util/fipstools/inject_hash_cpp/inject_hash.cpp:62:

- le;
+ le = 0;

@prikhap prikhap force-pushed the implement-inject-hash-clean branch from 381be2b to 62d0cb0 Compare July 21, 2025 18:35
@prikhap prikhap changed the title Implement inject hash clean Integrarting LIEF parser for SHARED builds Jul 21, 2025
@prikhap prikhap changed the title Integrarting LIEF parser for SHARED builds Integrating LIEF parser for SHARED builds Jul 21, 2025
@prikhap
Copy link
Author

prikhap commented Jul 22, 2025

Keywords to look for verify that everything is building correctly:
Entering the inject_hash.cpp script: "=== C++ inject_hash starting ==="
To see LIEF being integrated and loaded: "LIEF parser successfully loaded"
For test cases:
an expected failure while calling inject_hash without any arguments : "--Expected failure with no args--"
an expected failure for parsing a non-existent file: "--Expected failure with invalid file--"
normal run with correct flags and input: "=== C++ inject_hash starting ==="
Please review

DEPENDS bcm_hashunset inject_hash
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
)
#ignoring static builds for now
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be helpful to document the reason in the comments, but we can do that in the next PR.

CMakeLists.txt Outdated
Comment on lines 4 to 17
# Configure LIEF build options first
set(LIEF_PYTHON_API OFF CACHE BOOL "")
set(LIEF_EXAMPLES OFF CACHE BOOL "")
set(LIEF_TESTS OFF CACHE BOOL "")
set(LIEF_DOC OFF CACHE BOOL "")
set(LIEF_INSTALL ON CACHE BOOL "")
set(LIEF_STATIC ON CACHE BOOL "")
set(LIEF_ELF ON CACHE BOOL "Enable ELF format")
set(LIEF_PE ON CACHE BOOL "Enable PE format")
set(LIEF_MACHO ON CACHE BOOL "Enable MACHO format")
set(LIEF_DEX OFF CACHE BOOL "Disable DEX format")
set(LIEF_VDEX OFF CACHE BOOL "Disable VDEX format")
set(LIEF_ART OFF CACHE BOOL "Disable ART format")
set(LIEF_OAT OFF CACHE BOOL "Disable OAT format")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is much more useful if your comment explains what these options are and why you chose these specific values.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CMakeLists.txt Outdated
Comment on lines 19 to 20
# Add LIEF subdirectory
add_subdirectory(third_party/lief)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is not necessary to comment every line, especially when they are self explanatory like this.

Suggested change
# Add LIEF subdirectory
add_subdirectory(third_party/lief)
add_subdirectory(third_party/lief)

CMakeLists.txt Outdated
Comment on lines 22 to 23
# Make LIEF headers available
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/third_party/lief/include)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes the LIEF headers available to every target, can you scope this down to just the inject hash tool?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LIEF headers are scoped to inject_hash_cpp using the util/fipstools/inject_hash_cpp/CMakeLists.txt. I added it in the global CMake, to make the LIEF available throughout, but it surely can be removed and it is better directed in it's desired scope.

Comment on lines 655 to 656
if(USE_CPP_INJECT_HASH)
# Add dependency on C++ implementation
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indentation looks off for the if and else block, more superfluous comments

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

amdended!

COMMAND ${CMAKE_BINARY_DIR}/util/fipstools/inject_hash_cpp/inject_hash_cpp
-o $<TARGET_FILE:crypto>
-in-object $<TARGET_FILE:crypto>
${INJECT_HASH_APPLE_FLAG}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What are you using this flag for?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these flags currently aren't of much usage, but was trying maintain similarity with the flag format used by the inject_hash.go script. Currently these flags are just printed as a part of testing the integration of the C++ script, however while creating a proper parsing and hashing script, these flags would be required to have the input path of the binary, output path and if it is suited for apple or linux.


# Test actual FIPS injection
echo "TESTING INJECT_HASH.CPP WITH EDGE CASES..."
./util/fipstools/inject_hash_cpp/inject_hash_cpp || echo "--Expected failure with no args--"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this fail the build if this isn't an error? Also I prefer moving more of this test logic into actual test files like our tools.

Comment on lines 50 to 60
# Test with actual library
if [[ "$OSTYPE" == "darwin"* ]]; then
./util/fipstools/inject_hash_cpp/inject_hash_cpp \
-o ./crypto/libcrypto.dylib \
-in-object ./crypto/libcrypto.dylib \
-apple
else
./util/fipstools/inject_hash_cpp/inject_hash_cpp \
-o ./crypto/libcrypto.so \
-in-object ./crypto/libcrypto.so
fi
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't this run (with the correct paths) automatically during the normal FIPS build?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this was added to the test script just to show contrast between "expected failure" cases and a normal case.


// Validate arguments
if (!input_file || !output_file) {
std::cerr << "❌ Missing required arguments" << std::endl;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is more helpful to say which ones are missing to help future customers/developers debug the issue.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

modified.

Comment on lines 27 to 29
else if (strcmp(argv[i], "-apple") == 0) {
is_apple = true;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need to handle Apple in a special way?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesen't serve any purpose right now, was just setting foundations for the future builds.

Comment on lines 13 to 16
// Parse command line arguments
const char* input_file = nullptr;
const char* output_file = nullptr;
bool is_apple = false;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to re-use any of our existing argument parsing from our tools?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also brought this up in #2534 (comment). The answer seemed to imply that this would part of a larger future refactor/PR?

Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clang-tidy made some suggestions

}

// Get the input and output file paths
std::string input_file, output_file;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: variable 'input_file' is not initialized [cppcoreguidelines-init-variables]

Suggested change
std::string input_file, output_file;
s = 0

}

// Get the input and output file paths
std::string input_file, output_file;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

warning: variable 'output_file' is not initialized [cppcoreguidelines-init-variables]

util/fipstools/inject_hash_cpp/inject_hash.cpp:38:

- ;
+  = 0;

CMakeLists.txt Outdated
Comment on lines 11 to 12
# enabling installation of LIEF
set(LIEF_INSTALL ON CACHE BOOL "")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need to install LIEF?

Comment on lines 656 to 657
# Add dependency on C++ implementation
add_dependencies(crypto inject_hash_cpp)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think this needs a comment?

Comment on lines 392 to 402

#ignoring static builds for now as archive files require a seperate parser to extract .o files from it. The lief parser does not support archive files.
go_executable(inject_hash
boringssl.googlesource.com/boringssl/util/fipstools/inject_hash)
add_custom_command(
OUTPUT bcm.o
COMMAND ./inject_hash -o bcm.o -in-archive $<TARGET_FILE:bcm_hashunset>
DEPENDS bcm_hashunset inject_hash
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
)
# endif()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Besides the comment did anything change here? If not we shouldn't change any of the whitespace because it makes tracking actual changes in git history harder.

Comment on lines 12 to 25
if [[ "$OSTYPE" == "darwin"* ]]; then
# macOS only supports shared builds
run_build \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DFIPS=1 \
-DBUILD_SHARED_LIBS=1 \
-DUSE_CPP_INJECT_HASH=ON
else
run_build \
-DCMAKE_BUILD_TYPE=RelWithDebInfo \
-DFIPS=1 \
-DBUILD_SHARED_LIBS=1 \
-DUSE_CPP_INJECT_HASH=ON
fi
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there any difference between the if and else block?

@prikhap prikhap merged commit a23de3c into aws:inject-hash-cpp-experiment Jul 25, 2025
118 of 128 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants