Skip to content

Assignment 3 Python

bjjwwang edited this page May 7, 2025 · 5 revisions
../Assignment-3/
|-- CPP
|   |-- Assignment-3-Helper.cpp
|   |-- Assignment-3-Helper.h
|   |-- Assignment-3.cpp
|   |-- Assignment-3.h
|   |-- CMakeLists.txt
|   `-- test-ae.cpp
|-- Python
|   |-- Ass3_helper.py
|   |-- Assignment3.py
|   |-- CMakeLists.txt
|   |-- Main.py
|   |-- Test.py
`-- Tests
    |-- ae
    |   |-- test1.c
    |   |-- test1.ll
    |   |-- test2.c
    |   |-- test2.ll
    |   |-- test3.c
    |   |-- test3.ll
    |   |-- test4.c
    |   `-- test4.ll
    `-- buf
        |-- test1.c
        |-- test1.ll
        |-- test2.c
        |-- test2.ll
        |-- test3.c
        |-- test3.ll
        |-- test4.c
        |-- test4.ll
        |-- test5.c
        `-- test5.ll

1. Get the latest code template

* Before coding, please type cd $HOME/Software-Security-Analysis and git pull in your terminal to make sure you always have the latest version of the code template before each assignment.

Make sure to switch your program to ass3 before coding.

2. Assignment 3 task

Method Description
update_state_on_copy Handle COPYStmt
update_state_on_store Handle StoreStmt
update_state_on_load Handle LoadStmt
update_state_on_gep Handle GepStmt
update_state_on_binary Handle BinaryStmt.
update_state_on_phi Handle PhiStmt.
buf_overflow_detection Check buffer overflow at GepStmt.
handle_cycle_wto Widening and narrowing for loops.
update_state_on_ext_call handle External APIs.
  1. Implement the above methods of class AbstractExecution in Assignment3.py
  2. Run Test Pass the test without any assertion by Test.py.
  3. Upload Assignment3.py to UNSW WebCMS for your submission when you are finished with this assignment. Your implementation will be evaluated against X number of our internal tests. If you pass Y tests, you will receive Y/X * 100% marks. Here, we only provided several simple test cases under Assignment-3/Tests/ae for assertion validation and Assignment-3/Tests/buf for buffer overflow detection. You are encouraged to add more test cases by yourself to validate the correctness of your implementation.

*You will be working on Assignment3.py only and there is NO need to modify other files under the Assignment-3 folder

SVF AE API to help with your implementation.

2.1 Implementing update_state

The update_state_on_store function should store the RHS value at the memory address corresponding to the LHS value in AEState which is from calling self.post_abs_trace[node](node is an ICFG Node, same for the below function). Note that the RHS variable can be either IntervalValue or AddressValue.

The update_state_on_gep function aims to compute the virtual address by adding an offset to the base pointer and then store the updated state in LHS value in AEState which is from calling self.post_abs_trace[node].

The update_state_on_copy function should copy the RHS value to the LHS value in AEState which is from calling self.post_abs_trace[node].

The update_state_on_binary function should perform the binary operation specified by the BinaryStmt and store the result in the LHS value in AEState which is from calling self.post_abs_trace[node].

The update_state_on_load function should load the value from the memory address corresponding to the RHS value and store it in the LHS value in AEState which is from calling self.post_abs_trace[node].

The update_state_on_phi function should merge the values from the predecessor blocks and store the merged value in the LHS value in AEState which is from calling self.post_abs_trace[node].

2.2 Implementing handle_cycle_wto

The handleCycleWTO function needs to include widening and narrowing logic. This will enable the function to handle loop bounds efficiently (e.g., for i = 0; i < 10000; ++i), allowing it to exit the loop after several iterations and determine the correct value of i.

2.3 Implementing buf_overflow_detection

This function takes an SVFStmt as input. If the statement is a GepStmt, it indicates an attempt to access an offset of a pointer or array. An overflow checking is needed to make sure the access offset is smaller than the size of the underlying object.

The provided framework already includes the following steps:

  1. Identifying if the statement is a GepStmt.
  2. Using the updateGepObjOffsetFromBase function to update the offsets for the GEP objects.

You need to complete the following tasks:

  1. Check Object Sizes and Access Offsets: After updating the offsets using update_gep_obj_offset_from_base, you need to check if the access offset exceeds the effective byte size of the object.
  2. Report Buffer Overflow: If an access offset is found to exceed the object's size, you should report a buffer overflow.

Specifically, in the buf_overflow_detection function, you need to:

  • Retrieve the base address and size of the object.
  • Get the access offset.
  • Compare the access offset with the object's size. If the offset exceeds the size, report a buffer overflow.

Ensure you use the provided tools and functions correctly to perform these checks and report any buffer overflows.

It is important to note that a buffer overflow bug may occur during a GepStmt. For example:

int arr[5];
arr[10] = 1;

A buffer overflow might also occur after multiple GepStmts, such as:

int arr[5];
int* ptr = arr + 3;
ptr[4] = 1;

Therefore, each GepStmt must be checked to ensure that the RHS variable's effective length still supports the current offset. If a bug is detected, invoke reportBufOverflow to report a bug.

2.4 Implementing update_state_on_ext_call

The update_state_on_ext_call function is responsible for handling external function calls within the abstract execution framework. This function ensures that operations involving external calls, such as buffer manipulations, are safely executed without causing buffer overflows.

Key Responsibilities

  • Memory Insertion (mem_insert): This function checks whether the buffer has sufficient space to accommodate the data being inserted at a specified position.

    • Check: Ensure sizeof(buffer) > position + data_size.
    • Action: If the check fails, invoke report_buf_overflow to report a potential buffer overflow.
  • String Insertion (str_insert): Similar to mem_insert, but involves inserting a string into a buffer.

    • Check: Ensure sizeof(buffer) > position + strlen(data).
    • Action: If the check fails, invoke report_buf_overflow.

Implementation Details

For each external call, the function retrieves the relevant arguments and performs the necessary checks:

  • Buffer Size Retrieval: For each buffer address, determine the object's byte size using svfir.get_base_object(obj_id).get_byte_size_of_obj().
  • Offset Calculation: Calculate the access offset by adding the position and data size or string length.
  • Overflow Detection: Compare the calculated access offset with the buffer size. If the offset exceeds the size, report a buffer overflow using report_buf_overflow.

This function ensures robust handling of external calls, preventing unsafe memory operations that could lead to vulnerabilities.

3. Configuration && debugging

To enable debugging and running, switch your executable by setting the program and args fields as described here or follow the below screenshot.

3.2 Debugging

If you want to see the value of AbstractValue, you can call to_string() to print the value (either IntervalValue or AddressValue).

a = IntervalValue(1,1)
print(a.to_string())