diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e829bb4..56e0e2d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,7 +22,9 @@ on: pull_request: env: CFLAGS: -O2 -Wall -Werror - TEST_DEPENDENCIES: e2fsprogs python3 python3-pytest + BUILD_DEPENDENCIES: pandoc + # build dependencies + test dependencies + ALL_DEPENDENCIES: pandoc e2fsprogs python3 python3-pytest jobs: build-and-test: @@ -36,7 +38,7 @@ jobs: - name: Install dependencies run: | sudo apt-get update - sudo apt-get install -y clang $TEST_DEPENDENCIES + sudo apt-get install -y clang $ALL_DEPENDENCIES - name: Build and test run: make test-all CC=${{ matrix.compiler }} - name: C99/pedantic check @@ -52,7 +54,7 @@ jobs: - name: Install dependencies run: | sudo apt-get update - sudo apt-get install -y gcc-multilib $TEST_DEPENDENCIES + sudo apt-get install -y gcc-multilib $ALL_DEPENDENCIES - name: Build and test run: make test-all CFLAGS="$CFLAGS -m32" @@ -67,7 +69,10 @@ jobs: steps: - uses: actions/checkout@v2 - name: Build - run: make + run: | + sudo apt-get update + sudo apt-get install -y $BUILD_DEPENDENCIES + make build-and-test-valgrind: name: Build and test (valgrind enabled) @@ -77,7 +82,7 @@ jobs: - name: Install dependencies run: | sudo apt-get update - sudo apt-get install -y valgrind $TEST_DEPENDENCIES + sudo apt-get install -y valgrind $ALL_DEPENDENCIES - name: Build and test run: make test-all ENABLE_VALGRIND=1 @@ -89,7 +94,7 @@ jobs: - name: Install dependencies run: | sudo apt-get update - sudo apt-get install -y clang $TEST_DEPENDENCIES + sudo apt-get install -y clang $ALL_DEPENDENCIES - name: Build and test run: make test-all CC=clang CFLAGS="$CFLAGS -fsanitize=undefined -fno-sanitize-recover=undefined" @@ -101,7 +106,7 @@ jobs: - name: Install dependencies run: | sudo apt-get update - sudo apt-get install -y clang $TEST_DEPENDENCIES + sudo apt-get install -y clang $ALL_DEPENDENCIES - name: Build and test run: make test-all CC=clang CFLAGS="$CFLAGS -fsanitize=address -fno-sanitize-recover=address" @@ -113,7 +118,7 @@ jobs: - name: Install dependencies run: | sudo apt-get update - sudo apt-get install -y clang-format + sudo apt-get install -y clang-format $BUILD_DEPENDENCIES - name: Check source code formatting run: make format-check @@ -125,6 +130,6 @@ jobs: - name: Install dependencies run: | sudo apt-get update - sudo apt-get install -y clang-tools + sudo apt-get install -y clang-tools $BUILD_DEPENDENCIES - name: Run clang static analyzer run: scan-build --status-bugs make diff --git a/.gitignore b/.gitignore index 9a0a94d..f940601 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ fscryptctl +fscryptctl.1 *.o .cache/ __pycache__/ diff --git a/Makefile b/Makefile index 0480f3d..994de41 100644 --- a/Makefile +++ b/Makefile @@ -28,6 +28,9 @@ PREFIX ?= /usr/local # Directory where the binary gets installed BINDIR ?= $(PREFIX)/bin +# Direectory where the man page gets installed +MANDIR ?= $(PREFIX)/share/man + # C compiler flags CFLAGS ?= -O2 -Wall @@ -57,6 +60,13 @@ $(OBJ): %.o: %.c $(HDRS) ############################################################################## +# Build the manual page + +fscryptctl.1: fscryptctl.1.md + pandoc -s -t man $+ > $@ + +############################################################################## + # Don't format fscrypt_uapi.h, so that it stays identical to the kernel version. FILES_TO_FORMAT := $(filter-out fscrypt_uapi.h, $(SRC) $(HDRS)) @@ -123,15 +133,27 @@ test-all: # Installation, uninstallation, and cleanup targets -.PHONY: install uninstall clean -install: fscryptctl +all:fscryptctl fscryptctl.1 + +.PHONY: all install install-bin install-man uninstall clean + +install-bin: fscryptctl install -d $(DESTDIR)$(BINDIR) install -m755 $< $(DESTDIR)$(BINDIR) +install-man: fscryptctl.1 + install -d $(DESTDIR)$(MANDIR)/man1 + install -m644 $< $(DESTDIR)$(MANDIR)/man1 + +install:install-bin install-man + uninstall: rm -f $(DESTDIR)$(BINDIR)/fscryptctl + rm -f $(DESTDIR)$(MANDIR)/man1/fscryptctl.1 clean: - rm -f fscryptctl *.o *.pyc + rm -f fscryptctl fscryptctl.1 *.o *.pyc rm -rf __pycache__ rm -rf .pytest_cache + +.DEFAULT_GOAL = all diff --git a/README.md b/README.md index 9a103e0..404321c 100644 --- a/README.md +++ b/README.md @@ -32,10 +32,14 @@ before using `fscryptctl`. ## Building and Installing -To build `fscryptctl`, run `make`. The only build dependencies are GNU Make and -a C compiler (only C99 is needed). +To build, run `make`. The build dependencies are GNU Make, a C compiler (only +C99 is needed), and [pandoc](https://pandoc.org/). -To install `fscryptctl`, run `sudo make install`. +To install, run `sudo make install`. + +If you don't want to build and install the `fscryptctl.1` manual page, you can +instead run `make fscryptctl` and `sudo make install-bin`. This will build and +install the `fscryptctl` binary only, avoiding the build dependency on `pandoc`. See the `Makefile` for compilation and installation options. @@ -67,7 +71,8 @@ tips](https://github.com/google/fscrypt#getting-encryption-not-enabled-on-an-ext * `fscryptctl get_policy` - get the encryption policy of a file or directory * `fscryptctl set_policy` - set the encryption policy of an empty directory -Run `fscryptctl --help` for full usage details. +For full usage details, see the manual page (`man fscryptctl`), or alternatively +run `fscryptctl --help`. The `add_key` command accepts the encryption key in binary on standard input. It is critical that this be a real cryptographic key (and not a passphrase, for diff --git a/fscryptctl.1.md b/fscryptctl.1.md new file mode 100644 index 0000000..0654b79 --- /dev/null +++ b/fscryptctl.1.md @@ -0,0 +1,150 @@ +% FSCRYPTCTL(1) fscryptctl | User Commands + +# NAME + +fscryptctl - low-level userspace tool for Linux filesystem encryption + +# SYNOPSIS +**fscryptctl add_key** [*OPTION*...] *MOUNTPOINT*... \ +**fscryptctl remove_key** [*OPTION*...] *KEY_IDENTIFIER* *MOUNTPOINT* \ +**fscryptctl key_status** *KEY_IDENTIFIER* *MOUNTPOINT* \ +**fscryptctl get_policy** *PATH* \ +**fscryptctl set_policy** [*OPTION*...] *KEY_IDENTIFIER* *DIRECTORY* + +# DESCRIPTION + +**fscryptctl** is a low-level tool that handles raw keys and manages policies +for Linux filesystem encryption, specifically the "fscrypt" kernel interface +which is supported by some filesystems such as ext4 and f2fs. + +**fscryptctl** is mainly intended for embedded systems which can't use the +full-featured **fscrypt** tool, or for testing or experimenting with the kernel +interface to Linux filesystem encryption. **fscryptctl** does *not* handle key +generation, key stretching, key wrapping, or PAM integration. Most users should +instead use the **fscrypt** tool, which supports these features and generally is +much easier to use. + +This manual page focuses on documenting all **fscryptctl** subcommands and +options. For examples and more information about the corresponding kernel +feature, see the references at the end of this page. + +# OPTIONS + +**fscryptctl** always accepts the following options: + +**\-h**, **\-\-help** +: Show the help, for either one subcommand or for all subcommands. + +**\-v**, **\-\-version** +: Show the version of **fscryptctl**. + +# SUBCOMMANDS + +## **fscryptctl add_key** *MOUNTPOINT* + +Add an encryption key to the given mounted filesystem. This will "unlock" any +files and directories that are protected by the given key on the given +filesystem. This is a thin wrapper around the `FS_IOC_ADD_ENCRYPTION_KEY` +ioctl. + +The encryption key is read from standard input and must be given in raw binary. +This must be a real cryptographic key and *not* e.g. a password. + +If successful, **fscryptctl add_key** will print the key identifier of the newly +added key; this will be a 32-character hex string which can be passed to other +**fscryptctl** commands. + +**fscryptctl add_key** does not accept any options. + +## **fscryptctl remove_key** [*OPTION*...] *KEY_IDENTIFIER* *MOUNTPOINT* + +Remove an encryption key from the given mounted filesystem. + +This is a thin wrapper around the `FS_IOC_REMOVE_ENCRYPTION_KEY` ioctl (or +`FS_IOC_REMOVE_ENCRYPTION_KEY_ALL_USERS`). Normally, this removes the key and +"locks" any files or directories that are protected by it. Some caveats apply +when any of these files or directories is still in-use, or when the user trying +to remove the key differs from the user(s) who added the key. In general these +situations should be avoided, but for details on how they are handled, see the +Linux kernel documentation for `FS_IOC_REMOVE_ENCRYPTION_KEY`. + +Options accepted by **fscryptctl remove_key**: + +**\-\-all-users** +: Remove all users' claims to the key rather than just the current user's. + Requires root. + +## **fscryptctl key_status** *KEY_IDENTIFIER* *MOUNTPOINT* + +Get the status of an encryption key on the given mounted filesystem. This is a +thin wrapper around the `FS_IOC_GET_ENCRYPTION_KEY_STATUS` ioctl. The key +status will be one of the following: + +* Present +* Absent +* Incompletely removed + +In the "Present" case, some information about which users added the key will +also be shown. + +**fscryptctl key_status** does not accept any options. + +## **fscryptctl get_policy** *PATH* + +Show the encryption policy of the given file or directory. This is a thin +wrapper around the `FS_IOC_GET_ENCRYPTION_POLICY_EX` ioctl. + +The "encryption policy" refers to the encryption key with which the file or +directory is protected, along with encryption options such as the ciphers used +for file contents and filenames encryption. + +**fscryptctl get_policy** does not accept any options. + +## **fscryptctl set_policy** [*OPTION*...] *KEY_IDENTIFIER* *DIRECTORY* + +Set an encryption policy on the given directory. This is a thin wrapper around +the `FS_IOC_SET_ENCRYPTION_POLICY` ioctl. + +The encryption policy will use the given encryption key (specified by its key +identifier), along with any encryption options given. + +The policy will be version 2. Version 1 policies are no longer supported by +**fscryptctl**, except by **fscryptctl get_policy**. + +Options accepted by **fscryptctl set_policy**: + +**\-\-contents**=*MODE* +: The cipher that will be used to encrypt file contents. Valid options are + AES-256-XTS, AES-128-CBC, and Adiantum. Default is AES-256-XTS. + +**\-\-filenames**=*MODE* +: The cipher that will be used to encrypt filenames. Valid options are + AES-256-CTS, AES-128-CTS, and Adiantum. Default is AES-256-CTS. + +**\-\-padding**=*BYTES* +: The number of bytes to which encrypted filename lengths will be aligned + in order to hide the lengths of the original filenames. Valid options are + 4, 8, 16, and 32. Default is 32. + +**\-\-direct\-key** +: Optimize for Adiantum encryption. For details, see the Linux kernel + documentation for `FSCRYPT_POLICY_FLAG_DIRECT_KEY`. + +**\-\-iv\-ino\-lblk\-64** +: Optimize for UFS inline encryption hardware. For details, see the Linux + kernel documentation for `FSCRYPT_POLICY_FLAG_IV_INO_LBLK_64`. + +**\-\-iv\-ino\-lblk\-32** +: Optimize for eMMC inline encryption hardware. For details, see the Linux + kernel documentation for `FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32`. + +# SEE ALSO + +* [**fscryptctl** README + file](https://github.com/google/fscryptctl/blob/master/README.md) + +* [Linux kernel documentation for filesystem + encryption](https://www.kernel.org/doc/html/latest/filesystems/fscrypt.html) + +* [**fscrypt** tool, recommended for most users over + fscryptctl](https://github.com/google/fscrypt)