Skip to content
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

Restrict comparisons with pointers to legal operations #758

Merged
merged 4 commits into from
Oct 24, 2024

Conversation

Alan-Jowett
Copy link
Contributor

@Alan-Jowett Alan-Jowett commented Oct 24, 2024

This pull request includes several key changes to the src/assertions.cpp and src/test/ebpf_yaml.cpp files, focusing on enhancing the handling of condition checks and adding new options for assertions. The most important changes are summarized below:

Enhancements to Condition Handling:

  • src/assertions.cpp: Added a new allow_pointers flag to manage pointer comparisons based on the operation type and whether the operation is 64-bit. This ensures that only certain operations allow pointer comparisons.
  • src/assertions.cpp: Updated comments for better readability and clarity, particularly for binary operations.

Addition of New Options:

  • src/test/ebpf_yaml.cpp: Introduced the assume_assertions option to the ebpf_verifier_options_t structure, allowing the verifier to assume assertions during its operation.

Summary by CodeRabbit

  • New Features

    • Enhanced pointer comparison handling in assertions to improve type safety.
    • Introduced a new option for handling assertion assumptions during verification.
  • Tests

    • Added multiple test cases for conditional jumps and comparisons involving context types and immediate values, ensuring well-defined behavior in these scenarios.

Copy link

coderabbitai bot commented Oct 24, 2024

Warning

Rate limit exceeded

@Alan-Jowett has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 15 minutes and 59 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Files that changed from the base of the PR and between 998879b and 5a6052e.

Walkthrough

The changes in this pull request involve modifications to the AssertExtractor class in src/assertions.cpp, enhancing pointer comparison logic based on operation types. A new boolean variable, allow_pointers, is introduced to manage these comparisons, while assertions related to ValidAccess and TypeConstraint are also added. Additionally, src/test/ebpf_yaml.cpp sees the introduction of a new option for handling assertions, and multiple test cases are added in test-data/jump.yaml to evaluate conditional jumps against immediate values, particularly zero.

Changes

File Change Summary
src/assertions.cpp Modified AssertExtractor class to refine pointer comparison logic in explicate and operator() methods. Introduced allow_pointers variable. Added assertions for ValidAccess and TypeConstraint.
src/test/ebpf_yaml.cpp Added a new option handling mechanism in raw_options_to_options to set assume_assertions in ebpf_verifier_options_t.
test-data/jump.yaml Introduced multiple test cases for conditional jumps and comparisons involving context types against immediate value zero, including various operation types.

Possibly related PRs

Suggested reviewers

  • dthaler

Poem

In the land of code, where rabbits hop,
We refine our checks, we never stop.
Pointers dance with logic so bright,
Assertions now gleam in the soft moonlight.
With tests that leap, and conditions that play,
Our code grows stronger, hip-hip-hooray! 🐇✨


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Outside diff range and nitpick comments (4)
src/assertions.cpp (1)

140-164: LGTM! Consider using a lookup table for operation types.

The implementation correctly restricts pointer comparisons to specific operations and ensures they're only allowed in 64-bit context, which is a good security measure. The logic is clear and well-structured.

Consider using a lookup table to simplify the switch statement:

-                switch (cond.op) {
-                case Condition::Op::EQ: allow_pointers = true; break;
-                case Condition::Op::NE: allow_pointers = true; break;
-                case Condition::Op::SET: allow_pointers = true; break;
-                case Condition::Op::NSET: allow_pointers = true; break;
-                case Condition::Op::LT: allow_pointers = true; break;
-                case Condition::Op::LE: allow_pointers = true; break;
-                case Condition::Op::GT: allow_pointers = true; break;
-                case Condition::Op::GE: allow_pointers = true; break;
-                case Condition::Op::SLT: allow_pointers = false; break;
-                case Condition::Op::SLE: allow_pointers = false; break;
-                case Condition::Op::SGT: allow_pointers = false; break;
-                case Condition::Op::SGE: allow_pointers = false; break;
-                default: assert(!"unexpected condition");
-                }
+                static const std::unordered_map<Condition::Op, bool> POINTER_ALLOWED = {
+                    {Condition::Op::EQ, true},
+                    {Condition::Op::NE, true},
+                    {Condition::Op::SET, true},
+                    {Condition::Op::NSET, true},
+                    {Condition::Op::LT, true},
+                    {Condition::Op::LE, true},
+                    {Condition::Op::GT, true},
+                    {Condition::Op::GE, true},
+                    {Condition::Op::SLT, false},
+                    {Condition::Op::SLE, false},
+                    {Condition::Op::SGT, false},
+                    {Condition::Op::SGE, false}
+                };
+                auto it = POINTER_ALLOWED.find(cond.op);
+                assert(it != POINTER_ALLOWED.end() && "unexpected condition");
+                allow_pointers = it->second;
src/test/ebpf_yaml.cpp (1)

