-
Notifications
You must be signed in to change notification settings - Fork 25
Add: Qualcomm User Data Encryption test script & Document #141
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,100 @@ | ||
| Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. | ||
| SPDX-License-Identifier: BSD-3-Clause-Clear | ||
|
|
||
| # Qualcomm UserDataEncryption Functionality Test Script | ||
| ## Overview | ||
|
|
||
| The `UserDataEncryption` test script verifies basic filesystem encryption functionality. It generates a 64-byte key, adds it to the system, applies an encryption policy to a mount directory, and confirms the setup by creating and reading a test file. This ensures that key management and encryption policies work as expected. | ||
|
|
||
| ## Features | ||
|
|
||
| - **Dependency Check**: Verifies the presence of the `fscryptctl` binary. | ||
| - **Key Management**: Generates a 64-byte key and adds it to the filesystem. | ||
| - **Encryption Policy**: Applies and verifies encryption policy on a mount directory. | ||
| - **Functional Validation**: Creates and reads a test file to confirm encryption functionality. | ||
| - **Automated Result Logging**: Outputs test results to a `.res` file for automated result collection. | ||
|
|
||
| ## Prerequisites | ||
|
|
||
| Ensure the following components are present on the target device: | ||
|
|
||
| - `fscryptctl` binary available in `/data/` | ||
| - Sufficient permissions to create and mount directories | ||
|
|
||
| ## Directory Structure | ||
| ``` | ||
| Runner/ | ||
| ├── suites/ | ||
| │ ├── Kernel/ | ||
| │ │ │ ├── baseport/ | ||
| │ │ │ │ ├── UserDataEncryption/ | ||
| │ │ │ │ │ ├── run.sh | ||
| ``` | ||
| ## Usage | ||
|
|
||
| 1. Copy repo to Target Device: Use scp to transfer the scripts from the host to the target device. The scripts should be copied to the ```/<user-defined-location>``` directory on the target device. | ||
|
|
||
| 2. Verify Transfer: Ensure that the repo have been successfully copied to the ```/<user-defined-location>``` directory on the target device. | ||
|
|
||
| 3. Run Scripts: Navigate to the ```/<user-defined-location>``` directory on the target device and execute the scripts as needed. | ||
|
|
||
| --- | ||
| Quick Example | ||
| ``` | ||
| git clone <this-repo> | ||
| cd <this-repo> | ||
| scp -r common Runner user@target_device_ip:/<user-defined-location> | ||
| ssh user@target_device_ip | ||
| cd /<user-defined-location>/Runner && ./run-test.sh UserDataEncryption | ||
|
|
||
| Sample output: | ||
| sh-5.2# ./run-test.sh UserDataEncryption | ||
| [Executing test case: UserDataEncryption] 2025-12-19 14:30:04 - | ||
| [INFO] 2025-12-19 14:30:04 - Running as root. Continuing... | ||
| [INFO] 2025-12-19 14:30:04 - ----------------------------------------------------------------------------------------- | ||
| [INFO] 2025-12-19 14:30:04 - -------------------Starting UserDataEncryption Testcase---------------------------- | ||
| [INFO] 2025-12-19 14:30:04 - === Test Initialization === | ||
| [INFO] 2025-12-19 14:30:04 - Kernel supports fscrypt (CONFIG_FS_ENCRYPTION=y/m). | ||
| [INFO] 2025-12-19 14:30:04 - Checking if dependency binary is available | ||
| [INFO] 2025-12-19 14:30:04 - Temporary key file created: /tmp/tmp.mI6nEn6f1x | ||
| [INFO] 2025-12-19 14:30:04 - Generating 64-byte encryption key | ||
| [INFO] 2025-12-19 14:30:04 - Creating unique mount folder under /mnt | ||
| [INFO] 2025-12-19 14:30:04 - Created unique mount directory: /mnt/testing.XIPMnd | ||
| [INFO] 2025-12-19 14:30:04 - Derived filesystem mount point: /var | ||
| [INFO] 2025-12-19 14:30:04 - Filesystem at /var: ext4 | ||
| [INFO] 2025-12-19 14:30:04 - Adding encryption key to the filesystem | ||
| [INFO] 2025-12-19 14:30:04 - No relevant, non-benign errors for modules [fscrypt] in recent dmesg. | ||
| [INFO] 2025-12-19 14:30:04 - Key ID: 93c4e82e13a0d4472cb48a498047db57 | ||
| [INFO] 2025-12-19 14:30:04 - Checking key status | ||
| [INFO] 2025-12-19 14:30:04 - Key Status: Present (user_count=1, added_by_self) | ||
| [INFO] 2025-12-19 14:30:04 - Setting encryption policy on /mnt/testing.XIPMnd | ||
| [INFO] 2025-12-19 14:30:04 - No relevant, non-benign errors for modules [fscrypt] in recent dmesg. | ||
| [INFO] 2025-12-19 14:30:04 - Verifying encryption policy | ||
| [INFO] 2025-12-19 14:30:04 - No relevant, non-benign errors for modules [fscrypt] in recent dmesg. | ||
| [INFO] 2025-12-19 14:30:04 - Policy verification successful: Master key identifier matches key_id | ||
| [INFO] 2025-12-19 14:30:04 - Creating test file in encrypted directory | ||
| [INFO] 2025-12-19 14:30:04 - Reading test file | ||
| [PASS] 2025-12-19 14:30:04 - UserDataEncryption : Test Passed | ||
| [INFO] 2025-12-19 14:30:04 - -------------------Completed UserDataEncryption Testcase---------------------------- | ||
| [INFO] 2025-12-19 14:30:04 - Cleaning up mount directory: /mnt/testing.XIPMnd | ||
| [INFO] 2025-12-19 14:30:04 - Deleted test file: /mnt/testing.XIPMnd/file.txt | ||
| [INFO] 2025-12-19 14:30:04 - Removed mount directory: /mnt/testing.XIPMnd | ||
| [PASS] 2025-12-19 14:30:04 - UserDataEncryption passed | ||
|
|
||
| [INFO] 2025-12-19 14:30:04 - ========== Test Summary ========== | ||
| PASSED: | ||
| UserDataEncryption | ||
|
|
||
| FAILED: | ||
| None | ||
|
|
||
| SKIPPED: | ||
| None | ||
| [INFO] 2025-12-19 14:30:04 - ================================== | ||
| 4. Results will be available in the `/<user-defined-location>/Runner/suites/Kernel/baseport/UserDataEncryption/` directory. | ||
|
|
||
| ## Notes | ||
|
|
||
| - The script uses /data/UserDataEncryption for all operations. | ||
| - Temporary files such as the encryption key are cleaned up after the test. | ||
| - If any test fails, the script logs the error and exits with a failure code. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| metadata: | ||
| format: Lava-Test Test Definition 1.0 | ||
| name: UserDataEncryption | ||
| description: "Validates fscrypt-based user data encryption on supported filesystems" | ||
| maintainer: | ||
| - bbharani@qti.qualcomm.com | ||
| os: | ||
| - openembedded | ||
| scope: | ||
| - functional | ||
| devices: | ||
| - rb3gen2 | ||
| - ridesx | ||
| - lemans evk | ||
| - monaco evk | ||
|
|
||
| run: | ||
| steps: | ||
| - cd Runner | ||
| - $PWD/suites/Kernel/Baseport/UserDataEncryption/run.sh || true | ||
| - $PWD/utils/send-to-lava.sh $PWD/suites/Kernel/Baseport/UserDataEncryption/UserDataEncryption.res || true |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,236 @@ | ||
| #!/bin/sh | ||
|
|
||
| # Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries. | ||
| # SPDX-License-Identifier: BSD-3-Clause-Clear | ||
| # Robustly find and source init_env | ||
| SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" | ||
| INIT_ENV="" | ||
| SEARCH="$SCRIPT_DIR" | ||
| while [ "$SEARCH" != "/" ]; do | ||
| if [ -f "$SEARCH/init_env" ]; then | ||
| INIT_ENV="$SEARCH/init_env" | ||
| break | ||
| fi | ||
| SEARCH=$(dirname "$SEARCH") | ||
| done | ||
|
|
||
| if [ -z "$INIT_ENV" ]; then | ||
| echo "[ERROR] Could not find init_env (starting at $SCRIPT_DIR)" >&2 | ||
| exit 0 | ||
| fi | ||
|
|
||
| if [ -z "$__INIT_ENV_LOADED" ]; then | ||
| # shellcheck disable=SC1090 | ||
| . "$INIT_ENV" | ||
| fi | ||
|
|
||
| # shellcheck disable=SC1090,SC1091 | ||
| . "$TOOLS/functestlib.sh" | ||
|
|
||
| FSCRYPTCTL="${FSCRYPTCTL:-fscryptctl}" | ||
| TESTNAME="UserDataEncryption" | ||
| test_path=$(find_test_case_by_name "$TESTNAME") | ||
xbharani marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| if [ -z "$test_path" ]; then | ||
| log_fail "Path not found for $TESTNAME test. Falling back to SCRIPT_DIR: $SCRIPT_DIR" | ||
| test_path="$SCRIPT_DIR" | ||
| fi | ||
|
|
||
| res_file="$test_path/$TESTNAME.res" | ||
|
|
||
| # Ensure script runs as root | ||
| if [ "$(id -u)" -ne 0 ]; then | ||
| log_skip "This script must be run as root." | ||
| echo "$TESTNAME SKIP" > "$res_file" | ||
| exit 0 | ||
| else | ||
| log_info "Running as root. Continuing..." | ||
| fi | ||
|
|
||
| if ! cd "$test_path"; then | ||
| log_fail "Failed to change directory to $test_path" | ||
| echo "$TESTNAME FAIL" > "$res_file" | ||
| exit 0 | ||
| fi | ||
|
|
||
| # Globals that cleanup will use | ||
| MOUNT_DIR="" | ||
| FS_PATH="" | ||
| key_id="" | ||
| KEY_FILE="" | ||
xbharani marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| cleanup() { | ||
| if [ -n "$MOUNT_DIR" ] && [ "$MOUNT_DIR" != "/" ]; then | ||
| log_info "Cleaning up mount directory: $MOUNT_DIR" | ||
|
|
||
| if rm -f "$MOUNT_DIR/file.txt" 2>/dev/null; then | ||
| log_info "Deleted test file: $MOUNT_DIR/file.txt" | ||
| else | ||
| log_warn "Failed to delete test file: $MOUNT_DIR/file.txt" | ||
| fi | ||
|
|
||
| if rmdir "$MOUNT_DIR" 2>/dev/null; then | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. rm / rmdir cleanup is fine, but you should not assume the file exists. Your logging is OK, but make it quieter. |
||
| log_info "Removed mount directory: $MOUNT_DIR" | ||
| else | ||
| log_warn "Failed to remove mount directory: $MOUNT_DIR" | ||
| fi | ||
| fi | ||
|
|
||
| if [ -n "$key_id" ]; then | ||
| "$FSCRYPTCTL" remove_key "$key_id" "$FS_PATH" >/dev/null 2>&1 || true | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Cleanup removes key even if FS_PATH is empty. If key_id is set but FS_PATH is empty (partial failure), you may call remove_key with bad args. |
||
| fi | ||
|
|
||
|
|
||
| if [ -n "$KEY_FILE" ]; then | ||
| if ! rm -f "$KEY_FILE" 2>/dev/null; then | ||
| log_warn "Failed to remove key file: $KEY_FILE" | ||
| fi | ||
| fi | ||
| } | ||
|
|
||
| # Run cleanup on normal exit, Ctrl-C, or SIGTERM | ||
| trap cleanup EXIT INT TERM | ||
xbharani marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| log_info "-----------------------------------------------------------------------------------------" | ||
| log_info "-------------------Starting $TESTNAME Testcase----------------------------" | ||
| log_info "=== Test Initialization ===" | ||
|
|
||
|
|
||
| ## kernel config check | ||
| if [ -r /proc/config.gz ]; then | ||
| if zcat /proc/config.gz | grep -q '^CONFIG_FS_ENCRYPTION=[ym]'; then | ||
| log_info "Kernel supports fscrypt (CONFIG_FS_ENCRYPTION=y/m)." | ||
| else | ||
| log_skip "$TESTNAME : Kernel lacks CONFIG_FS_ENCRYPTION. Skipping." | ||
| echo "$TESTNAME SKIP" > "$res_file" | ||
| exit 0 | ||
| fi | ||
| else | ||
| log_warn "/proc/config.gz not available; cannot verify kernel config. Proceeding" | ||
| fi | ||
|
|
||
| log_info "Checking if dependency binary is available" | ||
| check_dependencies "$FSCRYPTCTL" | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. if check_dependencies returns non-zero you currently don’t handle it (you just call it). |
||
|
|
||
| # Create a secure temporary file for the key | ||
| if KEY_FILE="$(mktemp)"; then | ||
| log_info "Temporary key file created: $KEY_FILE" | ||
| chmod 600 "$KEY_FILE" | ||
| else | ||
| log_fail "$TESTNAME : Failed to create temporary key file" | ||
| echo "[ERROR] Failed to create temporary key file" >&2 | ||
| exit 0 | ||
| fi | ||
|
|
||
xbharani marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| # Step 1: Generate a 64-byte key | ||
| log_info "Generating 64-byte encryption key" | ||
| if ! head -c 64 /dev/urandom > "$KEY_FILE"; then | ||
| log_fail "$TESTNAME : Failed to generate encryption key" | ||
| echo "$TESTNAME FAIL" > "$res_file" | ||
| exit 0 | ||
| fi | ||
|
|
||
| # Step 2: Create mount folder (this will create an unique folder under mnt) | ||
| log_info "Creating unique mount folder under /mnt" | ||
| MOUNT_DIR=$(mktemp -d /mnt/testing.XXXXXX) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. mktemp under /mnt is not guaranteed to exist or be writable. On many images /mnt exists, but not always. Better: |
||
| if [ ! -d "$MOUNT_DIR" ]; then | ||
| log_fail "$TESTNAME : Failed to create mount directory" | ||
| echo "$TESTNAME FAIL" > "$res_file" | ||
| exit 0 | ||
| fi | ||
| log_info "Created unique mount directory: $MOUNT_DIR" | ||
|
|
||
|
|
||
| FS_PATH=$(df --output=target "$MOUNT_DIR" | tail -n 1) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. if there's any chance of a busybox/ non-GNU environment, just be aware --output=target may not exist. Given the meta-qcom target, it's probably fine. If we want to be ultra-portable in future, this part might be abstracted into hlper, but for now it's acceptable. |
||
| if [ -z "$FS_PATH" ]; then | ||
| log_fail "$TESTNAME : Failed to determine filesystem mount point for $MOUNT_DIR" | ||
| echo "$TESTNAME FAIL" > "$res_file" | ||
| exit 0 | ||
| fi | ||
| log_info "Derived filesystem mount point: $FS_PATH" | ||
|
|
||
|
|
||
| #file-system check | ||
| if fs_type="$(df -Th "$FS_PATH" 2>/dev/null | awk 'NR==2{print $2}')"; then | ||
| if [ -n "$fs_type" ]; then | ||
| log_info "Filesystem at $FS_PATH: $fs_type" | ||
| else | ||
| log_warn "df -Th succeeded but could not parse filesystem type for $FS_PATH" | ||
| fi | ||
| else | ||
| log_warn "df -Th failed for $FS_PATH" | ||
| fi | ||
|
|
||
| # Step 3: Add the key to the filesystem | ||
| log_info "Adding encryption key to the filesystem" | ||
| key_id=$("$FSCRYPTCTL" add_key "$FS_PATH" < "$KEY_FILE" 2>/dev/null) | ||
xbharani marked this conversation as resolved.
Show resolved
Hide resolved
xbharani marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| scan_dmesg_errors "$SCRIPT_DIR" "fscrypt" "" | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. scan_dmesg_errors is aggressive, consider only scan at end, or scan with a narrow time window. |
||
|
|
||
| if [ -z "$key_id" ]; then | ||
| log_fail "$TESTNAME : Failed to add encryption key" | ||
| echo "$TESTNAME FAIL" > "$res_file" | ||
| exit 0 | ||
| fi | ||
|
|
||
| log_info "Key ID: $key_id" | ||
|
|
||
| # Step 4: Check key status | ||
| log_info "Checking key status" | ||
| status=$("$FSCRYPTCTL" key_status "$key_id" "$FS_PATH" 2>/dev/null) | ||
xbharani marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| if [ -z "$status" ]; then | ||
| log_fail "$TESTNAME : Failed to get key status" | ||
| echo "$TESTNAME FAIL" > "$res_file" | ||
| exit 0 | ||
| fi | ||
| log_info "Key Status: $status" | ||
|
|
||
| if ! echo "$status" | grep -q "^Present"; then | ||
| log_fail "$TESTNAME : Key is not usable (status: $status)" | ||
| echo "$TESTNAME FAIL" > "$res_file" | ||
| exit 0 | ||
| fi | ||
|
|
||
|
|
||
| # Step 5: Set encryption policy | ||
| log_info "Setting encryption policy on $MOUNT_DIR" | ||
|
|
||
| if ! "$FSCRYPTCTL" set_policy "$key_id" "$MOUNT_DIR"; then | ||
| log_fail "$TESTNAME : Failed to set encryption policy" | ||
| echo "$TESTNAME FAIL" > "$res_file" | ||
| exit 0 | ||
| fi | ||
| scan_dmesg_errors "$SCRIPT_DIR" "fscrypt" "" | ||
|
|
||
|
|
||
| # Step 6: Verify policy | ||
| log_info "Verifying encryption policy" | ||
| policy_output=$("$FSCRYPTCTL" get_policy "$MOUNT_DIR" 2>/dev/null) | ||
xbharani marked this conversation as resolved.
Show resolved
Hide resolved
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Your “encryption validation” is too weak (it will pass even if nothing is encrypted)
That proves “filesystem writable”, not “data is encrypted”. At minimum add one real validation: |
||
| scan_dmesg_errors "$SCRIPT_DIR" "fscrypt" "" | ||
|
|
||
|
|
||
| policy_key=$(echo "$policy_output" | awk -F': ' '/Master key identifier/ {print $2}' | tr -d '[:space:]') | ||
|
|
||
| if [ "$policy_key" = "$key_id" ]; then | ||
| log_info "Policy verification successful: Master key identifier matches key_id" | ||
| else | ||
| log_fail "$TESTNAME : Policy verification failed (expected $key_id, got $policy_key)" | ||
| echo "$TESTNAME FAIL" > "$res_file" | ||
| exit 0 | ||
| fi | ||
|
|
||
xbharani marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| # Step 7: Create and read a test file | ||
| log_info "Creating test file in encrypted directory" | ||
| echo "file" > "$MOUNT_DIR/file.txt" | ||
|
|
||
| log_info "Reading test file" | ||
| file_content=$(cat "$MOUNT_DIR/file.txt") | ||
| if [ "$file_content" = "file" ]; then | ||
| log_pass "$TESTNAME : Test Passed" | ||
| echo "$TESTNAME PASS" > "$res_file" | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add |
||
| else | ||
| log_fail "$TESTNAME : Test Failed" | ||
| echo "$TESTNAME FAIL" > "$res_file" | ||
| exit 0 | ||
| fi | ||
|
|
||
| log_info "-------------------Completed $TESTNAME Testcase----------------------------" | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the var is unset, some shells can still behave oddly, also it will trigger set -u issues if added later.
Use:
if [ -z "${__INIT_ENV_LOADED:-}" ]; then