Skip to content

Add fscrypt filesystem-encryption test suite - #4595

Open
Deepu Thomas (dethoma) wants to merge 2 commits into
microsoft:mainfrom
dethoma:dethoma/add-fscrypt-test
Open

Add fscrypt filesystem-encryption test suite#4595
Deepu Thomas (dethoma) wants to merge 2 commits into
microsoft:mainfrom
dethoma:dethoma/add-fscrypt-test

Conversation

@dethoma

Copy link
Copy Markdown

Adds a security functional test suite validating native kernel filesystem encryption (fscrypt) end to end, with two variations: ext4 via e4crypt (e2fsprogs) and f2fs via f2fscrypt (f2fs-tools). Each formats a data disk with encryption support, applies an encryption policy to a directory, writes a known plaintext, then proves: (1) data is readable while the key is in the keyring, (2) a fresh mount without the key exposes only ciphertext filenames and denies plaintext access, and (3) re-adding the identical key transparently unlocks the data. Skips when the crypt tool is missing or the kernel lacks CONFIG_FS_ENCRYPTION=y.

Description

Related Issue

Type of Change

  • Bug fix
  • New feature
  • Breaking change
  • Refactoring
  • Documentation update

Checklist

  • Description is filled in above
  • No credentials, secrets, or internal details are included
  • Peer review requested (if not, add required peer reviewers after raising PR)
  • Tests executed and results posted below

Test Validation

Key Test Cases:

Impacted LISA Features:

Tested Azure Marketplace Images:

Test Results

Image VM Size Result
PASSED / FAILED / SKIPPED

Adds a security functional test suite validating native kernel filesystem encryption (fscrypt) end to end, with two variations: ext4 via e4crypt (e2fsprogs) and f2fs via f2fscrypt (f2fs-tools). Each formats a data disk with encryption support, applies an encryption policy to a directory, writes a known plaintext, then proves: (1) data is readable while the key is in the keyring, (2) a fresh mount without the key exposes only ciphertext filenames and denies plaintext access, and (3) re-adding the identical key transparently unlocks the data. Skips when the crypt tool is missing or the kernel lacks CONFIG_FS_ENCRYPTION=y.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds a new security functional test suite that validates end-to-end fscrypt filesystem encryption behavior on a data disk, covering both ext4 (e4crypt) and f2fs (f2fscrypt).

Changes:

  • Introduces FscryptSuite with two test cases: ext4 + e4crypt and f2fs + f2fscrypt.
  • Implements an end-to-end lifecycle validation: write with key present → remount without key (locked) → re-add key (unlocked).

Comment on lines +107 to +115
if (
node.execute(
"grep -q '^CONFIG_FS_ENCRYPTION=y' /boot/config-$(uname -r)",
sudo=True,
shell=True,
).exit_code
!= 0
):
raise SkippedException("kernel is not built with CONFIG_FS_ENCRYPTION=y")
mount.umount(data_disk, mount_point, erase=False)
mount.mount(data_disk, mount_point)

listing = node.execute(f"ls {secret_dir}", sudo=True, shell=True).stdout
Comment on lines +199 to +200
# --- Cleanup ------------------------------------------------------
mount.umount(data_disk, mount_point, erase=False)
install_packages is defined on Posix, not the base OperatingSystem type that node.os is annotated as. Cast to Posix (matching the pattern in security/openssl.py) to satisfy mypy.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 13, 2026 18:26

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 6 comments.

# Copyright (c) Microsoft Corporation.
# Licensed under the MIT license.

from typing import List, cast
Comment on lines +97 to +98
mount_point = "/mnt/fscrypt"
secret_dir = f"{mount_point}/secret"
Comment on lines +108 to +116
if (
node.execute(
"grep -q '^CONFIG_FS_ENCRYPTION=y' /boot/config-$(uname -r)",
sudo=True,
shell=True,
).exit_code
!= 0
):
raise SkippedException("kernel is not built with CONFIG_FS_ENCRYPTION=y")
Comment on lines +158 to +177
# --- Lock: fresh mount without the key ---------------------------
mount.umount(data_disk, mount_point, erase=False)
mount.mount(data_disk, mount_point)

listing = node.execute(f"ls {secret_dir}", sudo=True, shell=True).stdout
if "plain.txt" in listing:
raise AssertionError(
"filename 'plain.txt' is visible in cleartext without the key — "
"encryption policy is not in effect"
)