195-196: Consider adding documentation for the new option.

The addition of the assume_assertions option looks correct, but it would be helpful to document its purpose and impact, especially since it affects the verifier's behavior. Consider adding a comment explaining:

  • What assertions are assumed when this option is enabled
  • The implications of enabling this option
  • Any potential interactions with other options
+        } else if (name == "assume_assertions") {
+            // When enabled, the verifier assumes assertions during analysis,
+            // affecting how pointer comparisons are validated.
+            options.assume_assertions = true;
test-data/jump.yaml (2)

720-1257: Consider improving test organization and documentation.

While the test cases are comprehensive and well-structured, there are opportunities for improvement:

  1. The test cases follow a repetitive pattern that could be better organized by grouping similar operations (e.g., all equality comparisons, all inequality comparisons, etc.)
  2. Consider adding comments to explain the rationale behind expected behaviors, particularly for cases where the code becomes unreachable

Here's a suggested structure:

 # Test cases for special case of comparison of not a number against a number when immediate is 0
+# Equality comparisons (==, !=)
 test-case: JEQ with imm 0 and pointer
 ...
 test-case: JNE with imm 0 and pointer
 ...
+
+# Bitwise comparisons (&==, &!=)
 test-case: JSET with imm 0 and pointer
 ...
+
+# Unsigned comparisons (<, <=, >, >=)
 test-case: JLT with imm 0 and pointer
 ...
+
+# Signed comparisons (s<, s<=, s>, s>=)
 test-case: JSLT with imm 0 and pointer
 ...
🧰 Tools
🪛 GitHub Check: validate-yaml

[failure] 1006-1006:
1006:1 [empty-lines] too many blank lines (7 > 2)


[failure] 1006-1006:
1006:1 [empty-lines] too many blank lines (7 > 2)


1002-1007: Fix formatting: Remove extra blank lines.

The file contains too many consecutive blank lines (7) where the maximum allowed is 2.

Apply this diff to fix the formatting:

 test-case: JSGE with imm 0 and pointer
 ...
 messages:
   - "0: Code is unreachable after 0"
   - "0: Invalid type (r1.type == number)"
-
-
-
-
-
 ---
 test-case: JEQ32 with imm 0 and pointer
🧰 Tools
🪛 GitHub Check: validate-yaml

[failure] 1006-1006:
1006:1 [empty-lines] too many blank lines (7 > 2)


[failure] 1006-1006:
1006:1 [empty-lines] too many blank lines (7 > 2)

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Files that changed from the base of the PR and between 6f944ff and e7c5013.

📒 Files selected for processing (3)
  • src/assertions.cpp (2 hunks)
  • src/test/ebpf_yaml.cpp (1 hunks)
  • test-data/jump.yaml (1 hunks)
🧰 Additional context used
🪛 GitHub Check: validate-yaml
test-data/jump.yaml

[failure] 1006-1006:
1006:1 [empty-lines] too many blank lines (7 > 2)


[failure] 1006-1006:
1006:1 [empty-lines] too many blank lines (7 > 2)

🔇 Additional comments (3)
src/assertions.cpp (1)

270-271: LGTM! Clear and descriptive comment.

The updated comment clearly explains the requirements for both the destination register and source operands in binary operations.

src/test/ebpf_yaml.cpp (1)

195-196: Verify test coverage for the new option.

Let's ensure there are test cases that exercise this new option.

✅ Verification successful

Let me check the content of the test case that uses assume_assertions to verify its proper implementation.


Test coverage for assume_assertions option is well implemented

The test file test-data/jump.yaml contains comprehensive test cases for the assume_assertions option, specifically focusing on pointer comparison restrictions. The test cases include:

  • Multiple variations of pointer comparisons with immediate value 0
  • Tests for both 64-bit and 32-bit pointer comparisons
  • Coverage for all comparison operators (EQ, NE, SET, LT, LE, GT, GE)
  • Tests with signed and unsigned comparisons
  • Verification of error messages for invalid pointer comparisons
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for test cases using the new assume_assertions option

# Test: Search for test cases using assume_assertions
echo "Searching for test cases using assume_assertions..."
rg -l "assume_assertions" test-data/

# Test: Search for any related pointer comparison tests
echo "Searching for pointer comparison test cases..."
rg -l "ptr|pointer" test-data/

Length of output: 474


Script:

#!/bin/bash
# Check the content of the test case using assume_assertions
echo "Content of test-data/jump.yaml:"
cat test-data/jump.yaml

Length of output: 23039

test-data/jump.yaml (1)

718-719: LGTM!

Clear and descriptive comment header for the new test cases.

@coveralls
Copy link

coveralls commented Oct 24, 2024

Coverage Status

coverage: 90.403% (+0.03%) from 90.371%
when pulling 5a6052e on Alan-Jowett:issue757
into 6f944ff on vbpf:main.

Alan Jowett added 2 commits October 24, 2024 13:43
Signed-off-by: Alan Jowett <[email protected]>
Signed-off-by: Alan Jowett <[email protected]>
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE

📥 Commits

Files that changed from the base of the PR and between e7c5013 and 998879b.

📒 Files selected for processing (2)
  • src/test/ebpf_yaml.cpp (2 hunks)
  • test-data/jump.yaml (1 hunks)
🔇 Additional comments (4)
src/test/ebpf_yaml.cpp (2)

182-184: LGTM!

The default initialization is correct, though its placement has already been addressed in a previous review comment.


198-199: Verify test coverage for the new option.

Let's check if there are any test cases using this new option to ensure it's properly tested.

✅ Verification successful

Test coverage exists for the assume_assertions option

The verification shows that the assume_assertions option is well-tested:

  • The option is properly implemented in test-data/jump.yaml with multiple test cases using the options: ["assume_assertions"] configuration
  • Test cases cover various scenarios including pointer comparisons and different types of jumps (JEQ, JNE, JSET, etc.)
  • The implementation in src/main/check.cpp shows it's a configurable flag with proper documentation

The test coverage is comprehensive and validates the option's behavior across different use cases.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Search for test cases using the new assume_assertions option
# Test: Look for YAML test files using assume_assertions. Expect: At least one test case using this option.

echo "Searching for test cases using assume_assertions option..."
rg -l "assume_assertions" "test-data/*.yaml"

Length of output: 228


Script:

#!/bin/bash
# Let's first find the correct test data directory structure
fd -t d "test"

# Then search for yaml files in the repository
fd -e yaml

# Finally, let's look for the actual usage of assume_assertions in any file
rg -l "assume_assertions"

Length of output: 704


Script:

#!/bin/bash
# Let's examine the usage in test-data/jump.yaml to see how the option is used
cat test-data/jump.yaml

# Also check the implementation in src/main/check.cpp to understand how it's handled
rg -A 5 -B 5 "assume_assertions" src/main/check.cpp

Length of output: 23768

test-data/jump.yaml (2)

718-1251: Well-structured comprehensive test suite for pointer comparisons.

The test suite thoroughly covers pointer comparison validation across different operators:

  • Basic comparisons (==, !=)
  • Bitwise operations (&==, &!=)
  • Unsigned comparisons (<, <=, >, >=)
  • Signed comparisons (s<, s<=, s>, s>=)
  • 32-bit variants of all operators

The consistent structure and error validation patterns make the test cases easy to understand and maintain.


934-937: Consistent error handling patterns across test cases.

The error messages follow a well-defined pattern:

  • For signed and 32-bit operations: Both type validation ("Invalid type (r1.type == number)") and unreachability checks
  • For basic operations: Appropriate unreachability checks

This consistent approach helps verify that the verifier correctly prevents invalid pointer comparisons.

Also applies to: 1018-1021, 1081-1084, 1144-1147, 1186-1189, 1228-1231

src/test/ebpf_yaml.cpp Outdated Show resolved Hide resolved
test-data/jump.yaml Show resolved Hide resolved
Signed-off-by: Alan Jowett <[email protected]>
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.

3 participants