Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
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-11-18 15:03:05 -
[INFO] Running as root. Continuing...
[INFO] 2025-11-18 15:03:05 - -----------------------------------------------------------------------------------------
[INFO] 2025-11-18 15:03:05 - -------------------Starting UserDataEncryption Testcase----------------------------
[INFO] 2025-11-18 15:03:05 - === Test Initialization ===
[INFO] 2025-11-18 15:03:05 - Checking if dependency binary is available
[INFO] 2025-11-18 15:03:05 - Temporary key file created: /tmp/tmp.yV9Fgr7z7T
[INFO] 2025-11-18 15:03:05 - Generating 64-byte encryption key
[INFO] 2025-11-18 15:03:05 - Creating unique mount folder under /mnt
[INFO] 2025-11-18 15:03:05 - Created unique mount directory: /mnt/testing.pb1KIn
[INFO] 2025-11-18 15:03:05 - Derived filesystem mount point: /var
[INFO] 2025-11-18 15:03:05 - Adding encryption key to the filesystem
[INFO] 2025-11-18 15:03:05 - No relevant, non-benign errors for modules [fscrypt] in recent dmesg.
[INFO] 2025-11-18 15:03:05 - Key ID: 80ae0d678e52fb126ea6eda7d32861eb
[INFO] 2025-11-18 15:03:05 - Checking key status
[INFO] 2025-11-18 15:03:05 - Key Status: Present (user_count=1, added_by_self)
[INFO] 2025-11-18 15:03:05 - Setting encryption policy on /mnt/testing.pb1KIn
[INFO] 2025-11-18 15:03:06 - No relevant, non-benign errors for modules [fscrypt] in recent dmesg.
[INFO] 2025-11-18 15:03:06 - Verifying encryption policy
[INFO] 2025-11-18 15:03:06 - No relevant, non-benign errors for modules [fscrypt] in recent dmesg.
[INFO] 2025-11-18 15:03:06 - Policy verification successful: Master key identifier matches key_id
[INFO] 2025-11-18 15:03:06 - Creating test file in encrypted directory
[INFO] 2025-11-18 15:03:06 - Reading test file
[PASS] 2025-11-18 15:03:06 - UserDataEncryption : Test Passed
[INFO] 2025-11-18 15:03:06 - -------------------Completed UserDataEncryption Testcase----------------------------
[INFO] 2025-11-18 15:03:06 - Cleaning up mount directory: /mnt/testing.pb1KIn
[INFO] 2025-11-18 15:03:06 - Deleted test file: /mnt/testing.pb1KIn/file.txt
[INFO] 2025-11-18 15:03:06 - Removed mount directory: /mnt/testing.pb1KIn
[PASS] 2025-11-18 15:03:06 - UserDataEncryption passed

[INFO] 2025-11-18 15:03:06 - ========== Test Summary ==========
PASSED:
UserDataEncryption

FAILED:
None