# Reading the file without the key must fail (ENOKEY). Encrypted
# filenames make the original path non-existent, so a read is expected
# to return a non-zero exit code.
if (
node.execute(f"cat {secret_dir}/plain.txt", sudo=True, shell=True).exit_code
== 0
):
raise AssertionError("plaintext was readable without the key")
log.info("directory is locked (ciphertext filenames, no plaintext access)")
Comment on lines +194 to +197
if _PLAINTEXT_TOKEN not in result.stdout:
raise AssertionError(
"recovered content did not match the original plaintext"
)
Comment on lines +200 to +201
# --- Cleanup ------------------------------------------------------
mount.umount(data_disk, mount_point, erase=False)
if "plain.txt" in listing:
raise AssertionError(
"filename 'plain.txt' is visible in cleartext without the key — "
"encryption policy is not in effect"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

run against image canonical 0001-com-ubuntu-server-jammy 22_04-lts-gen2 22.04.202607110 failed with below exception


2026-07-15 03:41:30.081[4376][DEBUG] lisa.env[generated_0].node[0].cmd[9849].stdout /dev/sdc
2026-07-15 03:41:30.098[3520][DEBUG] lisa.env[generated_0].node[0].cmd[9849] execution time: 0.144 sec, exit code: 0
2026-07-15 03:41:30.098[3520][INFO] lisa.case[verify_fscrypt_ext4][lisa_0_0] using data disk /dev/sdc for ext4 fscrypt test
2026-07-15 03:41:30.099[3520][DEBUG] lisa.env[generated_0].node[0].cmd[2480] cmd: ['sudo', 'sh', '-c', 'umount  /mnt/fscrypt'], cwd: None, shell: True, sudo: True, nohup: False, posix: True, remote: True, encoding: utf-8
2026-07-15 03:41:30.219[7896][DEBUG] lisa.env[generated_0].node[0].cmd[2480].stdout umount: /mnt/fscrypt: no mount point specified.
2026-07-15 03:41:30.227[3520][DEBUG] lisa.env[generated_0].node[0].cmd[2480] execution time: 0.128 sec, exit code: 32
2026-07-15 03:41:30.228[3520][DEBUG] lisa.env[generated_0].node[0].cmd[1118] cmd: ['sudo', 'sh', '-c', 'mkfs.ext4 -F -O encrypt /dev/sdc'], cwd: None, shell: True, sudo: True, nohup: False, posix: True, remote: True, encoding: utf-8
2026-07-15 03:41:30.349[7808][DEBUG] lisa.env[generated_0].node[0].cmd[1118].stdout mke2fs 1.46.5 (30-Dec-2021)
2026-07-15 03:41:30.492[7808][DEBUG] lisa.env[generated_0].node[0].cmd[1118].stdout Discarding device blocks:       0/8388608���������������               ���������������done                            
2026-07-15 03:41:30.494[7808][DEBUG] lisa.env[generated_0].node[0].cmd[1118].stdout Creating filesystem with 8388608 4k blocks and 2097152 inodes
2026-07-15 03:41:30.494[7808][DEBUG] lisa.env[generated_0].node[0].cmd[1118].stdout Filesystem UUID: 9f73aa62-6b5f-4996-a0c7-5fe16d2342f9
2026-07-15 03:41:30.495[7808][DEBUG] lisa.env[generated_0].node[0].cmd[1118].stdout Superblock backups stored on blocks: 
2026-07-15 03:41:30.495[7808][DEBUG] lisa.env[generated_0].node[0].cmd[1118].stdout 	32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208, 
2026-07-15 03:41:30.495[7808][DEBUG] lisa.env[generated_0].node[0].cmd[1118].stdout 	4096000, 7962624
2026-07-15 03:41:30.496[7808][DEBUG] lisa.env[generated_0].node[0].cmd[1118].stdout Allocating group tables:   0/256�������       �������done                            
2026-07-15 03:41:30.499[7808][DEBUG] lisa.env[generated_0].node[0].cmd[1118].stdout Writing inode tables:   0/256�������       �������done                            
2026-07-15 03:41:33.064[7808][DEBUG] lisa.env[generated_0].node[0].cmd[1118].stdout Creating journal (65536 blocks): done
2026-07-15 03:41:33.183[7808][DEBUG] lisa.env[generated_0].node[0].cmd[1118].stdout Writing superblocks and filesystem accounting information:   0/256�������       �������done
2026-07-15 03:41:33.188[3520][DEBUG] lisa.env[generated_0].node[0].cmd[1118] execution time: 2.960 sec, exit code: 0
2026-07-15 03:41:33.373[3520][DEBUG] lisa.env[generated_0].node[0].cmd[6768] cmd: ['sudo', 'sh', '-c', 'mount /dev/sdc /mnt/fscrypt'], cwd: None, shell: True, sudo: True, nohup: False, posix: True, remote: True, encoding: utf-8
2026-07-15 03:41:33.597[3520][DEBUG] lisa.env[generated_0].node[0].cmd[6768] execution time: 0.219 sec, exit code: 0
2026-07-15 03:41:33.597[3520][DEBUG] lisa.env[generated_0].node[0].cmd[8009] cmd: ['sudo', 'sh', '-c', 'mkdir -p /mnt/fscrypt/secret && DESC=$(printf \'lisa-fscrypt-pass\\n\' | e4crypt add_key -S 0x00112233445566778899aabbccddeeff | grep -oE \'[0-9a-f]{16}\' | head -1) && test -n "$DESC" && e4crypt set_policy $DESC /mnt/fscrypt/secret && echo lisa-fscrypt-topsecret > /mnt/fscrypt/secret/plain.txt && grep -q lisa-fscrypt-topsecret /mnt/fscrypt/secret/plain.txt'], cwd: None, shell: True, sudo: True, nohup: False, posix: True, remote: True, encoding: utf-8
2026-07-15 03:41:33.782[7188][DEBUG] lisa.env[generated_0].node[0].cmd[8009].stdout Key with descriptor [dbd2ba8ec6f15173] applied to /mnt/fscrypt/secret.
2026-07-15 03:41:33.807[3520][DEBUG] lisa.env[generated_0].node[0].cmd[8009] execution time: 0.209 sec, exit code: 0
2026-07-15 03:41:33.808[3520][INFO] lisa.case[verify_fscrypt_ext4][lisa_0_0] plaintext readable while encryption key is present
2026-07-15 03:41:33.808[3520][DEBUG] lisa.env[generated_0].node[0].cmd[9828] cmd: ['sudo', 'sh', '-c', 'umount  /mnt/fscrypt'], cwd: None, shell: True, sudo: True, nohup: False, posix: True, remote: True, encoding: utf-8
2026-07-15 03:41:33.960[3520][DEBUG] lisa.env[generated_0].node[0].cmd[9828] execution time: 0.151 sec, exit code: 0
2026-07-15 03:41:34.033[3520][DEBUG] lisa.env[generated_0].node[0].cmd[4069] cmd: ['sudo', 'sh', '-c', 'mount /dev/sdc /mnt/fscrypt'], cwd: None, shell: True, sudo: True, nohup: False, posix: True, remote: True, encoding: utf-8
2026-07-15 03:41:34.207[3520][DEBUG] lisa.env[generated_0].node[0].cmd[4069] execution time: 0.172 sec, exit code: 0
2026-07-15 03:41:34.208[3520][DEBUG] lisa.env[generated_0].node[0].cmd[912] cmd: ['sudo', 'sh', '-c', 'ls /mnt/fscrypt/secret'], cwd: None, shell: True, sudo: True, nohup: False, posix: True, remote: True, encoding: utf-8
2026-07-15 03:41:34.340[3060][DEBUG] lisa.env[generated_0].node[0].cmd[912].stdout plain.txt
2026-07-15 03:41:34.350[3520][DEBUG] lisa.env[generated_0].node[0].cmd[912] execution time: 0.142 sec, exit code: 0
2026-07-15 03:41:34.351[5592][ERROR] lisa.case[verify_fscrypt_ext4][lisa_0_0] case failed
Traceback (most recent call last):
  File "C:\app\lsg-lisa\lisa\lisa\testsuite.py", line 914, in __run_case
    _call_with_timeout(
  File "C:\app\lsg-lisa\lisa\lisa\testsuite.py", line 60, in _call_with_timeout
    func_timeout(
  File "C:\Python\Lib\site-packages\func_timeout\dafunc.py", line 108, in func_timeout
    raise_exception(exception)
  File "C:\Python\Lib\site-packages\func_timeout\py3_raise.py", line 7, in raise_exception
    raise exception[0] from None
  File "C:\app\lsg-lisa\lisa\lisa\testsuite.py", line 649, in wrapper
    func(*args, **parameters)
  File "C:\app\lsg-lisa\lisa\lisa\microsoft\testsuites\security\fscrypt.py", line 57, in verify_fscrypt_ext4
    self._run_fscrypt_lifecycle(
  File "C:\app\lsg-lisa\lisa\lisa\microsoft\testsuites\security\fscrypt.py", line 164, in _run_fscrypt_lifecycle
    raise AssertionError(
AssertionError: filename 'plain.txt' is visible in cleartext without the key � encryption policy is not in effect

@LiliDeng

Copy link
Copy Markdown
Collaborator

Deepu Thomas (@dethoma) Please update it in a timely manner.

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