SKIPPED:
None
[INFO] 2025-11-18 15:03:06 - ==================================
```
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:
- [email protected]
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
209 changes: 209 additions & 0 deletions Runner/suites/Kernel/Baseport/UserDataEncryption/run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
#!/bin/sh

# Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
# SPDX-License-Identifier: BSD-3-Clause-Clear

# Ensure script runs as root
if [ "$(id -u)" -ne 0 ]; then
echo "[ERROR] This script must be run as root." >&2
exit 1
Copy link
Contributor

Choose a reason for hiding this comment

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

Use exit 0 as in Lava. If the script uses exit 1, it will not proceed to the remaining tests.

else
echo "[INFO] Running as root. Continuing..."
fi

# 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 1
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")

if [ -z "$test_path" ]; then
log_fail "Path not found for $TESTNAME test. Falling back to SCRIPT_DIR: $SCRIPT_DIR"
test_path="$SCRIPT_DIR"

echo "$TESTNAME FAIL" > "$SCRIPT_DIR/$TESTNAME.res"
Copy link
Contributor

Choose a reason for hiding this comment

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

It's nicer if every test always write the .res in test_path, not in SCRIPT_DIR

log_fail "$TESTNAME : Test case directory not found"
exit 1
fi

cd "$test_path" || {
log_fail "Failed to change directory to $test_path"
echo "$TESTNAME FAIL" > "$SCRIPT_DIR/$TESTNAME.res"
exit 1
}

res_file="./$TESTNAME.res"
Copy link
Contributor

Choose a reason for hiding this comment

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

Result file isn’t written for some early exits (e.g., not root / init_env missing).
If your CI expects a .res, write it before exiting anywhere you can. Minimal way: define res_file early and use it in early failures:

Copy link
Author

Choose a reason for hiding this comment

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

only early exits where res_file is not created is script root & init_env, we cannot create res_file for these as the res_file path is created post init_env.
No code change for fixing this.


# Globals that cleanup will use
key_id=""
KEY_FILE=""
Copy link
Contributor

Choose a reason for hiding this comment

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

It's slightly safer to inititalize globals before trap so they're always defined.
MOUNT_DIR=""
FS_PATH=""


cleanup() {
if [ -n "$MOUNT_DIR" ] && [ "$MOUNT_DIR" != "/" ]; then
log_info "Cleaning up mount directory: $MOUNT_DIR"
if [ -f "$MOUNT_DIR/file.txt" ]; then
rm -f "$MOUNT_DIR/file.txt" 2>/dev/null || true
log_info "Deleted test file: $MOUNT_DIR/file.txt"
fi

if [ -d "$MOUNT_DIR" ]; then
rmdir "$MOUNT_DIR" 2>/dev/null || true
Copy link
Contributor

Choose a reason for hiding this comment

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

you always log "Removed mount directory" even if it failed. Better add precise logs, check the return code.

log_info "Removed mount directory: $MOUNT_DIR"
fi
fi

if [ -n "$key_id" ]; then
"$FSCRYPTCTL" remove_key "$key_id" "$FS_PATH" >/dev/null 2>&1 || true
fi
[ -n "$KEY_FILE" ] && rm -f "$KEY_FILE" 2>/dev/null || true
}

# Run cleanup on normal exit, Ctrl-C, or SIGTERM
trap cleanup EXIT INT TERM

log_info "-----------------------------------------------------------------------------------------"
log_info "-------------------Starting $TESTNAME Testcase----------------------------"
log_info "=== Test Initialization ==="

log_info "Checking if dependency binary is available"
check_dependencies "$FSCRYPTCTL"

if ! command -v "$FSCRYPTCTL" >/dev/null 2>&1; then
log_fail "$FSCRYPTCTL binary was not found. Skipping $TESTNAME."
Copy link
Contributor

Choose a reason for hiding this comment

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

use log_warn

echo "$TESTNAME SKIP" > "$res_file"
exit 0
fi

# 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 1
Copy link
Contributor

Choose a reason for hiding this comment

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

NIT

fi

Copy link
Contributor

Choose a reason for hiding this comment

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

Kernel/filesystem precheck: Add check_kernel_config CONFIG_FS_ENCRYPTION (and optional CONFIG_FS_VERITY if you care) to SKIP gracefully on kernels without fscrypt. Also verify that the mount backing $MOUNT_DIR is ext4/f2fs with encryption support (or at least that add_key succeeds on that mountpoint).

Copy link
Author

Choose a reason for hiding this comment

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

check for add_key success exists,

key_id=$("$FSCRYPTCTL" add_key "$FS_PATH" < "$KEY_FILE" 2>/dev/null)
if [ -z "$key_id" ]; then
log_fail "$TESTNAME : Failed to add encryption key"

# 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 1
Copy link
Contributor

Choose a reason for hiding this comment

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

NIT

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)
if [ ! -d "$MOUNT_DIR" ]; then
log_fail "$TESTNAME : Failed to create mount directory"
echo "$TESTNAME FAIL" > "$res_file"
exit 1
Copy link
Contributor

Choose a reason for hiding this comment

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

NIT

fi
log_info "Created unique mount directory: $MOUNT_DIR"


FS_PATH=$(df --output=target "$MOUNT_DIR" | tail -n 1)
Copy link
Contributor

Choose a reason for hiding this comment

The 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 1
Copy link
Contributor

Choose a reason for hiding this comment

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

NIT

fi
log_info "Derived filesystem mount point: $FS_PATH"

# 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)
scan_dmesg_errors "$SCRIPT_DIR" "fscrypt" ""

if [ -z "$key_id" ]; then
log_fail "$TESTNAME : Failed to add encryption key"
echo "$TESTNAME FAIL" > "$res_file"
exit 1
Copy link
Contributor

Choose a reason for hiding this comment

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

NIT

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)
if [ -z "$status" ]; then
log_fail "$TESTNAME : Failed to get key status"
echo "$TESTNAME FAIL" > "$res_file"
exit 1
Copy link
Contributor

Choose a reason for hiding this comment

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

NIT

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 1
Copy link
Contributor

Choose a reason for hiding this comment

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

NIT

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 1
Copy link
Contributor

Choose a reason for hiding this comment

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

NIT

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)
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 1
fi

# 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"
else
log_fail "$TESTNAME : Test Failed"
echo "$TESTNAME FAIL" > "$res_file"
exit 1
Copy link
Contributor

Choose a reason for hiding this comment

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

NIT

fi

log_info "-------------------Completed $TESTNAME Testcase----------------------------"
Loading