diff --git a/.gitignore b/.gitignore index 4573ea0..d954773 100644 --- a/.gitignore +++ b/.gitignore @@ -55,9 +55,18 @@ dkms.conf # Eclipse project files .project .cproject +.settings/ # Shufflecake binaries shufflecake +shufflecake-lite +shufflecake-legacy + +# Build directory +bin/ + +# Test images +disks/ # Temporary working directories dm-vvz/ diff --git a/CHANGELOG.md b/CHANGELOG.md index ff7d25a..c4434fc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,35 +11,55 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Refactored - - Introduction of "Shufflecake Lite" scheme as default. - - Moving old Shufflescake scheme as "Legacy" option for backward support. - Global constants fully shared among components through `sflc_constants.h`. - - Global refactoring and simplification of code tree. +## [0.5.0] - 2024-09-01 + +### Added + + - Benchmark and fragmentation scripts for Shufflecake Lite. + - Schematics for new Lite headers. + +### Changed + + - BREAKING CHANGE: introduction of "Shufflecake Lite" scheme as default. + - BREAKING CHANGE: moved old Shufflescake scheme as "Legacy" option for backward support. + - Edited README.md to show the difference between the Lite and Legacy modes, and also added a usability warning. + +### Fixed + + - Volumes offered by the same device now show as all related to that device with `lsblk`. + +### Refactored + + - Global refactoring and simplification of code tree. + - Changed all occurrences of "Shufflecake Old" to "Shufflecake Legacy", including code paths and variables. + - Reordered entries in CHANGELOG.md with sections following the order Added -> Changed -> Fixed -> Refactored -> Removed. + ## [0.4.5] - 2024-06-03 +### Changed + + - Minor edits to README.md. + ### Fixed - Fixed a compile error on some new releases of LTS kernels due to the removal of a function API. - Fixed segmentation fault when opening an already opened device. -### Changed - - - Minor edits to README.md. - ## [0.4.4] - 2023-12-31 -### Fixed - - - Fixed a memory allocation error on large devices due to the use of a function not meant for allocating large amount of memory. - ### Changed - Variables `shuffled_psi_array` and `shuffled_psi_ctr` renamed to `prmslices` and `prmslices_octr` respectively, to be more consistent with reference paper. - Minor edits to README.md. +### Fixed + + - Fixed a memory allocation error on large devices due to the use of a function not meant for allocating large amount of memory. + ## [0.4.3] - 2023-11-29 @@ -51,6 +71,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [0.4.2] - 2023-11-28 +### Changed + + - All schematics and references now consistently map array indices of size N from 0 to N-1 rather than from 1 to N. + ### Fixed - Fixed persistent slice allocation ambiguity after a volume corruption by allocating fresh slices for the corrupted volume. This is done in order to help external recovery tools (e.g. RAID). @@ -58,10 +82,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fixed a missed deallocation problem which caused a kernel bug on volume close after some I/O errors. - Fixed a buggy swap procedure which made the permutation of PSIs not completely random. -### Changed - - - All schematics and references now consistently map array indices of size N from 0 to N-1 rather than from 1 to N. - ## [0.4.1] - 2023-07-30 @@ -80,21 +100,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Improved documentation in `README.md` on using `init` non-interactively. - `doc` section which for now includes figure of Shufflecake header structure. -### Refactored - - - Implemented reference slice allocation algorithm with much faster performance. - -### Fixed - - - Fixed a bug that made `--skip-randfill` option not work. - - Fixed a bug that made action `close` not work. - ### Changed - BREAKING CHANGE: slightly modified header field format, removing redundant MAC field and making it adherent to documentation. - Action `init` now reads password from secure interface (not echoing characters, etc). - Updated instructions in `SECURITY.md`. +### Fixed + + - Fixed a bug that made `--skip-randfill` option not work. + - Fixed a bug that made action `close` not work. + +### Refactored + + - Implemented reference slice allocation algorithm with much faster performance. + ## [0.3.1] - 2023-07-15 @@ -111,17 +131,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [0.3.0] - 2023-07-11 -### Refactored - - - Unified repositories of kernel module and userland tool into a single one. Makefile, docs, etc unified accordingly. - - Adopting SemVer as of release v0.3.0. - - Program version now defined within `sflc_constants.h`. - - CLI built with argp.h and following GNU behavior. - -### Fixed - - - Test routines available with `make install`, for now limited to low-level crypto operations. - ### Changed - License changed from GPLv3+ to GPLv2+. @@ -130,6 +139,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - One global salt for deriving keys for all headers in order to not slow down too much opening. This allows us to avoid a difficult choice between insecurity against brute-force attacks and unacceptably slow opening time. - Added a 1-block offset to accommodate for header format change. +### Fixed + + - Test routines available with `make install`, for now limited to low-level crypto operations. + +### Refactored + + - Unified repositories of kernel module and userland tool into a single one. Makefile, docs, etc unified accordingly. + - Adopting SemVer as of release v0.3.0. + - Program version now defined within `sflc_constants.h`. + - CLI built with argp.h and following GNU behavior. + ## [0.2.0] - 2023-04-17 @@ -139,10 +159,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Support larger volumes with headers of variable size. - Add interactive option to skip random filling during init. -### Fixed - -- Compile correctly on Linux kernel 6.1. - ### Changed - Switch from `libsodium` to `libgcrypt`. @@ -150,6 +166,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Change syntax of commands. - Switch to Scrypt KDF. +### Fixed + +- Compile correctly on Linux kernel 6.1. + ### Removed - Removed flag `--no-randfill`. diff --git a/README.md b/README.md index 560d944..beee2f9 100644 --- a/README.md +++ b/README.md @@ -1,23 +1,24 @@ [![Status](resources/images/badges/badge_status_active.png)](https://codeberg.org/shufflecake/shufflecake-c)  -[![Version](resources/images/badges/badge_version_0.4.5.png)](https://codeberg.org/shufflecake/shufflecake-c/releases/tag/v0.4.5)  +[![Version](resources/images/badges/badge_version_0.5.0.png)](https://codeberg.org/shufflecake/shufflecake-c/releases/tag/v0.5.0)  [![License](resources/images/badges/badge_license_gplv2plus.png)](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html)  [![Docs researchpaper](resources/images/badges/badge_docs_researchpaper.png)](https://eprint.iacr.org/2023/1529)  [![Website](resources/images/badges/badge_web_shufflecakedotnet.png)](https://shufflecake.net/)  [![Issue tracker](resources/images/badges/badge_community_issuetracker.png)](https://codeberg.org/shufflecake/shufflecake-c/issues)  [![Mastodon](resources/images/badges/badge_community_mastodon.png)](https://fosstodon.org/@shufflecake)  +[![Jabber](resources/images/badges/badge_community_jabber_chat.png)](xmpp:shufflecake@conference.draugr.de?join)  [![Please don't upload to GitHub](resources/images/badges/badge_no_github.png)](https://nogithub.codeberg.page) -# Shufflecake - Full C Implementation - v0.4.5 +# Shufflecake - Full C Implementation - v0.5.0 _Shufflecake_ is a plausible deniability (hidden storage) layer for Linux. You can consider Shufflecake a spiritual successor of tools like TrueCrypt and VeraCrypt, but vastly improved, both in terms of security and functionality. Official website: . This repository contains C source code and documentation to use and manage Shufflecake volumes. -__WARNING__: Shufflecake is still experimental software, please do not rely on its security or stability. +__WARNING__: Shufflecake is a strong encryption and plausible deniability solution. The mere presence of Shufflecake on your device might put you at risk of being targeted, accused of crime or foul play, arrested, or worse. In Shufflecake there is no easy way to convince an adversary that you have given up all your passwords. Please consider carefully your threat model before using Shufflecake. In any case, this is still experimental software, please do not rely on its security or stability. - [Overview](#overview) - [Installation](#installation) @@ -30,6 +31,9 @@ __WARNING__: Shufflecake is still experimental software, please do not rely on i - [Other Commands](#other) - [Changing A Password](#changepwd) - [Check If A Password Is Correct](#testpwd) + - [Modes of Operation](#modes) + - [Shufflecake Lite](#lite) + - [Shufflecake Legacy](#legacy) - [Advanced Usage](#advanced) - [Volume Corruption Mitigation](#mitigcorr) - [Providing Passwords Non-Interactively](#passwordnonint) @@ -47,17 +51,15 @@ __WARNING__: Shufflecake is still experimental software, please do not rely on i In the context of Shufflecake, a _device_, or _cake_, is the underlying raw block device (e.g., a disk) that is formatted to contain hidden data, while a _volume_, or _layer_, is the logical, encrypted and hidden "partition" within a device. The device can be a whole USB stick (or disk), a physical or logical partition, a file-backed loop device, etc. (you likely find it under `/dev`). The three operating principles of Shufflecake are: -- 1 device = multiple volumes; +- 1 device = multiple (concurrently usable) volumes; - 1 volume = 1 password = 1 "secrecy level"; - unlocking a volume also unlocks all those of lesser secrecy level. Volumes are password-protected, and embedded in the underlying device as data _slices_ which are indistinguishable from random noise without the proper password. Headers are also indistinguishable from random when not decrypted. A Shufflecake-initialized device does not have cleartext headers, and is indistinguishable from random noise when not decrypted. -Up to 15 _ordered_ Shufflecake volumes can be created on a single device, with the implicit assumption that "lower-order" volumes (e.g. layer 0) are _less_ _secret_ than "higher-order" ones (e.g. layer 3). The Shufflecake header is designed in such a way that it _chains_ volumes in a backwards-linked list: volume __i__ "points to" (contains the key of) volume __i-1__. This way, providing the key of volume __i__ allows this tool to traverse the list and also automatically open volumes __0__ through __i-1__ (besides volume __i__). +Up to 15 _ordered_ Shufflecake volumes can be created on a single device, with the implicit assumption that "lower-order" volumes (e.g. layer 0) are _less_ _secret_ than "higher-order" ones (e.g. layer 3). Shufflecake is designed in such a way that it _chains_ volumes in a backwards-linked list: volume __i__ "points to" (contains the key of) volume __i-1__. This way, providing the key of volume __i__ allows this tool to traverse the list and also automatically open volumes __0__ through __i-1__ (besides volume __i__). -![Scheme of Shufflecake device layout](resources/images/headers.png) - -Opened volumes appear as block devices of the form `sflc_x_y` in `/dev/mapper`. It is up to the user to format them with an appropriate filesystem and mounting them before use. It is recommended to always unlock the most sensitive volume for daily use ("home alone" scenario), even if that volume is not being used or even mounted. Only open a subset of volumes (with a "decoy password") if under coercion. This is due to the high possibility of corrupting hidden volumes otherwise. +Opened volumes appear as block devices of the form `sflc_x_y` in `/dev/mapper` and they can be used concurrently. It is up to the user to format them with an appropriate filesystem and mounting them before use. It is recommended to always unlock the most sensitive volume for daily use ("home alone" scenario), even if that volume is not being used or even mounted. Only open a subset of volumes (with a "decoy password") if under coercion. This is due to the high possibility of corrupting hidden volumes otherwise. For security and consistency reasons, you cannot init/open/close nested volumes within the same device one at a time; this tool only allows to perform these operations on a _chain_ of volumes in a device. @@ -67,7 +69,7 @@ For security and consistency reasons, you cannot init/open/close nested volumes ## Installation -This implementation of Shufflecake consists of two components: a module for the Linux kernel (`dm-sflc`), and a `shufflecake` userland tool. Both are necessary in order to use Shufflecake. They have been tested on Linux kernel versions 6.1 (LTS), up to 6.7. The following instructions are given for Debian/Ubuntu and similar derivatives. +This implementation of Shufflecake consists of two components: a module for the Linux kernel (`dm-sflc`), and a `shufflecake` userland tool. Both are necessary in order to use Shufflecake. They have been tested on Linux kernel versions 6.1 (LTS), up to 6.10. The following instructions are given for Debian/Ubuntu and similar derivatives. First of all, you need the kernel headers, device-mapper userspace library, and libgcrypt to compile the source. Use: @@ -75,10 +77,10 @@ First of all, you need the kernel headers, device-mapper userspace library, and sudo apt install linux-headers-$(uname -r) libdevmapper-dev libgcrypt-dev ``` -Important: you have to make sure to install an up-to-date version of `libgcrypt` that supports the Argon2id KDF algorithm. You need the 1.10.1 or later version, which might not be available in your local repositories (for example, Ubuntu 22.04 LTS), in which case you should find a workaround (either install manually or override your repositories by pinning an up-to-date package). You can check your current version with: +Important: you have to make sure to install an up-to-date version of `libgcrypt` that supports the Argon2id KDF algorithm. You need the 1.10.1 or later version, which might not be available in your local repositories (for example, Ubuntu 22.04 LTS), in which case you should find a workaround (either install manually or override your repositories by pinning an up-to-date package). You can check your current version (on Debian/Ubuntu) with: ``` -libgcrypt-config --version +dpkg -l libgcrypt20 ``` Also, make sure that the Kconfig options `CONFIG_CRYPTO_DRBG_HASH` (and possibly `CONFIG_CRYPTO_DRBG_CTR`) are enabled, as they are not default options in the kernel's defconfig, although they are enabled by default on some distributions such as Debian and Ubuntu. @@ -193,6 +195,23 @@ sudo shufflecake testpwd A password will be required. If this is the correct password for volume __M__, then this information will be returned to the user, without actually opening the volume. This can be useful if a user wants to be sure that a password unlocks a certain volume without risk of the OS logging the access to that volume and without the risk of corrupting the content of other, unlocked, hidden volumes. +### Modes of Operation + +Shufflecake can operate in two different modes, with different features in terms of security, performance, and data resilience. + +#### Shufflecake Lite + +As of v0.5.0, Shufflecake's default mode of operation is the "Lite" scheme. This mode introduces the AES-XTS encryption mode rather than AES-CTR, with a related change of header format. This mode has only advantages compared to the old "Legacy" scheme: it offers the _same_ level of security, but with better performance and data resilience, and it is therefore the strongly recommended way to use Shufflecake. It will be used by default whenever a Shufflecake command is invoked. + +![Scheme of Shufflecake Lite device layout](resources/images/headers_lite.png) + +#### Shufflecake Legacy + +For backward compatibility reasons, this release of Shufflecake still offers support for the old (pre-v0.5.x) "Legacy" scheme, which can be selected with the `--legacy` option when invoking `init` or `open`, all other actions (including `close`) do not require specifying a Shufflecake mode. This scheme uses AES-CTR with explicit IVs written on disks, and it offers therefore ciphertext re-randomization, which is in turn a necessary ingredient for achieving future modes with better security. However, since these modes have not yet been implemented, currently the use of Shufflecake Legacy has only drawbacks compared to other modes: it does not offer better security, while being slower, less space-efficient, and more prone to data corruption. The use of this mode is therefore discouraged, and will be deprecated at some point in the future. However, you must use this option when trying to open volumes created with an old (pre-v0.5.x) release of Shufflecake. You are strongly encouraged to migrate Legacy volumes to the new Lite ones if you haven't done it yet. + +![Scheme of Shufflecake Legacy device layout](resources/images/headers_legacy.png) + + ### Advanced Usage Certain features of Shufflecake are not yet implemented, but sometimes a workaround is possible. Consider all the instructions in this sections as experimental, use them at your own risk. @@ -246,6 +265,10 @@ Both methods works with the `init` action, and we do not have current plans to c Please see the file `CHANGELOG.md` for a detailed history of changes. +### [0.5.0] - 2024-09-01 + + - BREAKING CHANGE: major rewrite, bugfixes, introduced Shufflecake "Lite" as a default mode of operation. + ### [0.4.5] - 2024-06-03 - Fixed a compile error on some versions of LTS kernels. @@ -289,9 +312,9 @@ Bugs and other issues are tracked at + +# This file is part of the program shufflecake-c, which is part of the Shufflecake +# Project. Shufflecake is a plausible deniability (hidden storage) layer for +# Linux. See . + +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the Free +# Software Foundation, either version 2 of the License, or (at your option) +# any later version. This program is distributed in the hope that it will be +# useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. You should have received a copy of the +# GNU General Public License along with this program. +# If not, see . + +# Benchmarking script for Shufflecake + +# Variables +SCRIPTNAME=$(basename "$0") +SCRIPT_DIR="$(dirname "$(realpath "$0")")" +LOOP_FILENAME="$SCRIPT_DIR/sflc-legacy-benchmark-loop-file.img" +LOOP_DEVICE="" +TIMEFORMAT='%3R' +SFLCPATH="" +SFLCNAME="" +DMSFLC_INSTALLED=false + +# Colors +BLUE='\033[0;34m' +GREEN='\033[0;32m' +RED='\033[0;31m' +NC='\033[0m' # No color + +# Help +print_help() { +# xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 79 chars + echo -e "${BLUE}Usage: ${SCRIPTNAME} [OPTION]... [BLOCKDEVICE]${NC}" + echo " " + echo "This script is used to benchmark Shufflecake Legacy on this machine." + echo "This script is part of the Shufflecake benchmark suite." + echo "Shufflecake is a plausible deniability (hidden storage) layer for Linux." + echo -e "Please visit ${BLUE}https://www.shufflecake.net${NC} for more info and documentation." + echo " " + echo "This script requires root because it operates on block devices, please run it " + echo -e "with ${BLUE}sudo${NC}. It does the following:" + echo "1) Creates a Shufflecake (Legacy) device with two volumes." + echo "2) Opens the second (hidden) volume, formats it with ext4 and mounts it." + echo "3) Performs various fio r/w stress operations on it." + echo "4) Unmounts and closes the used volume." + echo " " +# xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 79 chars + echo "You must have already compiled and installed Shufflecake in order to run this." + echo "The script will search for Shufflecake either in the default installation " + echo "directory, or in the current directory, or in the parent directory (one level" + echo -e "above this). If the module ${BLUE}dm-sflc${NC} is not loaded, the script " + echo "will load it, execute, and then unload it." + echo " " +# xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 79 chars + echo "You can pass the path to a block device as an optional argument, otherwise the " + echo "script will ask for one. If no path is provided, the script will create a 1 GiB" + echo "local file and use it to back a loop device as a virtual block device to be " + echo "formatted with the appropriate tools. The file will be removed at the end." + echo " " +# xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 79 chars + echo -e "${BLUE}WARNING: ALL CONTENT OF THE PROVIDED BLOCK DEVICE WILL BE ERASED!${NC}" + echo " " + exit 0 +} + +# Function for debugging +bpx() { + if [ -z "$1" ]; then + echo "BPX: Paused. Press any key to continue..." >&2 + else + echo "BPX: $1. Press any key to continue..." >&2 + fi + read -n1 -s +} + +# Show usage +usage() { + echo -e "Use ${BLUE}${SCRIPTNAME} --help${NC} for usage and help." +} + +# Check that this is run as root +check_sudo() { + if [[ $EUID -ne 0 ]]; then + echo -e "${RED}Error: This script must be run as root.${NC}" + usage + exit 1 + fi +} + +# Find the path of Shufflecake executable +find_sflc_path() { + local cmd="shufflecake" + + # Check if the command exists in the current directory + if [[ -x "./$cmd" ]]; then + SFLCPATH=$(realpath ./) + SFLCNAME=$(realpath ./$cmd) + return + fi + + # Check if the command exists in the parent directory + if [[ -x "../$cmd" ]]; then + SFLCPATH=$(realpath ../) + SFLCNAME=$(realpath ../$cmd) + return + fi + + # Check if the command exists in the directories listed in PATH + IFS=':' read -ra dirs <<< "$PATH" + for dir in "${dirs[@]}"; do + if [[ -x "$dir/$cmd" ]]; then + SFLCPATH=$(realpath $dir) + SFLCNAME=$(realpath $dir/$cmd) + return + fi + done + + # If the command was not found, print an error message + echo -e "${RED}ERROR: Command '$cmd' not found${NC}." >&2 + exit 1 +} + +# Find and load module dm-sflc +load_dmsflc() { + local mod="dm-sflc" + + # Check if the module is already loaded + if lsmod | grep -q "^$mod "; then + DMSFLC_INSTALLED=true + echo "Module '$mod' is already loaded." + return + fi + + # If not, look for the module file and try to load it + local mod_file="$mod.ko" + + # Check if the module file exists in the current directory + if [[ -f "./$mod_file" ]]; then + insmod $(realpath ./$mod_file) || exit 1 + echo "Module '$mod' loaded from current directory." + return + fi + + # Check if the module file exists in the parent directory + if [[ -f "../$mod_file" ]]; then + insmod $(realpath ../$mod_file) || exit 1 + echo "Module '$mod' loaded from parent directory." + return + fi + + # If the module file was not found, print an error message + echo -e "${RED} ERROR: Module file '$mod_file' not found.${NC}." >&2 + exit 1 +} + +# Unload dm-sflc if it was loaded locally +unload_dmsflc() { + local mod="dm-sflc" + # Only unload dm-sflc if it was loaded manually when the script was invoked + if ! $DMSFLC_INSTALLED; then + rmmod $mod || exit 1 + echo "Module '$mod' unloaded." + else + echo "Module '$mod' was not unloaded because it was already loaded when the script was run." + fi +} + +# Function to check if argument is a block device +check_block_device() { + if [ -b "$1" ]; then + echo "OK, block device path $1 is valid." >&2 + else + echo -e "${RED}Error: $1 is not a valid block device, aborting.${NC}" + unload_dmsflc + usage + exit 1 + fi +} + +# Function to create loop device +create_loop_device() { + echo "I will now try to create a file $LOOP_FILENAME ..." >&2 + if [ -e "$LOOP_FILENAME" ]; then + echo -e "${RED}Error: Impossible to generate file, $LOOP_FILENAME already exists.${NC}" + exit 1 + fi + sudo dd if=/dev/zero of="$LOOP_FILENAME" bs=1M count=1024 > /dev/null + echo "Writing of empty file complete. I will now try to attach it to a new loop device..." >&2 + LOOP_DEVICE=$(sudo losetup -f --show "$LOOP_FILENAME") + echo "Successfully created loop device $LOOP_DEVICE ." >&2 + echo "$LOOP_DEVICE" +} + +# Finds the sflc volume that was created last +find_sflcvolname() { + # List all files in /dev/mapper, select those starting with sflc_, sort them, and pick the last one. + volname=$(ls /dev/mapper/sflc_* 2>/dev/null | sort -t '_' -k 2n,2 -k 3n,3 | tail -n 1) + # Check if volname is empty (no sflc_ files found). + if [ -z "$volname" ]; then + echo -e "${RED}ERROR: No sflc_ devices found in /dev/mapper !${NC}" + return 1 + else + echo $volname + return 0 + fi +} + +# Function for user confirmation +confirm() { + while true; do + echo -e "${BLUE}Are you sure you want to proceed? All data on disk $BLOCK_DEVICE will be erased. (y/n)${NC}" + read -r response + case "$response" in + [yY]|[yY][eE][sS]) # Responded Yes + return 0 # Return 0 for Yes (success, convention for bash scripting) + ;; + [nN]|[nN][oO]) # Responded No + return 1 # Return 1 for No (error, convention for bash scripting) + ;; + *) # Responded something else + echo "Please press only (y)es or (n)o." + ;; + esac + done +} + +# Benchmarks +benchmark() { + + SFLCVOLUME="" + MNTPOINT="" + TESTNAME="sflc-lgc" + RUNTIME="20" # running time in seconds FOR EACH TEST + DATASIZE="500M" + TESTFILENAME="testfile" + echo "Starting benchmark for Shufflecake Legacy..." + echo "Initializing block device $BLOCK_DEVICE with two Shufflecake Legacy volumes (--skip-randfill)..." + etime=$( (time echo -e "passwd1\npasswd2" | $SFLCNAME --skip-randfill --legacy -n 2 init $BLOCK_DEVICE > /dev/null) 2>&1 ) + echo -e "${GREEN}Action init took $etime seconds.${NC}" + echo "Shufflecake device initialized. Opening hidden volume (nr. 2)..." + # open + etime=$( (time echo -e "passwd2" | $SFLCNAME --legacy open $BLOCK_DEVICE > /dev/null) 2>&1 ) + echo -e "${GREEN}Action open took $etime seconds.${NC}" + # fetch SFLCVOLUME + SFLCVOLUME=$(find_sflcvolname) + echo "Shufflecake Legacy volume opened as $SFLCVOLUME. Formatting with ext4..." + # format with ext4, but mute output (too verbose) + mkfs.ext4 $SFLCVOLUME > /dev/null + echo "Volume $SFLCVOLUME formatted. Mounting that..." + # assign and create MNTPOINT + MNTPOINT=$(realpath "./sflc_mnt") + mkdir $MNTPOINT + # mount + mount $SFLCVOLUME $MNTPOINT + echo "Volume mounted at $MNTPOINT. Starting fio tests..." + # TESTS HERE + # test 01: random read + echo "Test 01: random read with a queue of 32 4kiB blocks on a file (${RUNTIME}s)..." + OUTPUT=$(fio --name=$TESTNAME-r-rnd --ioengine=libaio --iodepth=32 --rw=randread --bs=4k --numjobs=1 --direct=1 --size=$DATASIZE --runtime=$RUNTIME --time_based --end_fsync=1 --filename=$MNTPOINT/$TESTFILENAME --output-format=json | jq '.jobs[] | {name: .jobname, read_iops: .read.iops, read_bw: .read.bw}') + echo -e "${GREEN}${OUTPUT}${NC}" + # test 02: random write + echo "Test 02: random write with a queue of 32 4kiB blocks on a file (${RUNTIME}s)..." + OUTPUT=$(fio --name=$TESTNAME-w-rnd --ioengine=libaio --iodepth=32 --rw=randwrite --bs=4k --numjobs=1 --direct=1 --size=$DATASIZE --runtime=$RUNTIME --time_based --end_fsync=1 --filename=$MNTPOINT/$TESTFILENAME --output-format=json | jq '.jobs[] | {name: .jobname, write_iops: .write.iops, write_bw: .write.bw}') + echo -e "${GREEN}${OUTPUT}${NC}" + # test 03: sequential read + echo "Test 03: sequential read with a queue of 32 4kiB blocks on a file (${RUNTIME}s)..." + OUTPUT=$(fio --name=$TESTNAME-r-seq --ioengine=libaio --iodepth=32 --rw=read --bs=4k --numjobs=1 --direct=1 --size=$DATASIZE --runtime=$RUNTIME --time_based --end_fsync=1 --filename=$MNTPOINT/$TESTFILENAME --output-format=json | jq '.jobs[] | {name: .jobname, read_iops: .read.iops, read_bw: .read.bw}') + echo -e "${GREEN}${OUTPUT}${NC}" + # test 04: sequential write + echo "Test 04: sequential write with a queue of 32 4kiB blocks on a file (${RUNTIME}s)..." + OUTPUT=$(fio --name=$TESTNAME-w-seq --ioengine=libaio --iodepth=32 --rw=write --bs=4k --numjobs=1 --direct=1 --size=$DATASIZE --runtime=$RUNTIME --time_based --end_fsync=1 --filename=$MNTPOINT/$TESTFILENAME --output-format=json | jq '.jobs[] | {name: .jobname, write_iops: .write.iops, write_bw: .write.bw}') + echo -e "${GREEN}${OUTPUT}${NC}" + # END TESTS + echo "Shufflecake Legacy fio tests ended. Unmounting volume." + # unmount + umount $MNTPOINT + rmdir $MNTPOINT + echo "Volume unmounted. Closing Shufflecake device..." + # close + etime=$( (time $SFLCNAME close $BLOCK_DEVICE > /dev/null) 2>&1 ) + echo -e "${GREEN}Action close took $etime seconds.${NC}" + #end + +} + +# Clean up +cleanup() { + echo "Exiting and cleaning..." + if [[ -n $LOOP_DEVICE ]]; then + echo "Detaching $LOOP_DEVICE ..." + sudo losetup -d "$LOOP_DEVICE" + echo "Deleting $LOOP_FILENAME ..." + sudo rm -f "$LOOP_FILENAME" + echo "Loop device detached and backing file deleted." + fi +} + + +##################################################################### + +# MAIN SCRIPT BODY STARTS HERE + +##################################################################### + +# BANNER +# xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 79 chars +echo -e "${BLUE}===============================================================================${NC}" +echo -e "${BLUE} Benchmark Suite Script for Shufflecake Legacy${NC}" +echo -e "${BLUE}===============================================================================${NC}" + + +# PRELIMINARY: PARSE HELP, SUDO, AND LOAD SHUFFLECAKE (IF IT EXISTS, OTHERWISE ERROR) + +case "$1" in + # help + --help|-?) + print_help + exit 0 + ;; +esac + +check_sudo + +echo -e "${BLUE}Initializing Shufflecake...${NC}" +echo "Searching Shufflecake executable..." +find_sflc_path +echo "Shufflecake executable found at $SFLCNAME ." +echo "Searching and loading dm-sflc module..." +load_dmsflc +echo "Module dm-sflc found and loaded. Status DMSFLC_INSTALLED: $DMSFLC_INSTALLED ." +echo " " + + +# PARSER + +case "$1" in + "") +# xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 79 chars + + echo "Now you will be asked to enter the path for a block device to be used for the " + echo "benchmarks (all content will be erased). If no path is provided (default" + echo "choice), then the script will create a 1 GiB file in the current directory and " + echo "use it to back a loop device instead, then the file will be removed at the end." + echo " " + echo -n "Please enter the path for a block device (default: none): " + read BLOCK_DEVICE + if [ -z "$BLOCK_DEVICE" ]; then + echo "No path provided, creating a local file and loop device..." + LOOP_DEVICE=$(create_loop_device) + BLOCK_DEVICE=$LOOP_DEVICE + fi + + ;; + + # argument passed + *) + BLOCK_DEVICE="$1" + ;; +esac + +check_block_device "$BLOCK_DEVICE" + +# MAIN PROGRAM + +if confirm; then + benchmark +else + echo "Aborting..." +fi + +unload_dmsflc + +cleanup + + + + diff --git a/benchmark-suite/sflc-legacy-fragmentation.sh b/benchmark-suite/sflc-legacy-fragmentation.sh new file mode 100755 index 0000000..daf57ed --- /dev/null +++ b/benchmark-suite/sflc-legacy-fragmentation.sh @@ -0,0 +1,457 @@ +#!/bin/bash + +# Copyright The Shufflecake Project Authors (2022) +# Copyright The Shufflecake Project Contributors (2022) +# Copyright Contributors to the The Shufflecake Project. + +# See the AUTHORS file at the top-level directory of this distribution and at +# + +# This file is part of the program shufflecake-c, which is part of the Shufflecake +# Project. Shufflecake is a plausible deniability (hidden storage) layer for +# Linux. See . + +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by the Free +# Software Foundation, either version 2 of the License, or (at your option) +# any later version. This program is distributed in the hope that it will be +# useful, but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General +# Public License for more details. You should have received a copy of the +# GNU General Public License along with this program. +# If not, see . + +# Fragmentation evaluation script for Shufflecake + +# Global variables +SCRIPTNAME=$(basename "$0") +SCRIPT_DIR="$(dirname "$(realpath "$0")")" +LOOP_FILENAME="$SCRIPT_DIR/sflc-legacy-frag-loop-file.img" +LOOP_DEVICE="" +TIMEFORMAT='%3R' +SFLCPATH="" +SFLCNAME="" +DMSFLC_INSTALLED=false +VOLSIZE=0 +NUMPOINTS=11 # number of samples, max 65536 +FSTYPE="ext4" # fragmentation performance can depend on FS type in theory, so change it here if you want to test others + + +# Colors +BLUE='\033[0;34m' +GREEN='\033[0;32m' +RED='\033[0;31m' +NC='\033[0m' # No color + +# Help +print_help() { +# xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 79 chars + echo -e "${BLUE}Usage: ${SCRIPTNAME} [OPTION]... [BLOCKDEVICE]${NC}" + echo " " + echo "This script is used to evaluate Shufflecake Legacy volume fragmentation." + echo "This script is part of the Shufflecake benchmark suite." + echo "Shufflecake is a plausible deniability (hidden storage) layer for Linux." + echo -e "Please visit ${BLUE}https://www.shufflecake.net${NC} for more info and documentation." + echo " " + echo "This script requires root because it operates on block devices, please run it " + echo -e "with ${BLUE}sudo${NC}. It does the following:" + echo "1) Creates a Shufflecake Legacy device with two volumes." + echo "2) Opens the second (hidden) volume, formats it with $FSTYPE and mounts it." + echo "3) Performs incremental random write up to filling the space." + echo "4) After every write round, checks fragmentation status and reports it." + echo "5) Unmounts and closes the used volume." + echo " " +# xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 79 chars + echo "You must have already compiled and installed Shufflecake in order to run this." + echo "The script will search for Shufflecake either in the default installation " + echo "directory, or in the current directory, or in the parent directory (one level" + echo -e "above this). If the module ${BLUE}dm-sflc${NC} is not loaded, the script " + echo "will load it, execute, and then unload it." + echo " " +# xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 79 chars + echo "You can pass the path to a block device as an optional argument, otherwise the " + echo "script will ask for one. If no path is provided, the script will create a 1 GiB" + echo "local file and use it to back a loop device as a virtual block device to be " + echo "formatted with the appropriate tools. The file will be removed at the end." + echo " " +# xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 79 chars + echo -e "${BLUE}WARNING: ALL CONTENT OF THE PROVIDED BLOCK DEVICE WILL BE ERASED!${NC}" + echo " " + exit 0 +} + +# Function for debugging +bpx() { + if [ -z "$1" ]; then + echo "BPX: Paused. Press any key to continue..." >&2 + else + echo -e "BPX: $1. Press any key to continue..." >&2 + fi + read -n1 -s +} + +# Show usage +usage() { + echo -e "Use ${BLUE}${SCRIPTNAME} --help${NC} for usage and help." +} + +# Check that this is run as root +check_sudo() { + if [[ $EUID -ne 0 ]]; then + echo -e "${RED}Error: This script must be run as root.${NC}" + usage + exit 1 + fi +} + +# Find the path of Shufflecake executable +find_sflc_path() { + local cmd="shufflecake" + + # Check if the command exists in the current directory + if [[ -x "./$cmd" ]]; then + SFLCPATH=$(realpath ./) + SFLCNAME=$(realpath ./$cmd) + return + fi + + # Check if the command exists in the parent directory + if [[ -x "../$cmd" ]]; then + SFLCPATH=$(realpath ../) + SFLCNAME=$(realpath ../$cmd) + return + fi + + # Check if the command exists in the directories listed in PATH + IFS=':' read -ra dirs <<< "$PATH" + for dir in "${dirs[@]}"; do + if [[ -x "$dir/$cmd" ]]; then + SFLCPATH=$(realpath $dir) + SFLCNAME=$(realpath $dir/$cmd) + return + fi + done + + # If the command was not found, print an error message + echo -e "${RED}ERROR: Command '$cmd' not found${NC}." >&2 + exit 1 +} + +# Find and load module dm-sflc +load_dmsflc() { + local mod="dm-sflc" + + # Check if the module is already loaded + if lsmod | grep -q "^$mod "; then + DMSFLC_INSTALLED=true + echo "Module '$mod' is already loaded." + return + fi + + # If not, look for the module file and try to load it + local mod_file="$mod.ko" + + # Check if the module file exists in the current directory + if [[ -f "./$mod_file" ]]; then + insmod $(realpath ./$mod_file) || exit 1 + echo "Module '$mod' loaded from current directory." + return + fi + + # Check if the module file exists in the parent directory + if [[ -f "../$mod_file" ]]; then + insmod $(realpath ../$mod_file) || exit 1 + echo "Module '$mod' loaded from parent directory." + return + fi + + # If the module file was not found, print an error message + echo -e "${RED} ERROR: Module file '$mod_file' not found.${NC}." >&2 + exit 1 +} + +# Unload dm-sflc if it was loaded locally +unload_dmsflc() { + local mod="dm-sflc" + # Only unload dm-sflc if it was loaded manually when the script was invoked + if ! $DMSFLC_INSTALLED; then + rmmod $mod || exit 1 + echo "Module '$mod' unloaded." + else + echo "Module '$mod' was not unloaded because it was already loaded when the script was run." + fi +} + +# Function to check if argument is a block device +check_block_device() { + if [ -b "$1" ]; then + echo "OK, block device path $1 is valid." >&2 + else + echo -e "${RED}Error: $1 is not a valid block device, aborting.${NC}" + unload_dmsflc + usage + exit 1 + fi +} + +# Function to create loop device +create_loop_device() { + echo "I will now try to create a file $LOOP_FILENAME ..." >&2 + if [ -e "$LOOP_FILENAME" ]; then + echo -e "${RED}Error: Impossible to generate file, $LOOP_FILENAME already exists.${NC}" + exit 1 + fi + sudo dd if=/dev/zero of="$LOOP_FILENAME" bs=1M count=1024 > /dev/null + echo "Writing of empty file complete. I will now try to attach it to a new loop device..." >&2 + LOOP_DEVICE=$(sudo losetup -f --show "$LOOP_FILENAME") + echo "Successfully created loop device $LOOP_DEVICE ." >&2 + echo "$LOOP_DEVICE" +} + +# Finds the sflc volume that was created last +find_sflcvolname() { + # List all files in /dev/mapper, select those starting with sflc_, sort them, and pick the last one. + volname=$(ls /dev/mapper/sflc_* 2>/dev/null | sort -t '_' -k 2n,2 -k 3n,3 | tail -n 1) + # Check if volname is empty (no sflc_ files found). + if [ -z "$volname" ]; then + echo -e "${RED}ERROR: No sflc_ devices found in /dev/mapper !${NC}" + return 1 + else + echo $volname + return 0 + fi +} + +# Function for user confirmation +confirm() { + while true; do + echo -e "${BLUE}Are you sure you want to proceed? All data on disk $BLOCK_DEVICE will be erased. (y/n)${NC}" + read -r response + case "$response" in + [yY]|[yY][eE][sS]) # Responded Yes + return 0 # Return 0 for Yes (success, convention for bash scripting) + ;; + [nN]|[nN][oO]) # Responded No + return 1 # Return 1 for No (error, convention for bash scripting) + ;; + *) # Responded something else + echo "Please press only (y)es or (n)o." + ;; + esac + done +} + +# Benchmarks +benchmark() { + + SFLCVOLUME="" + VOLNAME="" + MNTPOINT="" + NUMPOINTS=21 # number of graph points + VOLSIZE=$(blockdev --getsize64 "$BLOCK_DEVICE") # first approximation, in bytes + + echo "Starting fragmentation test for Shufflecake Legacy..." + # init + echo "Initializing block device $BLOCK_DEVICE with two Shufflecake Legacy volumes (--skip-randfill)..." + etime=$( (time echo -e "passwd1\npasswd2" | $SFLCNAME --skip-randfill --legacy -n 2 init $BLOCK_DEVICE > /dev/null) 2>&1 ) + echo -e "${GREEN}Action init took $etime seconds.${NC}" + echo "Shufflecake Legacy device initialized. Opening hidden volume (nr. 2)..." + # open + etime=$( (time echo -e "passwd2" | $SFLCNAME --legacy open $BLOCK_DEVICE > /dev/null) 2>&1 ) + echo -e "${GREEN}Action open took $etime seconds.${NC}" + # fetch SFLCVOLUME + SFLCVOLUME=$(find_sflcvolname) + # trim path of SFLCVOLUME + VOLNAME=${SFLCVOLUME##*/} + echo "Shufflecake volume opened as $VOLNAME. Formatting with $FSTYPE..." + # format with FSTYPE, but mute output (too verbose) + mkfs.$FSTYPE $SFLCVOLUME > /dev/null + echo "Volume $SFLCVOLUME formatted. Mounting that..." + # assign and create MNTPOINT + MNTPOINT=$(realpath "./sflc_mnt") + mkdir $MNTPOINT + # mount + mount $SFLCVOLUME $MNTPOINT + echo "Volume mounted at $MNTPOINT. Starting fragmentation test..." + # TESTS HERE + + # Fragmentation test + # Shufflecake allocates data on disk by lazily allocating "slices", and then writing data on those slices. + # If no suitable slice is available for writing data, a new one is allocated. + # The number of allocated slices for a volume is tracked into /sys/devices/sflc/${VOLNAME}/mapped_slices + # At this point the volume is already formatted as FSTYPE and mounted at MNTPOINT + # sanity check: NUMPOINTS must be at least 1 and at most 65536, otherwise exit 1 + if [ $NUMPOINTS -lt 1 ] || [ $NUMPOINTS -gt 65536 ]; then + echo -e "${RED}Error: NUMPOINTS must be between 1 and 65536. Aborting...${NC}" + exit 1 + fi + + # read number of total available slices (round down) from /sys/module/dm_sflc/bdevs/SFLCDEVICENAME/tot_slices + MOST_RECENT_DIR=$(ls -td /sys/module/dm_sflc/bdevs/*/ | head -n 1) # include final slash / + read -r TOTSLICES < ${MOST_RECENT_DIR}tot_slices + + # refine down block device max size according to available slices, to make sure there is no overflow + NEWUPPERBOUND=$((TOTSLICES * 1048576 )) # in bytes + if ((VOLSIZE > NEWUPPERBOUND)); then + VOLSIZE=$NEWUPPERBOUND + fi + + # manage case NUMPOINTS = 1 + read -r OCCSLICES < /sys/devices/sflc/${VOLNAME}/mapped_slices + X_COORD=.0 + Y_COORD=$(echo "scale=3; $OCCSLICES/$TOTSLICES" | bc) + + # Print occupation table for graph + echo -e "${GREEN}Occupation table: X = percentage of data written, Y = percentage of slices used.${NC}" + echo -e "${GREEN}---------------------------------${NC}" + + echo -e "${GREEN}$X_COORD $Y_COORD${NC}" + + if [ $NUMPOINTS -gt 1 ]; then + # point 1 is always at X=0 and point NUMPOINT is always at X=1 + DATASIZE=$(( $VOLSIZE / ($NUMPOINTS-1) / 1048576 )) # data increments in MB, round down + + # loop for i = 1 to NUMPOINTS + for (( i=1; i<$NUMPOINTS-1; i++ )); do + X_COORD=$(echo "scale=3; $i / ($NUMPOINTS-1) " | bc) + # RNDDIRNAME = random name with 16 characters (loop while it does not exist already) + while :; do + RNDDIRNAME=$(cat /dev/urandom | tr -dc 'a-z0-9' | fold -w 16 | head -n 1) + [ ! -e "${MNTPOINT}/${RNDDIRNAME}" ] && break + done + # create random dir + mkdir "${MNTPOINT}/${RNDDIRNAME}" + + # RNDFILENAME= random name with 16 characters (loop while it does not exist already) + while :; do + RNDFILENAME=$(cat /dev/urandom | tr -dc 'a-z0-9' | fold -w 16 | head -n 1) + [ ! -e "${MNTPOINT}/${RNDDIRNAME}/${RNDFILENAME}" ] && break + done + + # create random file + dd if=/dev/zero of=${MNTPOINT}/${RNDDIRNAME}/${RNDFILENAME} bs=1M count=$DATASIZE >/dev/null 2>&1 + sync + + # compute slice occupation threshold + read -r OCCSLICES < /sys/devices/sflc/${VOLNAME}/mapped_slices + Y_COORD=$(echo "scale=3; $OCCSLICES / $TOTSLICES" | bc) + # sanity check i.e. Y_COORD is between 0 and 1 + if (( $(echo "$Y_COORD < 0" | bc -l) )) || (( $(echo "$Y_COORD > 1" | bc -l) )); then + echo "Error: Y_COORD is not between 0 and 1" + exit 1 + fi + # print point coords + echo -e "${GREEN}$X_COORD $Y_COORD${NC}" + done + # manually print last point to avoid rounding error artifacts at the last write + echo -e "${GREEN}1.0 1.0${NC}" + + fi + # end table + echo -e "${GREEN}---------------------------------${NC}" + + # END TESTS + echo "Shufflecake Legacy fragmentation test ended. Unmounting volume." + # unmount + umount $MNTPOINT + rmdir $MNTPOINT + echo "Volume unmounted. Closing Shufflecake device..." + # close + etime=$( (time $SFLCNAME close $BLOCK_DEVICE > /dev/null) 2>&1 ) + echo -e "${GREEN}Action close took $etime seconds.${NC}" + #end + +} + +# Clean up +cleanup() { + echo "Exiting and cleaning..." + if [[ -n $LOOP_DEVICE ]]; then + echo "Detaching $LOOP_DEVICE ..." + sudo losetup -d "$LOOP_DEVICE" + echo "Deleting $LOOP_FILENAME ..." + sudo rm -f "$LOOP_FILENAME" + echo "Loop device detached and backing file deleted." + fi +} + + +##################################################################### + +# MAIN SCRIPT BODY STARTS HERE + +##################################################################### + +# BANNER +# xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 79 chars +echo -e "${BLUE}===============================================================================${NC}" +echo -e "${BLUE} Evaluation Script for Shufflecake Legacy Volume Fragmentation${NC}" +echo -e "${BLUE}===============================================================================${NC}" + + +# PRELIMINARY: PARSE HELP, SUDO, AND LOAD SHUFFLECAKE (IF IT EXISTS, OTHERWISE ERROR) + +case "$1" in + # help + --help|-?) + print_help + exit 0 + ;; +esac + +check_sudo + +echo -e "${BLUE}Initializing Shufflecake...${NC}" +echo "Searching Shufflecake executable..." +find_sflc_path +echo "Shufflecake executable found at $SFLCNAME ." +echo "Searching and loading dm-sflc module..." +load_dmsflc +echo "Module dm-sflc found and loaded. Status DMSFLC_INSTALLED: $DMSFLC_INSTALLED ." +echo " " + + +# PARSER + +case "$1" in + "") +# xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 79 chars + + echo "Now you will be asked to enter the path for a block device to be used for the " + echo "evaluation (all content will be erased). If no path is provided (default" + echo "choice), then the script will create a 1 GiB file in the current directory and " + echo "use it to back a loop device instead, then the file will be removed at the end." + echo " " + echo -n "Please enter the path for a block device (default: none): " + read BLOCK_DEVICE + if [ -z "$BLOCK_DEVICE" ]; then + echo "No path provided, creating a local file and loop device..." + LOOP_DEVICE=$(create_loop_device) + BLOCK_DEVICE=$LOOP_DEVICE + fi + + ;; + + # argument passed + *) + BLOCK_DEVICE="$1" + ;; +esac + +check_block_device "$BLOCK_DEVICE" + +# MAIN PROGRAM + +if confirm; then + benchmark +else + echo "Aborting..." +fi + +unload_dmsflc + +cleanup + + + + diff --git a/benchmark-suite/sflc-benchmark.sh b/benchmark-suite/sflc-lite-benchmark.sh similarity index 95% rename from benchmark-suite/sflc-benchmark.sh rename to benchmark-suite/sflc-lite-benchmark.sh index d703e84..05805a0 100755 --- a/benchmark-suite/sflc-benchmark.sh +++ b/benchmark-suite/sflc-lite-benchmark.sh @@ -26,7 +26,7 @@ # Variables SCRIPTNAME=$(basename "$0") SCRIPT_DIR="$(dirname "$(realpath "$0")")" -LOOP_FILENAME="$SCRIPT_DIR/sflc-benchmark-loop-file.img" +LOOP_FILENAME="$SCRIPT_DIR/sflc-lite-benchmark-loop-file.img" LOOP_DEVICE="" TIMEFORMAT='%3R' SFLCPATH="" @@ -44,15 +44,15 @@ print_help() { # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 79 chars echo -e "${BLUE}Usage: ${SCRIPTNAME} [OPTION]... [BLOCKDEVICE]${NC}" echo " " - echo "This script is used to benchmark Shufflecake on this machine." + echo "This script is used to benchmark Shufflecake Lite on this machine." echo "This script is part of the Shufflecake benchmark suite." echo "Shufflecake is a plausible deniability (hidden storage) layer for Linux." echo -e "Please visit ${BLUE}https://www.shufflecake.net${NC} for more info and documentation." echo " " echo "This script requires root because it operates on block devices, please run it " echo -e "with ${BLUE}sudo${NC}. It does the following:" - echo "1) Creates a Shufflecake device with two volumes." - echo "2) Opens the second (hidden) one, formats it with ext4 and mounts it." + echo "1) Creates a Shufflecake (Lite) device with two volumes." + echo "2) Opens the second (hidden) volume, formats it with ext4 and mounts it." echo "3) Performs various fio r/w stress operations on it." echo "4) Unmounts and closes the used volume." echo " " @@ -241,20 +241,21 @@ benchmark() { SFLCVOLUME="" MNTPOINT="" - TESTNAME="sflc" + TESTNAME="sflc-lite" RUNTIME="20" # running time in seconds FOR EACH TEST DATASIZE="500M" TESTFILENAME="testfile" - echo "Starting benchmark for Shufflecake..." - echo "Initializing block device $BLOCK_DEVICE with two Shufflecake volumes (--skip-randfill)..." + echo "Starting benchmark for Shufflecake Lite..." + echo "Initializing block device $BLOCK_DEVICE with two Shufflecake Lite volumes (--skip-randfill)..." etime=$( (time echo -e "passwd1\npasswd2" | $SFLCNAME --skip-randfill -n 2 init $BLOCK_DEVICE > /dev/null) 2>&1 ) echo -e "${GREEN}Action init took $etime seconds.${NC}" echo "Shufflecake device initialized. Opening hidden volume (nr. 2)..." + # open etime=$( (time echo -e "passwd2" | $SFLCNAME open $BLOCK_DEVICE > /dev/null) 2>&1 ) echo -e "${GREEN}Action open took $etime seconds.${NC}" # fetch SFLCVOLUME SFLCVOLUME=$(find_sflcvolname) - echo "Shufflecake volume opened as $SFLCVOLUME. Formatting with ext4..." + echo "Shufflecake Lite volume opened as $SFLCVOLUME. Formatting with ext4..." # format with ext4, but mute output (too verbose) mkfs.ext4 $SFLCVOLUME > /dev/null echo "Volume $SFLCVOLUME formatted. Mounting that..." @@ -282,7 +283,7 @@ benchmark() { OUTPUT=$(fio --name=$TESTNAME-w-seq --ioengine=libaio --iodepth=32 --rw=write --bs=4k --numjobs=1 --direct=1 --size=$DATASIZE --runtime=$RUNTIME --time_based --end_fsync=1 --filename=$MNTPOINT/$TESTFILENAME --output-format=json | jq '.jobs[] | {name: .jobname, write_iops: .write.iops, write_bw: .write.bw}') echo -e "${GREEN}${OUTPUT}${NC}" # END TESTS - echo "Shufflecake fio tests ended. Unmounting volume." + echo "Shufflecake Lite fio tests ended. Unmounting volume." # unmount umount $MNTPOINT rmdir $MNTPOINT @@ -316,7 +317,7 @@ cleanup() { # BANNER # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 79 chars echo -e "${BLUE}===============================================================================${NC}" -echo -e "${BLUE} Benchmark Suite Script for Shufflecake${NC}" +echo -e "${BLUE} Benchmark Suite Script for Shufflecake Lite${NC}" echo -e "${BLUE}===============================================================================${NC}" diff --git a/benchmark-suite/sflc-fragmentation.sh b/benchmark-suite/sflc-lite-fragmentation.sh similarity index 96% rename from benchmark-suite/sflc-fragmentation.sh rename to benchmark-suite/sflc-lite-fragmentation.sh index dcd7c1d..2e72322 100755 --- a/benchmark-suite/sflc-fragmentation.sh +++ b/benchmark-suite/sflc-lite-fragmentation.sh @@ -26,7 +26,7 @@ # Global variables SCRIPTNAME=$(basename "$0") SCRIPT_DIR="$(dirname "$(realpath "$0")")" -LOOP_FILENAME="$SCRIPT_DIR/sflc-frag-loop-file.img" +LOOP_FILENAME="$SCRIPT_DIR/sflc-lite-frag-loop-file.img" LOOP_DEVICE="" TIMEFORMAT='%3R' SFLCPATH="" @@ -48,15 +48,15 @@ print_help() { # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 79 chars echo -e "${BLUE}Usage: ${SCRIPTNAME} [OPTION]... [BLOCKDEVICE]${NC}" echo " " - echo "This script is used to evaluate Shufflecake volume fragmentation." + echo "This script is used to evaluate Shufflecake Lite volume fragmentation." echo "This script is part of the Shufflecake benchmark suite." echo "Shufflecake is a plausible deniability (hidden storage) layer for Linux." echo -e "Please visit ${BLUE}https://www.shufflecake.net${NC} for more info and documentation." echo " " echo "This script requires root because it operates on block devices, please run it " echo -e "with ${BLUE}sudo${NC}. It does the following:" - echo "1) Creates a Shufflecake device with two volumes." - echo "2) Opens the second (hidden) one, formats it with $FSTYPE and mounts it." + echo "1) Creates a Shufflecake Lite device with two volumes." + echo "2) Opens the second (hidden) volume, formats it with $FSTYPE and mounts it." echo "3) Performs incremental random write up to filling the space." echo "4) After every write round, checks fragmentation status and reports it." echo "5) Unmounts and closes the used volume." @@ -250,12 +250,12 @@ benchmark() { NUMPOINTS=21 # number of graph points VOLSIZE=$(blockdev --getsize64 "$BLOCK_DEVICE") # first approximation, in bytes - echo "Starting fragmentation test for Shufflecake..." + echo "Starting fragmentation test for Shufflecake Lite..." # init - echo "Initializing block device $BLOCK_DEVICE with two Shufflecake volumes (--skip-randfill)..." + echo "Initializing block device $BLOCK_DEVICE with two Shufflecake Lite volumes (--skip-randfill)..." etime=$( (time echo -e "passwd1\npasswd2" | $SFLCNAME --skip-randfill -n 2 init $BLOCK_DEVICE > /dev/null) 2>&1 ) echo -e "${GREEN}Action init took $etime seconds.${NC}" - echo "Shufflecake device initialized. Opening hidden volume (nr. 2)..." + echo "Shufflecake Lite device initialized. Opening hidden volume (nr. 2)..." # open etime=$( (time echo -e "passwd2" | $SFLCNAME open $BLOCK_DEVICE > /dev/null) 2>&1 ) echo -e "${GREEN}Action open took $etime seconds.${NC}" @@ -351,7 +351,7 @@ benchmark() { echo -e "${GREEN}---------------------------------${NC}" # END TESTS - echo "Shufflecake fragmentation test ended. Unmounting volume." + echo "Shufflecake Lite fragmentation test ended. Unmounting volume." # unmount umount $MNTPOINT rmdir $MNTPOINT @@ -385,7 +385,7 @@ cleanup() { # BANNER # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 79 chars echo -e "${BLUE}===============================================================================${NC}" -echo -e "${BLUE} Evaluation Script for Shufflecake Volume Fragmentation${NC}" +echo -e "${BLUE} Evaluation Script for Shufflecake Lite Volume Fragmentation${NC}" echo -e "${BLUE}===============================================================================${NC}" diff --git a/benchmark-suite/veracrypt-benchmark.sh b/benchmark-suite/veracrypt-benchmark.sh index 06ab088..4a69071 100755 --- a/benchmark-suite/veracrypt-benchmark.sh +++ b/benchmark-suite/veracrypt-benchmark.sh @@ -26,7 +26,12 @@ # Variables SCRIPTNAME=$(basename "$0") SCRIPT_DIR="$(dirname "$(realpath "$0")")" +<<<<<<< HEAD CONTAINER_FILENAME="" +======= +LOOP_FILENAME="$SCRIPT_DIR/veracrypt-benchmark-loop-file.img" +LOOP_DEVICE="" +>>>>>>> feature/rewrite-kernel-mod TIMEFORMAT='%3R' # Colors @@ -38,7 +43,11 @@ NC='\033[0m' # No color # Help print_help() { # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 79 chars +<<<<<<< HEAD echo -e "${BLUE}Usage: ${SCRIPTNAME} [OPTION]... [BLOCKDEVICE]${NC}" +======= + echo -e "${BLUE}Usage: ${SCRIPTNAME} [OPTION]... [BLOCKDEVICE]...${NC}" +>>>>>>> feature/rewrite-kernel-mod echo " " echo "This script is used to benchmark VeraCrypt on this machine." echo "This script is part of the Shufflecake benchmark suite." @@ -47,6 +56,7 @@ print_help() { echo " " echo "This script requires root because it operates on block devices, please run it " echo -e "with ${BLUE}sudo${NC}. It does the following:" +<<<<<<< HEAD echo "1) Creates a standard and unformatted VeraCrypt volumes within a given device." echo "2) Creates a hidden ext4 VeraCrypt volume within the standard one." echo "3) Opens the hidden volume, and mounts it." @@ -61,6 +71,22 @@ print_help() { echo " " # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 79 chars echo -e "${BLUE}WARNING: ALL CONTENT OF THE PROVIDED BLOCK DEVICE WILL BE ERASED!${NC}" +======= + echo "1) Creates standard and hidden VeraCrypt volumes within a given device." + echo "2) Opens the hidden volume, formats it with ext4 and mounts it." + echo "3) Performs various fio r/w stress operations on it." + echo "4) Unmounts and closes the used volume." + echo " " +# xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 79 chars + echo "You can pass the path to a block device as an optional argument, otherwise the " + echo "script will ask for one. If no path is provided, the script will create a 1 GiB" + echo "local file and use it to back a loop device as a virtual block device to be " + echo "formatted with the appropriate tools. The file will be removed at the end." + echo " " +# xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 79 chars + echo "NOTICE: This script has been tested only with VeraCrypt v 1.25.9." + echo -e "${RED}WARNING: ALL CONTENT OF THE PROVIDED BLOCK DEVICE WILL BE ERASED!${NC}" +>>>>>>> feature/rewrite-kernel-mod echo " " exit 0 } @@ -84,7 +110,11 @@ usage() { # Check that this is run as root check_sudo() { if [[ $EUID -ne 0 ]]; then +<<<<<<< HEAD echo -e "${RED}Error: This script must be run as root.${NC}" +======= + echo -e "${RED}Error: This script must be run as root${NC}" +>>>>>>> feature/rewrite-kernel-mod usage exit 1 fi @@ -101,6 +131,7 @@ check_block_device() { fi } +<<<<<<< HEAD check_not_loopdevice() { DEVCHECK=$1 if [[ $DEVCHECK == /dev/loop* ]]; then @@ -121,12 +152,36 @@ create_container_file() { #dd if=/dev/zero of="$CONTAINER_FILENAME" bs=1M count=1024 > /dev/null #echo "Writing of empty file complete." >&2 echo "$CONTAINER_FILENAME" +======= +# Function to create loop device +create_loop_device() { + echo "I will now try to create a file $LOOP_FILENAME" >&2 + if [ -e "$LOOP_FILENAME" ]; then + echo -e "${RED}Error: Impossible to generate file, $LOOP_FILENAME already exists${NC}" + exit 1 + fi + sudo dd if=/dev/zero of="$LOOP_FILENAME" bs=1M count=1024 > /dev/null + echo "Writing of empty file complete. I will now try to attach it to a new loop device..." >&2 + LOOP_DEVICE=$(sudo losetup -f --show "$LOOP_FILENAME") + echo "Successfully created loop device $LOOP_DEVICE" >&2 + echo "$LOOP_DEVICE" +} + +# Generate a suitable VeraCrypt volume name +find_veracryptvolname() { + volname="/dev/mapper/vc01" #placeholder + echo "$volname" +>>>>>>> feature/rewrite-kernel-mod } # Function for user confirmation confirm() { while true; do +<<<<<<< HEAD echo -e "${BLUE}Are you sure you want to proceed? All data in $BLOCK_DEVICE will be erased. (y/n)${NC}" +======= + echo -e "${RED}Are you sure you want to proceed? All data on disk $BLOCK_DEVICE will be erased. (y/n)${NC}" +>>>>>>> feature/rewrite-kernel-mod read -r response case "$response" in [yY]|[yY][eE][sS]) # Responded Yes @@ -136,7 +191,11 @@ confirm() { return 1 # Return 1 for No (error, convention for bash scripting) ;; *) # Responded something else +<<<<<<< HEAD echo "Please press only (y)es or (n)o." +======= + echo "Please press only y or n." +>>>>>>> feature/rewrite-kernel-mod ;; esac done @@ -145,6 +204,7 @@ confirm() { # Benchmarks benchmark() { +<<<<<<< HEAD MNTPOINT="" TESTNAME="vc" RUNTIME="20" # running time in seconds FOR EACH TEST @@ -194,15 +254,35 @@ benchmark() { rmdir $MNTPOINT echo "Volume detached and local mountpoint removed." #end +======= + VOLUME="veracrypt-test" + MNTPOINT="" + PASSPHRASE="mypassword" + echo "Starting benchmark for VeraCrypt" + # TESTS HERE + bpx "THIS IS JUST A SKELETON, VERACRYPT SCRIPT NOT IMPLEMENTED YET, DOING NOTHING..." + # END TESTS + #end +>>>>>>> feature/rewrite-kernel-mod } # Clean up cleanup() { echo "Exiting and cleaning..." +<<<<<<< HEAD if [[ -n $CONTAINER_FILENAME ]]; then echo "Deleting $CONTAINER_FILENAME..." rm -f "$CONTAINER_FILENAME" echo "Container file deleted." +======= + # TODO clean other stuff if necessary + if [[ -n $LOOP_DEVICE ]]; then + echo "Detaching $LOOP_DEVICE" + sudo losetup -d "$LOOP_DEVICE" + echo "Deleting $LOOP_FILENAME" + sudo rm -f "$LOOP_FILENAME" + echo "Loop device detached and backing file deleted." +>>>>>>> feature/rewrite-kernel-mod fi } @@ -215,9 +295,15 @@ cleanup() { # BANNER # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 79 chars +<<<<<<< HEAD echo -e "${BLUE}===============================================================================${NC}" echo -e "${BLUE} Benchmark Suite Script for VeraCrypt${NC}" echo -e "${BLUE}===============================================================================${NC}" +======= +echo -e "${GREEN}===============================================================================${NC}" +echo -e "${GREEN} Benchmark Suite Script for VeraCrypt${NC}" +echo -e "${GREEN}===============================================================================${NC}" +>>>>>>> feature/rewrite-kernel-mod # PRELIMINARY: PARSE HELP, SUDO, AND CHECK VERACRYPT EXISTS @@ -243,12 +329,17 @@ echo " " # PARSER case "$1" in +<<<<<<< HEAD "") # no argument passed +======= + "") +>>>>>>> feature/rewrite-kernel-mod # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 79 chars echo "Now you will be asked to enter the path for a block device to be used for the " echo "benchmarks (all content will be erased). If no path is provided (default" echo "choice), then the script will create a 1 GiB file in the current directory and " +<<<<<<< HEAD echo "use it a VeraCrypt container instead, then the file will be removed at the end." echo " " echo -n "Please enter the path for a (non-loop) block device (default: none): " @@ -262,6 +353,16 @@ case "$1" in BLOCK_DEVICE="$CONTAINER_FILENAME" else check_block_device "$BLOCK_DEVICE" +======= + echo "use it to back a loop device instead, then the file will be removed at the end." + echo " " + echo -n "Please enter the path for a block device (default: none): " + read BLOCK_DEVICE + if [ -z "$BLOCK_DEVICE" ]; then + echo "No path provided, creating a local file and loop device..." + LOOP_DEVICE=$(create_loop_device) + BLOCK_DEVICE=$LOOP_DEVICE +>>>>>>> feature/rewrite-kernel-mod fi ;; @@ -269,16 +370,27 @@ case "$1" in # argument passed *) BLOCK_DEVICE="$1" +<<<<<<< HEAD check_block_device "$BLOCK_DEVICE" ;; esac check_not_loopdevice "$BLOCK_DEVICE" +======= + ;; +esac + +check_block_device "$BLOCK_DEVICE" +>>>>>>> feature/rewrite-kernel-mod # MAIN PROGRAM if confirm; then +<<<<<<< HEAD benchmark +======= + benchmark # Call your disk formatting function here +>>>>>>> feature/rewrite-kernel-mod else echo "Aborting..." fi @@ -286,3 +398,8 @@ fi cleanup +<<<<<<< HEAD +======= + + +>>>>>>> feature/rewrite-kernel-mod diff --git a/dm-sflc/.Kbuild b/dm-sflc/.Kbuild new file mode 100644 index 0000000..b909a50 --- /dev/null +++ b/dm-sflc/.Kbuild @@ -0,0 +1,53 @@ + # + # Copyright The Shufflecake Project Authors (2022) + # Copyright The Shufflecake Project Contributors (2022) + # Copyright Contributors to the The Shufflecake Project. + # + # See the AUTHORS file at the top-level directory of this distribution and at + # + # + # This file is part of the program shufflecake-c, which is part of the + # Shufflecake Project. Shufflecake is a plausible deniability (hidden storage) + # layer for Linux. See . + # + # This program is free software: you can redistribute it and/or modify it + # under the terms of the GNU General Public License as published by the Free + # Software Foundation, either version 2 of the License, or (at your option) + # any later version. This program is distributed in the hope that it will be + # useful, but WITHOUT ANY WARRANTY; without even the implied warranty of + # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + # Public License for more details. You should have received a copy of the + # GNU General Public License along with this program. + # If not, see . + # + +MODULE_NAME := dm_sflc +obj-m := $(MODULE_NAME).o + + +OBJ_LIST := sflc.o dev_vol.o sysfs.o + +OBJ_LIST += legacy/sflc_legacy.o legacy/target.o legacy/sysfs.o +OBJ_LIST += legacy/device/device.o legacy/device/volumes.o legacy/device/rawio.o legacy/device/rmap.o legacy/device/iv.o +OBJ_LIST += legacy/volume/volume.o legacy/volume/io.o legacy/volume/read.o legacy/volume/write.o legacy/volume/fmap.o +OBJ_LIST += legacy/utils/string.o legacy/utils/bio.o legacy/utils/pools.o legacy/utils/workqueues.o legacy/utils/vector.o +OBJ_LIST += legacy/crypto/rand/rand.o +OBJ_LIST += legacy/crypto/symkey/symkey.o legacy/crypto/symkey/skreq_pool.o + +OBJ_LIST += lite/sflc_lite.o lite/sysfs.o +OBJ_LIST += lite/device.o lite/volume.o +OBJ_LIST += lite/posmap.o lite/read.o lite/write.o lite/crypto.o + +$(MODULE_NAME)-y += $(OBJ_LIST) + + +# Normal CC flags +ccflags-y := -O2 +ccflags-y += -I$(src) +ccflags-y += -Wall -Wno-declaration-after-statement + +# Debug CC flags +ccflags-$(CONFIG_SFLC_DEBUG) += -DDEBUG +ccflags-$(CONFIG_SFLC_DEBUG) += -Og -g +ccflags-$(CONFIG_SFLC_DEBUG) += -fsanitize=kernel-address -fno-omit-frame-pointer + diff --git a/dm-sflc/.gitignore b/dm-sflc/.gitignore index ee31866..1ee0110 100644 --- a/dm-sflc/.gitignore +++ b/dm-sflc/.gitignore @@ -1,4 +1,8 @@ .project .cproject .settings/ -bin/ + +!bin/ +*.o +*.symvers +*.ko diff --git a/dm-sflc/Makefile b/dm-sflc/Makefile index b75f428..29c9b12 100644 --- a/dm-sflc/Makefile +++ b/dm-sflc/Makefile @@ -22,25 +22,27 @@ # KERNEL_DIR = /lib/modules/$(shell uname -r)/build -SRC_DIR = $(shell pwd) -BUILD_DIR = $(shell pwd)/bin -BUILD_DIR_MAKEFILE = $(BUILD_DIR)/Makefile +ROOT_DIR:=$(shell dirname $(realpath $(firstword $(MAKEFILE_LIST)))) -default: $(BUILD_DIR_MAKEFILE) - make -C $(KERNEL_DIR) M=$(BUILD_DIR) src=$(SRC_DIR) CONFIG_SFLC_DEBUG=$(CONFIG_SFLC_DEBUG) modules - -$(BUILD_DIR_MAKEFILE): $(BUILD_DIR) - echo "# This Makefile is here because of Kbuild" > $@ - -$(BUILD_DIR): - mkdir -p $@ +default: + make -C $(KERNEL_DIR) M=$(ROOT_DIR)/bin CONFIG_SFLC_DEBUG=$(CONFIG_SFLC_DEBUG) modules debug: CONFIG_SFLC_DEBUG=y debug: default install: - make -C $(KERNEL_DIR) M=$(BUILD_DIR) src=$(SRC_DIR) modules_install + make -C $(KERNEL_DIR) M=$(ROOT_DIR)/bin CONFIG_SFLC_DEBUG=$(CONFIG_SFLC_DEBUG) modules_install clean: - rm -rf $(BUILD_DIR) + make -C $(KERNEL_DIR) M=$(ROOT_DIR)/bin CONFIG_SFLC_DEBUG=$(CONFIG_SFLC_DEBUG) clean + +# Reserved +ORIGINALS = $(shell find src/ -type f) +SYMLINKS = $(patsubst src/%, bin/%, $(ORIGINALS)) + +symlinks: $(SYMLINKS) + +bin/%: src/% + @mkdir -p "$(@D)" + ln -s $(shell realpath -m --relative-to=$(@D) $<) $@ diff --git a/dm-sflc/Kbuild b/dm-sflc/bin/Kbuild similarity index 68% rename from dm-sflc/Kbuild rename to dm-sflc/bin/Kbuild index a86d8b9..a2e7f25 100644 --- a/dm-sflc/Kbuild +++ b/dm-sflc/bin/Kbuild @@ -25,14 +25,18 @@ MODULE_NAME := dm-sflc obj-m := $(MODULE_NAME).o -OBJ_LIST := module.o -OBJ_LIST += sysfs/sysfs.o sysfs/devices.o sysfs/volumes.o -OBJ_LIST += target/target.o -OBJ_LIST += device/device.o device/volumes.o device/rawio.o device/rmap.o device/iv.o -OBJ_LIST += volume/volume.o volume/io.o volume/read.o volume/write.o volume/fmap.o -OBJ_LIST += utils/string.o utils/bio.o utils/pools.o utils/workqueues.o utils/vector.o -OBJ_LIST += crypto/rand/rand.o crypto/rand/selftest.o -OBJ_LIST += crypto/symkey/symkey.o crypto/symkey/skreq_pool.o crypto/symkey/selftest.o +OBJ_LIST := sflc.o dev_vol.o sysfs.o + +OBJ_LIST += legacy/sflc_legacy.o legacy/target.o legacy/sysfs.o +OBJ_LIST += legacy/device/device.o legacy/device/volumes.o legacy/device/rawio.o legacy/device/rmap.o legacy/device/iv.o +OBJ_LIST += legacy/volume/volume.o legacy/volume/io.o legacy/volume/read.o legacy/volume/write.o legacy/volume/fmap.o +OBJ_LIST += legacy/utils/string.o legacy/utils/bio.o legacy/utils/pools.o legacy/utils/workqueues.o legacy/utils/vector.o +OBJ_LIST += legacy/crypto/rand/rand.o +OBJ_LIST += legacy/crypto/symkey/symkey.o legacy/crypto/symkey/skreq_pool.o + +OBJ_LIST += lite/sflc_lite.o lite/sysfs.o +OBJ_LIST += lite/device.o lite/volume.o +OBJ_LIST += lite/posmap.o lite/read.o lite/write.o lite/crypto.o $(MODULE_NAME)-y += $(OBJ_LIST) @@ -41,9 +45,9 @@ $(MODULE_NAME)-y += $(OBJ_LIST) ccflags-y := -O2 ccflags-y += -I$(src) ccflags-y += -Wall -Wno-declaration-after-statement -ccflags-y += -fmacro-prefix-map=$(src)/= # Strip the non-project directories from the filename used in the logs # Debug CC flags ccflags-$(CONFIG_SFLC_DEBUG) += -DDEBUG ccflags-$(CONFIG_SFLC_DEBUG) += -Og -g ccflags-$(CONFIG_SFLC_DEBUG) += -fsanitize=kernel-address -fno-omit-frame-pointer + diff --git a/dm-sflc/bin/dev_vol.c b/dm-sflc/bin/dev_vol.c new file mode 120000 index 0000000..a35e5d5 --- /dev/null +++ b/dm-sflc/bin/dev_vol.c @@ -0,0 +1 @@ +../src/dev_vol.c \ No newline at end of file diff --git a/dm-sflc/bin/legacy/crypto/rand/rand.c b/dm-sflc/bin/legacy/crypto/rand/rand.c new file mode 120000 index 0000000..113cc5e --- /dev/null +++ b/dm-sflc/bin/legacy/crypto/rand/rand.c @@ -0,0 +1 @@ +../../../../src/legacy/crypto/rand/rand.c \ No newline at end of file diff --git a/dm-sflc/bin/legacy/crypto/rand/rand.h b/dm-sflc/bin/legacy/crypto/rand/rand.h new file mode 120000 index 0000000..79a32c9 --- /dev/null +++ b/dm-sflc/bin/legacy/crypto/rand/rand.h @@ -0,0 +1 @@ +../../../../src/legacy/crypto/rand/rand.h \ No newline at end of file diff --git a/dm-sflc/bin/legacy/crypto/symkey/skreq_pool.c b/dm-sflc/bin/legacy/crypto/symkey/skreq_pool.c new file mode 120000 index 0000000..d7fd86c --- /dev/null +++ b/dm-sflc/bin/legacy/crypto/symkey/skreq_pool.c @@ -0,0 +1 @@ +../../../../src/legacy/crypto/symkey/skreq_pool.c \ No newline at end of file diff --git a/dm-sflc/bin/legacy/crypto/symkey/skreq_pool.h b/dm-sflc/bin/legacy/crypto/symkey/skreq_pool.h new file mode 120000 index 0000000..bbf5677 --- /dev/null +++ b/dm-sflc/bin/legacy/crypto/symkey/skreq_pool.h @@ -0,0 +1 @@ +../../../../src/legacy/crypto/symkey/skreq_pool.h \ No newline at end of file diff --git a/dm-sflc/bin/legacy/crypto/symkey/symkey.c b/dm-sflc/bin/legacy/crypto/symkey/symkey.c new file mode 120000 index 0000000..e930fb4 --- /dev/null +++ b/dm-sflc/bin/legacy/crypto/symkey/symkey.c @@ -0,0 +1 @@ +../../../../src/legacy/crypto/symkey/symkey.c \ No newline at end of file diff --git a/dm-sflc/bin/legacy/crypto/symkey/symkey.h b/dm-sflc/bin/legacy/crypto/symkey/symkey.h new file mode 120000 index 0000000..127df1b --- /dev/null +++ b/dm-sflc/bin/legacy/crypto/symkey/symkey.h @@ -0,0 +1 @@ +../../../../src/legacy/crypto/symkey/symkey.h \ No newline at end of file diff --git a/dm-sflc/bin/legacy/device/device.c b/dm-sflc/bin/legacy/device/device.c new file mode 120000 index 0000000..4770b03 --- /dev/null +++ b/dm-sflc/bin/legacy/device/device.c @@ -0,0 +1 @@ +../../../src/legacy/device/device.c \ No newline at end of file diff --git a/dm-sflc/bin/legacy/device/device.h b/dm-sflc/bin/legacy/device/device.h new file mode 120000 index 0000000..f268245 --- /dev/null +++ b/dm-sflc/bin/legacy/device/device.h @@ -0,0 +1 @@ +../../../src/legacy/device/device.h \ No newline at end of file diff --git a/dm-sflc/bin/legacy/device/iv.c b/dm-sflc/bin/legacy/device/iv.c new file mode 120000 index 0000000..3a8fe09 --- /dev/null +++ b/dm-sflc/bin/legacy/device/iv.c @@ -0,0 +1 @@ +../../../src/legacy/device/iv.c \ No newline at end of file diff --git a/dm-sflc/bin/legacy/device/rawio.c b/dm-sflc/bin/legacy/device/rawio.c new file mode 120000 index 0000000..2ec4dfb --- /dev/null +++ b/dm-sflc/bin/legacy/device/rawio.c @@ -0,0 +1 @@ +../../../src/legacy/device/rawio.c \ No newline at end of file diff --git a/dm-sflc/bin/legacy/device/rmap.c b/dm-sflc/bin/legacy/device/rmap.c new file mode 120000 index 0000000..b13a00b --- /dev/null +++ b/dm-sflc/bin/legacy/device/rmap.c @@ -0,0 +1 @@ +../../../src/legacy/device/rmap.c \ No newline at end of file diff --git a/dm-sflc/bin/legacy/device/volumes.c b/dm-sflc/bin/legacy/device/volumes.c new file mode 120000 index 0000000..56e34fc --- /dev/null +++ b/dm-sflc/bin/legacy/device/volumes.c @@ -0,0 +1 @@ +../../../src/legacy/device/volumes.c \ No newline at end of file diff --git a/dm-sflc/bin/legacy/log/log.h b/dm-sflc/bin/legacy/log/log.h new file mode 120000 index 0000000..b1a5082 --- /dev/null +++ b/dm-sflc/bin/legacy/log/log.h @@ -0,0 +1 @@ +../../../src/legacy/log/log.h \ No newline at end of file diff --git a/dm-sflc/bin/legacy/sflc_legacy.c b/dm-sflc/bin/legacy/sflc_legacy.c new file mode 120000 index 0000000..971b2cc --- /dev/null +++ b/dm-sflc/bin/legacy/sflc_legacy.c @@ -0,0 +1 @@ +../../src/legacy/sflc_legacy.c \ No newline at end of file diff --git a/dm-sflc/bin/legacy/sflc_legacy.h b/dm-sflc/bin/legacy/sflc_legacy.h new file mode 120000 index 0000000..0b29c03 --- /dev/null +++ b/dm-sflc/bin/legacy/sflc_legacy.h @@ -0,0 +1 @@ +../../src/legacy/sflc_legacy.h \ No newline at end of file diff --git a/dm-sflc/bin/legacy/sysfs.c b/dm-sflc/bin/legacy/sysfs.c new file mode 120000 index 0000000..b34d0a3 --- /dev/null +++ b/dm-sflc/bin/legacy/sysfs.c @@ -0,0 +1 @@ +../../src/legacy/sysfs.c \ No newline at end of file diff --git a/dm-sflc/bin/legacy/target.c b/dm-sflc/bin/legacy/target.c new file mode 120000 index 0000000..0553cf6 --- /dev/null +++ b/dm-sflc/bin/legacy/target.c @@ -0,0 +1 @@ +../../src/legacy/target.c \ No newline at end of file diff --git a/dm-sflc/bin/legacy/utils/bio.c b/dm-sflc/bin/legacy/utils/bio.c new file mode 120000 index 0000000..013aaf7 --- /dev/null +++ b/dm-sflc/bin/legacy/utils/bio.c @@ -0,0 +1 @@ +../../../src/legacy/utils/bio.c \ No newline at end of file diff --git a/dm-sflc/bin/legacy/utils/bio.h b/dm-sflc/bin/legacy/utils/bio.h new file mode 120000 index 0000000..7d66dc7 --- /dev/null +++ b/dm-sflc/bin/legacy/utils/bio.h @@ -0,0 +1 @@ +../../../src/legacy/utils/bio.h \ No newline at end of file diff --git a/dm-sflc/bin/legacy/utils/pools.c b/dm-sflc/bin/legacy/utils/pools.c new file mode 120000 index 0000000..51b1230 --- /dev/null +++ b/dm-sflc/bin/legacy/utils/pools.c @@ -0,0 +1 @@ +../../../src/legacy/utils/pools.c \ No newline at end of file diff --git a/dm-sflc/bin/legacy/utils/pools.h b/dm-sflc/bin/legacy/utils/pools.h new file mode 120000 index 0000000..63520d0 --- /dev/null +++ b/dm-sflc/bin/legacy/utils/pools.h @@ -0,0 +1 @@ +../../../src/legacy/utils/pools.h \ No newline at end of file diff --git a/dm-sflc/bin/legacy/utils/string.c b/dm-sflc/bin/legacy/utils/string.c new file mode 120000 index 0000000..8d1e9ce --- /dev/null +++ b/dm-sflc/bin/legacy/utils/string.c @@ -0,0 +1 @@ +../../../src/legacy/utils/string.c \ No newline at end of file diff --git a/dm-sflc/bin/legacy/utils/string.h b/dm-sflc/bin/legacy/utils/string.h new file mode 120000 index 0000000..41c5867 --- /dev/null +++ b/dm-sflc/bin/legacy/utils/string.h @@ -0,0 +1 @@ +../../../src/legacy/utils/string.h \ No newline at end of file diff --git a/dm-sflc/bin/legacy/utils/vector.c b/dm-sflc/bin/legacy/utils/vector.c new file mode 120000 index 0000000..e9c99ee --- /dev/null +++ b/dm-sflc/bin/legacy/utils/vector.c @@ -0,0 +1 @@ +../../../src/legacy/utils/vector.c \ No newline at end of file diff --git a/dm-sflc/bin/legacy/utils/vector.h b/dm-sflc/bin/legacy/utils/vector.h new file mode 120000 index 0000000..f89b563 --- /dev/null +++ b/dm-sflc/bin/legacy/utils/vector.h @@ -0,0 +1 @@ +../../../src/legacy/utils/vector.h \ No newline at end of file diff --git a/dm-sflc/bin/legacy/utils/workqueues.c b/dm-sflc/bin/legacy/utils/workqueues.c new file mode 120000 index 0000000..2ce7811 --- /dev/null +++ b/dm-sflc/bin/legacy/utils/workqueues.c @@ -0,0 +1 @@ +../../../src/legacy/utils/workqueues.c \ No newline at end of file diff --git a/dm-sflc/bin/legacy/utils/workqueues.h b/dm-sflc/bin/legacy/utils/workqueues.h new file mode 120000 index 0000000..596b3c3 --- /dev/null +++ b/dm-sflc/bin/legacy/utils/workqueues.h @@ -0,0 +1 @@ +../../../src/legacy/utils/workqueues.h \ No newline at end of file diff --git a/dm-sflc/bin/legacy/volume/fmap.c b/dm-sflc/bin/legacy/volume/fmap.c new file mode 120000 index 0000000..829e2e9 --- /dev/null +++ b/dm-sflc/bin/legacy/volume/fmap.c @@ -0,0 +1 @@ +../../../src/legacy/volume/fmap.c \ No newline at end of file diff --git a/dm-sflc/bin/legacy/volume/io.c b/dm-sflc/bin/legacy/volume/io.c new file mode 120000 index 0000000..b7e0d76 --- /dev/null +++ b/dm-sflc/bin/legacy/volume/io.c @@ -0,0 +1 @@ +../../../src/legacy/volume/io.c \ No newline at end of file diff --git a/dm-sflc/bin/legacy/volume/read.c b/dm-sflc/bin/legacy/volume/read.c new file mode 120000 index 0000000..4d76d13 --- /dev/null +++ b/dm-sflc/bin/legacy/volume/read.c @@ -0,0 +1 @@ +../../../src/legacy/volume/read.c \ No newline at end of file diff --git a/dm-sflc/bin/legacy/volume/volume.c b/dm-sflc/bin/legacy/volume/volume.c new file mode 120000 index 0000000..a67a330 --- /dev/null +++ b/dm-sflc/bin/legacy/volume/volume.c @@ -0,0 +1 @@ +../../../src/legacy/volume/volume.c \ No newline at end of file diff --git a/dm-sflc/bin/legacy/volume/volume.h b/dm-sflc/bin/legacy/volume/volume.h new file mode 120000 index 0000000..6555e2a --- /dev/null +++ b/dm-sflc/bin/legacy/volume/volume.h @@ -0,0 +1 @@ +../../../src/legacy/volume/volume.h \ No newline at end of file diff --git a/dm-sflc/bin/legacy/volume/write.c b/dm-sflc/bin/legacy/volume/write.c new file mode 120000 index 0000000..a24d88e --- /dev/null +++ b/dm-sflc/bin/legacy/volume/write.c @@ -0,0 +1 @@ +../../../src/legacy/volume/write.c \ No newline at end of file diff --git a/dm-sflc/bin/lite/crypto.c b/dm-sflc/bin/lite/crypto.c new file mode 120000 index 0000000..1f775dc --- /dev/null +++ b/dm-sflc/bin/lite/crypto.c @@ -0,0 +1 @@ +../../src/lite/crypto.c \ No newline at end of file diff --git a/dm-sflc/bin/lite/device.c b/dm-sflc/bin/lite/device.c new file mode 120000 index 0000000..d2bcea5 --- /dev/null +++ b/dm-sflc/bin/lite/device.c @@ -0,0 +1 @@ +../../src/lite/device.c \ No newline at end of file diff --git a/dm-sflc/bin/lite/dm_io_helper.h b/dm-sflc/bin/lite/dm_io_helper.h new file mode 120000 index 0000000..ec2aa8e --- /dev/null +++ b/dm-sflc/bin/lite/dm_io_helper.h @@ -0,0 +1 @@ +../../src/lite/dm_io_helper.h \ No newline at end of file diff --git a/dm-sflc/bin/lite/posmap.c b/dm-sflc/bin/lite/posmap.c new file mode 120000 index 0000000..e60d53b --- /dev/null +++ b/dm-sflc/bin/lite/posmap.c @@ -0,0 +1 @@ +../../src/lite/posmap.c \ No newline at end of file diff --git a/dm-sflc/bin/lite/read.c b/dm-sflc/bin/lite/read.c new file mode 120000 index 0000000..db9620e --- /dev/null +++ b/dm-sflc/bin/lite/read.c @@ -0,0 +1 @@ +../../src/lite/read.c \ No newline at end of file diff --git a/dm-sflc/bin/lite/sflc_lite.c b/dm-sflc/bin/lite/sflc_lite.c new file mode 120000 index 0000000..1f2a01a --- /dev/null +++ b/dm-sflc/bin/lite/sflc_lite.c @@ -0,0 +1 @@ +../../src/lite/sflc_lite.c \ No newline at end of file diff --git a/dm-sflc/bin/lite/sflc_lite.h b/dm-sflc/bin/lite/sflc_lite.h new file mode 120000 index 0000000..23798f5 --- /dev/null +++ b/dm-sflc/bin/lite/sflc_lite.h @@ -0,0 +1 @@ +../../src/lite/sflc_lite.h \ No newline at end of file diff --git a/dm-sflc/bin/lite/sflite_constants.h b/dm-sflc/bin/lite/sflite_constants.h new file mode 120000 index 0000000..3900993 --- /dev/null +++ b/dm-sflc/bin/lite/sflite_constants.h @@ -0,0 +1 @@ +../../src/lite/sflite_constants.h \ No newline at end of file diff --git a/dm-sflc/bin/lite/sysfs.c b/dm-sflc/bin/lite/sysfs.c new file mode 120000 index 0000000..4fd0f32 --- /dev/null +++ b/dm-sflc/bin/lite/sysfs.c @@ -0,0 +1 @@ +../../src/lite/sysfs.c \ No newline at end of file diff --git a/dm-sflc/bin/lite/volume.c b/dm-sflc/bin/lite/volume.c new file mode 120000 index 0000000..2242793 --- /dev/null +++ b/dm-sflc/bin/lite/volume.c @@ -0,0 +1 @@ +../../src/lite/volume.c \ No newline at end of file diff --git a/dm-sflc/bin/lite/write.c b/dm-sflc/bin/lite/write.c new file mode 120000 index 0000000..665a955 --- /dev/null +++ b/dm-sflc/bin/lite/write.c @@ -0,0 +1 @@ +../../src/lite/write.c \ No newline at end of file diff --git a/dm-sflc/bin/sflc.c b/dm-sflc/bin/sflc.c new file mode 120000 index 0000000..d090f9d --- /dev/null +++ b/dm-sflc/bin/sflc.c @@ -0,0 +1 @@ +../src/sflc.c \ No newline at end of file diff --git a/dm-sflc/bin/sflc.h b/dm-sflc/bin/sflc.h new file mode 120000 index 0000000..0b7ccf2 --- /dev/null +++ b/dm-sflc/bin/sflc.h @@ -0,0 +1 @@ +../src/sflc.h \ No newline at end of file diff --git a/dm-sflc/bin/sflc_constants.h b/dm-sflc/bin/sflc_constants.h new file mode 120000 index 0000000..69cd0ab --- /dev/null +++ b/dm-sflc/bin/sflc_constants.h @@ -0,0 +1 @@ +../src/sflc_constants.h \ No newline at end of file diff --git a/dm-sflc/bin/sysfs.c b/dm-sflc/bin/sysfs.c new file mode 120000 index 0000000..e250188 --- /dev/null +++ b/dm-sflc/bin/sysfs.c @@ -0,0 +1 @@ +../src/sysfs.c \ No newline at end of file diff --git a/dm-sflc/crypto/rand/selftest.c b/dm-sflc/crypto/rand/selftest.c deleted file mode 100644 index f0705b9..0000000 --- a/dm-sflc/crypto/rand/selftest.c +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright The Shufflecake Project Authors (2022) - * Copyright The Shufflecake Project Contributors (2022) - * Copyright Contributors to the The Shufflecake Project. - * - * See the AUTHORS file at the top-level directory of this distribution and at - * - * - * This file is part of the program shufflecake-c, which is part of the - * Shufflecake Project. Shufflecake is a plausible deniability (hidden storage) - * layer for Linux. See . - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation, either version 2 of the License, or (at your option) - * any later version. This program is distributed in the hope that it will be - * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General - * Public License for more details. You should have received a copy of the - * GNU General Public License along with this program. - * If not, see . - */ - -/***************************************************** - * INCLUDE SECTION * - *****************************************************/ - -#include - -#include "rand.h" -#include "log/log.h" - -/***************************************************** - * CONSTANTS * - *****************************************************/ - -/***************************************************** - * PRIVATE VARIABLES * - *****************************************************/ - -/***************************************************** - * PRIVATE FUNCTIONS PROTOTYPES * - *****************************************************/ - -static void dumpHex(u8 * buf, unsigned count); - -/***************************************************** - * PUBLIC FUNCTIONS DEFINITIONS * - *****************************************************/ - -/* Selftest to see (by eye :D) if generated bytes are actually random */ -int sflc_rand_selftest(void) -{ - u8 * buf; - int err; - - buf = kmalloc(32, GFP_KERNEL); - if (!buf) { - pr_err("Could not allocate random scratchpad\n"); - return -ENOMEM; - } - - /* Get random bytes the first time */ - err = sflc_rand_getBytes(buf, 32); - if (err) { - pr_err("Got error when trying to read random bytes the first time: %d\n", err); - kfree(buf); - return err; - } - pr_debug("Here's 32 random bytes, fresh fresh!\n"); - dumpHex(buf, 32); - - /* Do it again */ - err = sflc_rand_getBytes(buf, 32); - if (err) { - pr_err("Got error when trying to read random bytes the second time: %d\n", err); - kfree(buf); - return err; - } - pr_debug("Here's another 32 random bytes, fresh fresh pure questi!\n"); - dumpHex(buf, 32); - - pr_info("All well in the crypto rand self test? (Check random bytes)\n"); - kfree(buf); - - return 0; -} - -/***************************************************** - * PRIVATE FUNCTIONS DEFINITIONS * - *****************************************************/ - -static void dumpHex(u8 * buf, unsigned count) -{ - char * hex; - - hex = kmalloc(6*count + 1, GFP_KERNEL); - if (!hex) { - pr_err("Could not allocate hex dump string\n"); - return; - } - - int i; - for (i = 0; i < count; i++) { - sprintf(hex+6*i, "0x%02X, ", buf[i]); - } - - pr_notice("---- Hex dump ----\n"); - pr_notice("%s", hex); - pr_notice("---- End of hex dump ----\n"); - - kfree(hex); - return; -} diff --git a/dm-sflc/crypto/symkey/selftest.c b/dm-sflc/crypto/symkey/selftest.c deleted file mode 100644 index 332250d..0000000 --- a/dm-sflc/crypto/symkey/selftest.c +++ /dev/null @@ -1,261 +0,0 @@ -/* - * Copyright The Shufflecake Project Authors (2022) - * Copyright The Shufflecake Project Contributors (2022) - * Copyright Contributors to the The Shufflecake Project. - * - * See the AUTHORS file at the top-level directory of this distribution and at - * - * - * This file is part of the program shufflecake-c, which is part of the - * Shufflecake Project. Shufflecake is a plausible deniability (hidden storage) - * layer for Linux. See . - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation, either version 2 of the License, or (at your option) - * any later version. This program is distributed in the hope that it will be - * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General - * Public License for more details. You should have received a copy of the - * GNU General Public License along with this program. - * If not, see . - */ - -/***************************************************** - * INCLUDE SECTION * - *****************************************************/ - -#include -#include - -#include "symkey.h" -#include "log/log.h" - -/***************************************************** - * CONSTANTS * - *****************************************************/ - -#define KEYS \ -{ \ - {0xF6, 0xD6, 0x6D, 0x6B, 0xD5, 0x2D, 0x59, 0xBB, 0x07, 0x96, 0x36, 0x58, 0x79, 0xEF, 0xF8, 0x86, \ - 0xC6, 0x6D, 0xD5, 0x1A, 0x5B, 0x6A, 0x99, 0x74, 0x4B, 0x50, 0x59, 0x0C, 0x87, 0xA2, 0x38, 0x84}, \ - \ - {0xFF, 0x7A, 0x61, 0x7C, 0xE6, 0x91, 0x48, 0xE4, 0xF1, 0x72, 0x6E, 0x2F, 0x43, 0x58, 0x1D, 0xE2, \ - 0xAA, 0x62, 0xD9, 0xF8, 0x05, 0x53, 0x2E, 0xDF, 0xF1, 0xEE, 0xD6, 0x87, 0xFB, 0x54, 0x15, 0x3D}, \ -} - -#define IVS \ -{ \ - {0x00, 0xFA, 0xAC, 0x24, 0xC1, 0x58, 0x5E, 0xF1, 0x5A, 0x43, 0xD8, 0x75, 0x00, 0x00, 0x00, 0x01}, \ - \ - {0x00, 0x1C, 0xC5, 0xB7, 0x51, 0xA5, 0x1D, 0x70, 0xA1, 0xC1, 0x11, 0x48, 0x00, 0x00, 0x00, 0x01}, \ -} - -#define PLAINTEXTS \ -{ \ - {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, \ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F}, \ - \ - {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, \ - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F}, \ -} - -#define CIPHERTEXTS \ -{ \ - {0xF0, 0x5E, 0x23, 0x1B, 0x38, 0x94, 0x61, 0x2C, 0x49, 0xEE, 0x00, 0x0B, 0x80, 0x4E, 0xB2, 0xA9, \ - 0xB8, 0x30, 0x6B, 0x50, 0x8F, 0x83, 0x9D, 0x6A, 0x55, 0x30, 0x83, 0x1D, 0x93, 0x44, 0xAF, 0x1C}, \ - \ - {0xEB, 0x6C, 0x52, 0x82, 0x1D, 0x0B, 0xBB, 0xF7, 0xCE, 0x75, 0x94, 0x46, 0x2A, 0xCA, 0x4F, 0xAA, \ - 0xB4, 0x07, 0xDF, 0x86, 0x65, 0x69, 0xFD, 0x07, 0xF4, 0x8C, 0xC0, 0xB5, 0x83, 0xD6, 0x07, 0x1F}, \ -} - -/***************************************************** - * PRIVATE VARIABLES * - *****************************************************/ - -/***************************************************** - * PRIVATE FUNCTIONS PROTOTYPES * - *****************************************************/ - -/* Test encryption or decryption with known test vectors */ -static int testEncdec(bool encrypt); -/* Test that encryption and decryption invert each other */ -static int testRand(void); -static void dumpHex(u8 * buf, unsigned count); - -/***************************************************** - * PUBLIC FUNCTIONS DEFINITIONS * - *****************************************************/ - -/* Self test using known test vectors and random inputs */ -int sflc_sk_selftest(void) -{ - int err; - - /* Test encryption */ - err = testEncdec(true); - if (err) { - pr_err("Error in encryption test: %d\n", err); - return err; - } - - /* Test decryption */ - err = testEncdec(false); - if (err) { - pr_err("Error in decryption test: %d\n", err); - return err; - } - - /* Test with random inputs */ - err = testRand(); - if (err) { - pr_err("Error in random test: %d\n", err); - return err; - } - - pr_info("All good in crypto symkey selftest\n"); - return 0; -} - -/***************************************************** - * PRIVATE FUNCTIONS DEFINITIONS * - *****************************************************/ - -/* Test encryption or decryption with known test vectors */ -static int testEncdec(bool encrypt) -{ - sflc_sk_Context * ctx[2]; - u8 scratchpad[32]; - u8 key[2][32] = KEYS; - u8 iv[2][16] = IVS; - u8 pt[2][32] = PLAINTEXTS; - u8 ct[2][32] = CIPHERTEXTS; - int err; - - int i; - for (i = 0; i < 2; i++) { - memset(scratchpad, 0xa7, 32); - - ctx[i] = sflc_sk_createContext(key[i]); - if (IS_ERR(ctx)) { - err = PTR_ERR(ctx[i]); - pr_err("Could not create sk context; error %d\n", err); - return err; - } - - if (encrypt) { - err = sflc_sk_encrypt(ctx[i], pt[i], scratchpad, 32, iv[i]); - if (err) { - pr_err("Failure during encryption %d; error %d\n", i, err); - sflc_sk_destroyContext(ctx[i]); - return err; - } - if(memcmp(scratchpad, ct[i], 32) != 0) { - pr_err("Mismatch for encryption %d\n", i); - dumpHex(scratchpad, 16); - sflc_sk_destroyContext(ctx[i]); - return -EINVAL; - } - } - else /* decrypt*/ { - err = sflc_sk_decrypt(ctx[i], ct[i], scratchpad, 32, iv[i]); - if (err) { - pr_err("Failure during decryption %d; error %d\n", i, err); - sflc_sk_destroyContext(ctx[i]); - return err; - } - if (memcmp(scratchpad, pt[i], 32) != 0) { - pr_err("Mismatch for decryption %d\n", i); - dumpHex(scratchpad, 32); - sflc_sk_destroyContext(ctx[i]); - return -EINVAL; - } - } - - sflc_sk_destroyContext(ctx[i]); - } - - return 0; -} - -/* Test that encryption and decryption invert each other */ -static int testRand(void) -{ - u8 pt[48]; - u8 scratchpad[48]; - u8 key[32]; - u8 iv[16]; - sflc_sk_Context * ctx; - int err; - - get_random_bytes(key, 32); - ctx = sflc_sk_createContext(key); - if (IS_ERR(ctx)) { - err = PTR_ERR(ctx); - pr_err("Could not create context; error %d\n", err); - return err; - } - memset(iv, 0, 16); - - int i; - for (i = 0; i < 200; i++) { - get_random_bytes(pt, 48); - err = sflc_sk_encrypt(ctx, pt, scratchpad, 48, iv); - if (err) { - pr_err("Could not encrypt; error %d\n", err); - sflc_sk_destroyContext(ctx); - return err; - } - if (memcmp(pt, scratchpad, 48) == 0) { - pr_err("Random iteration %d; pt=scratchpad\n", i); - sflc_sk_destroyContext(ctx); - return -EINVAL; - } - - /* Reset IV */ - iv[15] = 0; - - err = sflc_sk_decrypt(ctx, scratchpad, scratchpad, 48, iv); - if (err) { - pr_err("Could not decrypt; error %d\n", err); - sflc_sk_destroyContext(ctx); - return err; - } - if (memcmp(pt, scratchpad, 48) != 0) { - pr_err("Random iteration %d; mismatch. Dumping plaintext and scratchpad\n", i); - dumpHex(pt, 48); - dumpHex(scratchpad, 48); - sflc_sk_destroyContext(ctx); - return -EINVAL; - } - - /* Reset IV */ - iv[15] = 0; - } - - sflc_sk_destroyContext(ctx); - return 0; -} - -static void dumpHex(u8 * buf, unsigned count) -{ - char * hex; - - hex = kmalloc(6*count + 1, GFP_KERNEL); - if (!hex) { - pr_err("Could not allocate hex dump string\n"); - return; - } - - int i; - for (i = 0; i < count; i++) { - sprintf(hex+6*i, "0x%02X, ", buf[i]); - } - - pr_notice("---- Hex dump ----\n"); - pr_notice("%s", hex); - pr_notice("---- End of hex dump ----\n"); - - kfree(hex); - return; -} diff --git a/dm-sflc/device/device.c b/dm-sflc/device/device.c deleted file mode 100644 index a03f3ea..0000000 --- a/dm-sflc/device/device.c +++ /dev/null @@ -1,376 +0,0 @@ -/* - * Copyright The Shufflecake Project Authors (2022) - * Copyright The Shufflecake Project Contributors (2022) - * Copyright Contributors to the The Shufflecake Project. - * - * See the AUTHORS file at the top-level directory of this distribution and at - * - * - * This file is part of the program shufflecake-c, which is part of the - * Shufflecake Project. Shufflecake is a plausible deniability (hidden storage) - * layer for Linux. See . - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation, either version 2 of the License, or (at your option) - * any later version. This program is distributed in the hope that it will be - * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General - * Public License for more details. You should have received a copy of the - * GNU General Public License along with this program. - * If not, see . - */ - -/* - * This file only implements the device-related device management functions. - */ - -/***************************************************** - * INCLUDE SECTION * - *****************************************************/ - -#include "device.h" -#include "sysfs/sysfs.h" -#include "utils/vector.h" -#include "log/log.h" - -#include -#include - -/***************************************************** - * CONSTANTS * - *****************************************************/ - -/***************************************************** - * PUBLIC VARIABLES DEFINITIONS * - *****************************************************/ - -/* The next available device ID */ -size_t sflc_dev_nextId; - -LIST_HEAD(sflc_dev_list); - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(6,4,0) - DEFINE_SEMAPHORE(sflc_dev_mutex, 1); -#else - DEFINE_SEMAPHORE(sflc_dev_mutex); -#endif - - -/***************************************************** - * PRIVATE VARIABLES * - *****************************************************/ - -/* Array tracking occupation of device IDs */ -static bool *sflc_dev_occupiedIds; - - -/***************************************************** - * PRIVATE FUNCTIONS PROTOTYPES * - *****************************************************/ - -/* Acquire device ID, returns false if not possible */ -static bool sflc_dev_acquireId(size_t id); - -/* Release device ID */ -static void sflc_dev_releaseId(size_t id); - -/* Initialises and pre-shuffles the PSI array */ -static int sflc_dev_initAndShufflePsiArray(u32 *psi_array, u32 len); - - -/***************************************************** - * PUBLIC FUNCTIONS DEFINITIONS * - *****************************************************/ - -/* Inits global variables */ -int sflc_dev_init(void) -{ - /* Allocate occupation array */ - sflc_dev_occupiedIds = kzalloc(SFLC_DEV_MAX_DEVICES_TOT, GFP_KERNEL); - if (!sflc_dev_occupiedIds) { - pr_err("Could not allocate array to track deviceID occupation"); - return -ENOMEM; - } - - /* First available ID is 0 */ - sflc_dev_nextId = 0; - - return 0; -} - -/* Tears down global variables */ -void sflc_dev_exit(void) -{ - kfree(sflc_dev_occupiedIds); -} - -/* Creates Device and adds it to the list. Returns an ERR_PTR() if unsuccessful. */ -sflc_Device * sflc_dev_create(struct dm_target * ti, char * real_dev_path, u32 tot_slices) -{ - sflc_Device * dev; - int err; - int i; - - pr_debug("Called to create sflc_Device on %s\n", real_dev_path); - - /* Allocate device */ - dev = kzalloc(sizeof(sflc_Device), GFP_KERNEL); - if (!dev) { - pr_err("Could not allocate %lu bytes for sflc_Device\n", sizeof(sflc_Device)); - err = -ENOMEM; - goto err_alloc_dev; - } - - /* Init list node here, so it's always safe to list_del() */ - INIT_LIST_HEAD(&dev->list_node); - - /* Set device ID */ - dev->dev_id = sflc_dev_nextId; - if (!sflc_dev_acquireId(sflc_dev_nextId)) { - pr_err("Could not create Device: max number of open devices reached"); - err = -EINVAL; - goto err_dev_id; - } - - /* Set backing real device */ - err = dm_get_device(ti, real_dev_path, dm_table_get_mode(ti->table), &dev->bdev); - if (err) { - pr_err("Could not dm_get_device: error %d\n", err); - goto err_dm_get_dev; - } - /* And its path */ - dev->bdev_path = kmalloc(strlen(real_dev_path) + 1, GFP_KERNEL); - if (!dev->bdev_path) { - pr_err("Could not allocate %lu bytes for dev->real_dev_path\n", strlen(real_dev_path) + 1); - err = -ENOMEM; - goto err_alloc_real_dev_path; - } - strcpy(dev->bdev_path, real_dev_path); - - /* Init volumes */ - for (i = 0; i < SFLC_DEV_MAX_VOLUMES; ++i) { - dev->vol[i] = NULL; - } - dev->vol_cnt = 0; - - /* Set slices info */ - dev->tot_slices = tot_slices; - dev->free_slices = tot_slices; - /* Compute header info (like in userland tool) */ - u32 nr_pmbs_per_vol = DIV_ROUND_UP(tot_slices, SFLC_VOL_HEADER_MAPPINGS_PER_BLOCK); - dev->vol_header_nr_iv_blocks = DIV_ROUND_UP(nr_pmbs_per_vol, SFLC_VOL_LOG_SLICE_SIZE); - dev->vol_header_size = 1 + nr_pmbs_per_vol + dev->vol_header_nr_iv_blocks; - dev->dev_header_size = 1 + (SFLC_DEV_MAX_VOLUMES * dev->vol_header_size); - - /* Init slices lock */ - mutex_init(&dev->slices_lock); - /* Allocate reverse slice map */ - dev->rmap = vmalloc(dev->tot_slices * sizeof(u8)); - if (!dev->rmap) { - pr_err("Could not allocate reverse slice map\n"); - err = -ENOMEM; - goto err_alloc_rmap; - } - /* Initialise it */ - memset(dev->rmap, SFLC_DEV_RMAP_INVALID_VOL, dev->tot_slices * sizeof(u8)); - /* Allocate PSI array */ - dev->prmslices = vmalloc(dev->tot_slices * sizeof(u32)); - if (!dev->prmslices) { - pr_err("Could not allocate PSI array\n"); - err = -ENOMEM; - goto err_alloc_psi_array; - } - /* Initialise it and pre-shuffle it */ - err = sflc_dev_initAndShufflePsiArray(dev->prmslices, dev->tot_slices); - if (err) { - pr_err("Could not init-and-shuffle PSI array: error %d", err); - goto err_initshuffle_psi_array; - } - /* Init related counter */ - dev->prmslices_octr = 0; - - /* Init IV cache lock */ - mutex_init(&dev->iv_cache_lock); - /* Init IV cache waitqueue */ - init_waitqueue_head(&dev->iv_cache_waitqueue); - /* Allocate IV cache */ - dev->iv_cache = vzalloc(dev->tot_slices * sizeof(sflc_dev_IvCacheEntry *)); - if (!dev->iv_cache) { - pr_err("Could not allocate IV cache\n"); - err = -ENOMEM; - goto err_alloc_iv_cache; - } - /* Set it empty */ - dev->iv_cache_nr_entries = 0; - /* Init list head */ - INIT_LIST_HEAD(&dev->iv_lru_list); - - /* Create kobject */ - dev->kobj = sflc_sysfs_devCreateAndAdd(dev); - if (IS_ERR(dev->kobj)) { - err = PTR_ERR(dev->kobj); - pr_err("Could not create kobject; error %d\n", err); - goto err_sysfs; - } - - /* Create dm_io_client */ - dev->dmio_client = dm_io_client_create(); - if (IS_ERR(dev->dmio_client)) { - err = PTR_ERR(dev->dmio_client); - pr_err("Could not create dm_io_client; error %d\n", err); - goto err_dmio; - } - - /* Add to device list */ - list_add_tail(&dev->list_node, &sflc_dev_list); - - return dev; - - -err_dmio: - sflc_sysfs_putDev(dev->kobj); -err_sysfs: - vfree(dev->iv_cache); -err_alloc_iv_cache: -err_initshuffle_psi_array: - vfree(dev->prmslices); -err_alloc_psi_array: - vfree(dev->rmap); -err_alloc_rmap: - kfree(dev->bdev_path); -err_alloc_real_dev_path: - dm_put_device(ti, dev->bdev); -err_dm_get_dev: - sflc_dev_releaseId(dev->dev_id); -err_dev_id: - kfree(dev); -err_alloc_dev: - return ERR_PTR(err); -} - -/* Returns NULL if not found */ -sflc_Device * sflc_dev_lookupByPath(char * real_dev_path) -{ - sflc_Device * dev; - - /* Sweep the list of devices */ - list_for_each_entry(dev, &sflc_dev_list, list_node) { - if (strcmp(real_dev_path, dev->bdev_path) == 0) { - return dev; - } - } - - return NULL; -} - -/* Returns false if still busy (not all volumes have been removed). Frees the Device. */ -bool sflc_dev_destroy(struct dm_target * ti, sflc_Device * dev) -{ - /* Check if we actually have to put this device */ - if (!dev) { - return false; - } - if (dev->vol_cnt > 0) { - pr_warn("Called while still holding %d volumes\n", dev->vol_cnt); - return false; - } - - /* Flush all IVs */ - sflc_dev_flushIvs(dev); - - /* List */ - list_del(&dev->list_node); - - /* dm_io */ - dm_io_client_destroy(dev->dmio_client); - - /* Sysfs */ - sflc_sysfs_putDev(dev->kobj); - - /* IV cache */ - vfree(dev->iv_cache); - - /* PSI array */ - vfree(dev->prmslices); - - /* Reverse slice map */ - vfree(dev->rmap); - - /* Backing device */ - dm_put_device(ti, dev->bdev); - kfree(dev->bdev_path); - - /* Release device ID */ - sflc_dev_releaseId(dev->dev_id); - - /* Free the device itself */ - kfree(dev); - - return true; -} - - -/***************************************************** - * PRIVATE FUNCTIONS DEFINITIONS * - *****************************************************/ - -/* Acquire device ID, returns false if not possible */ -static bool sflc_dev_acquireId(size_t id) -{ - /* Sanity check */ - if (id >= SFLC_DEV_MAX_DEVICES_TOT) { - return false; - } - /* Check occupation */ - if (sflc_dev_occupiedIds[id]) { - return false; - } - - /* Mark as occupied */ - sflc_dev_occupiedIds[id] = true; - - /* Update the nextId if necessary */ - if (id == sflc_dev_nextId) { - /* Jump to the next unoccupied ID */ - for (; id < SFLC_DEV_MAX_DEVICES_TOT && sflc_dev_occupiedIds[id]; id++); - sflc_dev_nextId = id; - } - - return true; -} - -/* Release volume ID */ -static void sflc_dev_releaseId(size_t id) -{ - /* Sanity check */ - if (id >= SFLC_DEV_MAX_DEVICES_TOT) { - return; - } - - /* Mark as unoccupied */ - sflc_dev_occupiedIds[id] = false; - - /* Update the nextId if necessary */ - if (id < sflc_dev_nextId) { - sflc_dev_nextId = id; - } - - return; -} - - -/* Initialises and pre-shuffles the PSI array */ -static int sflc_dev_initAndShufflePsiArray(u32 *psi_array, u32 len) -{ - u32 i; - - /* Init to the identity map */ - for (i = 0; i < len; i++) { - psi_array[i] = i; - } - - /* Permute */ - return sflc_vec_u32shuffle(psi_array, len); -} - diff --git a/dm-sflc/module.c b/dm-sflc/module.c deleted file mode 100644 index 230e60c..0000000 --- a/dm-sflc/module.c +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright The Shufflecake Project Authors (2022) - * Copyright The Shufflecake Project Contributors (2022) - * Copyright Contributors to the The Shufflecake Project. - * - * See the AUTHORS file at the top-level directory of this distribution and at - * - * - * This file is part of the program shufflecake-c, which is part of the - * Shufflecake Project. Shufflecake is a plausible deniability (hidden storage) - * layer for Linux. See . - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation, either version 2 of the License, or (at your option) - * any later version. This program is distributed in the hope that it will be - * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General - * Public License for more details. You should have received a copy of the - * GNU General Public License along with this program. - * If not, see . - */ - -/***************************************************** - * INCLUDE SECTION * - *****************************************************/ - -#include -#include - -#include "sysfs/sysfs.h" -#include "target/target.h" -#include "crypto/symkey/symkey.h" -#include "crypto/rand/rand.h" -#include "utils/pools.h" -#include "utils/workqueues.h" -#include "log/log.h" - -/***************************************************** - * MODULE FUNCTION PROTOTYPES * - *****************************************************/ - -static int sflc_init(void); -static void sflc_exit(void); - -/***************************************************** - * MODULE FUNCTIONS DEFINITIONS * - *****************************************************/ - -/* Module entry point, called just once, at module-load time */ -static int sflc_init(void) -{ - int ret; - - ret = sflc_dev_init(); - if (ret) { - pr_err("Could not init device module; error %d\n", ret); - goto err_dev_init; - } - - ret = sflc_rand_init(); - if (ret) { - pr_err("Could not init rand; error %d\n", ret); - goto err_rand_init; - } - - /* Run crypto symkey self test */ - ret = sflc_sk_selftest(); - if (ret) { - pr_err("Error in crypto symkey self test: %d\n", ret); - goto err_sk; - } - /* Run crypto rand self test */ - ret = sflc_rand_selftest(); - if (ret) { - pr_err("Error in crypto rand self test: %d\n", ret); - goto err_rand_selftest; - } - - /* Create the first sysfs entries */ - ret = sflc_sysfs_init(); - if (ret) { - pr_err("Could not init sysfs; error %d\n", ret); - goto err_sysfs; - } - - /* Init the memory pools */ - ret = sflc_pools_init(); - if (ret) { - pr_err("Could not init memory pools; error %d\n", ret); - goto err_pools; - } - - /* Init the workqueues */ - ret = sflc_queues_init(); - if (ret) { - pr_err("Could not init workqueues; error %d\n", ret); - goto err_queues; - } - - /* Register the DM callbacks */ - ret = dm_register_target(&sflc_target); - if (ret < 0) { - pr_err("dm_register failed: %d", ret); - goto err_dm; - } - - pr_info("Shufflecake loaded"); - return 0; - - -err_dm: - sflc_queues_exit(); -err_queues: - sflc_pools_exit(); -err_pools: - sflc_sysfs_exit(); -err_sysfs: -err_rand_selftest: -err_sk: - sflc_rand_exit(); -err_rand_init: - sflc_dev_exit(); -err_dev_init: - return ret; -} - -/* Module exit point, called just once, at module-unload time */ -static void sflc_exit(void) -{ - dm_unregister_target(&sflc_target); - sflc_queues_exit(); - sflc_pools_exit(); - sflc_sysfs_exit(); - sflc_rand_exit(); - sflc_dev_exit(); - - pr_info("Shufflecake unloaded"); - return; -} - -/* Declare them as such to the kernel */ -module_init(sflc_init); -module_exit(sflc_exit); - -/***************************************************** - * MODULE INFO * - *****************************************************/ - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Toninov"); diff --git a/dm-sflc/src/dev_vol.c b/dm-sflc/src/dev_vol.c new file mode 100644 index 0000000..6c454b9 --- /dev/null +++ b/dm-sflc/src/dev_vol.c @@ -0,0 +1,209 @@ +/* + * Copyright The Shufflecake Project Authors (2022) + * Copyright The Shufflecake Project Contributors (2022) + * Copyright Contributors to the The Shufflecake Project. + * + * See the AUTHORS file at the top-level directory of this distribution and at + * + * + * This file is part of the program shufflecake-c, which is part of the + * Shufflecake Project. Shufflecake is a plausible deniability (hidden storage) + * layer for Linux. See . + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 2 of the License, or (at your option) + * any later version. This program is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. You should have received a copy of the + * GNU General Public License along with this program. + * If not, see . + */ + +#include + +#include "sflc.h" +#include "legacy/sflc_legacy.h" + + +/* Create a sflc_device containing the appropriate mode-specific struct */ +struct sflc_device *sflc_dev_create(struct dm_target *ti, int argc, char **argv) +{ + struct sflc_device *sdev; + u32 dev_id; + dev_t devt; + int mode; + int err; + + sdev = kzalloc(sizeof(*sdev), GFP_KERNEL); + if (!sdev) { + DMERR("Could not allocate device"); + return ERR_PTR(-ENOMEM); + } + + /* Parse arguments */ + if (sscanf(argv[0], "%d", &mode) != 1) { + err = -EINVAL; + goto bad_parse; + } + sscanf(argv[1], "%u", &dev_id); + err = lookup_bdev(argv[2], &devt); + if (err) { + DMERR("Could not look up block device"); + goto bad_parse; + } + + /* Assign fields */ + sdev->dev_id = dev_id; + sdev->nr_volumes = 0; + sdev->mode = mode; + format_dev_t(sdev->name, devt); + + /* Register with sysfs */ + err = sflc_sysfs_register_device(sdev); + if (err) + goto bad_sysfs; + + /* Instantiate inner device. Sysfs has to be inited by now */ + switch (mode) + { + case SFLC_MODE_LEGACY: + sdev->sflegc_dev = sflegc_dev_create(ti, argc, argv, &sdev->kobj); + if (IS_ERR(sdev->sflegc_dev)) { + err = PTR_ERR(sdev->sflegc_dev); + goto bad_inner; + } + break; + case SFLC_MODE_LITE: + sdev->sflite_dev = sflite_dev_create(ti, argc, argv, &sdev->kobj); + if (IS_ERR(sdev->sflite_dev)) { + err = PTR_ERR(sdev->sflite_dev); + goto bad_inner; + } + break; + default: + DMERR("Invalid Shufflecake mode %d", mode); + err = -EINVAL; + goto bad_mode; + } + + return sdev; + + +bad_mode: +bad_inner: + sflc_sysfs_unregister_device(sdev); +bad_sysfs: +bad_parse: + kfree(sdev); + return ERR_PTR(err); +} + + +void sflc_dev_destroy(struct sflc_device *sdev) +{ + switch (sdev->mode) + { + case SFLC_MODE_LEGACY: + sflegc_dev_destroy(sdev->sflegc_dev); + break; + case SFLC_MODE_LITE: + sflite_dev_destroy(sdev->sflite_dev); + break; + default: + DMCRIT("Destroying device with invalid Shufflecake mode %d", sdev->mode); + return; + } + + sflc_sysfs_unregister_device(sdev); + kfree(sdev); +} + +/* Create a sflc_volume containing the appropriate mode-specific struct */ +struct sflc_volume *sflc_vol_create(struct sflc_device *sdev, struct dm_target *ti, + int argc, char **argv) +{ + struct sflc_volume *svol; + u32 vol_idx; + int mode; + int err; + + svol = kzalloc(sizeof(*svol), GFP_KERNEL); + if (!svol) { + DMERR("Could not allocate volume"); + return ERR_PTR(-ENOMEM); + } + + /* Parse arguments */ + if (sscanf(argv[0], "%d", &mode) != 1) { + err = -EINVAL; + goto bad_parse; + } + sscanf(argv[3], "%u", &vol_idx); + + /* Assign fields */ + svol->mode = mode; + sprintf(svol->name, "sflc_%u_%u", sdev->dev_id, vol_idx); + svol->sdev = sdev; + + /* Register with sysfs */ + err = sflc_sysfs_register_volume(svol); + if (err) + goto bad_sysfs; + + /* Instantiate inner volume. Sysfs has to be inited by now */ + switch (mode) + { + case SFLC_MODE_LEGACY: + svol->sflegc_vol = sflegc_vol_create(ti, sdev->sflegc_dev, argc, argv, &svol->kobj); + if (IS_ERR(svol->sflegc_vol)) { + err = PTR_ERR(svol->sflegc_vol); + goto bad_inner; + } + svol->tt = &sflegc_target_type; + break; + case SFLC_MODE_LITE: + svol->sflite_vol = sflite_vol_create(ti, sdev->sflite_dev, argc, argv, &svol->kobj); + if (IS_ERR(svol->sflite_vol)) { + err = PTR_ERR(svol->sflite_vol); + goto bad_inner; + } + svol->tt = &sflite_target_type; + break; + default: + DMERR("Invalid Shufflecake mode %d", mode); + err = -EINVAL; + goto bad_mode; + } + + return svol; + + +bad_mode: +bad_inner: + sflc_sysfs_unregister_volume(svol); +bad_sysfs: +bad_parse: + kfree(svol); + return ERR_PTR(err); +} + +void sflc_vol_destroy(struct sflc_volume *svol) +{ + switch (svol->mode) + { + case SFLC_MODE_LEGACY: + sflegc_vol_destroy(svol->sflegc_vol); + break; + case SFLC_MODE_LITE: + sflite_vol_destroy(svol->sflite_vol); + break; + default: + DMCRIT("Destroying volume with invalid Shufflecake mode %d", svol->mode); + return; + } + + sflc_sysfs_unregister_volume(svol); + kfree(svol); +} diff --git a/dm-sflc/crypto/rand/rand.c b/dm-sflc/src/legacy/crypto/rand/rand.c similarity index 77% rename from dm-sflc/crypto/rand/rand.c rename to dm-sflc/src/legacy/crypto/rand/rand.c index 150a909..7ad6f9b 100644 --- a/dm-sflc/crypto/rand/rand.c +++ b/dm-sflc/src/legacy/crypto/rand/rand.c @@ -28,55 +28,55 @@ #include #include -#include "rand.h" -#include "log/log.h" +#include "legacy/crypto/rand/rand.h" +#include "legacy/log/log.h" /***************************************************** * CONSTANTS * *****************************************************/ -#define SFLC_RAND_RNG_NAME "drbg_nopr_sha256" +#define SFLEGC_RAND_RNG_NAME "drbg_nopr_sha256" /***************************************************** * PRIVATE VARIABLES * *****************************************************/ -static struct mutex sflc_rand_tfm_lock; -static struct crypto_rng * sflc_rand_tfm = NULL; +static struct mutex sflegc_rand_tfm_lock; +static struct crypto_rng * sflegc_rand_tfm = NULL; /***************************************************** * PRIVATE FUNCTIONS PROTOTYPES * *****************************************************/ /* Flexible to accommodate for both required and non-required reseeding */ -static int sflc_rand_reseed(void); +static int sflegc_rand_reseed(void); /***************************************************** * PUBLIC FUNCTIONS DEFINITIONS * *****************************************************/ /* Init the submodule */ -int sflc_rand_init(void) +int sflegc_rand_init(void) { int err; /* Init the lock governing the SFLC RNG */ - mutex_init(&sflc_rand_tfm_lock); + mutex_init(&sflegc_rand_tfm_lock); /* Allocate module-wide RNG */ - sflc_rand_tfm = crypto_alloc_rng(SFLC_RAND_RNG_NAME, CRYPTO_ALG_TYPE_RNG, 0); - if (IS_ERR(sflc_rand_tfm)) { - err = PTR_ERR(sflc_rand_tfm); - sflc_rand_tfm = NULL; - pr_err("Could not allocate RNG %s; error %d\n", SFLC_RAND_RNG_NAME, err); + sflegc_rand_tfm = crypto_alloc_rng(SFLEGC_RAND_RNG_NAME, CRYPTO_ALG_TYPE_RNG, 0); + if (IS_ERR(sflegc_rand_tfm)) { + err = PTR_ERR(sflegc_rand_tfm); + sflegc_rand_tfm = NULL; + pr_err("Could not allocate RNG %s; error %d\n", SFLEGC_RAND_RNG_NAME, err); return err; } /* The new RNG comes not seeded, right? */ - err = sflc_rand_reseed(); + err = sflegc_rand_reseed(); if (err) { pr_err("Could not seed the RNG; error %d\n", err); - sflc_rand_exit(); + sflegc_rand_exit(); return err; } @@ -84,26 +84,26 @@ int sflc_rand_init(void) } /* Get random bytes. Might sleep for re-seeding (not implemented yet), or for contention (mutex). */ -int sflc_rand_getBytes(u8 * buf, unsigned count) +int sflegc_rand_getBytes(u8 * buf, unsigned count) { int ret; /* Acquire lock */ - if (mutex_lock_interruptible(&sflc_rand_tfm_lock)) { + if (mutex_lock_interruptible(&sflegc_rand_tfm_lock)) { pr_err("Got error while waiting for SFLC RNG\n"); return -EINTR; } - ret = crypto_rng_get_bytes(sflc_rand_tfm, buf, count); + ret = crypto_rng_get_bytes(sflegc_rand_tfm, buf, count); /* End of critical region */ - mutex_unlock(&sflc_rand_tfm_lock); + mutex_unlock(&sflegc_rand_tfm_lock); return ret; } /* Get a random s32 from 0 (inclusive) to max (exclusive). Returns < 0 if error. */ -s32 sflc_rand_uniform(s32 max) +s32 sflegc_rand_uniform(s32 max) { s32 rand; s32 thresh; @@ -120,7 +120,7 @@ s32 sflc_rand_uniform(s32 max) thresh = S32_MAX - (S32_MAX % max); do { /* Sample a random signed integer, then make it positive */ - int err = sflc_rand_getBytes((void *) &rand, sizeof(rand)); + int err = sflegc_rand_getBytes((void *) &rand, sizeof(rand)); /* Can't make it positive if it's all 1's */ if (rand == S32_MIN) { continue; @@ -140,11 +140,11 @@ s32 sflc_rand_uniform(s32 max) } /* Tear down the submodule */ -void sflc_rand_exit(void) +void sflegc_rand_exit(void) { - if (sflc_rand_tfm) { - crypto_free_rng(sflc_rand_tfm); - sflc_rand_tfm = NULL; + if (sflegc_rand_tfm) { + crypto_free_rng(sflegc_rand_tfm); + sflegc_rand_tfm = NULL; } return; @@ -155,12 +155,12 @@ void sflc_rand_exit(void) *****************************************************/ /* Flexible to accommodate for both required and non-required reseeding */ -static int sflc_rand_reseed(void) +static int sflegc_rand_reseed(void) { int err; /* Reseed the RNG */ - err = crypto_rng_reset(sflc_rand_tfm, NULL, crypto_rng_seedsize(sflc_rand_tfm)); + err = crypto_rng_reset(sflegc_rand_tfm, NULL, crypto_rng_seedsize(sflegc_rand_tfm)); if (err) { pr_err("Could not feed seed to the RNG; error %d\n", err); return err; diff --git a/dm-sflc/crypto/rand/rand.h b/dm-sflc/src/legacy/crypto/rand/rand.h similarity index 85% rename from dm-sflc/crypto/rand/rand.h rename to dm-sflc/src/legacy/crypto/rand/rand.h index 4d5f8a7..a661e9b 100644 --- a/dm-sflc/crypto/rand/rand.h +++ b/dm-sflc/src/legacy/crypto/rand/rand.h @@ -27,8 +27,8 @@ * no need to make it more fine grained. */ -#ifndef _SFLC_CRYPTO_RAND_RAND_H_ -#define _SFLC_CRYPTO_RAND_RAND_H_ +#ifndef _SFLEGC_CRYPTO_RAND_RAND_H_ +#define _SFLEGC_CRYPTO_RAND_RAND_H_ /***************************************************** * INCLUDE SECTION * @@ -40,20 +40,17 @@ * PUBLIC FUNCTIONS PROTOTYPES * *****************************************************/ -/* Selftest to see (by eye :D) if generated bytes are actually random */ -int sflc_rand_selftest(void); - /* Init the submodule */ -int sflc_rand_init(void); +int sflegc_rand_init(void); /* Get random bytes. Might sleep for re-seeding (not implemented yet), or for contention (mutex). */ -int sflc_rand_getBytes(u8 * buf, unsigned count); +int sflegc_rand_getBytes(u8 * buf, unsigned count); /* Get a random s32 from 0 (inclusive) to max (exclusive). Returns < 0 if error. */ -s32 sflc_rand_uniform(s32 max); +s32 sflegc_rand_uniform(s32 max); /* Tear down the submodule */ -void sflc_rand_exit(void); +void sflegc_rand_exit(void); -#endif /* _SFLC_CRYPTO_RAND_RAND_H_ */ +#endif /* _SFLEGC_CRYPTO_RAND_RAND_H_ */ diff --git a/dm-sflc/crypto/symkey/skreq_pool.c b/dm-sflc/src/legacy/crypto/symkey/skreq_pool.c similarity index 82% rename from dm-sflc/crypto/symkey/skreq_pool.c rename to dm-sflc/src/legacy/crypto/symkey/skreq_pool.c index d77c9e1..fd27875 100644 --- a/dm-sflc/crypto/symkey/skreq_pool.c +++ b/dm-sflc/src/legacy/crypto/symkey/skreq_pool.c @@ -25,8 +25,8 @@ * INCLUDE SECTION * *****************************************************/ -#include "skreq_pool.h" -#include "log/log.h" +#include "legacy/crypto/symkey/skreq_pool.h" +#include "legacy/log/log.h" /***************************************************** * CONSTANTS * @@ -37,17 +37,17 @@ *****************************************************/ /* A mempool_alloc_t using skcipher_request_alloc as backend */ -static void * sflc_sk_allocRequest(gfp_t gfp_mask, void * pool_data); +static void * sflegc_sk_allocRequest(gfp_t gfp_mask, void * pool_data); /* A mempool_free_t using skcipher_request_free as backend */ -static void sflc_sk_freeRequest(void * element, void * pool_data); +static void sflegc_sk_freeRequest(void * element, void * pool_data); /***************************************************** * PUBLIC FUNCTIONS DEFINITIONS * *****************************************************/ -mempool_t * sflc_sk_createReqPool(int min_nr, sflc_sk_Context * ctx) +mempool_t * sflegc_sk_createReqPool(int min_nr, sflegc_sk_Context * ctx) { - return mempool_create(min_nr, sflc_sk_allocRequest, sflc_sk_freeRequest, (void *) ctx); + return mempool_create(min_nr, sflegc_sk_allocRequest, sflegc_sk_freeRequest, (void *) ctx); } /***************************************************** @@ -55,9 +55,9 @@ mempool_t * sflc_sk_createReqPool(int min_nr, sflc_sk_Context * ctx) *****************************************************/ /* A mempool_alloc_t using skcipher_request_alloc as backend */ -static void * sflc_sk_allocRequest(gfp_t gfp_mask, void * pool_data) +static void * sflegc_sk_allocRequest(gfp_t gfp_mask, void * pool_data) { - sflc_sk_Context * ctx = pool_data; + sflegc_sk_Context * ctx = pool_data; struct skcipher_request * skreq; skreq = skcipher_request_alloc(ctx->tfm, gfp_mask); @@ -70,7 +70,7 @@ static void * sflc_sk_allocRequest(gfp_t gfp_mask, void * pool_data) } /* A mempool_free_t using skcipher_request_free as backend */ -static void sflc_sk_freeRequest(void * element, void * pool_data) +static void sflegc_sk_freeRequest(void * element, void * pool_data) { struct skcipher_request * skreq = element; diff --git a/dm-sflc/crypto/symkey/skreq_pool.h b/dm-sflc/src/legacy/crypto/symkey/skreq_pool.h similarity index 88% rename from dm-sflc/crypto/symkey/skreq_pool.h rename to dm-sflc/src/legacy/crypto/symkey/skreq_pool.h index cb57f53..e2c2c0b 100644 --- a/dm-sflc/crypto/symkey/skreq_pool.h +++ b/dm-sflc/src/legacy/crypto/symkey/skreq_pool.h @@ -26,8 +26,8 @@ * functions to the mempool interface. */ -#ifndef _SFLC_CRYPTO_SYMKEY_SKREQ_POOL_H_ -#define _SFLC_CRYPTO_SYMKEY_SKREQ_POOL_H_ +#ifndef _SFLEGC_CRYPTO_SYMKEY_SKREQ_POOL_H_ +#define _SFLEGC_CRYPTO_SYMKEY_SKREQ_POOL_H_ /***************************************************** * INCLUDE SECTION * @@ -35,7 +35,7 @@ #include -#include "symkey.h" +#include "legacy/crypto/symkey/symkey.h" /***************************************************** * CONSTANTS * @@ -49,7 +49,7 @@ * PUBLIC FUNCTIONS PROTOTYPES * *****************************************************/ -mempool_t * sflc_sk_createReqPool(int min_nr, sflc_sk_Context * ctx); +mempool_t * sflegc_sk_createReqPool(int min_nr, sflegc_sk_Context * ctx); -#endif /* _SFLC_CRYPTO_SYMKEY_SKREQ_POOL_H_ */ +#endif /* _SFLEGC_CRYPTO_SYMKEY_SKREQ_POOL_H_ */ diff --git a/dm-sflc/crypto/symkey/symkey.c b/dm-sflc/src/legacy/crypto/symkey/symkey.c similarity index 74% rename from dm-sflc/crypto/symkey/symkey.c rename to dm-sflc/src/legacy/crypto/symkey/symkey.c index 2a78085..3efcdf4 100644 --- a/dm-sflc/crypto/symkey/symkey.c +++ b/dm-sflc/src/legacy/crypto/symkey/symkey.c @@ -27,66 +27,66 @@ #include -#include "symkey.h" -#include "skreq_pool.h" -#include "log/log.h" +#include "legacy/crypto/symkey/symkey.h" +#include "legacy/crypto/symkey/skreq_pool.h" +#include "legacy/log/log.h" /***************************************************** * CONSTANTS * *****************************************************/ -#define SFLC_SK_REQ_POOL_SIZE 1024 +#define SFLEGC_SK_REQ_POOL_SIZE 1024 -#define SFLC_SK_ENCRYPT 0 -#define SFLC_SK_DECRYPT 1 +#define SFLEGC_SK_ENCRYPT 0 +#define SFLEGC_SK_DECRYPT 1 /***************************************************** * PRIVATE FUNCTIONS PROTOTYPES * *****************************************************/ -static int sflc_sk_encdec(sflc_sk_Context * ctx, u8 * src, u8 * dst, unsigned int len, u8 * iv, int op); +static int sflegc_sk_encdec(sflegc_sk_Context * ctx, u8 * src, u8 * dst, unsigned int len, u8 * iv, int op); /***************************************************** * PUBLIC FUNCTIONS DEFINITIONS * *****************************************************/ /* Create a new context with the given key. Returns an ERR_PTR() on failure. */ -sflc_sk_Context * sflc_sk_createContext(u8 * key) +sflegc_sk_Context * sflegc_sk_createContext(u8 * key) { - sflc_sk_Context * ctx; + sflegc_sk_Context * ctx; int err; /* Allocate context */ - ctx = kzalloc(sizeof(sflc_sk_Context), GFP_KERNEL); + ctx = kzalloc(sizeof(sflegc_sk_Context), GFP_KERNEL); if (!ctx) { - pr_err("Could not allocate %lu bytes for the sflc_sk_Context\n", sizeof(sflc_sk_Context)); + pr_err("Could not allocate %lu bytes for the sflegc_sk_Context\n", sizeof(sflegc_sk_Context)); return ERR_PTR(-ENOMEM); } /* Allocate crypto transform */ - ctx->tfm = crypto_alloc_skcipher(SFLC_SK_CIPHER_NAME, CRYPTO_ALG_ASYNC, 0); + ctx->tfm = crypto_alloc_skcipher(SFLEGC_SK_CIPHER_NAME, CRYPTO_ALG_ASYNC, 0); if (IS_ERR(ctx->tfm)) { err = PTR_ERR(ctx->tfm); ctx->tfm = NULL; pr_err("Could not allocate skcipher handle: error %d\n", err); - sflc_sk_destroyContext(ctx); + sflegc_sk_destroyContext(ctx); return ERR_PTR(err); } /* Copy and set key */ - memcpy(ctx->key, key, SFLC_SK_KEY_LEN); - err = crypto_skcipher_setkey(ctx->tfm, ctx->key, SFLC_SK_KEY_LEN); + memcpy(ctx->key, key, SFLEGC_SK_KEY_LEN); + err = crypto_skcipher_setkey(ctx->tfm, ctx->key, SFLEGC_SK_KEY_LEN); if (err) { pr_err("Could not set key in crypto transform: error %d\n", err); - sflc_sk_destroyContext(ctx); + sflegc_sk_destroyContext(ctx); return ERR_PTR(err); } /* Create request memory pool */ - ctx->sk_req_pool = sflc_sk_createReqPool(SFLC_SK_REQ_POOL_SIZE, ctx); + ctx->sk_req_pool = sflegc_sk_createReqPool(SFLEGC_SK_REQ_POOL_SIZE, ctx); if (!ctx->sk_req_pool) { pr_err("Could not allocate skcipher_request memory pool\n"); - sflc_sk_destroyContext(ctx); + sflegc_sk_destroyContext(ctx); return ERR_PTR(-ENOMEM); } @@ -94,7 +94,7 @@ sflc_sk_Context * sflc_sk_createContext(u8 * key) } /* Destroy the given context */ -void sflc_sk_destroyContext(sflc_sk_Context * ctx) +void sflegc_sk_destroyContext(sflegc_sk_Context * ctx) { if (!ctx) { return; @@ -116,21 +116,21 @@ void sflc_sk_destroyContext(sflc_sk_Context * ctx) } /* Encrypt synchronously. Provide src = dst for in-place operation. */ -int sflc_sk_encrypt(sflc_sk_Context * ctx, u8 * src, u8 * dst, unsigned int len, u8 * iv) +int sflegc_sk_encrypt(sflegc_sk_Context * ctx, u8 * src, u8 * dst, unsigned int len, u8 * iv) { - return sflc_sk_encdec(ctx, src, dst, len, iv, SFLC_SK_ENCRYPT); + return sflegc_sk_encdec(ctx, src, dst, len, iv, SFLEGC_SK_ENCRYPT); } -int sflc_sk_decrypt(sflc_sk_Context * ctx, u8 * src, u8 * dst, unsigned int len, u8 * iv) +int sflegc_sk_decrypt(sflegc_sk_Context * ctx, u8 * src, u8 * dst, unsigned int len, u8 * iv) { - return sflc_sk_encdec(ctx, src, dst, len, iv, SFLC_SK_DECRYPT); + return sflegc_sk_encdec(ctx, src, dst, len, iv, SFLEGC_SK_DECRYPT); } /***************************************************** * PRIVATE FUNCTIONS DEFINITIONS * *****************************************************/ -static int sflc_sk_encdec(sflc_sk_Context * ctx, u8 * src, u8 * dst, unsigned int len, u8 * iv, int op) +static int sflegc_sk_encdec(sflegc_sk_Context * ctx, u8 * src, u8 * dst, unsigned int len, u8 * iv, int op) { struct skcipher_request * skreq; struct scatterlist srcsg; @@ -162,7 +162,7 @@ static int sflc_sk_encdec(sflc_sk_Context * ctx, u8 * src, u8 * dst, unsigned in crypto_req_done, &skreq_wait); /* Do it */ - if (op == SFLC_SK_ENCRYPT) { + if (op == SFLEGC_SK_ENCRYPT) { ret = crypto_skcipher_encrypt(skreq); } else { ret = crypto_skcipher_decrypt(skreq); diff --git a/dm-sflc/crypto/symkey/symkey.h b/dm-sflc/src/legacy/crypto/symkey/symkey.h similarity index 78% rename from dm-sflc/crypto/symkey/symkey.h rename to dm-sflc/src/legacy/crypto/symkey/symkey.h index 1b6d40b..ec814fe 100644 --- a/dm-sflc/crypto/symkey/symkey.h +++ b/dm-sflc/src/legacy/crypto/symkey/symkey.h @@ -25,8 +25,8 @@ * A thin wrapper around the kernel's synchronous block cipher API. */ -#ifndef _SFLC_CRYPTO_SYMKEY_SYMKEY_H_ -#define _SFLC_CRYPTO_SYMKEY_SYMKEY_H_ +#ifndef _SFLEGC_CRYPTO_SYMKEY_SYMKEY_H_ +#define _SFLEGC_CRYPTO_SYMKEY_SYMKEY_H_ /***************************************************** * INCLUDE SECTION * @@ -39,9 +39,9 @@ * CONSTANTS * *****************************************************/ -#define SFLC_SK_CIPHER_NAME "ctr(aes)" -#define SFLC_SK_KEY_LEN 32 -#define SFLC_SK_IV_LEN 16 +#define SFLEGC_SK_CIPHER_NAME "ctr(aes)" +#define SFLEGC_SK_KEY_LEN 32 +#define SFLEGC_SK_IV_LEN 16 /***************************************************** * TYPES * @@ -51,34 +51,31 @@ * There is one of these Context's for each volume. * No need for locking, methods can be called in parallel. */ -typedef struct sflc_sk_context_s +typedef struct sflegc_sk_context_s { /* Only one transform for now */ struct crypto_skcipher * tfm; /* 32-byte key */ - u8 key[SFLC_SK_KEY_LEN]; + u8 key[SFLEGC_SK_KEY_LEN]; /* Memory pool for skcipher_request's */ mempool_t * sk_req_pool; -} sflc_sk_Context; +} sflegc_sk_Context; /***************************************************** * PUBLIC FUNCTIONS PROTOTYPES * *****************************************************/ -/* Self test using known test vectors and random inputs */ -int sflc_sk_selftest(void); - /* Create a new context with the given key. Returns an ERR_PTR() on failure. */ -sflc_sk_Context * sflc_sk_createContext(u8 * key); +sflegc_sk_Context * sflegc_sk_createContext(u8 * key); /* Destroy the given context */ -void sflc_sk_destroyContext(sflc_sk_Context * ctx); +void sflegc_sk_destroyContext(sflegc_sk_Context * ctx); /* Encrypt/decrypt synchronously. Provide src = dst for in-place operation. */ -int sflc_sk_encrypt(sflc_sk_Context * ctx, u8 * src, u8 * dst, unsigned int len, u8 * iv); -int sflc_sk_decrypt(sflc_sk_Context * ctx, u8 * src, u8 * dst, unsigned int len, u8 * iv); +int sflegc_sk_encrypt(sflegc_sk_Context * ctx, u8 * src, u8 * dst, unsigned int len, u8 * iv); +int sflegc_sk_decrypt(sflegc_sk_Context * ctx, u8 * src, u8 * dst, unsigned int len, u8 * iv); -#endif /* _SFLC_CRYPTO_SYMKEY_SYMKEY_H_ */ +#endif /* _SFLEGC_CRYPTO_SYMKEY_SYMKEY_H_ */ diff --git a/dm-sflc/src/legacy/device/device.c b/dm-sflc/src/legacy/device/device.c new file mode 100644 index 0000000..1725d65 --- /dev/null +++ b/dm-sflc/src/legacy/device/device.c @@ -0,0 +1,259 @@ +/* + * Copyright The Shufflecake Project Authors (2022) + * Copyright The Shufflecake Project Contributors (2022) + * Copyright Contributors to the The Shufflecake Project. + * + * See the AUTHORS file at the top-level directory of this distribution and at + * + * + * This file is part of the program shufflecake-c, which is part of the + * Shufflecake Project. Shufflecake is a plausible deniability (hidden storage) + * layer for Linux. See . + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 2 of the License, or (at your option) + * any later version. This program is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. You should have received a copy of the + * GNU General Public License along with this program. + * If not, see . + */ + +/* + * This file only implements the device-related device management functions. + */ + +/***************************************************** + * INCLUDE SECTION * + *****************************************************/ + +#include "legacy/sflc_legacy.h" +#include "legacy/device/device.h" +#include "legacy/utils/vector.h" +#include "legacy/log/log.h" + +#include + +/***************************************************** + * CONSTANTS * + *****************************************************/ + +/***************************************************** + * PUBLIC VARIABLES DEFINITIONS * + *****************************************************/ + + +/* Initialises and pre-shuffles the PSI array */ +static int sflegc_dev_initAndShufflePsiArray(u32 *psi_array, u32 len); + + +/***************************************************** + * PUBLIC FUNCTIONS DEFINITIONS * + *****************************************************/ + +/** + * Creates Device. Returns an ERR_PTR() if unsuccessful. + * Arguments: + * argv[0]: Shufflecake mode: legacy/lite + * argv[1]: Shufflecake-unique device ID + * argv[2]: path to underlying physical device + * argv[3]: volume index within the device + * argv[4]: number of 1 MB slices in the underlying device + * argv[5]: 32-byte encryption key (hex-encoded) + */ +sflegc_Device *sflegc_dev_create(struct dm_target *ti, int argc, char **argv, struct kobject *kobj) +{ + sflegc_Device * dev; + u32 tot_slices; + u32 dev_id; + int err; + int i; + + /* Allocate device */ + dev = kzalloc(sizeof(sflegc_Device), GFP_KERNEL); + if (!dev) { + pr_err("Could not allocate %lu bytes for sflegc_Device\n", sizeof(sflegc_Device)); + err = -ENOMEM; + goto err_alloc_dev; + } + + /* Parse args */ + if (argc != 6) { + pr_err("Wrong argument count"); + err = -EINVAL; + goto err_parse; + } + sscanf(argv[1], "%u", &dev_id); + if (sscanf(argv[4], "%u", &tot_slices) != 1) { + pr_err("Could not decode tot_slices\n"); + err = -EINVAL; + goto err_parse; + } + + /* Init list node here, so it's always safe to list_del() */ + INIT_LIST_HEAD(&dev->list_node); + + /* Set device ID */ + dev->dev_id = dev_id; + + /* Set backing real device */ + err = dm_get_device(ti, argv[2], dm_table_get_mode(ti->table), &dev->bdev); + if (err) { + pr_err("Could not dm_get_device: error %d\n", err); + goto err_dm_get_dev; + } + dev->ti = ti; + /* And its path */ + dev->bdev_path = kmalloc(strlen(argv[2]) + 1, GFP_KERNEL); + if (!dev->bdev_path) { + pr_err("Could not allocate %lu bytes for dev->real_dev_path\n", strlen(argv[2]) + 1); + err = -ENOMEM; + goto err_alloc_real_dev_path; + } + strcpy(dev->bdev_path, argv[2]); + + /* Init volumes */ + for (i = 0; i < SFLEGC_DEV_MAX_VOLUMES; ++i) { + dev->vol[i] = NULL; + } + dev->vol_cnt = 0; + + /* Set slices info */ + dev->tot_slices = tot_slices; + dev->free_slices = tot_slices; + /* Compute header info (like in userland tool) */ + u32 nr_pmbs_per_vol = DIV_ROUND_UP(tot_slices, SFLEGC_VOL_HEADER_MAPPINGS_PER_BLOCK); + dev->vol_header_nr_iv_blocks = DIV_ROUND_UP(nr_pmbs_per_vol, SFLEGC_VOL_LOG_SLICE_SIZE); + dev->vol_header_size = 1 + nr_pmbs_per_vol + dev->vol_header_nr_iv_blocks; + dev->dev_header_size = 1 + (SFLEGC_DEV_MAX_VOLUMES * dev->vol_header_size); + + /* Init slices lock */ + mutex_init(&dev->slices_lock); + /* Allocate reverse slice map */ + dev->rmap = vmalloc(dev->tot_slices * sizeof(u8)); + if (!dev->rmap) { + pr_err("Could not allocate reverse slice map\n"); + err = -ENOMEM; + goto err_alloc_rmap; + } + /* Initialise it */ + memset(dev->rmap, SFLEGC_DEV_RMAP_INVALID_VOL, dev->tot_slices * sizeof(u8)); + /* Allocate PSI array */ + dev->shuffled_psi_array = vmalloc(dev->tot_slices * sizeof(u32)); + if (!dev->shuffled_psi_array) { + pr_err("Could not allocate PSI array\n"); + err = -ENOMEM; + goto err_alloc_psi_array; + } + /* Initialise it and pre-shuffle it */ + err = sflegc_dev_initAndShufflePsiArray(dev->shuffled_psi_array, dev->tot_slices); + if (err) { + pr_err("Could not init-and-shuffle PSI array: error %d", err); + goto err_initshuffle_psi_array; + } + /* Init related counter */ + dev->shuffled_psi_ctr = 0; + + /* Init IV cache lock */ + mutex_init(&dev->iv_cache_lock); + /* Init IV cache waitqueue */ + init_waitqueue_head(&dev->iv_cache_waitqueue); + /* Allocate IV cache */ + dev->iv_cache = kzalloc(dev->tot_slices * sizeof(sflegc_dev_IvCacheEntry *), GFP_KERNEL); + if (!dev->iv_cache) { + pr_err("Could not allocate IV cache\n"); + err = -ENOMEM; + goto err_alloc_iv_cache; + } + /* Set it empty */ + dev->iv_cache_nr_entries = 0; + /* Init list head */ + INIT_LIST_HEAD(&dev->iv_lru_list); + + /* Add to sysfs */ + dev->kobj_parent = kobj; + err = sflegc_sysfs_add_device(dev); + if (err) { + pr_err("Could not add device to sysfs; error %d\n", err); + goto err_sysfs; + } + + return dev; + + +err_sysfs: + kfree(dev->iv_cache); +err_alloc_iv_cache: +err_initshuffle_psi_array: + vfree(dev->shuffled_psi_array); +err_alloc_psi_array: + vfree(dev->rmap); +err_alloc_rmap: + kfree(dev->bdev_path); +err_alloc_real_dev_path: + dm_put_device(ti, dev->bdev); +err_dm_get_dev: +err_parse: + kfree(dev); +err_alloc_dev: + return ERR_PTR(err); +} + + +/* Returns false if still busy (not all volumes have been removed). Frees the Device. */ +bool sflegc_dev_destroy(sflegc_Device * dev) +{ + /* Check if we actually have to put this device */ + if (!dev) { + return false; + } + if (dev->vol_cnt > 0) { + pr_warn("Called while still holding %d volumes\n", dev->vol_cnt); + return false; + } + + /* Flush all IVs */ + sflegc_dev_flushIvs(dev); + + /* List */ + list_del(&dev->list_node); + + /* Sysfs */ + sflegc_sysfs_remove_device(dev); + + /* IV cache */ + kfree(dev->iv_cache); + + /* PSI array */ + vfree(dev->shuffled_psi_array); + + /* Reverse slice map */ + vfree(dev->rmap); + + /* Backing device */ + dm_put_device(dev->ti, dev->bdev); + kfree(dev->bdev_path); + + /* Free the device itself */ + kfree(dev); + + return true; +} + + +/* Initialises and pre-shuffles the PSI array */ +static int sflegc_dev_initAndShufflePsiArray(u32 *psi_array, u32 len) +{ + u32 i; + + /* Init to the identity map */ + for (i = 0; i < len; i++) { + psi_array[i] = i; + } + + /* Permute */ + return sflegc_vec_u32shuffle(psi_array, len); +} + diff --git a/dm-sflc/device/device.h b/dm-sflc/src/legacy/device/device.h similarity index 65% rename from dm-sflc/device/device.h rename to dm-sflc/src/legacy/device/device.h index 68ef3dc..a6109e7 100644 --- a/dm-sflc/device/device.h +++ b/dm-sflc/src/legacy/device/device.h @@ -30,8 +30,8 @@ * are stored in increasing degree of "secrecy"). */ -#ifndef _SFLC_DEVICE_DEVICE_H_ -#define _SFLC_DEVICE_DEVICE_H_ +#ifndef _SFLEGC_DEVICE_DEVICE_H_ +#define _SFLEGC_DEVICE_DEVICE_H_ /***************************************************** @@ -40,8 +40,8 @@ /* Necessary since device.h, volume.h, and sysfs.h all include each other */ -typedef struct sflc_device_s sflc_Device; -typedef struct sflc_dev_iv_cache_entry_s sflc_dev_IvCacheEntry; +typedef struct sflegc_device_s sflegc_Device; +typedef struct sflegc_dev_iv_cache_entry_s sflegc_dev_IvCacheEntry; /***************************************************** @@ -49,11 +49,10 @@ typedef struct sflc_dev_iv_cache_entry_s sflc_dev_IvCacheEntry; *****************************************************/ #include -#include -#include "volume/volume.h" -#include "crypto/symkey/symkey.h" -#include "sysfs/sysfs.h" +#include "legacy/sflc_legacy.h" +#include "legacy/volume/volume.h" +#include "legacy/crypto/symkey/symkey.h" /***************************************************** @@ -61,30 +60,30 @@ typedef struct sflc_dev_iv_cache_entry_s sflc_dev_IvCacheEntry; *****************************************************/ /* We need 4096-byte sectors to amortise the space overhead of the IVs */ -#define SFLC_DEV_SECTOR_SIZE 4096 +#define SFLEGC_DEV_SECTOR_SIZE 4096 /* A SFLC sector encompasses 8 kernel sectors */ -#define SFLC_DEV_SECTOR_SCALE (SFLC_DEV_SECTOR_SIZE / SECTOR_SIZE) +#define SFLEGC_DEV_SECTOR_SCALE (SFLEGC_DEV_SECTOR_SIZE / SECTOR_SIZE) /* An IV block holds IVs for 256 data blocks */ -#define SFLC_DEV_SECTOR_TO_IV_RATIO (SFLC_DEV_SECTOR_SIZE / SFLC_SK_IV_LEN) +#define SFLEGC_DEV_SECTOR_TO_IV_RATIO (SFLEGC_DEV_SECTOR_SIZE / SFLEGC_SK_IV_LEN) /* Max number of volumes linked to a single device */ -#define SFLC_DEV_MAX_VOLUMES 15 +#define SFLEGC_DEV_MAX_VOLUMES 15 /* A physical slice contains the 256 encrypted data blocks and the IV block */ -#define SFLC_DEV_PHYS_SLICE_SIZE (SFLC_VOL_LOG_SLICE_SIZE + (SFLC_VOL_LOG_SLICE_SIZE / SFLC_DEV_SECTOR_TO_IV_RATIO)) +#define SFLEGC_DEV_PHYS_SLICE_SIZE (SFLEGC_VOL_LOG_SLICE_SIZE + (SFLEGC_VOL_LOG_SLICE_SIZE / SFLEGC_DEV_SECTOR_TO_IV_RATIO)) /* Value marking a PSI as unassigned */ -#define SFLC_DEV_RMAP_INVALID_VOL 0xFFU +#define SFLEGC_DEV_RMAP_INVALID_VOL 0xFFU /* Maximum number of open devices in total across shufflecake */ -#define SFLC_DEV_MAX_DEVICES_TOT 1024 +#define SFLEGC_DEV_MAX_DEVICES_TOT 1024 /***************************************************** * TYPES * *****************************************************/ -struct sflc_dev_iv_cache_entry_s +struct sflegc_dev_iv_cache_entry_s { /* The PSI it refers to */ u32 psi; @@ -100,23 +99,25 @@ struct sflc_dev_iv_cache_entry_s struct list_head lru_node; }; -struct sflc_device_s +struct sflegc_device_s { /* Underlying block device */ struct dm_dev * bdev; char * bdev_path; + /* Target instance that owns the bdev reference */ + struct dm_target *ti; /* Shufflecake-unique numeric ID of this device */ - size_t dev_id; + u32 dev_id; /* All volumes linked to this device */ - sflc_Volume * vol[SFLC_DEV_MAX_VOLUMES]; + sflegc_Volume * vol[SFLEGC_DEV_MAX_VOLUMES]; int vol_cnt; /* Reverse slice map, associating PSIs to volume indices */ u8 * rmap; /* Shuffled array of PSIs, with advancement counter */ - u32 *prmslices; - u32 prmslices_octr; + u32 *shuffled_psi_array; + u32 shuffled_psi_ctr; /* Lock for all three of these objects */ struct mutex slices_lock; @@ -129,98 +130,57 @@ struct sflc_device_s u32 vol_header_size; u32 dev_header_size; + /* Parent sysfs directory */ + struct kobject *kobj_parent; + /* LRU cache of IV blocks */ struct mutex iv_cache_lock; wait_queue_head_t iv_cache_waitqueue; - sflc_dev_IvCacheEntry ** iv_cache; + sflegc_dev_IvCacheEntry ** iv_cache; u32 iv_cache_nr_entries; struct list_head iv_lru_list; - /* Sysfs stuff */ - sflc_sysfs_Device * kobj; - - /* DM-io */ - struct dm_io_client *dmio_client; - /* We keep all devices in a list */ struct list_head list_node; }; -/***************************************************** - * MACROS * - *****************************************************/ - -#define sflc_dev_psiToIvBlock(dev, psi) (dev->dev_header_size + (sector_t)(psi) * SFLC_DEV_PHYS_SLICE_SIZE) - - -/***************************************************** - * PUBLIC VARIABLES DECLARATIONS * - *****************************************************/ - -/* The next available device ID */ -extern size_t sflc_dev_nextId; - -/* List of all devices */ -extern struct list_head sflc_dev_list; -/* Big, coarse-grained lock for all modifying operations on any device or the device list */ -extern struct semaphore sflc_dev_mutex; - - /***************************************************** * PUBLIC FUNCTIONS PROTOTYPES * *****************************************************/ - -/* Inits global variables */ -int sflc_dev_init(void); -/* Tears down global variables */ -void sflc_dev_exit(void); - /* * None of these functions acquire the big device lock: it must be held * by the caller. */ /* Creates Device and adds it to the list. Returns an ERR_PTR() if unsuccessful. */ -sflc_Device * sflc_dev_create(struct dm_target * ti, char * real_dev_path, u32 tot_slices); - -/* Returns NULL if not found */ -sflc_Device * sflc_dev_lookupByPath(char * real_dev_path); +sflegc_Device * sflegc_dev_create(struct dm_target *ti, int argc, char **argv, struct kobject *kobj); /* Returns false if still busy (not all volumes have been removed) Frees the Device. */ -bool sflc_dev_destroy(struct dm_target * ti, sflc_Device * dev); +bool sflegc_dev_destroy(sflegc_Device * dev); /* Returns false if volume index was already occupied. */ -bool sflc_dev_addVolume(sflc_Device * dev, sflc_Volume * vol, int vol_idx); - -/* Looks at all volumes in all devices. Returns NULL if not found */ -sflc_Volume * sflc_dev_lookupVolumeByName(char * vol_name); +bool sflegc_dev_addVolume(sflegc_Device * dev, sflegc_Volume * vol, int vol_idx); /* Does not put the volume. Returns false if was already NULL. */ -bool sflc_dev_removeVolume(sflc_Device * dev, int vol_idx); +bool sflegc_dev_removeVolume(sflegc_Device * dev, int vol_idx); /* Synchronously reads/writes one 4096-byte sector from/to the underlying device to/from the provided page */ -int sflc_dev_rwSector(sflc_Device * dev, struct page * page, sector_t sector, int rw); - -/* Synchronously read/write entire PSI (257 blocks) to/from VMA */ -int sflc_dev_rwPsi(sflc_Device *dev, void *vma, u32 psi, int rw); +int sflegc_dev_rwSector(sflegc_Device * dev, struct page * page, sector_t sector, int rw); /* The caller needs to hold slices_lock to call these functions */ -/* Checks if PSI is free */ -bool sflc_dev_isPsiFree(sflc_Device *dev, u32 psi); - /* Sets the PSI as owned by the given volume (also decreases free_slices). * Returns < 0 if already taken. */ -int sflc_dev_markPsiTaken(sflc_Device * dev, u32 psi, u8 vol_idx); +int sflegc_dev_markPsiTaken(sflegc_Device * dev, u32 psi, u8 vol_idx); /* Returns a random free physical slice, or < 0 if error */ -s32 sflc_dev_getNextRandomFreePsi(sflc_Device * dev); +s32 sflegc_dev_getNextRandomFreePsi(sflegc_Device * dev); /* These functions provide concurrent-safe access to the entries of the IV cache. @@ -231,13 +191,13 @@ s32 sflc_dev_getNextRandomFreePsi(sflc_Device * dev); When the refcount reaches 0, the IV block is flushed. */ /* Get a pointer to the specified IV block. Increases the refcount and possibly the dirtyness (if WRITE). */ -u8 * sflc_dev_getIvBlockRef(sflc_Device * dev, u32 psi, int rw); +u8 * sflegc_dev_getIvBlockRef(sflegc_Device * dev, u32 psi, int rw); /* Signal end of usage of an IV block. Decreases the refcount. */ -int sflc_dev_putIvBlockRef(sflc_Device * dev, u32 psi); +int sflegc_dev_putIvBlockRef(sflegc_Device * dev, u32 psi); /* Flush all dirty IV blocks */ -void sflc_dev_flushIvs(sflc_Device * dev); +void sflegc_dev_flushIvs(sflegc_Device * dev); -#endif /* _SFLC_DEVICE_DEVICE_H_ */ +#endif /* _SFLEGC_DEVICE_DEVICE_H_ */ diff --git a/dm-sflc/device/iv.c b/dm-sflc/src/legacy/device/iv.c similarity index 81% rename from dm-sflc/device/iv.c rename to dm-sflc/src/legacy/device/iv.c index 48acdfa..5c01201 100644 --- a/dm-sflc/device/iv.c +++ b/dm-sflc/src/legacy/device/iv.c @@ -25,24 +25,30 @@ * INCLUDE SECTION * *****************************************************/ -#include "device.h" -#include "utils/pools.h" -#include "log/log.h" + +#include "legacy/device/device.h" +#include "legacy/utils/pools.h" +#include "legacy/log/log.h" /***************************************************** * CONSTANTS * *****************************************************/ /* Capacity of IV cache */ -#define SFLC_DEV_IV_CACHE_CAPACITY 1024 +#define SFLEGC_DEV_IV_CACHE_CAPACITY 1024 +/***************************************************** + * MACROS * + *****************************************************/ + +#define sflegc_dev_psiToIvBlockSector(dev, psi) (dev->dev_header_size + (sector_t)(psi) * SFLEGC_DEV_PHYS_SLICE_SIZE) /***************************************************** * PRIVATE FUNCTIONS PROTOTYPES * *****************************************************/ -static sflc_dev_IvCacheEntry * sflc_dev_newIvCacheEntry(sflc_Device * dev, u32 psi); -static int sflc_dev_destroyIvCacheEntry(sflc_Device * dev, sflc_dev_IvCacheEntry * entry); +static sflegc_dev_IvCacheEntry * sflegc_dev_newIvCacheEntry(sflegc_Device * dev, u32 psi); +static int sflegc_dev_destroyIvCacheEntry(sflegc_Device * dev, sflegc_dev_IvCacheEntry * entry); /***************************************************** * PUBLIC FUNCTIONS DEFINITIONS * @@ -50,9 +56,9 @@ static int sflc_dev_destroyIvCacheEntry(sflc_Device * dev, sflc_dev_IvCacheEntry /* Get a read/write pointer to the specified IV block. Increases the refcount. Returns an ERR_PTR() if error. */ -u8 * sflc_dev_getIvBlockRef(sflc_Device * dev, u32 psi, int rw) +u8 * sflegc_dev_getIvBlockRef(sflegc_Device * dev, u32 psi, int rw) { - sflc_dev_IvCacheEntry * entry; + sflegc_dev_IvCacheEntry * entry; int err; /* Lock + waitqueue pattern */ @@ -65,13 +71,13 @@ u8 * sflc_dev_getIvBlockRef(sflc_Device * dev, u32 psi, int rw) } /* Check for either of two conditions in order to go through */ - while (dev->iv_cache[psi] == NULL && dev->iv_cache_nr_entries >= SFLC_DEV_IV_CACHE_CAPACITY) { + while (dev->iv_cache[psi] == NULL && dev->iv_cache_nr_entries >= SFLEGC_DEV_IV_CACHE_CAPACITY) { /* We can't go through, yield the lock */ mutex_unlock(&dev->iv_cache_lock); /* Sleep in the waitqueue (same conditions) */ if (wait_event_interruptible(dev->iv_cache_waitqueue, dev->iv_cache[psi] != NULL || - dev->iv_cache_nr_entries < SFLC_DEV_IV_CACHE_CAPACITY)) { + dev->iv_cache_nr_entries < SFLEGC_DEV_IV_CACHE_CAPACITY)) { err = -EINTR; pr_err("Interrupted while waiting in waitqueue\n"); goto err_wait_queue; @@ -93,7 +99,7 @@ u8 * sflc_dev_getIvBlockRef(sflc_Device * dev, u32 psi, int rw) entry = dev->iv_cache[psi]; if (!entry) { /* Create it */ - entry = sflc_dev_newIvCacheEntry(dev, psi); + entry = sflegc_dev_newIvCacheEntry(dev, psi); if (IS_ERR(entry)) { err = PTR_ERR(entry); pr_err("Could not create new cache entry; error %d\n", err); @@ -133,9 +139,9 @@ err_lock_cache: } /* Signal end of usage of an IV block. Decreases the refcount. */ -int sflc_dev_putIvBlockRef(sflc_Device * dev, u32 psi) +int sflegc_dev_putIvBlockRef(sflegc_Device * dev, u32 psi) { - sflc_dev_IvCacheEntry * entry; + sflegc_dev_IvCacheEntry * entry; int err; /* No condition needed besides mutual exclusion: just grab the lock (no waitqueue) */ @@ -156,12 +162,12 @@ int sflc_dev_putIvBlockRef(sflc_Device * dev, u32 psi) list_add(&entry->lru_node, &dev->iv_lru_list); /* If cache is not full, we can return now */ - if (dev->iv_cache_nr_entries < SFLC_DEV_IV_CACHE_CAPACITY) { + if (dev->iv_cache_nr_entries < SFLEGC_DEV_IV_CACHE_CAPACITY) { goto out; } /* Otherwise, let's look for the least recent unreffed entry, and evict it */ - sflc_dev_IvCacheEntry * evicted; + sflegc_dev_IvCacheEntry * evicted; bool found = false; list_for_each_entry_reverse(evicted, &dev->iv_lru_list, lru_node) { if (evicted->refcnt == 0) { @@ -182,7 +188,7 @@ int sflc_dev_putIvBlockRef(sflc_Device * dev, u32 psi) /* Pull it out of the LRU list */ __list_del_entry(&evicted->lru_node); /* Destroy it (free and flush to disk) */ - err = sflc_dev_destroyIvCacheEntry(dev, evicted); + err = sflegc_dev_destroyIvCacheEntry(dev, evicted); if (err) { pr_err("Could not evict cache entry for PSI %u; error %d\n", evicted->psi, err); goto err_destroy_entry; @@ -210,9 +216,9 @@ err_lock_cache: } /* Flush all dirty IV blocks */ -void sflc_dev_flushIvs(sflc_Device * dev) +void sflegc_dev_flushIvs(sflegc_Device * dev) { - sflc_dev_IvCacheEntry * entry, * _next; + sflegc_dev_IvCacheEntry * entry, * _next; int err; /* Iterate over all entries */ @@ -221,7 +227,7 @@ void sflc_dev_flushIvs(sflc_Device * dev) __list_del_entry(&entry->lru_node); /* Destroy it */ - err = sflc_dev_destroyIvCacheEntry(dev, entry); + err = sflegc_dev_destroyIvCacheEntry(dev, entry); if (err) { pr_err("Could not destroy IV cache entry for PSI %u; error %d\n", entry->psi, err); } @@ -232,16 +238,16 @@ void sflc_dev_flushIvs(sflc_Device * dev) * PRIVATE FUNCTIONS PROTOTYPES * *****************************************************/ -static sflc_dev_IvCacheEntry * sflc_dev_newIvCacheEntry(sflc_Device * dev, u32 psi) +static sflegc_dev_IvCacheEntry * sflegc_dev_newIvCacheEntry(sflegc_Device * dev, u32 psi) { - sflc_dev_IvCacheEntry * entry; + sflegc_dev_IvCacheEntry * entry; int err; sector_t sector; /* Allocate and init structure */ /* Allocate structure */ - entry = kmem_cache_alloc(sflc_pools_ivSlab, GFP_NOIO); + entry = kmem_cache_alloc(sflegc_pools_ivSlab, GFP_NOIO); if (!entry) { pr_err("Could not allocate IvCacheEntry structure\n"); err = -ENOMEM; @@ -251,7 +257,7 @@ static sflc_dev_IvCacheEntry * sflc_dev_newIvCacheEntry(sflc_Device * dev, u32 p /* Set PSI */ entry->psi = psi; /* Allocate page */ - entry->iv_page = mempool_alloc(sflc_pools_pagePool, GFP_NOIO); + entry->iv_page = mempool_alloc(sflegc_pools_pagePool, GFP_NOIO); if (!entry->iv_page) { pr_err("Could not allocate IV page\n"); err = -ENOMEM; @@ -271,10 +277,10 @@ static sflc_dev_IvCacheEntry * sflc_dev_newIvCacheEntry(sflc_Device * dev, u32 p /* Read from disk */ /* Position on disk */ - sector = sflc_dev_psiToIvBlock(dev, psi); + sector = sflegc_dev_psiToIvBlockSector(dev, psi); /* Read */ - err = sflc_dev_rwSector(dev, entry->iv_page, sector, READ); + err = sflegc_dev_rwSector(dev, entry->iv_page, sector, READ); if (err) { pr_err("Could not read IV block from disk; error %d\n", err); goto err_read; @@ -285,14 +291,14 @@ static sflc_dev_IvCacheEntry * sflc_dev_newIvCacheEntry(sflc_Device * dev, u32 p err_read: kunmap(entry->iv_page); - mempool_free(entry->iv_page, sflc_pools_pagePool); + mempool_free(entry->iv_page, sflegc_pools_pagePool); err_alloc_page: - kmem_cache_free(sflc_pools_ivSlab, entry); + kmem_cache_free(sflegc_pools_ivSlab, entry); err_alloc_entry: return ERR_PTR(err); } -static int sflc_dev_destroyIvCacheEntry(sflc_Device * dev, sflc_dev_IvCacheEntry * entry) +static int sflegc_dev_destroyIvCacheEntry(sflegc_Device * dev, sflegc_dev_IvCacheEntry * entry) { int err; sector_t sector; @@ -300,11 +306,11 @@ static int sflc_dev_destroyIvCacheEntry(sflc_Device * dev, sflc_dev_IvCacheEntry /* Write to disk */ /* Position on disk */ - sector = sflc_dev_psiToIvBlock(dev, entry->psi); + sector = sflegc_dev_psiToIvBlockSector(dev, entry->psi); /* Write (if necessary) */ if (entry->dirtyness) { - err = sflc_dev_rwSector(dev, entry->iv_page, sector, WRITE); + err = sflegc_dev_rwSector(dev, entry->iv_page, sector, WRITE); if (err) { pr_err("Could not write IV block to disk; error %d\n", err); return err; @@ -317,10 +323,10 @@ static int sflc_dev_destroyIvCacheEntry(sflc_Device * dev, sflc_dev_IvCacheEntry /* Kunmap page */ kunmap(entry->iv_page); /* Free it */ - mempool_free(entry->iv_page, sflc_pools_pagePool); + mempool_free(entry->iv_page, sflegc_pools_pagePool); /* Free structure */ - kmem_cache_free(sflc_pools_ivSlab, entry); + kmem_cache_free(sflegc_pools_ivSlab, entry); return 0; } diff --git a/dm-sflc/device/rawio.c b/dm-sflc/src/legacy/device/rawio.c similarity index 75% rename from dm-sflc/device/rawio.c rename to dm-sflc/src/legacy/device/rawio.c index 3c4ee0e..02da426 100644 --- a/dm-sflc/device/rawio.c +++ b/dm-sflc/src/legacy/device/rawio.c @@ -25,14 +25,12 @@ * INCLUDE SECTION * *****************************************************/ -#include "device.h" -#include "utils/pools.h" -#include "log/log.h" +#include "legacy/device/device.h" +#include "legacy/utils/pools.h" +#include "legacy/log/log.h" #include -#include #include -//#include /***************************************************** * CONSTANTS * @@ -48,7 +46,7 @@ /* Synchronously reads/writes one 4096-byte sector from/to the underlying device to/from the provided page */ -int sflc_dev_rwSector(sflc_Device * dev, struct page * page, sector_t sector, int rw) +int sflegc_dev_rwSector(sflegc_Device * dev, struct page * page, sector_t sector, int rw) { struct bio *bio; blk_opf_t opf; @@ -59,16 +57,16 @@ int sflc_dev_rwSector(sflc_Device * dev, struct page * page, sector_t sector, in opf |= REQ_SYNC; /* Allocate bio */ - bio = bio_alloc_bioset(dev->bdev->bdev, 1, opf, GFP_NOIO, &sflc_pools_bioset); + bio = bio_alloc_bioset(dev->bdev->bdev, 1, opf, GFP_NOIO, &sflegc_pools_bioset); if (!bio) { pr_err("Could not allocate bio\n"); return -ENOMEM; } /* Set sector */ - bio->bi_iter.bi_sector = sector * SFLC_DEV_SECTOR_SCALE; + bio->bi_iter.bi_sector = sector * SFLEGC_DEV_SECTOR_SCALE; /* Add page */ - if (!bio_add_page(bio, page, SFLC_DEV_SECTOR_SIZE, 0)) { + if (!bio_add_page(bio, page, SFLEGC_DEV_SECTOR_SIZE, 0)) { pr_err("Catastrophe: could not add page to bio! WTF?\n"); err = EINVAL; goto out; @@ -83,32 +81,6 @@ out: return err; } - -/* -// Synchronously read/write entire PSI (257 blocks) to/from VMA -int sflc_dev_rwPsi(sflc_Device *dev, void *vma, u32 psi, int rw) -{ - struct dm_io_request io_req = { - .bi_opf = ((rw == READ) ? REQ_OP_READ : REQ_OP_WRITE) | REQ_SYNC, - - .mem.type = DM_IO_VMA, - .mem.offset = 0, - .mem.ptr.vma = vma, - - .notify.fn = NULL, - - .client = dev->dmio_client - }; - struct dm_io_region io_reg = { - .bdev = dev->bdev->bdev, - .sector = sflc_dev_psiToIvBlock(dev, psi) * SFLC_DEV_SECTOR_SCALE, - .count = SFLC_DEV_PHYS_SLICE_SIZE * SFLC_DEV_SECTOR_SCALE - }; - - return dm_io(&io_req, 1, &io_reg, NULL); -} -*/ - /***************************************************** * PRIVATE FUNCTIONS DEFINITIONS * *****************************************************/ diff --git a/dm-sflc/device/rmap.c b/dm-sflc/src/legacy/device/rmap.c similarity index 78% rename from dm-sflc/device/rmap.c rename to dm-sflc/src/legacy/device/rmap.c index 8e3635d..f953009 100644 --- a/dm-sflc/device/rmap.c +++ b/dm-sflc/src/legacy/device/rmap.c @@ -29,9 +29,9 @@ * INCLUDE SECTION * *****************************************************/ -#include "device.h" -#include "crypto/rand/rand.h" -#include "log/log.h" +#include "legacy/device/device.h" +#include "legacy/crypto/rand/rand.h" +#include "legacy/log/log.h" /***************************************************** * CONSTANTS * @@ -41,18 +41,12 @@ * PUBLIC FUNCTIONS DEFINITIONS * *****************************************************/ -/* Checks if PSI is free */ -bool sflc_dev_isPsiFree(sflc_Device *dev, u32 psi) -{ - return ((psi < dev->tot_slices) && - (dev->rmap[psi] == SFLC_DEV_RMAP_INVALID_VOL)); -} - - /* Sets the PSI as owned by the given volume (also decreases free_slices). * Returns < 0 if already taken. */ -int sflc_dev_markPsiTaken(sflc_Device * dev, u32 psi, u8 vol_idx) +int sflegc_dev_markPsiTaken(sflegc_Device * dev, u32 psi, u8 vol_idx) { + u8 prev_vol_idx; + /* Bounds check */ if (psi >= dev->tot_slices) { pr_err("Requested to set ownership for invalid PSI\n"); @@ -60,7 +54,8 @@ int sflc_dev_markPsiTaken(sflc_Device * dev, u32 psi, u8 vol_idx) } /* Check that it's free */ - if (dev->rmap[psi] != SFLC_DEV_RMAP_INVALID_VOL) { + prev_vol_idx = dev->rmap[psi]; + if (prev_vol_idx != SFLEGC_DEV_RMAP_INVALID_VOL) { pr_err("Requested to set ownership for already-owned PSI\n"); return -EINVAL; } @@ -74,7 +69,7 @@ int sflc_dev_markPsiTaken(sflc_Device * dev, u32 psi, u8 vol_idx) /* Returns a random free physical slice, or < 0 if error */ -s32 sflc_dev_getNextRandomFreePsi(sflc_Device * dev) +s32 sflegc_dev_getNextRandomFreePsi(sflegc_Device * dev) { u32 psi; @@ -87,15 +82,14 @@ s32 sflc_dev_getNextRandomFreePsi(sflc_Device * dev) /* Repeatedly advance the counter in the shuffled array * until you find a free one */ do { - if (dev->prmslices_octr >= dev->tot_slices) { - pr_err("Double catastrophe! No free PSIs on the device, " - "and didn't catch it before!\n"); + psi = dev->shuffled_psi_array[dev->shuffled_psi_ctr]; + dev->shuffled_psi_ctr += 1; + + if (dev->shuffled_psi_ctr >= dev->tot_slices) { + pr_err("Double catastrophe! No free PSIs on the device, and didn't catch it before!\n"); return -ENOSPC; } - - psi = dev->prmslices[dev->prmslices_octr]; - dev->prmslices_octr += 1; - } while (dev->rmap[psi] != SFLC_DEV_RMAP_INVALID_VOL); + } while (dev->rmap[psi] != SFLEGC_DEV_RMAP_INVALID_VOL); return psi; } diff --git a/dm-sflc/device/volumes.c b/dm-sflc/src/legacy/device/volumes.c similarity index 70% rename from dm-sflc/device/volumes.c rename to dm-sflc/src/legacy/device/volumes.c index b6ec553..32efa1b 100644 --- a/dm-sflc/device/volumes.c +++ b/dm-sflc/src/legacy/device/volumes.c @@ -29,8 +29,8 @@ * INCLUDE SECTION * *****************************************************/ -#include "device.h" -#include "log/log.h" +#include "legacy/device/device.h" +#include "legacy/log/log.h" /***************************************************** * CONSTANTS * @@ -41,22 +41,13 @@ *****************************************************/ /* Returns false if volume index was already occupied. */ -bool sflc_dev_addVolume(sflc_Device * dev, sflc_Volume * vol, int vol_idx) +bool sflegc_dev_addVolume(sflegc_Device * dev, sflegc_Volume * vol, int vol_idx) { - int err; - if (dev->vol[vol_idx]) { pr_err("Something's wrong, asked to set volume number %d, already occupied\n", vol_idx); return false; } - /* Update sysfs */ - err = sflc_sysfs_addVolumeToDevice(dev->kobj, vol->kvol); - if (err) { - pr_err("Could not add volume symlink in sysfs device subdir; error %d\n", err); - return false; - } - /* Update fields */ dev->vol[vol_idx] = vol; dev->vol_cnt += 1; @@ -64,39 +55,15 @@ bool sflc_dev_addVolume(sflc_Device * dev, sflc_Volume * vol, int vol_idx) return true; } -/* Looks at all volumes in all devices. Returns NULL if not found */ -sflc_Volume * sflc_dev_lookupVolumeByName(char * vol_name) -{ - sflc_Device * dev; - sflc_Volume * vol; - - /* Sweep all devices */ - list_for_each_entry(dev, &sflc_dev_list, list_node) { - /* Sweep all volumes */ - int i; - for (i = 0; i < SFLC_DEV_MAX_VOLUMES; ++i) { - vol = dev->vol[i]; - if (vol && (strcmp(vol_name, vol->vol_name) == 0)) { - return vol; - } - } - } - - return NULL; -} /* Does not put the volume. Returns false if was already NULL. */ -bool sflc_dev_removeVolume(sflc_Device * dev, int vol_idx) +bool sflegc_dev_removeVolume(sflegc_Device * dev, int vol_idx) { if (!dev->vol[vol_idx]) { pr_err("Something's wrong, asked to unset volume number %d, already NULL\n", vol_idx); return false; } - - /* Remove sysfs entry */ - if (dev->vol[vol_idx]->kvol) { - sflc_sysfs_removeVolumeFromDevice(dev->kobj, dev->vol[vol_idx]->kvol); - } + /* Update fields */ dev->vol[vol_idx] = NULL; diff --git a/dm-sflc/log/log.h b/dm-sflc/src/legacy/log/log.h similarity index 95% rename from dm-sflc/log/log.h rename to dm-sflc/src/legacy/log/log.h index 7ef7729..1d415d1 100644 --- a/dm-sflc/log/log.h +++ b/dm-sflc/src/legacy/log/log.h @@ -25,8 +25,8 @@ * Logging format */ -#ifndef _SFLC_LOG_LOG_H_ -#define _SFLC_LOG_LOG_H_ +#ifndef _SFLEGC_LOG_LOG_H_ +#define _SFLEGC_LOG_LOG_H_ /***************************************************** * INCLUDE SECTION * @@ -41,4 +41,4 @@ #undef pr_fmt #define pr_fmt(fmt) "[%s] %s in %s:%d: " fmt, KBUILD_MODNAME, __func__, __FILE__, __LINE__ -#endif /* _SFLC_LOG_LOG_H_ */ +#endif /* _SFLEGC_LOG_LOG_H_ */ diff --git a/dm-sflc/src/legacy/sflc_legacy.c b/dm-sflc/src/legacy/sflc_legacy.c new file mode 100644 index 0000000..cd4167c --- /dev/null +++ b/dm-sflc/src/legacy/sflc_legacy.c @@ -0,0 +1,87 @@ +/* + * Copyright The Shufflecake Project Authors (2022) + * Copyright The Shufflecake Project Contributors (2022) + * Copyright Contributors to the The Shufflecake Project. + * + * See the AUTHORS file at the top-level directory of this distribution and at + * + * + * This file is part of the program shufflecake-c, which is part of the + * Shufflecake Project. Shufflecake is a plausible deniability (hidden storage) + * layer for Linux. See . + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 2 of the License, or (at your option) + * any later version. This program is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. You should have received a copy of the + * GNU General Public License along with this program. + * If not, see . + */ + +/***************************************************** + * INCLUDE SECTION * + *****************************************************/ + +#include +#include + +#include "legacy/sflc_legacy.h" +#include "legacy/crypto/symkey/symkey.h" +#include "legacy/crypto/rand/rand.h" +#include "legacy/utils/pools.h" +#include "legacy/utils/workqueues.h" +#include "legacy/log/log.h" + + +/***************************************************** + * MODULE FUNCTIONS DEFINITIONS * + *****************************************************/ + +/* Module entry point, called just once, at module-load time */ +int sflegc_init(void) +{ + int ret; + + ret = sflegc_rand_init(); + if (ret) { + pr_err("Could not init rand; error %d\n", ret); + goto err_rand_init; + } + + /* Init the memory pools */ + ret = sflegc_pools_init(); + if (ret) { + pr_err("Could not init memory pools; error %d\n", ret); + goto err_pools; + } + + /* Init the workqueues */ + ret = sflegc_queues_init(); + if (ret) { + pr_err("Could not init workqueues; error %d\n", ret); + goto err_queues; + } + + return 0; + + +err_queues: + sflegc_pools_exit(); +err_pools: + sflegc_rand_exit(); +err_rand_init: + return ret; +} + +/* Module exit point, called just once, at module-unload time */ +void sflegc_exit(void) +{ + sflegc_queues_exit(); + sflegc_pools_exit(); + sflegc_rand_exit(); + + return; +} diff --git a/dm-sflc/target/target.h b/dm-sflc/src/legacy/sflc_legacy.h similarity index 68% rename from dm-sflc/target/target.h rename to dm-sflc/src/legacy/sflc_legacy.h index 43eb64e..70f0a95 100644 --- a/dm-sflc/target/target.h +++ b/dm-sflc/src/legacy/sflc_legacy.h @@ -20,25 +20,27 @@ * GNU General Public License along with this program. * If not, see . */ - -/* - * Methods of our DM target - */ -#ifndef _SFLC_TARGET_TARGET_H_ -#define _SFLC_TARGET_TARGET_H_ - -/***************************************************** - * INCLUDE SECTION * - *****************************************************/ - -#include - -/***************************************************** - * PUBLIC VARIABLES DECLARATIONS * - *****************************************************/ - -extern struct target_type sflc_target; +#ifndef _SFLEGC_SFLEGC_H +#define _SFLEGC_SFLEGC_H -#endif /* _SFLC_TARGET_TARGET_H_ */ +// For the definition of sflegc_Device and its functions +#include "legacy/device/device.h" +// For the definition of sflegc_Volume and its functions +#include "legacy/volume/volume.h" + + +extern struct target_type sflegc_target_type; + + +int sflegc_init(void); +void sflegc_exit(void); + +int sflegc_sysfs_add_device(sflegc_Device *dev); +void sflegc_sysfs_remove_device(sflegc_Device *dev); +int sflegc_sysfs_add_volume(sflegc_Volume *vol); +void sflegc_sysfs_remove_volume(sflegc_Volume *vol); + + +#endif /* _SFLEGC_SFLEGC_H */ diff --git a/dm-sflc/src/legacy/sysfs.c b/dm-sflc/src/legacy/sysfs.c new file mode 100644 index 0000000..df6615e --- /dev/null +++ b/dm-sflc/src/legacy/sysfs.c @@ -0,0 +1,142 @@ +/* + * Copyright The Shufflecake Project Authors (2022) + * Copyright The Shufflecake Project Contributors (2022) + * Copyright Contributors to the The Shufflecake Project. + * + * See the AUTHORS file at the top-level directory of this distribution and at + * + * + * This file is part of the program shufflecake-c, which is part of the + * Shufflecake Project. Shufflecake is a plausible deniability (hidden storage) + * layer for Linux. See . + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 2 of the License, or (at your option) + * any later version. This program is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. You should have received a copy of the + * GNU General Public License along with this program. + * If not, see . + */ + +/***************************************************** + * INCLUDE SECTION * + *****************************************************/ + +#include + +#include "legacy/sflc_legacy.h" +#include "legacy/log/log.h" + +// Only to import the definitions of structs sflc_volume and sflc_device +#include "sflc.h" + + +/* + *---------------------------- + * Devices + *---------------------------- + */ + +/* Show the total number of slices in a device */ +static ssize_t tot_slices_show(struct kobject *kobj, struct kobj_attribute *kattr, char *buf) +{ + struct sflc_device *top_dev; + sflegc_Device * dev; + ssize_t ret; + + top_dev = container_of(kobj, struct sflc_device, kobj); + dev = top_dev->sflegc_dev; + + /* Write the tot_slices */ + ret = sysfs_emit(buf, "%u\n", dev->tot_slices); + + return ret; +} + +/* Show the number of free slices in a device */ +static ssize_t free_slices_show(struct kobject *kobj, struct kobj_attribute *kattr, char *buf) +{ + struct sflc_device *top_dev; + sflegc_Device * dev; + ssize_t ret; + + top_dev = container_of(kobj, struct sflc_device, kobj); + dev = top_dev->sflegc_dev; + + /* Write the free_slices */ + if (mutex_lock_interruptible(&dev->slices_lock)) + return -ERESTARTSYS; + ret = sysfs_emit(buf, "%u\n", dev->free_slices); + mutex_unlock(&dev->slices_lock); + + return ret; +} + +static struct kobj_attribute tot_slices_kattr = __ATTR_RO(tot_slices); +static struct kobj_attribute free_slices_kattr = __ATTR_RO(free_slices); +static struct attribute *sflegc_device_attrs[] = { + &tot_slices_kattr.attr, + &free_slices_kattr.attr, + NULL +}; +static const struct attribute_group sflegc_device_attr_group = { + .attrs = sflegc_device_attrs, +}; + +int sflegc_sysfs_add_device(sflegc_Device *dev) +{ + return sysfs_create_group(dev->kobj_parent, &sflegc_device_attr_group); +} + +void sflegc_sysfs_remove_device(sflegc_Device *dev) +{ + sysfs_remove_group(dev->kobj_parent, &sflegc_device_attr_group); +} + + +/* + *---------------------------- + * Volumes + *---------------------------- + */ + +/* Show the number of mapped slices in a volume */ +static ssize_t mapped_slices_show(struct kobject *kobj, struct kobj_attribute *kattr, char *buf) +{ + struct sflc_volume *top_vol; + sflegc_Volume * vol; + ssize_t ret; + + top_vol = container_of(kobj, struct sflc_volume, kobj); + vol = top_vol->sflegc_vol; + + /* Write the free_slices */ + if (mutex_lock_interruptible(&vol->fmap_lock)) + return -ERESTARTSYS; + ret = sysfs_emit(buf, "%u\n", vol->mapped_slices); + mutex_unlock(&vol->fmap_lock); + + return ret; +} + +static struct kobj_attribute mapped_slices_kattr = __ATTR_RO(mapped_slices); +static struct attribute *sflegc_volume_attrs[] = { + &mapped_slices_kattr.attr, + NULL +}; +static const struct attribute_group sflegc_volume_attr_group = { + .attrs = sflegc_volume_attrs, +}; + +int sflegc_sysfs_add_volume(sflegc_Volume *vol) +{ + return sysfs_create_group(vol->kobj_parent, &sflegc_volume_attr_group); +} + +void sflegc_sysfs_remove_volume(sflegc_Volume *vol) +{ + sysfs_remove_group(vol->kobj_parent, &sflegc_volume_attr_group); +} diff --git a/dm-sflc/src/legacy/target.c b/dm-sflc/src/legacy/target.c new file mode 100644 index 0000000..08a0d40 --- /dev/null +++ b/dm-sflc/src/legacy/target.c @@ -0,0 +1,150 @@ +/* + * Copyright The Shufflecake Project Authors (2022) + * Copyright The Shufflecake Project Contributors (2022) + * Copyright Contributors to the The Shufflecake Project. + * + * See the AUTHORS file at the top-level directory of this distribution and at + * + * + * This file is part of the program shufflecake-c, which is part of the + * Shufflecake Project. Shufflecake is a plausible deniability (hidden storage) + * layer for Linux. See . + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 2 of the License, or (at your option) + * any later version. This program is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. You should have received a copy of the + * GNU General Public License along with this program. + * If not, see . + */ + +/* + * Methods of our DM target + */ + +/***************************************************** + * INCLUDE SECTION * + *****************************************************/ + +#include "legacy/device/device.h" +#include "legacy/volume/volume.h" +#include "legacy/utils/bio.h" +#include "legacy/utils/string.h" +#include "legacy/log/log.h" + +// Only to import the definition of struct sflc_volume +#include "sflc.h" + +/***************************************************** + * CONSTANTS * + *****************************************************/ + +/***************************************************** + * PRIVATE FUNCTIONS PROTOTYPES * + *****************************************************/ + +static int sflegc_tgt_map(struct dm_target *ti, struct bio *bio); +static void sflegc_tgt_ioHints(struct dm_target *ti, struct queue_limits *limits); +static int sflegc_tgt_iterateDevices(struct dm_target *ti, iterate_devices_callout_fn fn, + void *data); + +/***************************************************** + * PUBLIC VARIABLES DEFINITIONS * + *****************************************************/ + +struct target_type sflegc_target_type = { + .map = sflegc_tgt_map, + .io_hints = sflegc_tgt_ioHints, + .iterate_devices = sflegc_tgt_iterateDevices, +}; + +/***************************************************** + * PRIVATE FUNCTIONS DEFINITIONS * + *****************************************************/ + + +/* Callback for every bio submitted to our virtual block device */ +static int sflegc_tgt_map(struct dm_target *ti, struct bio *bio) +{ + int err; + struct sflc_volume *top_vol = ti->private; + sflegc_Volume *vol = top_vol->sflegc_vol; + + /* If no data, just quickly remap the sector and the block device (no crypto) */ + /* TODO: this is dangerous for deniability, will need more filtering */ + if (unlikely(!bio_has_data(bio))) { + pr_debug("No-data bio: bio_op = %d", bio_op(bio)); + err = sflegc_vol_remapBioFast(vol, bio); + if (err) { + pr_err("Could not remap bio; error %d\n", err); + return DM_MAPIO_KILL; + } + return DM_MAPIO_REMAPPED; + } + + /* At this point, the bio has data. Do a few sanity checks */ + /* TODO: I think we can get rid of all of them */ + + /* Check that it is properly aligned and it doesn't cross vector boundaries */ + if (unlikely(!sflegc_bio_isAligned(bio))) { + pr_err("Unaligned bio!\n"); + return DM_MAPIO_KILL; + } + /* If it contains more than one SFLC sector, complain with the DM layer and continue */ + if (unlikely(bio->bi_iter.bi_size > SFLEGC_DEV_SECTOR_SIZE)) { + pr_notice("Large bio of size %u\n", bio->bi_iter.bi_size); + dm_accept_partial_bio(bio, SFLEGC_DEV_SECTOR_SCALE); + } + /* Check that it contains exactly one SFLC sector */ + if (unlikely(bio->bi_iter.bi_size != SFLEGC_DEV_SECTOR_SIZE)) { + pr_err("Wrong length (%u) of bio\n", bio->bi_iter.bi_size); + return DM_MAPIO_KILL; + } + + /* Now it is safe, process it */ + err = sflegc_vol_processBio(vol, bio); + if (err) { + pr_err("Could not enqueue bio\n"); + return DM_MAPIO_KILL; + } + + return DM_MAPIO_SUBMITTED; +} + +/* Callback executed to inform the DM about our 4096-byte sector size */ +static void sflegc_tgt_ioHints(struct dm_target *ti, struct queue_limits *limits) +{ + struct sflc_volume *top_vol = ti->private; + sflegc_Volume *vol = top_vol->sflegc_vol; + + pr_info("Called io_hints on volume \"%s\"\n", vol->vol_name); + + limits->logical_block_size = SFLEGC_DEV_SECTOR_SIZE; + limits->physical_block_size = SFLEGC_DEV_SECTOR_SIZE; + + limits->io_min = SFLEGC_DEV_SECTOR_SIZE; + limits->io_opt = SFLEGC_DEV_SECTOR_SIZE; + + return; +} + +/* Callback needed for God knows what, otherwise io_hints never gets called */ +static int sflegc_tgt_iterateDevices(struct dm_target *ti, iterate_devices_callout_fn fn, + void *data) +{ + struct sflc_volume *top_vol = ti->private; + sflegc_Volume *vol = top_vol->sflegc_vol; + sflegc_Device * dev = vol->dev; + + pr_debug("Called iterate_devices on volume \"%s\"\n", vol->vol_name); + + if (!fn) { + return -EINVAL; + } + return fn(ti, vol->dev->bdev, 0, + (dev->dev_header_size + dev->tot_slices * SFLEGC_DEV_PHYS_SLICE_SIZE) * SFLEGC_DEV_SECTOR_SCALE, + data); +} diff --git a/dm-sflc/utils/bio.c b/dm-sflc/src/legacy/utils/bio.c similarity index 88% rename from dm-sflc/utils/bio.c rename to dm-sflc/src/legacy/utils/bio.c index 7591c52..ff2ce25 100644 --- a/dm-sflc/utils/bio.c +++ b/dm-sflc/src/legacy/utils/bio.c @@ -29,8 +29,8 @@ * INCLUDE SECTION * *****************************************************/ -#include "bio.h" -#include "log/log.h" +#include "legacy/utils/bio.h" +#include "legacy/log/log.h" /***************************************************** @@ -41,7 +41,7 @@ * Checks whether each of the bio's segments contains a whole * number of 4096-byte sectors. */ -bool sflc_bio_isAligned(struct bio * bio) +bool sflegc_bio_isAligned(struct bio * bio) { bool ret = true; @@ -51,12 +51,12 @@ bool sflc_bio_isAligned(struct bio * bio) return false; } /* Unlikely because we tell the DM layer about our sector size */ - if (unlikely(bio->bi_iter.bi_size % SFLC_DEV_SECTOR_SIZE != 0)) { + if (unlikely(bio->bi_iter.bi_size % SFLEGC_DEV_SECTOR_SIZE != 0)) { pr_err("Abnormal bi_size = %u\n", bio->bi_iter.bi_size); return false; } /* Unlikely because we tell the DM layer about our sector size */ - if (unlikely(bio->bi_iter.bi_sector % SFLC_DEV_SECTOR_SCALE != 0)) { + if (unlikely(bio->bi_iter.bi_sector % SFLEGC_DEV_SECTOR_SCALE != 0)) { pr_err("Abnormal bi_sector = %llu\n", bio->bi_iter.bi_sector); return false; } @@ -64,7 +64,7 @@ bool sflc_bio_isAligned(struct bio * bio) struct bio_vec bvl; struct bvec_iter iter; bio_for_each_segment(bvl, bio, iter) { - if ((bvl.bv_len == 0) || (bvl.bv_len % SFLC_DEV_SECTOR_SIZE != 0)) { + if ((bvl.bv_len == 0) || (bvl.bv_len % SFLEGC_DEV_SECTOR_SIZE != 0)) { pr_err("Abnormal vector: bv_len = %u\n", bvl.bv_len); ret = false; } diff --git a/dm-sflc/utils/bio.h b/dm-sflc/src/legacy/utils/bio.h similarity index 90% rename from dm-sflc/utils/bio.h rename to dm-sflc/src/legacy/utils/bio.h index d7bf7b2..b5af43d 100644 --- a/dm-sflc/utils/bio.h +++ b/dm-sflc/src/legacy/utils/bio.h @@ -25,14 +25,14 @@ * A collection of utility bio functions */ -#ifndef _SFLC_UTILS_BIO_H_ -#define _SFLC_UTILS_BIO_H_ +#ifndef _SFLEGC_UTILS_BIO_H_ +#define _SFLEGC_UTILS_BIO_H_ /***************************************************** * INCLUDE SECTION * *****************************************************/ -#include "device/device.h" +#include "legacy/device/device.h" /***************************************************** * PUBLIC FUNCTIONS PROTOTYPES * @@ -42,7 +42,7 @@ * Checks whether each of the bio's segments contains a whole * number of 4096-byte sectors. */ -bool sflc_bio_isAligned(struct bio * bio); +bool sflegc_bio_isAligned(struct bio * bio); -#endif /* _SFLC_UTILS_BIO_H_ */ +#endif /* _SFLEGC_UTILS_BIO_H_ */ diff --git a/dm-sflc/utils/pools.c b/dm-sflc/src/legacy/utils/pools.c similarity index 56% rename from dm-sflc/utils/pools.c rename to dm-sflc/src/legacy/utils/pools.c index 9e9af0b..c141729 100644 --- a/dm-sflc/utils/pools.c +++ b/dm-sflc/src/legacy/utils/pools.c @@ -29,100 +29,100 @@ * INCLUDE SECTION * *****************************************************/ -#include "pools.h" -#include "log/log.h" +#include "legacy/utils/pools.h" +#include "legacy/log/log.h" /***************************************************** * CONSTANTS * *****************************************************/ /* Pool sizes */ -#define SFLC_POOLS_BIOSET_POOL_SIZE 1024 -#define SFLC_POOLS_PAGE_POOL_SIZE 1024 -#define SFLC_POOLS_WRITE_WORK_POOL_SIZE 1024 -#define SFLC_POOLS_DECRYPT_WORK_POOL_SIZE 1024 +#define SFLEGC_POOLS_BIOSET_POOL_SIZE 1024 +#define SFLEGC_POOLS_PAGE_POOL_SIZE 1024 +#define SFLEGC_POOLS_WRITE_WORK_POOL_SIZE 1024 +#define SFLEGC_POOLS_DECRYPT_WORK_POOL_SIZE 1024 /* Slab cache names */ -#define SFLC_POOLS_WRITE_WORK_SLAB_NAME "sflc_write_work_slab" -#define SFLC_POOLS_DECRYPT_WORK_SLAB_NAME "sflc_decrypt_work_slab" -#define SFLC_POOLS_IV_SLAB_NAME "sflc_iv_slab" +#define SFLEGC_POOLS_WRITE_WORK_SLAB_NAME "sflegc_write_work_slab" +#define SFLEGC_POOLS_DECRYPT_WORK_SLAB_NAME "sflegc_decrypt_work_slab" +#define SFLEGC_POOLS_IV_SLAB_NAME "sflegc_iv_slab" /***************************************************** * PUBLIC VARIABLES DEFINITIONS * *****************************************************/ -struct bio_set sflc_pools_bioset; -mempool_t * sflc_pools_pagePool; -mempool_t * sflc_pools_writeWorkPool; -mempool_t * sflc_pools_decryptWorkPool; -struct kmem_cache * sflc_pools_ivSlab; +struct bio_set sflegc_pools_bioset; +mempool_t * sflegc_pools_pagePool; +mempool_t * sflegc_pools_writeWorkPool; +mempool_t * sflegc_pools_decryptWorkPool; +struct kmem_cache * sflegc_pools_ivSlab; /***************************************************** * PRIVATE VARIABLES * *****************************************************/ -static struct kmem_cache * sflc_pools_writeWorkSlab; -static struct kmem_cache * sflc_pools_decryptWorkSlab; +static struct kmem_cache * sflegc_pools_writeWorkSlab; +static struct kmem_cache * sflegc_pools_decryptWorkSlab; /***************************************************** * PUBLIC FUNCTIONS DEFINITIONS * *****************************************************/ -int sflc_pools_init(void) +int sflegc_pools_init(void) { int err; /* Memory pools: bioset */ - err = bioset_init(&sflc_pools_bioset, SFLC_POOLS_BIOSET_POOL_SIZE, 0, BIOSET_NEED_BVECS); + err = bioset_init(&sflegc_pools_bioset, SFLEGC_POOLS_BIOSET_POOL_SIZE, 0, BIOSET_NEED_BVECS); if (err) { pr_err("Could not init bioset: error %d\n", err); goto err_bioset; } /* Memory pools: page_pool */ - sflc_pools_pagePool = mempool_create_page_pool(SFLC_POOLS_PAGE_POOL_SIZE, 0); - if (!sflc_pools_pagePool) { + sflegc_pools_pagePool = mempool_create_page_pool(SFLEGC_POOLS_PAGE_POOL_SIZE, 0); + if (!sflegc_pools_pagePool) { pr_err("Could not create page pool\n"); err = -ENOMEM; goto err_pagepool; } /* Memory pools: writeWork slab cache */ - sflc_pools_writeWorkSlab = kmem_cache_create(SFLC_POOLS_WRITE_WORK_SLAB_NAME, sizeof(sflc_vol_WriteWork), 0, SLAB_POISON | SLAB_RED_ZONE, NULL); - if (IS_ERR(sflc_pools_writeWorkSlab)) { - err = PTR_ERR(sflc_pools_writeWorkSlab); + sflegc_pools_writeWorkSlab = kmem_cache_create(SFLEGC_POOLS_WRITE_WORK_SLAB_NAME, sizeof(sflegc_vol_WriteWork), 0, SLAB_POISON | SLAB_RED_ZONE, NULL); + if (IS_ERR(sflegc_pools_writeWorkSlab)) { + err = PTR_ERR(sflegc_pools_writeWorkSlab); pr_err("Could not create writeWork slab cache; error %d\n", err); goto err_create_write_work_slab; } /* Memory pools: writeWork pool */ - sflc_pools_writeWorkPool = mempool_create_slab_pool(SFLC_POOLS_WRITE_WORK_POOL_SIZE, sflc_pools_writeWorkSlab); - if (!sflc_pools_writeWorkPool) { + sflegc_pools_writeWorkPool = mempool_create_slab_pool(SFLEGC_POOLS_WRITE_WORK_POOL_SIZE, sflegc_pools_writeWorkSlab); + if (!sflegc_pools_writeWorkPool) { pr_err("Could not create writeWork pool\n"); err = -ENOMEM; goto err_write_work_pool; } /* Memory pools: decryptWork slab cache */ - sflc_pools_decryptWorkSlab = kmem_cache_create(SFLC_POOLS_DECRYPT_WORK_SLAB_NAME, sizeof(sflc_vol_DecryptWork), 0, SLAB_POISON | SLAB_RED_ZONE, NULL); - if (IS_ERR(sflc_pools_decryptWorkSlab)) { - err = PTR_ERR(sflc_pools_decryptWorkSlab); + sflegc_pools_decryptWorkSlab = kmem_cache_create(SFLEGC_POOLS_DECRYPT_WORK_SLAB_NAME, sizeof(sflegc_vol_DecryptWork), 0, SLAB_POISON | SLAB_RED_ZONE, NULL); + if (IS_ERR(sflegc_pools_decryptWorkSlab)) { + err = PTR_ERR(sflegc_pools_decryptWorkSlab); pr_err("Could not create decryptWork slab cache; error %d\n", err); goto err_create_decrypt_work_slab; } /* Memory pools: decryptWork pool */ - sflc_pools_decryptWorkPool = mempool_create_slab_pool(SFLC_POOLS_DECRYPT_WORK_POOL_SIZE, sflc_pools_decryptWorkSlab); - if (!sflc_pools_decryptWorkPool) { + sflegc_pools_decryptWorkPool = mempool_create_slab_pool(SFLEGC_POOLS_DECRYPT_WORK_POOL_SIZE, sflegc_pools_decryptWorkSlab); + if (!sflegc_pools_decryptWorkPool) { pr_err("Could not create decryptWork pool\n"); err = -ENOMEM; goto err_decrypt_work_pool; } /* Memory pools: IV slab cache */ - sflc_pools_ivSlab = kmem_cache_create(SFLC_POOLS_IV_SLAB_NAME, sizeof(sflc_dev_IvCacheEntry), 0, SLAB_POISON | SLAB_RED_ZONE, NULL); - if (IS_ERR(sflc_pools_ivSlab)) { - err = PTR_ERR(sflc_pools_ivSlab); + sflegc_pools_ivSlab = kmem_cache_create(SFLEGC_POOLS_IV_SLAB_NAME, sizeof(sflegc_dev_IvCacheEntry), 0, SLAB_POISON | SLAB_RED_ZONE, NULL); + if (IS_ERR(sflegc_pools_ivSlab)) { + err = PTR_ERR(sflegc_pools_ivSlab); pr_err("Could not create IV slab cache; error %d\n", err); goto err_create_iv_slab; } @@ -131,28 +131,28 @@ int sflc_pools_init(void) err_create_iv_slab: - mempool_destroy(sflc_pools_decryptWorkPool); + mempool_destroy(sflegc_pools_decryptWorkPool); err_decrypt_work_pool: - kmem_cache_destroy(sflc_pools_decryptWorkSlab); + kmem_cache_destroy(sflegc_pools_decryptWorkSlab); err_create_decrypt_work_slab: - mempool_destroy(sflc_pools_writeWorkPool); + mempool_destroy(sflegc_pools_writeWorkPool); err_write_work_pool: - kmem_cache_destroy(sflc_pools_writeWorkSlab); + kmem_cache_destroy(sflegc_pools_writeWorkSlab); err_create_write_work_slab: - mempool_destroy(sflc_pools_pagePool); + mempool_destroy(sflegc_pools_pagePool); err_pagepool: - bioset_exit(&sflc_pools_bioset); + bioset_exit(&sflegc_pools_bioset); err_bioset: return err; } -void sflc_pools_exit(void) +void sflegc_pools_exit(void) { - kmem_cache_destroy(sflc_pools_ivSlab); - mempool_destroy(sflc_pools_decryptWorkPool); - kmem_cache_destroy(sflc_pools_decryptWorkSlab); - mempool_destroy(sflc_pools_writeWorkPool); - kmem_cache_destroy(sflc_pools_writeWorkSlab); - mempool_destroy(sflc_pools_pagePool); - bioset_exit(&sflc_pools_bioset); + kmem_cache_destroy(sflegc_pools_ivSlab); + mempool_destroy(sflegc_pools_decryptWorkPool); + kmem_cache_destroy(sflegc_pools_decryptWorkSlab); + mempool_destroy(sflegc_pools_writeWorkPool); + kmem_cache_destroy(sflegc_pools_writeWorkSlab); + mempool_destroy(sflegc_pools_pagePool); + bioset_exit(&sflegc_pools_bioset); } diff --git a/dm-sflc/utils/pools.h b/dm-sflc/src/legacy/utils/pools.h similarity index 80% rename from dm-sflc/utils/pools.h rename to dm-sflc/src/legacy/utils/pools.h index e0a1261..46427d5 100644 --- a/dm-sflc/utils/pools.h +++ b/dm-sflc/src/legacy/utils/pools.h @@ -25,31 +25,31 @@ * A set of memory pools */ -#ifndef _SFLC_UTILS_POOLS_H_ -#define _SFLC_UTILS_POOLS_H_ +#ifndef _SFLEGC_UTILS_POOLS_H_ +#define _SFLEGC_UTILS_POOLS_H_ /***************************************************** * INCLUDE SECTION * *****************************************************/ -#include "device/device.h" +#include "legacy/device/device.h" /***************************************************** * PUBLIC VARIABLES DECLARATIONS * *****************************************************/ -extern struct bio_set sflc_pools_bioset; -extern mempool_t * sflc_pools_pagePool; -extern mempool_t * sflc_pools_writeWorkPool; -extern mempool_t * sflc_pools_decryptWorkPool; -extern struct kmem_cache * sflc_pools_ivSlab; +extern struct bio_set sflegc_pools_bioset; +extern mempool_t * sflegc_pools_pagePool; +extern mempool_t * sflegc_pools_writeWorkPool; +extern mempool_t * sflegc_pools_decryptWorkPool; +extern struct kmem_cache * sflegc_pools_ivSlab; /***************************************************** * PUBLIC FUNCTIONS PROTOTYPES * *****************************************************/ -int sflc_pools_init(void); -void sflc_pools_exit(void); +int sflegc_pools_init(void); +void sflegc_pools_exit(void); -#endif /* _SFLC_UTILS_POOLS_H_ */ +#endif /* _SFLEGC_UTILS_POOLS_H_ */ diff --git a/dm-sflc/utils/string.c b/dm-sflc/src/legacy/utils/string.c similarity index 92% rename from dm-sflc/utils/string.c rename to dm-sflc/src/legacy/utils/string.c index 0199dae..cd231a2 100644 --- a/dm-sflc/utils/string.c +++ b/dm-sflc/src/legacy/utils/string.c @@ -31,15 +31,15 @@ #include -#include "string.h" -#include "log/log.h" +#include "legacy/utils/string.h" +#include "legacy/log/log.h" /***************************************************** * PUBLIC FUNCTIONS DEFINITIONS * *****************************************************/ -int sflc_str_hexDecode(char * hex, u8 * bin) +int sflegc_str_hexDecode(char * hex, u8 * bin) { char buf[3]; unsigned len; @@ -64,7 +64,7 @@ int sflc_str_hexDecode(char * hex, u8 * bin) } -void sflc_str_replaceAll(char * str, char old, char new) +void sflegc_str_replaceAll(char * str, char old, char new) { int i; diff --git a/dm-sflc/utils/string.h b/dm-sflc/src/legacy/utils/string.h similarity index 88% rename from dm-sflc/utils/string.h rename to dm-sflc/src/legacy/utils/string.h index 8ac29df..40aa5c1 100644 --- a/dm-sflc/utils/string.h +++ b/dm-sflc/src/legacy/utils/string.h @@ -25,8 +25,8 @@ * A collection of utility string functions */ -#ifndef _SFLC_UTILS_STRING_H_ -#define _SFLC_UTILS_STRING_H_ +#ifndef _SFLEGC_UTILS_STRING_H_ +#define _SFLEGC_UTILS_STRING_H_ /***************************************************** * INCLUDE SECTION * @@ -38,8 +38,8 @@ * PUBLIC FUNCTIONS PROTOTYPES * *****************************************************/ -int sflc_str_hexDecode(char * hex, u8 * bin); -void sflc_str_replaceAll(char * str, char old, char new); +int sflegc_str_hexDecode(char * hex, u8 * bin); +void sflegc_str_replaceAll(char * str, char old, char new); -#endif /* _SFLC_UTILS_STRING_H_ */ +#endif /* _SFLEGC_UTILS_STRING_H_ */ diff --git a/dm-sflc/utils/vector.c b/dm-sflc/src/legacy/utils/vector.c similarity index 83% rename from dm-sflc/utils/vector.c rename to dm-sflc/src/legacy/utils/vector.c index 5ad0939..536997d 100644 --- a/dm-sflc/utils/vector.c +++ b/dm-sflc/src/legacy/utils/vector.c @@ -29,9 +29,9 @@ * INCLUDE SECTION * *****************************************************/ -#include "vector.h" -#include "crypto/rand/rand.h" -#include "log/log.h" +#include "legacy/utils/vector.h" +#include "legacy/crypto/rand/rand.h" +#include "legacy/log/log.h" /***************************************************** @@ -39,22 +39,22 @@ *****************************************************/ /* Shuffle a vector of u32's with the Fisher-Yates algorithm */ -int sflc_vec_u32shuffle(u32 *v, u32 len) +int sflegc_vec_u32shuffle(u32 *v, u32 len) { u32 i; for (i = len-1; i >= 1; i--) { /* Sample a random index from 0 to i (inclusive) */ - s32 j = sflc_rand_uniform(i+1); + s32 j = sflegc_rand_uniform(i+1); if (j < 0) { pr_err("Could not sample j; error %d", j); return j; } - /* Swap v[i] and v[j] */ - u32 tmp = v[i]; - v[i] = v[j]; - v[j] = tmp; + /* Swap v[i] and v[j] (without third variable 'cuz we're cool) */ + v[i] ^= v[j]; // v[i] <- a XOR b + v[j] ^= v[i]; // v[j] <- b XOR (a XOR b) = a + v[i] ^= v[j]; // v[i] <- (a XOR b) XOR a = b } return 0; diff --git a/dm-sflc/utils/vector.h b/dm-sflc/src/legacy/utils/vector.h similarity index 91% rename from dm-sflc/utils/vector.h rename to dm-sflc/src/legacy/utils/vector.h index 4edc7ff..a734cfc 100644 --- a/dm-sflc/utils/vector.h +++ b/dm-sflc/src/legacy/utils/vector.h @@ -25,8 +25,8 @@ * A collection of utility vector functions */ -#ifndef _SFLC_UTILS_VECTOR_H_ -#define _SFLC_UTILS_VECTOR_H_ +#ifndef _SFLEGC_UTILS_VECTOR_H_ +#define _SFLEGC_UTILS_VECTOR_H_ /***************************************************** * INCLUDE SECTION * @@ -39,7 +39,7 @@ *****************************************************/ /* Shuffle a vector of u32's */ -int sflc_vec_u32shuffle(u32 *v, u32 len); +int sflegc_vec_u32shuffle(u32 *v, u32 len); -#endif /* _SFLC_UTILS_VECTOR_H_ */ +#endif /* _SFLEGC_UTILS_VECTOR_H_ */ diff --git a/dm-sflc/utils/workqueues.c b/dm-sflc/src/legacy/utils/workqueues.c similarity index 75% rename from dm-sflc/utils/workqueues.c rename to dm-sflc/src/legacy/utils/workqueues.c index 15697b1..d069027 100644 --- a/dm-sflc/utils/workqueues.c +++ b/dm-sflc/src/legacy/utils/workqueues.c @@ -28,42 +28,42 @@ * INCLUDE SECTION * *****************************************************/ -#include "workqueues.h" -#include "log/log.h" +#include "legacy/utils/workqueues.h" +#include "legacy/log/log.h" /***************************************************** * CONSTANTS * *****************************************************/ -#define SFLC_QUEUES_WRITE_WQ_NAME "sflc_write_workqueue" -#define SFLC_QUEUES_DECRYPT_WQ_NAME "sflc_decrypt_workqueue" +#define SFLEGC_QUEUES_WRITE_WQ_NAME "sflegc_write_workqueue" +#define SFLEGC_QUEUES_DECRYPT_WQ_NAME "sflegc_decrypt_workqueue" /***************************************************** * PUBLIC VARIABLES DEFINITIONS * *****************************************************/ -struct workqueue_struct * sflc_queues_writeQueue; -struct workqueue_struct * sflc_queues_decryptQueue; +struct workqueue_struct * sflegc_queues_writeQueue; +struct workqueue_struct * sflegc_queues_decryptQueue; /***************************************************** * PUBLIC FUNCTIONS DEFINITIONS * *****************************************************/ -int sflc_queues_init(void) +int sflegc_queues_init(void) { int err; /* Write workqueue */ - sflc_queues_writeQueue = create_workqueue(SFLC_QUEUES_WRITE_WQ_NAME); - if (!sflc_queues_writeQueue) { + sflegc_queues_writeQueue = create_workqueue(SFLEGC_QUEUES_WRITE_WQ_NAME); + if (!sflegc_queues_writeQueue) { pr_err("Could not create write workqueue\n"); err = -ENOMEM; goto err_write_queue; } /* Decrypt workqueue */ - sflc_queues_decryptQueue = create_workqueue(SFLC_QUEUES_DECRYPT_WQ_NAME); - if (!sflc_queues_decryptQueue) { + sflegc_queues_decryptQueue = create_workqueue(SFLEGC_QUEUES_DECRYPT_WQ_NAME); + if (!sflegc_queues_decryptQueue) { pr_err("Could not create decrypt workqueue\n"); err = -ENOMEM; goto err_decrypt_queue; @@ -73,13 +73,13 @@ int sflc_queues_init(void) err_decrypt_queue: - destroy_workqueue(sflc_queues_writeQueue); + destroy_workqueue(sflegc_queues_writeQueue); err_write_queue: return err; } -void sflc_queues_exit(void) +void sflegc_queues_exit(void) { - destroy_workqueue(sflc_queues_decryptQueue); - destroy_workqueue(sflc_queues_writeQueue); + destroy_workqueue(sflegc_queues_decryptQueue); + destroy_workqueue(sflegc_queues_writeQueue); } diff --git a/dm-sflc/utils/workqueues.h b/dm-sflc/src/legacy/utils/workqueues.h similarity index 86% rename from dm-sflc/utils/workqueues.h rename to dm-sflc/src/legacy/utils/workqueues.h index 38fb031..8c04dcd 100644 --- a/dm-sflc/utils/workqueues.h +++ b/dm-sflc/src/legacy/utils/workqueues.h @@ -25,8 +25,8 @@ * A set of workqueues */ -#ifndef _SFLC_UTILS_QUEUES_H_ -#define _SFLC_UTILS_QUEUES_H_ +#ifndef _SFLEGC_UTILS_QUEUES_H_ +#define _SFLEGC_UTILS_QUEUES_H_ /***************************************************** * INCLUDE SECTION * @@ -38,15 +38,15 @@ * PUBLIC VARIABLES DECLARATIONS * *****************************************************/ -extern struct workqueue_struct * sflc_queues_writeQueue; -extern struct workqueue_struct * sflc_queues_decryptQueue; +extern struct workqueue_struct * sflegc_queues_writeQueue; +extern struct workqueue_struct * sflegc_queues_decryptQueue; /***************************************************** * PUBLIC FUNCTIONS PROTOTYPES * *****************************************************/ -int sflc_queues_init(void); -void sflc_queues_exit(void); +int sflegc_queues_init(void); +void sflegc_queues_exit(void); -#endif /* _SFLC_UTILS_QUEUES_H_ */ +#endif /* _SFLEGC_UTILS_QUEUES_H_ */ diff --git a/dm-sflc/volume/fmap.c b/dm-sflc/src/legacy/volume/fmap.c similarity index 69% rename from dm-sflc/volume/fmap.c rename to dm-sflc/src/legacy/volume/fmap.c index f7af843..c0ca78c 100644 --- a/dm-sflc/volume/fmap.c +++ b/dm-sflc/src/legacy/volume/fmap.c @@ -29,12 +29,10 @@ * INCLUDE SECTION * *****************************************************/ -#include - -#include "volume.h" -#include "crypto/rand/rand.h" -#include "utils/pools.h" -#include "log/log.h" +#include "legacy/volume/volume.h" +#include "legacy/crypto/rand/rand.h" +#include "legacy/utils/pools.h" +#include "legacy/log/log.h" /***************************************************** * CONSTANTS * @@ -44,8 +42,7 @@ * PRIVATE FUNCTIONS PROTOTYPES * *****************************************************/ -static s32 sflc_vol_mapSlice(sflc_Volume * vol, u32 lsi, int op); -static int sflc_vol_reassignLsi(sflc_Volume *vol, u32 lsi, u32 old_psi); +static s32 sflegc_vol_mapSlice(sflegc_Volume * vol, u32 lsi, int op); /***************************************************** * PUBLIC FUNCTIONS DEFINITIONS * @@ -53,28 +50,28 @@ static int sflc_vol_reassignLsi(sflc_Volume *vol, u32 lsi, u32 old_psi); /* Maps a logical 512-byte sector to a physical 512-byte sector. Returns < 0 if error. * Specifically, if op == READ, and the logical slice is unmapped, -ENXIO is returned. */ -s64 sflc_vol_remapSector(sflc_Volume * vol, sector_t log_sector, int op, u32 * psi_out, u32 * off_in_slice_out) +s64 sflegc_vol_remapSector(sflegc_Volume * vol, sector_t log_sector, int op, u32 * psi_out, u32 * off_in_slice_out) { u32 lsi; u32 off_in_slice; s32 psi; sector_t phys_sector; - sflc_Device *dev = vol->dev; + sflegc_Device *dev = vol->dev; /* Start by scaling down to a Shufflecake sector */ - log_sector /= SFLC_DEV_SECTOR_SCALE; + log_sector /= SFLEGC_DEV_SECTOR_SCALE; /* Get the logical slice index it belongs to */ - lsi = log_sector / SFLC_VOL_LOG_SLICE_SIZE; + lsi = log_sector / SFLEGC_VOL_LOG_SLICE_SIZE; /* Get which block it is within the slice */ - off_in_slice = log_sector % SFLC_VOL_LOG_SLICE_SIZE; + off_in_slice = log_sector % SFLEGC_VOL_LOG_SLICE_SIZE; /* Output the off_in_slice */ if (off_in_slice_out) { *off_in_slice_out = off_in_slice; } /* Map it to a physical slice */ - psi = sflc_vol_mapSlice(vol, lsi, op); + psi = sflegc_vol_mapSlice(vol, lsi, op); /* -ENXIO is a special case */ if (psi == -ENXIO) { pr_debug("mapSlice returned -ENXIO: stupid READ\n"); @@ -91,20 +88,20 @@ s64 sflc_vol_remapSector(sflc_Volume * vol, sector_t log_sector, int op, u32 * p } /* Get the physical sector (the first of every slice contains the IVs) */ - phys_sector = ((sector_t)psi * SFLC_DEV_PHYS_SLICE_SIZE) + 1 + off_in_slice; + phys_sector = ((sector_t)psi * SFLEGC_DEV_PHYS_SLICE_SIZE) + 1 + off_in_slice; /* Add the device header */ phys_sector += dev->dev_header_size; /* Scale it back up to a kernel sector */ - phys_sector *= SFLC_DEV_SECTOR_SCALE; + phys_sector *= SFLEGC_DEV_SECTOR_SCALE; return phys_sector; } /* Loads (and decrypts) the position map from the volume's header */ -int sflc_vol_loadFmap(sflc_Volume * vol) +int sflegc_vol_loadFmap(sflegc_Volume * vol) { - sflc_Device * dev = vol->dev; + sflegc_Device * dev = vol->dev; sector_t sector; struct page * iv_page; u8 * iv_ptr; @@ -114,12 +111,12 @@ int sflc_vol_loadFmap(sflc_Volume * vol) int err; /* Allocate pages */ - iv_page = mempool_alloc(sflc_pools_pagePool, GFP_NOIO); + iv_page = mempool_alloc(sflegc_pools_pagePool, GFP_NOIO); if (!iv_page) { pr_err("Could not allocate IV page\n"); return -ENOMEM; } - data_page = mempool_alloc(sflc_pools_pagePool, GFP_NOIO); + data_page = mempool_alloc(sflegc_pools_pagePool, GFP_NOIO); if (!data_page) { pr_err("Could not allocate data page\n"); return -ENOMEM; @@ -148,7 +145,7 @@ int sflc_vol_loadFmap(sflc_Volume * vol) int i; for (i = 0; i < dev->vol_header_nr_iv_blocks && lsi < dev->tot_slices; i++) { /* Load the IV block */ - err = sflc_dev_rwSector(dev, iv_page, sector, READ); + err = sflegc_dev_rwSector(dev, iv_page, sector, READ); if (err) { pr_err("Could not read IV block i=%d at sector %llu; error %d\n", i, sector, err); goto out; @@ -157,9 +154,9 @@ int sflc_vol_loadFmap(sflc_Volume * vol) /* Loop over the 256 data blocks */ int j; - for (j = 0; j < SFLC_DEV_SECTOR_TO_IV_RATIO && lsi < dev->tot_slices; j++) { + for (j = 0; j < SFLEGC_DEV_SECTOR_TO_IV_RATIO && lsi < dev->tot_slices; j++) { /* Load the data block */ - err = sflc_dev_rwSector(dev, data_page, sector, READ); + err = sflegc_dev_rwSector(dev, data_page, sector, READ); if (err) { pr_err("Could not read data block i=%d, j=%d at sector %llu; error %d\n", i, j, sector, err); goto out; @@ -167,7 +164,7 @@ int sflc_vol_loadFmap(sflc_Volume * vol) sector += 1; /* Decrypt it in place */ - err = sflc_sk_decrypt(vol->skctx, data_ptr, data_ptr, SFLC_DEV_SECTOR_SIZE, (iv_ptr + j*SFLC_SK_IV_LEN)); + err = sflegc_sk_decrypt(vol->skctx, data_ptr, data_ptr, SFLEGC_DEV_SECTOR_SIZE, (iv_ptr + j*SFLEGC_SK_IV_LEN)); if (err) { pr_err("Could not decrypt data block i=%d, j=%d at sector %llu; error %d\n", i, j, sector, err); goto out; @@ -175,42 +172,22 @@ int sflc_vol_loadFmap(sflc_Volume * vol) /* Loop over the 1024 fmap entries in this data block */ int k; - for (k = 0; k < SFLC_VOL_HEADER_MAPPINGS_PER_BLOCK && lsi < dev->tot_slices; k++) { + for (k = 0; k < SFLEGC_VOL_HEADER_MAPPINGS_PER_BLOCK && lsi < dev->tot_slices; k++) { /* An entry is just a single big-endian PSI, the LSI is implicitly the index of this entry */ __be32 * be_psi = (void *) (data_ptr + (k * sizeof(__be32))); u32 psi = be32_to_cpu(*be_psi); - /* If unassigned, just move on */ - if (psi == SFLC_VOL_FMAP_INVALID_PSI) { - vol->fmap[lsi] = psi; - /* Next iteration */ - lsi += 1; - continue; + /* Add mapping to the volume's fmap */ + vol->fmap[lsi] = psi; + /* Also add it to the device's rmap and to the count, if LSI is actually mapped */ + if (psi != SFLEGC_VOL_FMAP_INVALID_PSI) { + sflegc_dev_markPsiTaken(dev, psi, vol->vol_idx); + vol->mapped_slices += 1; } - /* If already assigned to lower-order volume, sample a new one */ - if (!sflc_dev_isPsiFree(dev, psi)) { - pr_warn("Corruption of volume %d: LSI %u was evicted from PSI %u\n", - vol->vol_idx, lsi, psi); - err = sflc_vol_reassignLsi(vol, lsi, psi); - if (err) { - pr_err("Could not reassign evicted LSI; " - "error %d\n", err); - goto out; - } - - /* Next iteration */ - lsi += 1; - } else { - /* Just assign */ - vol->fmap[lsi] = psi; - sflc_dev_markPsiTaken(dev, psi, vol->vol_idx); - vol->mapped_slices += 1; - - /* Next iteration */ - lsi += 1; - } + /* Next iteration */ + lsi += 1; } } } @@ -225,16 +202,16 @@ out: kunmap(iv_page); kunmap(data_page); /* Free them */ - mempool_free(iv_page, sflc_pools_pagePool); - mempool_free(data_page, sflc_pools_pagePool); + mempool_free(iv_page, sflegc_pools_pagePool); + mempool_free(data_page, sflegc_pools_pagePool); return err; } /* Stores (and encrypts) the position map to the volume's header */ -int sflc_vol_storeFmap(sflc_Volume * vol) +int sflegc_vol_storeFmap(sflegc_Volume * vol) { - sflc_Device * dev = vol->dev; + sflegc_Device * dev = vol->dev; sector_t sector; struct page * iv_page; u8 * iv_ptr; @@ -244,12 +221,12 @@ int sflc_vol_storeFmap(sflc_Volume * vol) int err; /* Allocate pages */ - iv_page = mempool_alloc(sflc_pools_pagePool, GFP_NOIO); + iv_page = mempool_alloc(sflegc_pools_pagePool, GFP_NOIO); if (!iv_page) { pr_err("Could not allocate IV page\n"); return -ENOMEM; } - data_page = mempool_alloc(sflc_pools_pagePool, GFP_NOIO); + data_page = mempool_alloc(sflegc_pools_pagePool, GFP_NOIO); if (!data_page) { pr_err("Could not allocate data page\n"); return -ENOMEM; @@ -278,13 +255,13 @@ int sflc_vol_storeFmap(sflc_Volume * vol) int i; for (i = 0; i < dev->vol_header_nr_iv_blocks && lsi < dev->tot_slices; i++) { /* Fill the IV block with random bytes */ - err = sflc_rand_getBytes(iv_ptr, SFLC_DEV_SECTOR_SIZE); + err = sflegc_rand_getBytes(iv_ptr, SFLEGC_DEV_SECTOR_SIZE); if (err) { pr_err("Could not sample random IV for block i=%d at sector %llu; error %d\n", i, sector, err); goto out; } /* Store it on the disk (before it gets changed by the encryption) */ - err = sflc_dev_rwSector(dev, iv_page, sector, WRITE); + err = sflegc_dev_rwSector(dev, iv_page, sector, WRITE); if (err) { pr_err("Could not read IV block i=%d at sector %llu; error %d\n", i, sector, err); goto out; @@ -293,10 +270,10 @@ int sflc_vol_storeFmap(sflc_Volume * vol) /* Loop over the 256 data blocks */ int j; - for (j = 0; j < SFLC_DEV_SECTOR_TO_IV_RATIO && lsi < dev->tot_slices; j++) { + for (j = 0; j < SFLEGC_DEV_SECTOR_TO_IV_RATIO && lsi < dev->tot_slices; j++) { /* Loop over the 1024 fmap entries that fit in this data block */ int k; - for (k = 0; k < SFLC_VOL_HEADER_MAPPINGS_PER_BLOCK && lsi < dev->tot_slices; k++) { + for (k = 0; k < SFLEGC_VOL_HEADER_MAPPINGS_PER_BLOCK && lsi < dev->tot_slices; k++) { /* Get the PSI for the current LSI */ u32 psi = vol->fmap[lsi]; /* Write it into the block as big-endian */ @@ -308,14 +285,14 @@ int sflc_vol_storeFmap(sflc_Volume * vol) } /* Encrypt it in place */ - err = sflc_sk_encrypt(vol->skctx, data_ptr, data_ptr, SFLC_DEV_SECTOR_SIZE, (iv_ptr + j*SFLC_SK_IV_LEN)); + err = sflegc_sk_encrypt(vol->skctx, data_ptr, data_ptr, SFLEGC_DEV_SECTOR_SIZE, (iv_ptr + j*SFLEGC_SK_IV_LEN)); if (err) { pr_err("Could not encrypt data block i=%d, j=%d at sector %llu; error %d\n", i, j, sector, err); goto out; } /* Store the data block */ - err = sflc_dev_rwSector(dev, data_page, sector, WRITE); + err = sflegc_dev_rwSector(dev, data_page, sector, WRITE); if (err) { pr_err("Could not write data block i=%d, j=%d at sector %llu; error %d\n", i, j, sector, err); goto out; @@ -334,8 +311,8 @@ out: kunmap(iv_page); kunmap(data_page); /* Free them */ - mempool_free(iv_page, sflc_pools_pagePool); - mempool_free(data_page, sflc_pools_pagePool); + mempool_free(iv_page, sflegc_pools_pagePool); + mempool_free(data_page, sflegc_pools_pagePool); return err; } @@ -344,10 +321,10 @@ out: * PRIVATE FUNCTIONS DEFINITIONS * *****************************************************/ -static s32 sflc_vol_mapSlice(sflc_Volume * vol, u32 lsi, int op) +static s32 sflegc_vol_mapSlice(sflegc_Volume * vol, u32 lsi, int op) { s32 psi; - sflc_Device * dev = vol->dev; + sflegc_Device * dev = vol->dev; /* Lock the volume's forward map */ if (mutex_lock_interruptible(&vol->fmap_lock)) { @@ -356,7 +333,7 @@ static s32 sflc_vol_mapSlice(sflc_Volume * vol, u32 lsi, int op) } /* If slice is already mapped, just return the mapping */ - if (vol->fmap[lsi] != SFLC_VOL_FMAP_INVALID_PSI) { + if (vol->fmap[lsi] != SFLEGC_VOL_FMAP_INVALID_PSI) { mutex_unlock(&vol->fmap_lock); return vol->fmap[lsi]; } @@ -377,7 +354,7 @@ static s32 sflc_vol_mapSlice(sflc_Volume * vol, u32 lsi, int op) } /* Get a free physical slice */ - psi = sflc_dev_getNextRandomFreePsi(dev); + psi = sflegc_dev_getNextRandomFreePsi(dev); if (psi < 0) { pr_err("Could not get a random free physical slice; error %d\n", psi); mutex_unlock(&dev->slices_lock); @@ -389,7 +366,7 @@ static s32 sflc_vol_mapSlice(sflc_Volume * vol, u32 lsi, int op) vol->fmap[lsi] = psi; vol->mapped_slices += 1; /* And in the device's rmap */ - sflc_dev_markPsiTaken(dev, psi, vol->vol_idx); + sflegc_dev_markPsiTaken(dev, psi, vol->vol_idx); /* Unlock both maps */ mutex_unlock(&dev->slices_lock); @@ -397,58 +374,3 @@ static s32 sflc_vol_mapSlice(sflc_Volume * vol, u32 lsi, int op) return psi; } - - -static int sflc_vol_reassignLsi(sflc_Volume *vol, u32 lsi, u32 old_psi) -{ - sflc_Device *dev = vol->dev; - s32 new_psi; -// void *vma; - int err; - -// /* Allocate array holding the raw PSI */ -// vma = vmalloc(SFLC_DEV_PHYS_SLICE_SIZE * SFLC_DEV_SECTOR_SIZE); -// if (!vma) { -// pr_err("Could not allocate VMA for raw PSI"); -// return -ENOMEM; -// } - - /* Sample new PSI */ - new_psi = sflc_dev_getNextRandomFreePsi(dev); - if (new_psi < 0) { - err = new_psi; - pr_err("Could not sample new PSI for evicted LSI; " - "error %d\n", err); - goto out; - } - -// /* Read PSI contents */ -// err = sflc_dev_rwPsi(dev, vma, old_psi, READ); -// if (err) { -// pr_err("Could not read PSI; error %d", err); -// goto out; -// } -// -// /* Write them to new location */ -// err = sflc_dev_rwPsi(dev, vma, new_psi, WRITE); -// if (err) { -// pr_err("Could not write PSI; error %d", err); -// goto out; -// } - - /* Assign */ - vol->fmap[lsi] = new_psi; - sflc_dev_markPsiTaken(dev, new_psi, vol->vol_idx); - vol->mapped_slices += 1; - - pr_notice("Volume %d reassign LSI %u -> PSI %u", - vol->vol_idx, lsi, new_psi); - - /* No prob */ - err = 0; - -out: -// vfree(vma); - return err; -} - diff --git a/dm-sflc/volume/io.c b/dm-sflc/src/legacy/volume/io.c similarity index 83% rename from dm-sflc/volume/io.c rename to dm-sflc/src/legacy/volume/io.c index 71ecc9c..3f97de7 100644 --- a/dm-sflc/volume/io.c +++ b/dm-sflc/src/legacy/volume/io.c @@ -29,10 +29,10 @@ * INCLUDE SECTION * *****************************************************/ -#include "volume.h" -#include "utils/pools.h" -#include "utils/workqueues.h" -#include "log/log.h" +#include "legacy/volume/volume.h" +#include "legacy/utils/pools.h" +#include "legacy/utils/workqueues.h" +#include "legacy/log/log.h" /***************************************************** * CONSTANTS * @@ -47,7 +47,7 @@ *****************************************************/ /* Remaps the underlying block device and the sector number */ -int sflc_vol_remapBioFast(sflc_Volume * vol, struct bio * bio) +int sflegc_vol_remapBioFast(sflegc_Volume * vol, struct bio * bio) { s64 phys_sector; int err; @@ -56,7 +56,7 @@ int sflc_vol_remapBioFast(sflc_Volume * vol, struct bio * bio) bio_set_dev(bio, vol->dev->bdev->bdev); /* Remap the starting sector (we don't care about PSI and off_in_slice). Also no slice allocation */ - phys_sector = sflc_vol_remapSector(vol, bio->bi_iter.bi_sector, READ, NULL, NULL); + phys_sector = sflegc_vol_remapSector(vol, bio->bi_iter.bi_sector, READ, NULL, NULL); if (phys_sector < 0) { err = (int) phys_sector; pr_err("Could not remap sector; error %d\n", err); @@ -68,18 +68,18 @@ int sflc_vol_remapBioFast(sflc_Volume * vol, struct bio * bio) } /* Submits the bio to the device's workqueue */ -int sflc_vol_processBio(sflc_Volume * vol, struct bio * bio) +int sflegc_vol_processBio(sflegc_Volume * vol, struct bio * bio) { - sflc_vol_WriteWork * write_work; + sflegc_vol_WriteWork * write_work; /* If it is a READ, no need to pass it through a workqueue */ if (bio_data_dir(bio) == READ) { - sflc_vol_doRead(vol, bio); + sflegc_vol_doRead(vol, bio); return 0; } /* Allocate writeWork structure */ - write_work = mempool_alloc(sflc_pools_writeWorkPool, GFP_NOIO); + write_work = mempool_alloc(sflegc_pools_writeWorkPool, GFP_NOIO); if (!write_work) { pr_err("Failed allocation of work structure\n"); return -ENOMEM; @@ -88,10 +88,10 @@ int sflc_vol_processBio(sflc_Volume * vol, struct bio * bio) /* Set fields */ write_work->vol = vol; write_work->orig_bio = bio; - INIT_WORK(&write_work->work, sflc_vol_doWrite); + INIT_WORK(&write_work->work, sflegc_vol_doWrite); /* Enqueue */ - queue_work(sflc_queues_writeQueue, &write_work->work); + queue_work(sflegc_queues_writeQueue, &write_work->work); return 0; } diff --git a/dm-sflc/volume/read.c b/dm-sflc/src/legacy/volume/read.c similarity index 72% rename from dm-sflc/volume/read.c rename to dm-sflc/src/legacy/volume/read.c index 2d64784..0fb424a 100644 --- a/dm-sflc/volume/read.c +++ b/dm-sflc/src/legacy/volume/read.c @@ -32,10 +32,10 @@ * INCLUDE SECTION * *****************************************************/ -#include "volume.h" -#include "utils/pools.h" -#include "utils/workqueues.h" -#include "log/log.h" +#include "legacy/volume/volume.h" +#include "legacy/utils/pools.h" +#include "legacy/utils/workqueues.h" +#include "legacy/log/log.h" #include @@ -47,28 +47,28 @@ * PRIVATE FUNCTIONS PROTOTYPES * *****************************************************/ -static void sflc_vol_fillBioWithZeros(struct bio * orig_bio); -static void sflc_vol_readEndIo(struct bio * phys_bio); -static void sflc_vol_readEndIoBottomHalf(struct work_struct * work); -static int sflc_vol_decryptBio(sflc_Volume * vol, struct bio * orig_bio, u32 psi, u32 off_in_slice); -static int sflc_vol_fetchIv(sflc_Volume * vol, u8 * iv, u32 psi, u32 off_in_slice); +static void sflegc_vol_fillBioWithZeros(struct bio * orig_bio); +static void sflegc_vol_readEndIo(struct bio * phys_bio); +static void sflegc_vol_readEndIoBottomHalf(struct work_struct * work); +static int sflegc_vol_decryptBio(sflegc_Volume * vol, struct bio * orig_bio, u32 psi, u32 off_in_slice); +static int sflegc_vol_fetchIv(sflegc_Volume * vol, u8 * iv, u32 psi, u32 off_in_slice); /***************************************************** * PUBLIC FUNCTIONS DEFINITIONS * *****************************************************/ -/* Executed in context from sflc_tgt_map() */ -void sflc_vol_doRead(sflc_Volume * vol, struct bio * bio) +/* Executed in context from sflegc_tgt_map() */ +void sflegc_vol_doRead(sflegc_Volume * vol, struct bio * bio) { - sflc_Device * dev = vol->dev; + sflegc_Device * dev = vol->dev; struct bio * orig_bio = bio; struct bio * phys_bio; s64 phys_sector; - sflc_vol_DecryptWork * dec_work; + sflegc_vol_DecryptWork * dec_work; blk_status_t status; /* Allocate decryptWork structure */ - dec_work = mempool_alloc(sflc_pools_decryptWorkPool, GFP_NOIO); + dec_work = mempool_alloc(sflegc_pools_decryptWorkPool, GFP_NOIO); if (!dec_work) { pr_err("Could not allocate decryptWork structure\n"); status = BLK_STS_IOERR; @@ -83,7 +83,7 @@ void sflc_vol_doRead(sflc_Volume * vol, struct bio * bio) we can decrypt in place. */ /* Shallow copy */ - phys_bio = bio_alloc_clone(dev->bdev->bdev, orig_bio, GFP_NOIO, &sflc_pools_bioset); + phys_bio = bio_alloc_clone(dev->bdev->bdev, orig_bio, GFP_NOIO, &sflegc_pools_bioset); if (!phys_bio) { pr_err("Could not clone original bio\n"); status = BLK_STS_IOERR; @@ -91,11 +91,11 @@ void sflc_vol_doRead(sflc_Volume * vol, struct bio * bio) } /* Remap sector */ - phys_sector = sflc_vol_remapSector(vol, orig_bio->bi_iter.bi_sector, READ, &dec_work->psi, &dec_work->off_in_slice); + phys_sector = sflegc_vol_remapSector(vol, orig_bio->bi_iter.bi_sector, READ, &dec_work->psi, &dec_work->off_in_slice); /* If -ENXIO, special case: stupid READ */ if (phys_sector == -ENXIO) { pr_debug("Stupid READ. Returning all zeros\n"); - sflc_vol_fillBioWithZeros(orig_bio); + sflegc_vol_fillBioWithZeros(orig_bio); status = BLK_STS_OK; goto err_stupid_read; } @@ -113,7 +113,7 @@ void sflc_vol_doRead(sflc_Volume * vol, struct bio * bio) dec_work->orig_bio = orig_bio; dec_work->phys_bio = phys_bio; /* Set fields for the endio */ - phys_bio->bi_end_io = sflc_vol_readEndIo; + phys_bio->bi_end_io = sflegc_vol_readEndIo; phys_bio->bi_private = dec_work; /* Only submit the physical bio */ @@ -127,7 +127,7 @@ err_stupid_read: bio_put(phys_bio); err_clone_orig_bio: bio_put(orig_bio); - mempool_free(dec_work, sflc_pools_decryptWorkPool); + mempool_free(dec_work, sflegc_pools_decryptWorkPool); err_alloc_dec_work: orig_bio->bi_status = status; @@ -139,42 +139,42 @@ err_alloc_dec_work: * PRIVATE FUNCTIONS DEFINITIONS * *****************************************************/ -static void sflc_vol_fillBioWithZeros(struct bio * orig_bio) +static void sflegc_vol_fillBioWithZeros(struct bio * orig_bio) { struct bio_vec bvl = bio_iovec(orig_bio); void * sector_ptr = kmap(bvl.bv_page) + bvl.bv_offset; - memset(sector_ptr, 0, SFLC_DEV_SECTOR_SIZE); - bio_advance(orig_bio, SFLC_DEV_SECTOR_SIZE); + memset(sector_ptr, 0, SFLEGC_DEV_SECTOR_SIZE); + bio_advance(orig_bio, SFLEGC_DEV_SECTOR_SIZE); kunmap(bvl.bv_page); return; } /* Pushes all the decryption work to a workqueue bottom half */ -static void sflc_vol_readEndIo(struct bio * phys_bio) +static void sflegc_vol_readEndIo(struct bio * phys_bio) { - sflc_vol_DecryptWork * dec_work = phys_bio->bi_private; + sflegc_vol_DecryptWork * dec_work = phys_bio->bi_private; /* Init work structure */ - INIT_WORK(&dec_work->work, sflc_vol_readEndIoBottomHalf); + INIT_WORK(&dec_work->work, sflegc_vol_readEndIoBottomHalf); /* Enqueue it */ - queue_work(sflc_queues_decryptQueue, &dec_work->work); + queue_work(sflegc_queues_decryptQueue, &dec_work->work); return; } -static void sflc_vol_readEndIoBottomHalf(struct work_struct * work) +static void sflegc_vol_readEndIoBottomHalf(struct work_struct * work) { - sflc_vol_DecryptWork * dec_work = container_of(work, sflc_vol_DecryptWork, work); - sflc_Volume * vol = dec_work->vol; + sflegc_vol_DecryptWork * dec_work = container_of(work, sflegc_vol_DecryptWork, work); + sflegc_Volume * vol = dec_work->vol; struct bio * orig_bio = dec_work->orig_bio; struct bio * phys_bio = dec_work->phys_bio; blk_status_t status = phys_bio->bi_status; int err; /* Decrypt the physical bio and advance the original bio */ - err = sflc_vol_decryptBio(vol, orig_bio, dec_work->psi, dec_work->off_in_slice); + err = sflegc_vol_decryptBio(vol, orig_bio, dec_work->psi, dec_work->off_in_slice); if (err) { pr_err("Could not decrypt bio; error %d\n", err); status = BLK_STS_IOERR; @@ -189,19 +189,19 @@ static void sflc_vol_readEndIoBottomHalf(struct work_struct * work) /* Free the physical bio */ bio_put(phys_bio); /* Free the work item */ - mempool_free(dec_work, sflc_pools_decryptWorkPool); + mempool_free(dec_work, sflegc_pools_decryptWorkPool); return; } /* Decrypts the content of the physical bio, and at the same time it advances the original bio */ -static int sflc_vol_decryptBio(sflc_Volume * vol, struct bio * orig_bio, u32 psi, u32 off_in_slice) +static int sflegc_vol_decryptBio(sflegc_Volume * vol, struct bio * orig_bio, u32 psi, u32 off_in_slice) { - u8 iv[SFLC_SK_IV_LEN]; + u8 iv[SFLEGC_SK_IV_LEN]; int err; /* Fetch IV */ - err = sflc_vol_fetchIv(vol, iv, psi, off_in_slice); + err = sflegc_vol_fetchIv(vol, iv, psi, off_in_slice); if (err) { pr_err("Could not fetch IV; error %d\n", err); return err; @@ -210,7 +210,7 @@ static int sflc_vol_decryptBio(sflc_Volume * vol, struct bio * orig_bio, u32 psi /* Decrypt sector in place */ struct bio_vec bvl = bio_iovec(orig_bio); void * sector_ptr = kmap(bvl.bv_page) + bvl.bv_offset; - err = sflc_sk_decrypt(vol->skctx, sector_ptr, sector_ptr, SFLC_DEV_SECTOR_SIZE, iv); + err = sflegc_sk_decrypt(vol->skctx, sector_ptr, sector_ptr, SFLEGC_DEV_SECTOR_SIZE, iv); kunmap(bvl.bv_page); if (err) { pr_err("Error while decrypting sector: %d\n", err); @@ -218,19 +218,19 @@ static int sflc_vol_decryptBio(sflc_Volume * vol, struct bio * orig_bio, u32 psi } /* Advance original bio by one sector */ - bio_advance(orig_bio, SFLC_DEV_SECTOR_SIZE); + bio_advance(orig_bio, SFLEGC_DEV_SECTOR_SIZE); return 0; } -static int sflc_vol_fetchIv(sflc_Volume * vol, u8 * iv, u32 psi, u32 off_in_slice) +static int sflegc_vol_fetchIv(sflegc_Volume * vol, u8 * iv, u32 psi, u32 off_in_slice) { - sflc_Device * dev = vol->dev; + sflegc_Device * dev = vol->dev; u8 * iv_block; int err; /* Acquire a reference to the whole relevant IV block */ - iv_block = sflc_dev_getIvBlockRef(dev, psi, READ); + iv_block = sflegc_dev_getIvBlockRef(dev, psi, READ); if (IS_ERR(iv_block)) { err = PTR_ERR(iv_block); pr_err("Could not acquire reference to IV block; error %ld\n", PTR_ERR(iv_block)); @@ -238,10 +238,10 @@ static int sflc_vol_fetchIv(sflc_Volume * vol, u8 * iv, u32 psi, u32 off_in_slic } /* Copy the relevant portion */ - memcpy(iv, iv_block + (off_in_slice * SFLC_SK_IV_LEN), SFLC_SK_IV_LEN); + memcpy(iv, iv_block + (off_in_slice * SFLEGC_SK_IV_LEN), SFLEGC_SK_IV_LEN); /* Release reference to the IV block */ - err = sflc_dev_putIvBlockRef(dev, psi); + err = sflegc_dev_putIvBlockRef(dev, psi); if (err) { pr_err("Could not release reference to IV block; error %d\n", err); goto err_put_iv_block_ref; diff --git a/dm-sflc/volume/volume.c b/dm-sflc/src/legacy/volume/volume.c similarity index 56% rename from dm-sflc/volume/volume.c rename to dm-sflc/src/legacy/volume/volume.c index ec4dedc..e229312 100644 --- a/dm-sflc/volume/volume.c +++ b/dm-sflc/src/legacy/volume/volume.c @@ -29,8 +29,9 @@ * INCLUDE SECTION * *****************************************************/ -#include "volume.h" -#include "log/log.h" +#include "legacy/volume/volume.h" +#include "legacy/utils/string.h" +#include "legacy/log/log.h" #include @@ -39,35 +40,69 @@ * PUBLIC FUNCTIONS DEFINITIONS * *****************************************************/ -/* Creates volume and adds it to the device. Returns an ERR_PTR() if unsuccessful */ -sflc_Volume * sflc_vol_create(struct dm_target *ti, sflc_Device *dev, int vol_idx, u8 * enckey) +/** + * Creates volume. Returns an ERR_PTR() if unsuccessful + * Arguments: + * argv[0]: Shufflecake mode: legacy/lite + * argv[1]: Shufflecake-unique device ID + * argv[2]: path to underlying physical device + * argv[3]: volume index within the device + * argv[4]: number of 1 MB slices in the underlying device + * argv[5]: 32-byte encryption key (hex-encoded) + */ +sflegc_Volume * sflegc_vol_create(struct dm_target * ti, sflegc_Device* dev, + int argc, char **argv, struct kobject *kobj) { - sflc_Volume * vol; + sflegc_Volume * vol; + int vol_idx; + u8 enckey[SFLEGC_SK_KEY_LEN]; int err; - pr_debug("Called to create sflc_Volume #%d on Device %s\n", vol_idx, dev->bdev_path); - /* Allocate volume */ - vol = kzalloc(sizeof(sflc_Volume), GFP_KERNEL); + vol = kzalloc(sizeof(sflegc_Volume), GFP_KERNEL); if (!vol) { - pr_err("Could not allocate %lu bytes for sflc_Volume\n", sizeof(sflc_Volume)); + pr_err("Could not allocate %lu bytes for sflegc_Volume\n", sizeof(sflegc_Volume)); err = -ENOMEM; goto err_alloc_vol; } + /* Parse args */ + if (argc != 6) { + pr_err("Wrong argument count"); + err = -EINVAL; + goto err_parse; + } + if (sscanf(argv[3], "%u", &vol_idx) != 1) { + pr_err("Could not decode tot_slices\n"); + err = -EINVAL; + goto err_parse; + } + /* Decode the encryption key */ + if (strlen(argv[5]) != 2 * SFLEGC_SK_KEY_LEN) { + pr_err("Hexadecimal key (length %lu): %s\n", strlen(argv[5]), argv[5]); + err = -EINVAL; + goto err_parse; + } + err = sflegc_str_hexDecode(argv[5], enckey); + if (err) { + pr_err("Could not decode hexadecimal encryption key"); + err = -EINVAL; + goto err_parse; + } + /* Set volume name */ - sprintf(vol->vol_name, "sflc_%lu_%d", dev->dev_id, vol_idx); + sprintf(vol->vol_name, "sflc_%u_%d", dev->dev_id, vol_idx); /* Sysfs stuff */ - vol->kvol = sflc_sysfs_volCreateAndAdd(vol); - if (IS_ERR(vol->kvol)) { - err = PTR_ERR(vol->kvol); - pr_err("Could not create sysfs entry; error %d\n", err); + vol->kobj_parent = kobj; + err = sflegc_sysfs_add_volume(vol); + if (err) { + pr_err("Could not add volume to sysfs; error %d\n", err); goto err_sysfs; } /* Backing device */ - if (!sflc_dev_addVolume(dev, vol, vol_idx)) { + if (!sflegc_dev_addVolume(dev, vol, vol_idx)) { pr_err("Could not add volume to device\n"); err = -EINVAL; goto err_add_to_dev; @@ -76,7 +111,7 @@ sflc_Volume * sflc_vol_create(struct dm_target *ti, sflc_Device *dev, int vol_id vol->vol_idx = vol_idx; /* Crypto */ - vol->skctx = sflc_sk_createContext(enckey); + vol->skctx = sflegc_sk_createContext(enckey); if (IS_ERR(vol->skctx)) { err = PTR_ERR(vol->skctx); pr_err("Could not create crypto context\n"); @@ -97,38 +132,52 @@ sflc_Volume * sflc_vol_create(struct dm_target *ti, sflc_Device *dev, int vol_id /* Initialise fmap */ pr_notice("Volume opening for volume %s: loading fmap from header\n", vol->vol_name); - err = sflc_vol_loadFmap(vol); + err = sflegc_vol_loadFmap(vol); if (err) { pr_err("Could not load position map; error %d\n", err); goto err_load_fmap; } pr_debug("Successfully loaded position map for volume %s\n", vol->vol_name); + + /* Tell DM we want one SFLC sector at a time */ + ti->max_io_len = SFLEGC_DEV_SECTOR_SCALE; + /* Enable REQ_OP_FLUSH bios */ + ti->num_flush_bios = 1; + /* Disable REQ_OP_WRITE_ZEROES and REQ_OP_SECURE_ERASE (can't be passed through as + they would break deniability, and they would be too complicated to handle individually) */ + ti->num_secure_erase_bios = 0; + ti->num_write_zeroes_bios = 0; + /* Momentarily disable REQ_OP_DISCARD_BIOS + TODO: will need to support them to release slice mappings */ + ti->num_discard_bios = 0; + return vol; err_load_fmap: vfree(vol->fmap); err_alloc_fmap: - sflc_sk_destroyContext(vol->skctx); + sflegc_sk_destroyContext(vol->skctx); err_create_skctx: - sflc_dev_removeVolume(vol->dev, vol->vol_idx); + sflegc_dev_removeVolume(vol->dev, vol->vol_idx); err_add_to_dev: - sflc_sysfs_putVol(vol->kvol); + sflegc_sysfs_remove_volume(vol); err_sysfs: +err_parse: kfree(vol); err_alloc_vol: return ERR_PTR(err); } /* Removes the volume from the device and frees it. */ -void sflc_vol_destroy(struct dm_target * ti, sflc_Volume * vol) +void sflegc_vol_destroy(sflegc_Volume * vol) { int err; /* Store fmap */ pr_notice("Going to store position map of volume %s\n", vol->vol_name); - err = sflc_vol_storeFmap(vol); + err = sflegc_vol_storeFmap(vol); if (err) { pr_err("Could not store position map; error %d\n", err); } @@ -137,13 +186,13 @@ void sflc_vol_destroy(struct dm_target * ti, sflc_Volume * vol) vfree(vol->fmap); /* Skctx */ - sflc_sk_destroyContext(vol->skctx); + sflegc_sk_destroyContext(vol->skctx); /* Remove from device */ - sflc_dev_removeVolume(vol->dev, vol->vol_idx); + sflegc_dev_removeVolume(vol->dev, vol->vol_idx); /* Destroy sysfs entries */ - sflc_sysfs_putVol(vol->kvol); + sflegc_sysfs_remove_volume(vol); /* Free volume structure */ kfree(vol); diff --git a/dm-sflc/volume/volume.h b/dm-sflc/src/legacy/volume/volume.h similarity index 69% rename from dm-sflc/volume/volume.h rename to dm-sflc/src/legacy/volume/volume.h index 401cd97..3222433 100644 --- a/dm-sflc/volume/volume.h +++ b/dm-sflc/src/legacy/volume/volume.h @@ -26,8 +26,8 @@ * a "real" device represented by a device. */ -#ifndef _SFLC_VOLUME_VOLUME_H_ -#define _SFLC_VOLUME_VOLUME_H_ +#ifndef _SFLEGC_VOLUME_VOLUME_H_ +#define _SFLEGC_VOLUME_VOLUME_H_ /***************************************************** @@ -36,9 +36,9 @@ /* Necessary since device.h, volume.h, and sysfs.h all include each other */ -typedef struct sflc_vol_write_work_s sflc_vol_WriteWork; -typedef struct sflc_vol_decrypt_work_s sflc_vol_DecryptWork; -typedef struct sflc_volume_s sflc_Volume; +typedef struct sflegc_vol_write_work_s sflegc_vol_WriteWork; +typedef struct sflegc_vol_decrypt_work_s sflegc_vol_DecryptWork; +typedef struct sflegc_volume_s sflegc_Volume; /***************************************************** @@ -47,9 +47,9 @@ typedef struct sflc_volume_s sflc_Volume; #include -#include "device/device.h" -#include "crypto/symkey/symkey.h" -#include "sysfs/sysfs.h" +#include "legacy/sflc_legacy.h" +#include "legacy/device/device.h" +#include "legacy/crypto/symkey/symkey.h" /***************************************************** @@ -57,26 +57,26 @@ typedef struct sflc_volume_s sflc_Volume; *****************************************************/ /* A single header data block contains 1024 fmap mappings */ -#define SFLC_VOL_HEADER_MAPPINGS_PER_BLOCK (SFLC_DEV_SECTOR_SIZE / sizeof(u32)) +#define SFLEGC_VOL_HEADER_MAPPINGS_PER_BLOCK (SFLEGC_DEV_SECTOR_SIZE / sizeof(u32)) /* We split the volume's logical addressing space into 1 MB slices */ -#define SFLC_VOL_LOG_SLICE_SIZE 256 // In 4096-byte sectors +#define SFLEGC_VOL_LOG_SLICE_SIZE 256 // In 4096-byte sectors /* Value marking an LSI as unassigned */ -#define SFLC_VOL_FMAP_INVALID_PSI 0xFFFFFFFFU +#define SFLEGC_VOL_FMAP_INVALID_PSI 0xFFFFFFFFU /* The volume name is "sflc--" */ -#define SFLC_VOL_NAME_MAX_LEN 12 +#define SFLEGC_VOL_NAME_MAX_LEN 12 /***************************************************** * TYPES * *****************************************************/ -struct sflc_vol_write_work_s +struct sflegc_vol_write_work_s { /* Essential information */ - sflc_Volume * vol; + sflegc_Volume * vol; struct bio * orig_bio; /* Write requests need to allocate own page */ @@ -86,10 +86,10 @@ struct sflc_vol_write_work_s struct work_struct work; }; -struct sflc_vol_decrypt_work_s +struct sflegc_vol_decrypt_work_s { /* Essential information */ - sflc_Volume * vol; + sflegc_Volume * vol; struct bio * orig_bio; struct bio * phys_bio; @@ -101,15 +101,15 @@ struct sflc_vol_decrypt_work_s struct work_struct work; }; -struct sflc_volume_s +struct sflegc_volume_s { - /* Name of the volume, sflc--*/ - char vol_name[SFLC_VOL_NAME_MAX_LEN + 1]; + /* Name of the volume, sflc__*/ + char vol_name[SFLEGC_VOL_NAME_MAX_LEN + 1]; /* Backing device */ - sflc_Device * dev; + sflegc_Device * dev; /* Index of this volume within the device's volume array */ - int vol_idx; + u32 vol_idx; /* Forward position map */ struct mutex fmap_lock; @@ -117,11 +117,11 @@ struct sflc_volume_s /* Stats on the fmap */ u32 mapped_slices; - /* Sysfs stuff */ - sflc_sysfs_Volume * kvol; + /* Parent sysfs directory */ + struct kobject *kobj_parent; /* Crypto */ - sflc_sk_Context * skctx; + sflegc_sk_Context * skctx; }; @@ -130,27 +130,28 @@ struct sflc_volume_s *****************************************************/ /* Creates volume and adds it to the device. Returns an ERR_PTR() if unsuccessful */ -sflc_Volume * sflc_vol_create(struct dm_target * ti, sflc_Device* dev, int vol_idx, u8 * enckey); +sflegc_Volume * sflegc_vol_create(struct dm_target * ti, sflegc_Device* dev, + int argc, char **argv, struct kobject *kobj); /* Removes the volume from the device and frees it. */ -void sflc_vol_destroy(struct dm_target * ti, sflc_Volume * vol); +void sflegc_vol_destroy(sflegc_Volume * vol); /* Remaps the underlying block device and the sector number */ -int sflc_vol_remapBioFast(sflc_Volume * vol, struct bio * bio); +int sflegc_vol_remapBioFast(sflegc_Volume * vol, struct bio * bio); /* Processes the bio in the normal indirection+crypto way */ -int sflc_vol_processBio(sflc_Volume * vol, struct bio * bio); +int sflegc_vol_processBio(sflegc_Volume * vol, struct bio * bio); /* Executed in top half */ -void sflc_vol_doRead(sflc_Volume * vol, struct bio * bio); +void sflegc_vol_doRead(sflegc_Volume * vol, struct bio * bio); /* Executed in bottom half */ -void sflc_vol_doWrite(struct work_struct * work); +void sflegc_vol_doWrite(struct work_struct * work); /* Maps a logical 512-byte sector to a physical 512-byte sector. Returns < 0 if error. * Specifically, if op == READ, and the logical slice is unmapped, -ENXIO is returned. */ -s64 sflc_vol_remapSector(sflc_Volume * vol, sector_t log_sector, int op, u32 * psi_out, u32 * off_in_slice_out); +s64 sflegc_vol_remapSector(sflegc_Volume * vol, sector_t log_sector, int op, u32 * psi_out, u32 * off_in_slice_out); /* Loads (and decrypts) the position map from the volume's header */ -int sflc_vol_loadFmap(sflc_Volume * vol); +int sflegc_vol_loadFmap(sflegc_Volume * vol); /* Stores (and encrypts) the position map to the volume's header */ -int sflc_vol_storeFmap(sflc_Volume * vol); +int sflegc_vol_storeFmap(sflegc_Volume * vol); -#endif /* _SFLC_VOLUME_VOLUME_H_ */ +#endif /* _SFLEGC_VOLUME_VOLUME_H_ */ diff --git a/dm-sflc/volume/write.c b/dm-sflc/src/legacy/volume/write.c similarity index 76% rename from dm-sflc/volume/write.c rename to dm-sflc/src/legacy/volume/write.c index d6903d9..cbfb7c2 100644 --- a/dm-sflc/volume/write.c +++ b/dm-sflc/src/legacy/volume/write.c @@ -32,10 +32,10 @@ * INCLUDE SECTION * *****************************************************/ -#include "volume.h" -#include "crypto/rand/rand.h" -#include "utils/pools.h" -#include "log/log.h" +#include "legacy/volume/volume.h" +#include "legacy/crypto/rand/rand.h" +#include "legacy/utils/pools.h" +#include "legacy/log/log.h" #include @@ -47,9 +47,9 @@ * PRIVATE FUNCTIONS PROTOTYPES * *****************************************************/ -static int sflc_vol_encryptOrigBio(sflc_Volume * vol, struct bio * orig_bio, struct bio * phys_bio, u32 psi, u32 off_in_slice); -static int sflc_vol_sampleAndWriteIv(sflc_Volume * vol, u8 * iv, u32 psi, u32 off_in_slice); -static void sflc_vol_writeEndIo(struct bio * phys_bio); +static int sflegc_vol_encryptOrigBio(sflegc_Volume * vol, struct bio * orig_bio, struct bio * phys_bio, u32 psi, u32 off_in_slice); +static int sflegc_vol_sampleAndWriteIv(sflegc_Volume * vol, u8 * iv, u32 psi, u32 off_in_slice); +static void sflegc_vol_writeEndIo(struct bio * phys_bio); /***************************************************** * PRIVATE VARIABLES * @@ -60,11 +60,11 @@ static void sflc_vol_writeEndIo(struct bio * phys_bio); *****************************************************/ /* Executed in workqueue bottom half */ -void sflc_vol_doWrite(struct work_struct * work) +void sflegc_vol_doWrite(struct work_struct * work) { - sflc_vol_WriteWork * write_work = container_of(work, sflc_vol_WriteWork, work); - sflc_Volume * vol = write_work->vol; - sflc_Device * dev = vol->dev; + sflegc_vol_WriteWork * write_work = container_of(work, sflegc_vol_WriteWork, work); + sflegc_Volume * vol = write_work->vol; + sflegc_Device * dev = vol->dev; struct bio * orig_bio = write_work->orig_bio; struct bio * phys_bio; s64 phys_sector; @@ -80,14 +80,14 @@ void sflc_vol_doWrite(struct work_struct * work) non-owned bio's. So we need our own. */ /* Allocate an empty bio */ - phys_bio = bio_alloc_bioset(dev->bdev->bdev, bio_segments(orig_bio), orig_bio->bi_opf, GFP_NOIO, &sflc_pools_bioset); + phys_bio = bio_alloc_bioset(dev->bdev->bdev, bio_segments(orig_bio), orig_bio->bi_opf, GFP_NOIO, &sflegc_pools_bioset); if (!phys_bio) { pr_err("Could not allocate bio\n"); goto err_alloc_phys_bio; } /* Remap sector */ - phys_sector = sflc_vol_remapSector(vol, orig_bio->bi_iter.bi_sector, WRITE, &psi, &off_in_slice); + phys_sector = sflegc_vol_remapSector(vol, orig_bio->bi_iter.bi_sector, WRITE, &psi, &off_in_slice); if (phys_sector < 0) { pr_err("Could not remap sector for physical bio; error %d\n", (int) phys_sector); goto err_remap_sector; @@ -95,11 +95,11 @@ void sflc_vol_doWrite(struct work_struct * work) phys_bio->bi_iter.bi_sector = phys_sector; /* Set fields for the endio */ - phys_bio->bi_end_io = sflc_vol_writeEndIo; + phys_bio->bi_end_io = sflegc_vol_writeEndIo; phys_bio->bi_private = write_work; /* Encrypt the original bio into the physical bio (newly-allocated pages) */ - int err = sflc_vol_encryptOrigBio(vol, orig_bio, phys_bio, psi, off_in_slice); + int err = sflegc_vol_encryptOrigBio(vol, orig_bio, phys_bio, psi, off_in_slice); if (err) { pr_err("Could not encrypt original bio; error %d\n", err); goto err_encrypt_orig_bio; @@ -119,7 +119,6 @@ err_alloc_phys_bio: orig_bio->bi_status = BLK_STS_IOERR; bio_endio(orig_bio); - mempool_free(write_work, sflc_pools_writeWorkPool); return; } @@ -128,14 +127,14 @@ err_alloc_phys_bio: *****************************************************/ /* Encrypts the contents of the original bio into newly-allocated pages for the physical bio */ -static int sflc_vol_encryptOrigBio(sflc_Volume * vol, struct bio * orig_bio, struct bio * phys_bio, u32 psi, u32 off_in_slice) +static int sflegc_vol_encryptOrigBio(sflegc_Volume * vol, struct bio * orig_bio, struct bio * phys_bio, u32 psi, u32 off_in_slice) { - sflc_vol_WriteWork * write_work = phys_bio->bi_private; - u8 iv[SFLC_SK_IV_LEN]; + sflegc_vol_WriteWork * write_work = phys_bio->bi_private; + u8 iv[SFLEGC_SK_IV_LEN]; int err; /* Allocate new page for the physical bio */ - write_work->page = mempool_alloc(sflc_pools_pagePool, GFP_NOIO); + write_work->page = mempool_alloc(sflegc_pools_pagePool, GFP_NOIO); if (!write_work->page) { pr_err("Could not allocate page\n"); err = -ENOMEM; @@ -143,14 +142,14 @@ static int sflc_vol_encryptOrigBio(sflc_Volume * vol, struct bio * orig_bio, str } /* Add it to physical bio */ - if (!bio_add_page(phys_bio, write_work->page, SFLC_DEV_SECTOR_SIZE, 0)) { + if (!bio_add_page(phys_bio, write_work->page, SFLEGC_DEV_SECTOR_SIZE, 0)) { pr_err("Catastrophe. Could not add page to copy bio. WTF?\n"); err = -EIO; goto err_bio_add_page; } /* Sample a random IV and write it in the IV block */ - err = sflc_vol_sampleAndWriteIv(vol, iv, psi, off_in_slice); + err = sflegc_vol_sampleAndWriteIv(vol, iv, psi, off_in_slice); if (err) { pr_err("Could not sample and write IV; error %d\n", err); err = -EIO; @@ -161,7 +160,7 @@ static int sflc_vol_encryptOrigBio(sflc_Volume * vol, struct bio * orig_bio, str struct bio_vec bvl = bio_iovec(orig_bio); void * enc_sector_ptr = kmap(write_work->page); void * plain_sector_ptr = kmap(bvl.bv_page) + bvl.bv_offset; - err = sflc_sk_encrypt(vol->skctx, plain_sector_ptr, enc_sector_ptr, SFLC_DEV_SECTOR_SIZE, iv); + err = sflegc_sk_encrypt(vol->skctx, plain_sector_ptr, enc_sector_ptr, SFLEGC_DEV_SECTOR_SIZE, iv); kunmap(bvl.bv_page); kunmap(write_work->page); if (err) { @@ -175,21 +174,21 @@ static int sflc_vol_encryptOrigBio(sflc_Volume * vol, struct bio * orig_bio, str err_encrypt: err_sample_and_write_iv: err_bio_add_page: - mempool_free(write_work->page, sflc_pools_pagePool); + mempool_free(write_work->page, sflegc_pools_pagePool); err_alloc_page: return err; } /* Allocates the io_work's IV (will need to be freed afterwards), fills it with random bytes, and writes it into the IV block pointed by the io_work's PSI and off_in_slice. */ -static int sflc_vol_sampleAndWriteIv(sflc_Volume * vol, u8 * iv, u32 psi, u32 off_in_slice) +static int sflegc_vol_sampleAndWriteIv(sflegc_Volume * vol, u8 * iv, u32 psi, u32 off_in_slice) { - sflc_Device * dev = vol->dev; + sflegc_Device * dev = vol->dev; u8 * iv_block; int err; /* Sample IV */ - err = sflc_rand_getBytes(iv, SFLC_SK_IV_LEN); + err = sflegc_rand_getBytes(iv, SFLEGC_SK_IV_LEN); if (err) { pr_err("Could not sample IV; error %d\n", err); err = -EIO; @@ -197,7 +196,7 @@ static int sflc_vol_sampleAndWriteIv(sflc_Volume * vol, u8 * iv, u32 psi, u32 of } /* Acquire a reference to the whole relevant IV block */ - iv_block = sflc_dev_getIvBlockRef(dev, psi, WRITE); + iv_block = sflegc_dev_getIvBlockRef(dev, psi, WRITE); if (IS_ERR(iv_block)) { err = PTR_ERR(iv_block); pr_err("Could not acquire reference to IV block; error %d\n", err); @@ -205,10 +204,10 @@ static int sflc_vol_sampleAndWriteIv(sflc_Volume * vol, u8 * iv, u32 psi, u32 of } /* Copy it into the relevant portion of the block */ - memcpy(iv_block + (off_in_slice * SFLC_SK_IV_LEN), iv, SFLC_SK_IV_LEN); + memcpy(iv_block + (off_in_slice * SFLEGC_SK_IV_LEN), iv, SFLEGC_SK_IV_LEN); /* Release reference to the IV block */ - err = sflc_dev_putIvBlockRef(dev, psi); + err = sflegc_dev_putIvBlockRef(dev, psi); if (err) { pr_err("Could not release reference to IV block; error %d\n", err); goto err_put_iv_block_ref; @@ -223,9 +222,9 @@ err_sample_iv: return err; } -static void sflc_vol_writeEndIo(struct bio * phys_bio) +static void sflegc_vol_writeEndIo(struct bio * phys_bio) { - sflc_vol_WriteWork * write_work = phys_bio->bi_private; + sflegc_vol_WriteWork * write_work = phys_bio->bi_private; struct bio * orig_bio = write_work->orig_bio; unsigned completed_bytes; @@ -246,8 +245,8 @@ static void sflc_vol_writeEndIo(struct bio * phys_bio) if (unlikely(page_ref_count(write_work->page) != 1)) { pr_err("WTF: page_ref_count = %d\n", page_ref_count(write_work->page)); } - mempool_free(write_work->page, sflc_pools_pagePool); - mempool_free(write_work, sflc_pools_writeWorkPool); + mempool_free(write_work->page, sflegc_pools_pagePool); + mempool_free(write_work, sflegc_pools_writeWorkPool); return; } diff --git a/dm-sflc/src/lite/crypto.c b/dm-sflc/src/lite/crypto.c new file mode 100644 index 0000000..8e27203 --- /dev/null +++ b/dm-sflc/src/lite/crypto.c @@ -0,0 +1,125 @@ +/* + * Copyright The Shufflecake Project Authors (2022) + * Copyright The Shufflecake Project Contributors (2022) + * Copyright Contributors to the The Shufflecake Project. + * + * See the AUTHORS file at the top-level directory of this distribution and at + * + * + * This file is part of the program shufflecake-c, which is part of the + * Shufflecake Project. Shufflecake is a plausible deniability (hidden storage) + * layer for Linux. See . + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 2 of the License, or (at your option) + * any later version. This program is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. You should have received a copy of the + * GNU General Public License along with this program. + * If not, see . + */ + +#include +#include +#include +#include "sflite_constants.h" + +#include "sflc_lite.h" + + +/** + * Encrypt/decrypt exactly one block, already encoded in the scatterlist. + * All other crypto functions reduce to this one. + * The IV is constructed as the right-0-padded LE representation of the + * physical block number, which is exactly what dm-crypt does when using the + * IV mode "plain64". + */ +static int crypt_sg(struct crypto_skcipher *tfm, struct scatterlist *src, + struct scatterlist *dst, u64 pblk_num, int rw) +{ + u8 iv[SFLITE_XTS_IVLEN]; + struct skcipher_request *req = NULL; + DECLARE_CRYPTO_WAIT(wait); + int err; + + // TODO not too sure about the gfp_mask here + // TODO move @req into struct sflite_io? + req = skcipher_request_alloc(tfm, GFP_NOIO); + if (!req) + return -ENOMEM; + + skcipher_request_set_callback(req, + CRYPTO_TFM_REQ_MAY_BACKLOG | CRYPTO_TFM_REQ_MAY_SLEEP, + crypto_req_done, &wait); + + /* Construct IV */ + memset(iv, 0, SFLITE_XTS_IVLEN); + *(__le64 *)iv = cpu_to_le64(pblk_num); + + skcipher_request_set_crypt(req, src, dst, SFLITE_BLOCK_SIZE, iv); + if (rw == READ) + err = crypto_wait_req(crypto_skcipher_decrypt(req), &wait); + else + err = crypto_wait_req(crypto_skcipher_encrypt(req), &wait); + skcipher_request_free(req); + + return err; +} + +/* Encrypt-decrypt a single block (memory buffer is a page) */ +int sflite_crypt_block_page(struct crypto_skcipher *tfm, struct page *src_page, + struct page *dst_page, u64 pblk_num, int rw) +{ + struct scatterlist dst, src, *p_dst; + bool is_inplace; + + /* Use same scatterlist if in-place */ + is_inplace = (src_page == dst_page); + p_dst = is_inplace ? &src : &dst; + + /* We assume PAGE_SIZE == SFLITE_BLOCK_SIZE */ + /* And orig_bio to start at offset 0 within the page */ + sg_init_table(&src, 1); + sg_set_page(&src, src_page, SFLITE_BLOCK_SIZE, 0); + if (!is_inplace) { + sg_init_table(&dst, 1); + sg_set_page(&dst, dst_page, SFLITE_BLOCK_SIZE, 0); + } + + return crypt_sg(tfm, &src, p_dst, pblk_num, rw); +} + + +/* Encrypt-decrypt consecutive blocks (memory buffer is vmalloc'ed) */ +int sflite_crypt_blocks_vm(struct crypto_skcipher *tfm, void *src_buf, void *dst_buf, + u64 num_blocks, u64 first_pblk_num, int rw) +{ + struct scatterlist dst, src, *p_dst; + u64 pblk_num; + bool is_inplace; + int err; + + /* Use same scatterlist if in-place */ + is_inplace = (src_buf == dst_buf); + p_dst = is_inplace ? &src : &dst; + + for (pblk_num = first_pblk_num; + pblk_num < first_pblk_num + num_blocks; + pblk_num++) { + sg_init_one(&src, src_buf, SFLITE_BLOCK_SIZE); + if (!is_inplace) + sg_init_one(&dst, dst_buf, SFLITE_BLOCK_SIZE); + + err = crypt_sg(tfm, &src, p_dst, pblk_num, rw); + if (err) + return err; + + src_buf += SFLITE_BLOCK_SIZE; + dst_buf += SFLITE_BLOCK_SIZE; + } + + return 0; +} + diff --git a/dm-sflc/src/lite/device.c b/dm-sflc/src/lite/device.c new file mode 100644 index 0000000..e62aa54 --- /dev/null +++ b/dm-sflc/src/lite/device.c @@ -0,0 +1,204 @@ +/* + * Copyright The Shufflecake Project Authors (2022) + * Copyright The Shufflecake Project Contributors (2022) + * Copyright Contributors to the The Shufflecake Project. + * + * See the AUTHORS file at the top-level directory of this distribution and at + * + * + * This file is part of the program shufflecake-c, which is part of the + * Shufflecake Project. Shufflecake is a plausible deniability (hidden storage) + * layer for Linux. See . + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 2 of the License, or (at your option) + * any later version. This program is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. You should have received a copy of the + * GNU General Public License along with this program. + * If not, see . + */ + +#include +#include +#include +#include +#include "sflc_lite.h" + + + +/* Depth of the mempool backing the bio_set */ +#define SFLITE_BIOSET_BIOS 64 + + +/* Fisher-Yates shuffle */ +static void fisheryates_u32(u32 *v, u32 len) +{ + u32 i, j; + + for (i = len-1; i >= 1; i--) { + j = get_random_u32_below(i+1); + swap(v[i], v[j]); + } + + return; +} + +/** + * Arguments: + * argv[0]: Shufflecake mode: legacy/lite + * argv[1]: Shufflecake-unique device ID + * argv[2]: path to underlying physical device + * argv[3]: volume index within the device + * argv[4]: number of 1 MB slices in the underlying device + * argv[5]: 64-byte encryption key (hex-encoded) + */ +struct sflite_device *sflite_dev_create(struct dm_target *ti, int argc, char **argv, struct kobject *kobj) +{ + struct sflite_device *sdev; + dev_t devt; + u32 dev_id; + u32 tot_slices; + int i; + int err; + + sdev = kzalloc(sizeof(*sdev), GFP_KERNEL); + if (!sdev) { + DMERR("Could not allocate device"); + return ERR_PTR(-ENOMEM); + } + + /* Parse args */ + if (argc != 6) { + pr_err("Wrong argument count"); + err = -EINVAL; + goto bad_parse; + } + sscanf(argv[1], "%u", &dev_id); + if (sscanf(argv[4], "%u", &tot_slices) != 1) { + pr_err("Could not decode tot_slices\n"); + err = -EINVAL; + goto bad_parse; + } + + sdev->dev_id = dev_id; + + /* Look up block device and set name */ + err = lookup_bdev(argv[2], &devt); + if (err) { + DMERR("Could not look up block device"); + goto bad_lookup; + } + format_dev_t(sdev->name, devt); + + /* Compute sizes */ + sdev->tot_slices = tot_slices; + sdev->nr_free_slices = tot_slices; + /* Enough posmap blocks to fit all the entries */ + sdev->posmap_size_sectors = SFLITE_BLOCK_SCALE * + DIV_ROUND_UP(tot_slices, SFLITE_PSIS_PER_BLOCK); + /* DMB + VMBs + PosMaps */ + sdev->dev_header_size_sectors = SFLITE_BLOCK_SCALE + + (SFLITE_DEV_MAX_VOLUMES * SFLITE_BLOCK_SCALE) + + (SFLITE_DEV_MAX_VOLUMES * sdev->posmap_size_sectors); + + /* Shuffled PSIs */ + mutex_init(&sdev->slices_lock); + sdev->slices_ofld = vzalloc(tot_slices * sizeof(bool)); + if (!sdev->slices_ofld) { + DMERR("Could not allocate PSI occupation bitfield"); + err = -ENOMEM; + goto bad_ofld; + } + + sdev->prmslices = vmalloc(tot_slices * sizeof(u32)); + if (!sdev->prmslices) { + DMERR("Could not allocate shuffled PSI array"); + err = -ENOMEM; + goto bad_prmslices; + } + /* Generate a permutation */ + for (i = 0; i < tot_slices; i++) + sdev->prmslices[i] = i; + fisheryates_u32(sdev->prmslices, tot_slices); + sdev->prmslices_octr = 0; + + /* Bioset */ + err = bioset_init(&sdev->bioset, SFLITE_BIOSET_BIOS, 0, BIOSET_NEED_BVECS); + if (err) { + DMERR("Could not init bioset; error %d", err); + goto bad_bioset; + } + + /* Client for dm-io */ + sdev->io_client = dm_io_client_create(); + if (IS_ERR(sdev->io_client)) { + err = PTR_ERR(sdev->io_client); + DMERR("Could not create dm-io client; error %d", err); + goto bad_dmio_client; + } + + /* I/O workqueue */ + sdev->io_queue = alloc_workqueue("sflite_%s_io", + WQ_MEM_RECLAIM | WQ_CPU_INTENSIVE, + 0, sdev->name); + if (!sdev->io_queue) { + err = -ENOMEM; + DMERR("Could not allocate I/O workqueue"); + goto bad_io_wq; + } + /* Decryption workqueue */ + sdev->crypt_queue = alloc_workqueue("sflite_%s_crypt", + WQ_MEM_RECLAIM | WQ_CPU_INTENSIVE, + 0, sdev->name); + if (!sdev->crypt_queue) { + err = -ENOMEM; + DMERR("Could not allocate decryption workqueue"); + goto bad_crypt_wq; + } + + /* Add to sysfs, once initialised */ + sdev->kobj_parent = kobj; + err = sflite_sysfs_add_device(sdev); + if (err) + goto bad_sysfs; + + return sdev; + + +bad_sysfs: + destroy_workqueue(sdev->crypt_queue); +bad_crypt_wq: + destroy_workqueue(sdev->io_queue); +bad_io_wq: + dm_io_client_destroy(sdev->io_client); +bad_dmio_client: + bioset_exit(&sdev->bioset); +bad_bioset: + vfree(sdev->prmslices); +bad_prmslices: + vfree(sdev->slices_ofld); +bad_ofld: +bad_lookup: +bad_parse: + kfree(sdev); + return ERR_PTR(err); +} + + +void sflite_dev_destroy(struct sflite_device *sdev) +{ + sflite_sysfs_remove_device(sdev); + destroy_workqueue(sdev->crypt_queue); + destroy_workqueue(sdev->io_queue); + dm_io_client_destroy(sdev->io_client); + bioset_exit(&sdev->bioset); + vfree(sdev->prmslices); + vfree(sdev->slices_ofld); + kfree(sdev); + + return; +} + diff --git a/dm-sflc/src/lite/dm_io_helper.h b/dm-sflc/src/lite/dm_io_helper.h new file mode 100644 index 0000000..7e0d915 --- /dev/null +++ b/dm-sflc/src/lite/dm_io_helper.h @@ -0,0 +1,56 @@ +/* + * Copyright The Shufflecake Project Authors (2022) + * Copyright The Shufflecake Project Contributors (2022) + * Copyright Contributors to the The Shufflecake Project. + * + * See the AUTHORS file at the top-level directory of this distribution and at + * + * + * This file is part of the program shufflecake-c, which is part of the + * Shufflecake Project. Shufflecake is a plausible deniability (hidden storage) + * layer for Linux. See . + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 2 of the License, or (at your option) + * any later version. This program is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. You should have received a copy of the + * GNU General Public License along with this program. + * If not, see . + */ + +#ifndef _SFLITE_DMIOHELPER_H +#define _SFLITE_DMIOHELPER_H + +#include +#include + +/** + * The function dm_io() has changed signature in recent kernels. + * Here we provide a version-independent adapter, which uses a default value + * for the fifth parameter (the new one). + * The new signature is present for kernel 6.1.x with x>=83, 6.6.x with x>=23, + * 6.7.x with x>=11, 6.8.x with x>=2, 6.x with x>=9 + */ +#if LINUX_VERSION_MAJOR <= 5 // Old +#define sflc_dm_io(ioreq, numreg, region, err) dm_io(ioreq, numreg, region, err) +#elif LINUX_VERSION_MAJOR >= 7 // New +#define sflc_dm_io(ioreq, numreg, region, err) dm_io(ioreq, numreg, region, err, IOPRIO_DEFAULT) +// Ok LINUX_VERSION_MAJOR is 6 +#elif LINUX_VERSION_PATCHLEVEL >= 9 // New +#define sflc_dm_io(ioreq, numreg, region, err) dm_io(ioreq, numreg, region, err, IOPRIO_DEFAULT) +#elif LINUX_VERSION_PATCHLEVEL == 8 && LINUX_VERSION_SUBLEVEL >= 2 // New +#define sflc_dm_io(ioreq, numreg, region, err) dm_io(ioreq, numreg, region, err, IOPRIO_DEFAULT) +#elif LINUX_VERSION_PATCHLEVEL == 7 && LINUX_VERSION_SUBLEVEL >= 11 // New +#define sflc_dm_io(ioreq, numreg, region, err) dm_io(ioreq, numreg, region, err, IOPRIO_DEFAULT) +#elif LINUX_VERSION_PATCHLEVEL == 6 && LINUX_VERSION_SUBLEVEL >= 23 // New +#define sflc_dm_io(ioreq, numreg, region, err) dm_io(ioreq, numreg, region, err, IOPRIO_DEFAULT) +#elif LINUX_VERSION_PATCHLEVEL == 1 && LINUX_VERSION_SUBLEVEL >= 83 // New +#define sflc_dm_io(ioreq, numreg, region, err) dm_io(ioreq, numreg, region, err, IOPRIO_DEFAULT) +#else // Old +#define sflc_dm_io(ioreq, numreg, region, err) dm_io(ioreq, numreg, region, err) +#endif + +#endif /* _SFLITE_DMIOHELPER_H */ diff --git a/dm-sflc/src/lite/posmap.c b/dm-sflc/src/lite/posmap.c new file mode 100644 index 0000000..3ee2551 --- /dev/null +++ b/dm-sflc/src/lite/posmap.c @@ -0,0 +1,377 @@ +/* + * Copyright The Shufflecake Project Authors (2022) + * Copyright The Shufflecake Project Contributors (2022) + * Copyright Contributors to the The Shufflecake Project. + * + * See the AUTHORS file at the top-level directory of this distribution and at + * + * + * This file is part of the program shufflecake-c, which is part of the + * Shufflecake Project. Shufflecake is a plausible deniability (hidden storage) + * layer for Linux. See . + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 2 of the License, or (at your option) + * any later version. This program is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. You should have received a copy of the + * GNU General Public License along with this program. + * If not, see . + */ + +#include +#include +#include "dm_io_helper.h" +#include "sflc_lite.h" + + +/* Helpers */ + +#define IS_PSI_TAKEN(sdev, psi) ( (sdev)->slices_ofld[(psi)] ) +#define NEXT_RANDOM_PSI(sdev) ( (sdev)->prmslices[(sdev)->prmslices_octr] ) +#define IS_LAST_LSI_IN_BLOCK(lsi, sdev) ( (((lsi)+1) % SFLITE_PSIS_PER_BLOCK == 0) || \ + (((lsi)+1) == (sdev)->tot_slices) ) + + +/* + *---------------------------- + * Create slice mapping + *---------------------------- + */ + +/** + * Return the next free PSI in the device's shuffled array, without modifying + * the device state. + * + * MUTEX: @sdev->slices_lock must be held. + */ +static int peek_next_free_psi(struct sflite_device *sdev, u32 *psi) +{ + if (unlikely(!sdev->nr_free_slices)) + return -ENOSPC; + if (unlikely(sdev->prmslices_octr >= sdev->tot_slices)) { + DMCRIT("octr = %u, tot_slices = %u, free_slices = %u", sdev->prmslices_octr, sdev->tot_slices, sdev->nr_free_slices); + print_hex_dump(KERN_CRIT, "prmslices(REV) ", DUMP_PREFIX_OFFSET, 32, 4, sdev->prmslices, 4*sdev->tot_slices, false); + msleep(10000); + print_hex_dump(KERN_CRIT, "ofld(REV) ", DUMP_PREFIX_OFFSET, 32, 1, sdev->slices_ofld, sdev->tot_slices, false); + msleep(10000); + return -ENOTRECOVERABLE; // Grave inconsistency + } + + /* Invariant: @prmslices_octr points to a free slice */ + *psi = NEXT_RANDOM_PSI(sdev); + if (unlikely(IS_PSI_TAKEN(sdev, *psi))){ + DMCRIT("octr = %u, tot_slices = %u, free_slices = %u", sdev->prmslices_octr, sdev->tot_slices, sdev->nr_free_slices); + DMCRIT("PSI %u is occupied", *psi); + print_hex_dump(KERN_CRIT, "prmslices ", DUMP_PREFIX_OFFSET, 32, 4, sdev->prmslices, 4*sdev->tot_slices, false); + msleep(10000); + print_hex_dump(KERN_CRIT, "ofld ", DUMP_PREFIX_OFFSET, 32, 1, sdev->slices_ofld, sdev->tot_slices, false); + msleep(10000); + return -ENOTRECOVERABLE; // Grave inconsistency + } + + return 0; +} + +/** + * Map LSI => PSI, only in memory. + * Sanity checks to be performed by the caller. + * + * MUTEX: @sdev->slices_lock must be held. + * MUTEX: @svol->posmap_lock must be held, except under volume ctor. + */ +static void _create_local_slice_mapping(struct sflite_volume *svol, u32 lsi, u32 psi) +{ + struct sflite_device *sdev = svol->sdev; + + /* Grab it from the device */ + sdev->slices_ofld[psi] = true; + sdev->nr_free_slices--; + // Preserve the invariant: @prmslices_octr must point to a free slice + while(sdev->prmslices_octr < sdev->tot_slices && + IS_PSI_TAKEN(sdev, NEXT_RANDOM_PSI(sdev))) { + sdev->prmslices_octr++; + } + + /* Insert in the volume */ + svol->posmap[lsi] = psi; + svol->nr_mapped_slices++; + + return; +} + +/** + * Delete mapping for the given LSI, only in memory. + * Sanity checks to be performed by the caller. + * + * MUTEX: @svol->posmap_lock must be held, except under volume ctor. + */ +static void _delete_local_slice_mapping(struct sflite_volume *svol, u32 lsi) +{ + /* Delete mapping in the volume */ + svol->posmap[lsi] = SFLITE_PSI_INVALID; + svol->nr_mapped_slices--; + + /* Don't do anything in the device though, leave it there: we don't yet + * have an obvious way to release PSIs. + * This means a PSI will be incorrectly marked as occupied, but that's + * not too bad: the PSI shuffling and its occupation counter are + * ephemeral, so they reset if you close and reopen all the volumes. */ + return; +} + +/** + * Synchronously store (and flush) the given posmap block + * + * MUTEX: @svol->posmap_lock must be held, except under volume ctor. + */ +static int store_posmap_block(struct sflite_volume *svol, u32 posmap_block_num) +{ + struct sflite_device *sdev = svol->sdev; + struct page *page; + struct bio *bio; + int err; + + /* Sync + flush TODO GFP mask ok? */ + bio = bio_alloc_bioset(svol->dm_dev->bdev, 1, + REQ_OP_WRITE | REQ_SYNC | REQ_FUA, GFP_NOIO, + &sdev->bioset); + if (!bio) { + DMERR("Could not allocate posmap block bio"); + return -ENOMEM; + } + bio->bi_iter.bi_sector = SFLITE_POSMAP_START_SECTOR(svol) + + (posmap_block_num << SFLITE_BLOCK_SHIFT); + + /* Alloc and add page TODO GFP mask */ + page = alloc_page(GFP_NOIO); + if (!page) { + DMERR("Could not allocate posmap block page"); + err = -ENOMEM; + goto bad_alloc_page; + } + // TODO remove this error check + if (unlikely(!bio_add_page(bio, page, SFLITE_BLOCK_SIZE, 0))) { + DMCRIT("Could not add posmap block page to bio!"); + err = -ENOTRECOVERABLE; + goto bad_add_page; + } + + /* Serialise posmap block onto the page */ + void *page_ptr = kmap_local_page(page); + u32 first_lsi = posmap_block_num * SFLITE_PSIS_PER_BLOCK; + u32 last_lsi = min(first_lsi + SFLITE_PSIS_PER_BLOCK, sdev->tot_slices); + u32 lsi; + for (lsi = first_lsi; lsi < last_lsi; lsi++) { + u32 psi = svol->posmap[lsi]; + __be32 *be_psi = (__be32*) (page_ptr + ((lsi-first_lsi) * sizeof(__be32))); + *be_psi = cpu_to_be32(psi); + } + +// print_hex_dump(KERN_WARNING, "page_ptr(REV) ", DUMP_PREFIX_OFFSET, 32, 4, page_ptr, SFLITE_BLOCK_SIZE, false); +// msleep(100); + + kunmap_local(page_ptr); + + /* Encrypt the block in place */ + err = sflite_crypt_block_page(svol->tfm, page, page, + bio->bi_iter.bi_sector >> SFLITE_BLOCK_SHIFT, WRITE); + if (err) { + DMERR("Could not encrypt posmap block; error %d", err); + goto bad_encrypt; + } + + /* Submit */ + err = submit_bio_wait(bio); + if (err) + DMERR("Could not complete posmap block bio; error %d", err); + +bad_encrypt: +bad_add_page: + __free_page(page); +bad_alloc_page: + bio_put(bio); + return err; +} + + +/** + * Create a new mapping for the given LSI, and synchronise back to disk. + * + * MUTEX: @svol->posmap_lock must be held, except under volume ctor. + * MUTEX: takes @sdev->slices_lock. + * + * Syncing to disk means the posmap lock will be held (by the caller) for a long + * time thus blocking out all the other incoming bio's, even unrelated ones + * (falling in different slices). Several strategies are possible to avoid this + * problem, but for now we keep this simple implementation. + */ +int sflite_create_persistent_slice_mapping(struct sflite_volume *svol, u32 lsi, u32 *psi) +{ + struct sflite_device *sdev = svol->sdev; + int err; + + /* Bounds check TODO redundant? */ + if(unlikely(lsi >= svol->sdev->tot_slices)) + return -EINVAL; + /* Check mapping not existent TODO redundant? */ + if (unlikely(svol->posmap[lsi] != SFLITE_PSI_INVALID)) + return -EINVAL; + + /* Create mapping */ + if (mutex_lock_interruptible(&sdev->slices_lock)) + return -ERESTARTSYS; + err = peek_next_free_psi(sdev, psi); + if (err) { + mutex_unlock(&sdev->slices_lock); + return err; + } + _create_local_slice_mapping(svol, lsi, *psi); + mutex_unlock(&sdev->slices_lock); + + /* Write posmap block to disk */ + err = store_posmap_block(svol, lsi/SFLITE_PSIS_PER_BLOCK); + if (err) { + DMERR("Could not store posmap block; error %d", err); + _delete_local_slice_mapping(svol, lsi); + return err; + } + + return 0; +} + + +/* + *---------------------------- + * Load position map + *---------------------------- + */ + +/** + * Synchronously read the entire on-disk encrypted position map + * + * MUTEX: no need for the caller to hold @svol->posmap_lock (we are in ctor). + */ +static int read_encrypted_posmap(struct sflite_volume *svol) +{ + struct dm_io_request io_req = { + .bi_opf = REQ_OP_READ | REQ_SYNC, + .mem.type = DM_IO_VMA, + .mem.ptr.vma = svol->posmap, + .notify.fn = NULL, + .client = svol->sdev->io_client + }; + struct dm_io_region io_region = { + .bdev = svol->dm_dev->bdev, + .sector = SFLITE_POSMAP_START_SECTOR(svol), + .count = svol->sdev->posmap_size_sectors + }; + + return sflc_dm_io(&io_req, 1, &io_region, NULL); +} + +/** + * De-serialise the position map entries. On the fly, if a conflict is detected, + * resolve it by sampling a new PSI, and sync to disk (block by block). + * + * MUTEX: no need for the caller to hold @svol->posmap_lock (we are in ctor). + * MUTEX: @sdev->slices_lock must be held. + */ +static int _deserialise_and_sanitise_posmap(struct sflite_volume *svol) +{ + struct sflite_device *sdev = svol->sdev; + void *posmap_ptr = svol->posmap; + u32 lsi; + bool posmap_block_dirty; + int err; + + for (lsi = 0; lsi < sdev->tot_slices; lsi++) { + /* Reset dirty bit at the start of every posmap block */ + if (lsi % SFLITE_PSIS_PER_BLOCK == 0) + posmap_block_dirty = false; + + /* De-serialise posmap entry */ + __be32 *be_psi = (__be32*) (posmap_ptr + (lsi * sizeof(__be32))); + u32 psi = be32_to_cpu(*be_psi); + + /* If LSI unmapped, skip mapping creation */ + if (psi == SFLITE_PSI_INVALID) { + svol->posmap[lsi] = psi; + goto skip_create_mapping; + } + + /* If PSI out of bounds, something's seriously wrong */ + if (psi >= sdev->tot_slices) { + DMERR("Decrypted PSI out of bounds: %u >= %u", psi, sdev->tot_slices); + return -EDOM; + } + + /* If PSI already taken, sample a new one */ + if (sdev->slices_ofld[psi]) { + DMWARN("Corruption of volume %u: LSI %u was evicted from PSI %u", + svol->vol_idx, lsi, psi); + err = peek_next_free_psi(sdev, &psi); + if (err) + return err; + posmap_block_dirty = true; + } + /* Whether sanitised or not, create the mapping locally */ + _create_local_slice_mapping(svol, lsi, psi); + +skip_create_mapping: + + /* Only check dirty bit at the end of the posmap block */ + if (posmap_block_dirty && + IS_LAST_LSI_IN_BLOCK(lsi, sdev)) { + err = store_posmap_block(svol, lsi/SFLITE_PSIS_PER_BLOCK); + if (err) + return err; + } + } + + return 0; +} + + +/** + * Load the volume's position map from the disk. If some conflicts are present + * (i.e. an LSI is mapped to a PSI that's already taken), then resolve them + * (i.e. re-sample a free PSI for the "unlucky" LSI) and sync back to disk. + * + * MUTEX: no need for the caller to hold @svol->posmap_lock (we are in ctor). + * MUTEX: takes @sdev->slices_lock. + */ +int sflite_load_and_sanitise_posmap(struct sflite_volume *svol) +{ + int err; + struct sflite_device *sdev = svol->sdev; + + /* Read raw posmap from disk */ + err = read_encrypted_posmap(svol); + if (err) + return err; + + /* Decrypt in place */ + err = sflite_crypt_blocks_vm(svol->tfm, svol->posmap, svol->posmap, + svol->sdev->posmap_size_sectors >> SFLITE_BLOCK_SHIFT, + SFLITE_POSMAP_START_SECTOR(svol) >> SFLITE_BLOCK_SHIFT, + READ); + if (err) + return err; + + /* Deserialise and sanitise as you go */ + if (mutex_lock_interruptible(&sdev->slices_lock)) + return -ERESTARTSYS; + err = _deserialise_and_sanitise_posmap(svol); + mutex_unlock(&sdev->slices_lock); + if (err) + return err; + +// print_hex_dump(KERN_CRIT, "posmap(REV) ", DUMP_PREFIX_OFFSET, 32, 4, svol->posmap, 4*sdev->tot_slices, false); +// msleep(2000); + + return 0; +} + diff --git a/dm-sflc/src/lite/read.c b/dm-sflc/src/lite/read.c new file mode 100644 index 0000000..c7a2016 --- /dev/null +++ b/dm-sflc/src/lite/read.c @@ -0,0 +1,168 @@ +/* + * Copyright The Shufflecake Project Authors (2022) + * Copyright The Shufflecake Project Contributors (2022) + * Copyright Contributors to the The Shufflecake Project. + * + * See the AUTHORS file at the top-level directory of this distribution and at + * + * + * This file is part of the program shufflecake-c, which is part of the + * Shufflecake Project. Shufflecake is a plausible deniability (hidden storage) + * layer for Linux. See . + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 2 of the License, or (at your option) + * any later version. This program is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. You should have received a copy of the + * GNU General Public License along with this program. + * If not, see . + */ + +#include "sflc_lite.h" +#include + + +static void sflite_read_endio(struct bio *phys_bio); +static void sflite_decrypt_work_fn(struct work_struct *work); + + +/* Landing here from ->map() through the io_queue */ +void sflite_read_work_fn(struct work_struct *work) +{ + struct sflite_io *sio = container_of(work, struct sflite_io, work); + struct sflite_volume *svol = sio->svol; + struct sflite_device *sdev = svol->sdev; + struct bio *orig_bio = sio->orig_bio; + struct bio *phys_bio; + u32 lsi = sio->lsi; + u32 block_offset = sio->block_offset; + u32 psi; + + /* Read position map */ + if (mutex_lock_interruptible(&svol->posmap_lock)) { + orig_bio->bi_status = BLK_STS_IOERR; + goto endio; + } + psi = svol->posmap[lsi]; + mutex_unlock(&svol->posmap_lock); + + /* If LSI is unmapped, short-circuit and return all zeros */ + if (psi == SFLITE_PSI_INVALID) { + + zero_fill_bio(orig_bio); + orig_bio->bi_status = BLK_STS_OK; + goto endio; + } + sio->psi = psi; + +// DMWARN("READ: LSI=%u, PSI=%u, offset=%u", lsi, psi, sio->block_offset); +// msleep(100); + + /* Shallow-copy the bio and submit it (different bi_endio). + We can shallow-copy because we don't need to own the pages, + we can decrypt in place. */ + + + //DMWARN("READ: shallow copying"); + //msleep(500); + + /* Shallow copy */ + phys_bio = bio_alloc_clone(svol->dm_dev->bdev, orig_bio, GFP_NOIO, &sdev->bioset); + if (!phys_bio) { + DMERR("Could not clone original bio"); + orig_bio->bi_status = BLK_STS_IOERR; + goto endio; + } + /* Insert in the I/O struct */ + sio->phys_bio = phys_bio; + +// DMWARN("READ: submitting bio"); +// msleep(500); + + /* Remap sector */ + phys_bio->bi_iter.bi_sector = SFLITE_PHYS_BIO_SECTOR(sdev, psi, block_offset); + /* Set fields for the endio */ + phys_bio->bi_private = sio; + phys_bio->bi_end_io = sflite_read_endio; + /* Submit */ + dm_submit_bio_remap(orig_bio, phys_bio); + + return; + + +endio: + bio_endio(orig_bio); + return; +} + + +/* ISR for the phys_bio */ +static void sflite_read_endio(struct bio *phys_bio) +{ + struct sflite_io *sio = phys_bio->bi_private; + +// DMWARN("READ ENDIO: queueing decryption"); +// //msleep(500); + + /* Can't decrypt here in ISR: submit to decryption workqueue. + * Can reuse the same work item, though, since it was popped out of the + * io_queue already */ + INIT_WORK(&sio->work, sflite_decrypt_work_fn); + queue_work(sio->svol->sdev->crypt_queue, &sio->work); +} + + +/* Decrypt and endio */ +static void sflite_decrypt_work_fn(struct work_struct *work) +{ + struct sflite_io *sio = container_of(work, struct sflite_io, work); + struct sflite_volume *svol = sio->svol; + struct bio *orig_bio = sio->orig_bio; + struct bio *phys_bio = sio->phys_bio; + struct bio_vec bvl = bio_iovec(orig_bio); + int err; + + /* If physical bio failed, then fail-fast */ + if (phys_bio->bi_status != BLK_STS_OK) { + orig_bio->bi_status = phys_bio->bi_status; + goto endio; + } + +// DMWARN("DECRYPT FN: decrypting page in place"); +// msleep(2000); + + /* Decrypt page in-place */ + err = sflite_crypt_block_page(svol->tfm, bvl.bv_page, bvl.bv_page, + SFLITE_PHYS_BIO_SECTOR(svol->sdev, sio->psi, sio->block_offset) >> SFLITE_BLOCK_SHIFT, + READ); + if (err) { + DMERR("Could not decrypt bio; error %d", err); + orig_bio->bi_status = BLK_STS_IOERR; + goto endio; + } + +// print_hex_dump(KERN_WARNING, "readpage ", DUMP_PREFIX_OFFSET, 32, 1, bvl.bv_page, SFLITE_BLOCK_SIZE, true); +// msleep(2000); + +// DMWARN("DECRYPT FN: bio_advance"); +// msleep(300); + + /* Advance original bio by one block */ + bio_advance(orig_bio, SFLITE_BLOCK_SIZE); + orig_bio->bi_status = BLK_STS_OK; + +endio: + /* Free the physical bio */ +// DMWARN("DECRYPT FN: bio_put"); +// msleep(300); + bio_put(phys_bio); + /* End original bio */ +// DMWARN("DECRYPT FN: bio_endio\n\n\n\n"); +// msleep(300); + bio_endio(orig_bio); + + return; +} diff --git a/dm-sflc/src/lite/sflc_lite.c b/dm-sflc/src/lite/sflc_lite.c new file mode 100644 index 0000000..edc245f --- /dev/null +++ b/dm-sflc/src/lite/sflc_lite.c @@ -0,0 +1,161 @@ +/* + * Copyright The Shufflecake Project Authors (2022) + * Copyright The Shufflecake Project Contributors (2022) + * Copyright Contributors to the The Shufflecake Project. + * + * See the AUTHORS file at the top-level directory of this distribution and at + * + * + * This file is part of the program shufflecake-c, which is part of the + * Shufflecake Project. Shufflecake is a plausible deniability (hidden storage) + * layer for Linux. See . + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 2 of the License, or (at your option) + * any later version. This program is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. You should have received a copy of the + * GNU General Public License along with this program. + * If not, see . + */ + +#include +#include +#include +#include "sflite_constants.h" +#include "sflc_lite.h" + +// Only to import the definition of struct sflc_volume +#include "sflc.h" + +#include + + +/* + *---------------------------- + * Device mapper target + *---------------------------- + */ + +static int sflite_map(struct dm_target *ti, struct bio *bio) +{ + struct sflite_io *sio = dm_per_bio_data(bio, sizeof(struct sflite_io)); + struct sflc_volume *top_vol = ti->private; + struct sflite_volume *svol = top_vol->sflite_vol; + sector_t lblk_num = bio->bi_iter.bi_sector >> SFLITE_BLOCK_SHIFT; + + if (unlikely(!bio_has_data(bio))) { +// DMWARN("No-data bio: bio_op() = %d, bi_opf = %u, bi_io_vec = %p, bi_idx = %u", bio_op(bio), bio->bi_opf, bio->bi_io_vec, bio->bi_iter.bi_idx); +// msleep(100); + } + + /* Flush requests are just passed down, since our position map is + * currently write-through, so we have no volatile cache */ + if (unlikely(bio->bi_opf & REQ_PREFLUSH)) { + /* Has to be empty though */ + if (bio_sectors(bio)) { + DMWARN("Non-empty flush request!"); + msleep(3000); + return DM_MAPIO_KILL; + } +// DMWARN("REQ_PREFLUSH empty (phew), sector: %llu", bio->bi_iter.bi_sector); +// msleep(100); + bio_set_dev(bio, svol->dm_dev->bdev); + return DM_MAPIO_REMAPPED; + } + + /* Accept one block at a time TODO improve */ + if (unlikely(bio->bi_iter.bi_size > SFLITE_BLOCK_SIZE)) { + DMWARN("Big bio: %u", bio->bi_iter.bi_size); + msleep(300); + dm_accept_partial_bio(bio, SFLITE_BLOCK_SCALE); + } + /* Only one segment, single page, starting at 0 TODO improve */ + if (unlikely(bio_segments(bio) > 1 || + bio_offset(bio) != 0)) { + DMWARN("Unaligned bio!"); + msleep(3000); + return DM_MAPIO_KILL; + } + if (unlikely(bio->bi_iter.bi_size != SFLITE_BLOCK_SIZE)) { + DMWARN("Wrong bio size: %u", bio->bi_iter.bi_size); + msleep(3000); + return DM_MAPIO_KILL; + } + + /* Init I/O struct */ + sio->svol = svol; + sio->orig_bio = bio; + sio->lsi = lblk_num >> SFLITE_SLICE_SHIFT; + sio->block_offset = lblk_num & ((1U << SFLITE_SLICE_SHIFT) - 1); + + /* Enqueue */ + if (bio_data_dir(bio) == READ) + INIT_WORK(&sio->work, sflite_read_work_fn); + else + INIT_WORK(&sio->work, sflite_write_work_fn); + queue_work(svol->sdev->io_queue, &sio->work); + + return DM_MAPIO_SUBMITTED; +} + + +static void sflite_io_hints(struct dm_target *ti, struct queue_limits *limits) +{ + // Currently, we only handle one block at a time TODO improve + limits->logical_block_size = SFLITE_BLOCK_SIZE; + limits->physical_block_size = SFLITE_BLOCK_SIZE; + limits->io_min = SFLITE_BLOCK_SIZE; + limits->io_opt = SFLITE_BLOCK_SIZE; + + return; +} + + +static int sflite_iterate_devices(struct dm_target *ti, iterate_devices_callout_fn fn, void *data) +{ + struct sflc_volume *top_vol = ti->private; + struct sflite_volume *svol = top_vol->sflite_vol; + struct sflite_device *sdev = svol->sdev; + + if (!fn) { + dump_stack(); + msleep(2000); + return -EINVAL; + } + return fn(ti, svol->dm_dev, 0, sdev->dev_header_size_sectors + ti->len, data); +} + + +struct target_type sflite_target_type = { + .map = sflite_map, + .io_hints = sflite_io_hints, + .iterate_devices = sflite_iterate_devices, +}; + + +/* + *---------------------------- + * Init and exit + *---------------------------- + */ + +int sflite_init(void) +{ + /* For the moment, we assume PAGE_SIZE == SFLITE_BLOCK_SIZE TODO improve */ + if (SFLITE_BLOCK_SIZE != PAGE_SIZE) { + DMERR("Error, PAGE_SIZE != %d bytes not yet supported", SFLITE_BLOCK_SIZE); + return -ENOTRECOVERABLE; + } + + return 0; +} + + +void sflite_exit(void) +{ + return; +} + diff --git a/dm-sflc/src/lite/sflc_lite.h b/dm-sflc/src/lite/sflc_lite.h new file mode 100644 index 0000000..1c2e5a7 --- /dev/null +++ b/dm-sflc/src/lite/sflc_lite.h @@ -0,0 +1,182 @@ +/* + * Copyright The Shufflecake Project Authors (2022) + * Copyright The Shufflecake Project Contributors (2022) + * Copyright Contributors to the The Shufflecake Project. + * + * See the AUTHORS file at the top-level directory of this distribution and at + * + * + * This file is part of the program shufflecake-c, which is part of the + * Shufflecake Project. Shufflecake is a plausible deniability (hidden storage) + * layer for Linux. See . + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 2 of the License, or (at your option) + * any later version. This program is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. You should have received a copy of the + * GNU General Public License along with this program. + * If not, see . + */ + +#ifndef _SFLITE_SFLITE_H +#define _SFLITE_SFLITE_H + +#include +#include +#include +#include +#include "sflite_constants.h" +#include "sflc_constants.h" + + +/* + *---------------------------- + * Structs + *---------------------------- + */ + +struct sflite_device +{ + /* Shufflecake-unique device ID */ + u32 dev_id; + /* : */ + char name[16]; + + /* Logical size of each volume */ + u32 tot_slices; + /* Header sizes in 512-byte sectors */ + sector_t posmap_size_sectors; + sector_t dev_header_size_sectors; + + /* Shuffled array of PSIs */ + struct mutex slices_lock; + u32 *prmslices; + u32 prmslices_octr; + bool *slices_ofld; + u32 nr_free_slices; + + /* Parent sysfs directory */ + struct kobject *kobj_parent; + + /* Resource sharing */ + struct bio_set bioset; + struct dm_io_client *io_client; + struct workqueue_struct *io_queue; + struct workqueue_struct *crypt_queue; +}; + +struct sflite_volume +{ + /* Backing device */ + struct sflite_device *sdev; + + /* Underlying block device. This can't go in the sflite_device struct, + * because each ti grabs its own reference. */ + struct dm_dev *dm_dev; + struct dm_target *ti; + + /* Volume index within the device */ + u32 vol_idx; + /* Volume name: sflite__ */ + char name[32]; + + /* Position map */ + struct mutex posmap_lock; + u32 *posmap; + u32 nr_mapped_slices; + + /* Parent sysfs directory */ + struct kobject *kobj_parent; + + /* Crypto */ + u8 enckey[SFLITE_XTS_KEYLEN]; + struct crypto_skcipher *tfm; +}; + +struct sflite_io +{ + struct sflite_volume *svol; + + struct bio *orig_bio; + struct bio *phys_bio; + u32 lsi; + u32 block_offset; + u32 psi; + + struct work_struct work; +}; + + +/* + *---------------------------- + * Macros + *---------------------------- + */ + +/* Starting sector of position map */ +#define SFLITE_POSMAP_START_SECTOR(svol) \ + (SFLITE_BLOCK_SCALE * (1 + SFLITE_DEV_MAX_VOLUMES) + \ + (svol)->vol_idx * (svol)->sdev->posmap_size_sectors) + + +/* Physical sector of a remapped bio */ +#define SFLITE_PHYS_BIO_SECTOR(sdev, psi, off) ( \ + (sdev)->dev_header_size_sectors + ( \ + ((psi << SFLITE_SLICE_SHIFT) + off) << SFLITE_BLOCK_SHIFT \ + ) \ +) + + +/* + *---------------------------- + * Public variables + *---------------------------- + */ + +extern struct target_type sflite_target_type; + + +/* + *---------------------------- + * Functions + *---------------------------- + */ + +/* Init and exit */ +int sflite_init(void); +void sflite_exit(void); + +/* Device */ +struct sflite_device *sflite_dev_create(struct dm_target *ti, int argc, char **argv, struct kobject *kobj); +void sflite_dev_destroy(struct sflite_device *sdev); + +/* Volume */ +struct sflite_volume *sflite_vol_create(struct dm_target *ti, struct sflite_device *sdev, + int argc, char **argv, struct kobject *kobj); +void sflite_vol_destroy(struct sflite_volume *svol); + +/* Sysfs */ +int sflite_sysfs_add_device(struct sflite_device *sdev); +void sflite_sysfs_remove_device(struct sflite_device *sdev); +int sflite_sysfs_add_volume(struct sflite_volume *svol); +void sflite_sysfs_remove_volume(struct sflite_volume *svol); + +/* Bio mapping */ +void sflite_read_work_fn(struct work_struct *work); +void sflite_write_work_fn(struct work_struct *work); + +/* Position map */ +int sflite_load_and_sanitise_posmap(struct sflite_volume *svol); +int sflite_create_persistent_slice_mapping(struct sflite_volume *svol, u32 lsi, u32 *psi); + +/* Crypto */ +int sflite_crypt_blocks_vm(struct crypto_skcipher *tfm, void *src_buf, void *dst_buf, + u64 num_blocks, u64 first_pblk_num, int rw); +int sflite_crypt_block_page(struct crypto_skcipher *tfm, struct page *src_page, + struct page *dst_page, u64 pblk_num, int rw); + + +#endif /* _SFLITE_SFLITE_H */ diff --git a/dm-sflc/src/lite/sflite_constants.h b/dm-sflc/src/lite/sflite_constants.h new file mode 100644 index 0000000..801ff59 --- /dev/null +++ b/dm-sflc/src/lite/sflite_constants.h @@ -0,0 +1,53 @@ +/* + * Copyright The Shufflecake Project Authors (2022) + * Copyright The Shufflecake Project Contributors (2022) + * Copyright Contributors to the The Shufflecake Project. + * + * See the AUTHORS file at the top-level directory of this distribution and at + * + * + * This file is part of the program shufflecake-c, which is part of the + * Shufflecake Project. Shufflecake is a plausible deniability (hidden storage) + * layer for Linux. See . + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 2 of the License, or (at your option) + * any later version. This program is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. You should have received a copy of the + * GNU General Public License along with this program. + * If not, see . + */ + +/* Constants specific to Shufflecake Lite */ + +#ifndef _SFLITE_SFLITE_CONSTANTS_H_ +#define _SFLITE_SFLITE_CONSTANTS_H_ + + +#define SFLITE_BLOCK_SIZE 4096 /* bytes */ +#define SFLITE_BLOCK_SHIFT 3 +#define SFLITE_BLOCK_SCALE (1 << SFLITE_BLOCK_SHIFT) /* 8 sectors in a block */ +#define SFLITE_SLICE_SHIFT 8 +#define SFLITE_SLICE_SCALE (1 << SFLITE_SLICE_SHIFT) /* 256 blocks in a slice */ + + +/* XTS requires doubling the key size */ +#define SFLITE_XTS_KEYLEN 64 /* bytes */ +/* The IV is the right-0-padded LE physical block number */ +#define SFLITE_XTS_IVLEN 16 /* bytes */ + + +#define SFLITE_DEV_MAX_VOLUMES 15 +#define SFLITE_MAX_DEVS 1024 + + +#define SFLITE_PSI_INVALID 0xFFFFFFFF +/* PosMap entries are 4 bytes, therefore there are 1024 of them in a block */ +#define SFLITE_PSIS_PER_BLOCK 1024 + + + +#endif /* _SFLITE_SFLITE_CONSTANTS_H_ */ diff --git a/dm-sflc/src/lite/sysfs.c b/dm-sflc/src/lite/sysfs.c new file mode 100644 index 0000000..88e2d06 --- /dev/null +++ b/dm-sflc/src/lite/sysfs.c @@ -0,0 +1,116 @@ +/* + * Copyright The Shufflecake Project Authors (2022) + * Copyright The Shufflecake Project Contributors (2022) + * Copyright Contributors to the The Shufflecake Project. + * + * See the AUTHORS file at the top-level directory of this distribution and at + * + * + * This file is part of the program shufflecake-c, which is part of the + * Shufflecake Project. Shufflecake is a plausible deniability (hidden storage) + * layer for Linux. See . + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 2 of the License, or (at your option) + * any later version. This program is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. You should have received a copy of the + * GNU General Public License along with this program. + * If not, see . + */ + +#include "sflc_lite.h" + +// Only to import the definitions of structs sflc_volume and sflc_device +#include "sflc.h" + +/* + *---------------------------- + * Device entries + *---------------------------- + */ + +static ssize_t tot_slices_show(struct kobject *kobj, struct kobj_attribute *kattr, char *buf) +{ + struct sflc_device *top_dev = container_of(kobj, struct sflc_device, kobj); + struct sflite_device *sdev = top_dev->sflite_dev; + + return sysfs_emit(buf, "%u\n", sdev->tot_slices); +} + +static ssize_t free_slices_show(struct kobject *kobj, struct kobj_attribute *kattr, char *buf) +{ + struct sflc_device *top_dev = container_of(kobj, struct sflc_device, kobj); + struct sflite_device *sdev = top_dev->sflite_dev; + int ret; + + if (mutex_lock_interruptible(&sdev->slices_lock)) + return -ERESTARTSYS; + ret = sysfs_emit(buf, "%u\n", sdev->nr_free_slices); + mutex_unlock(&sdev->slices_lock); + + return ret; +} + +static struct kobj_attribute tot_slices_kattr = __ATTR_RO(tot_slices); +static struct kobj_attribute free_slices_kattr = __ATTR_RO(free_slices); +static struct attribute *sflite_device_attrs[] = { + &tot_slices_kattr.attr, + &free_slices_kattr.attr, + NULL +}; +static const struct attribute_group sflite_device_attr_group = { + .attrs = sflite_device_attrs, +}; + +int sflite_sysfs_add_device(struct sflite_device *sdev) +{ + return sysfs_create_group(sdev->kobj_parent, &sflite_device_attr_group); +} + +void sflite_sysfs_remove_device(struct sflite_device *sdev) +{ + sysfs_remove_group(sdev->kobj_parent, &sflite_device_attr_group); +} + + +/* + *---------------------------- + * Volume entries + *---------------------------- + */ + +static ssize_t mapped_slices_show(struct kobject *kobj, struct kobj_attribute *kattr, char *buf) +{ + struct sflc_volume *top_vol = container_of(kobj, struct sflc_volume, kobj); + struct sflite_volume *svol = top_vol->sflite_vol; + int ret; + + if (mutex_lock_interruptible(&svol->posmap_lock)) + return -ERESTARTSYS; + ret = sysfs_emit(buf, "%u\n", svol->nr_mapped_slices); + mutex_unlock(&svol->posmap_lock); + + return ret; +} + +static struct kobj_attribute mapped_slices_kattr = __ATTR_RO(mapped_slices); +static struct attribute *sflite_volume_attrs[] = { + &mapped_slices_kattr.attr, + NULL +}; +static const struct attribute_group sflite_volume_attr_group = { + .attrs = sflite_volume_attrs, +}; + +int sflite_sysfs_add_volume(struct sflite_volume *svol) +{ + return sysfs_create_group(svol->kobj_parent, &sflite_volume_attr_group); +} + +void sflite_sysfs_remove_volume(struct sflite_volume *svol) +{ + sysfs_remove_group(svol->kobj_parent, &sflite_volume_attr_group); +} diff --git a/dm-sflc/src/lite/volume.c b/dm-sflc/src/lite/volume.c new file mode 100644 index 0000000..e37d9c1 --- /dev/null +++ b/dm-sflc/src/lite/volume.c @@ -0,0 +1,163 @@ +/* + * Copyright The Shufflecake Project Authors (2022) + * Copyright The Shufflecake Project Contributors (2022) + * Copyright Contributors to the The Shufflecake Project. + * + * See the AUTHORS file at the top-level directory of this distribution and at + * + * + * This file is part of the program shufflecake-c, which is part of the + * Shufflecake Project. Shufflecake is a plausible deniability (hidden storage) + * layer for Linux. See . + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 2 of the License, or (at your option) + * any later version. This program is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. You should have received a copy of the + * GNU General Public License along with this program. + * If not, see . + */ + +#include +#include "sflc_lite.h" + + +/** + * Arguments: + * argv[0]: Shufflecake mode: legacy/lite + * argv[1]: Shufflecake-unique device ID + * argv[2]: path to underlying physical device + * argv[3]: volume index within the device + * argv[4]: number of 1 MB slices in the underlying device + * argv[5]: 64-byte encryption key (hex-encoded) + */ +struct sflite_volume *sflite_vol_create(struct dm_target *ti, struct sflite_device* sdev, + int argc, char **argv, struct kobject *kobj) +{ + struct sflite_volume *svol; + u32 vol_idx; + int err; + + svol = kzalloc(sizeof(*svol), GFP_KERNEL); + if (!svol) { + DMERR("Could not allocate volume"); + return ERR_PTR(-ENOMEM); + } + + /* Parse arguments */ + if (argc != 6) { + DMERR("Wrong argument count"); + err = -EINVAL; + goto bad_parse; + } + if (sscanf(argv[3], "%u", &vol_idx) != 1) { + DMERR("Could not decode tot_slices\n"); + err = -EINVAL; + goto bad_parse; + } + /* Decode the encryption key */ + if (strlen(argv[5]) != 2 * SFLITE_XTS_KEYLEN) { + DMERR("Invalid key length"); + err = -EINVAL; + goto bad_parse; + } + err = hex2bin(svol->enckey, argv[5], SFLITE_XTS_KEYLEN); + if (err) { + DMERR("Could not decode hexadecimal encryption key"); + err = -EINVAL; + goto bad_parse; + } + + svol->sdev = sdev; + svol->vol_idx = vol_idx; + sprintf(svol->name, "sflc_%u_%u", sdev->dev_id, vol_idx); + + svol->ti = ti; + err = dm_get_device(ti, sdev->name, + dm_table_get_mode(ti->table), &svol->dm_dev); + if (err) { + ti->error = "Device lookup failed"; + goto bad_dm_dev; + } + + /* Crypto */ + svol->tfm = crypto_alloc_skcipher("xts(aes)", 0, 0); + if (IS_ERR(svol->tfm)) { + err = PTR_ERR(svol->tfm); + DMERR("Could not allocate AES-XTS cipher handle; error %d", err); + goto bad_tfm_alloc; + } + err = crypto_skcipher_setkey(svol->tfm, svol->enckey, SFLITE_XTS_KEYLEN); + if (err) { + DMERR("Could not set key in crypto transform; error %d", err); + goto bad_tfm_setkey; + } + + /* Position map */ + mutex_init(&svol->posmap_lock); + /* Slight over-allocation, to fit a whole number of blocks */ + svol->posmap = vmalloc(sdev->posmap_size_sectors * SECTOR_SIZE); + if (!svol->posmap) { + DMERR("Could not allocate position map"); + err = -ENOMEM; + goto bad_posmap_alloc; + } + svol->nr_mapped_slices = 0; + /* Load from disk */ + err = sflite_load_and_sanitise_posmap(svol); + if (err) { + DMERR("Could not load position map from disk; error %d", err); + goto bad_posmap_load; + } + + /* Add to sysfs, once initialised */ + svol->kobj_parent = kobj; + err = sflite_sysfs_add_volume(svol); + if (err) { + DMERR("Could not register volume with sysfs; error %d", err); + goto bad_sysfs; + } + + /* Only accept one block per request for simplicity TODO: improve to one slice*/ + ti->max_io_len = SFLITE_BLOCK_SCALE; + ti->flush_supported = true; + ti->num_flush_bios = 1; + ti->discards_supported = false; + ti->num_discard_bios = 0; + ti->num_secure_erase_bios = 0; + ti->num_write_zeroes_bios = 0; + ti->accounts_remapped_io = true; + ti->per_io_data_size = sizeof(struct sflite_io); + ti->private = svol; + + return svol; + + +bad_sysfs: +bad_posmap_load: + vfree(svol->posmap); +bad_posmap_alloc: +bad_tfm_setkey: + crypto_free_skcipher(svol->tfm); +bad_tfm_alloc: + dm_put_device(ti, svol->dm_dev); +bad_dm_dev: +bad_parse: + kfree(svol); + return ERR_PTR(err); +} + + +void sflite_vol_destroy(struct sflite_volume *svol) +{ + sflite_sysfs_remove_volume(svol); + vfree(svol->posmap); + crypto_free_skcipher(svol->tfm); + dm_put_device(svol->ti, svol->dm_dev); + kfree(svol); + + return; +} diff --git a/dm-sflc/src/lite/write.c b/dm-sflc/src/lite/write.c new file mode 100644 index 0000000..5b2fb66 --- /dev/null +++ b/dm-sflc/src/lite/write.c @@ -0,0 +1,148 @@ +/* + * Copyright The Shufflecake Project Authors (2022) + * Copyright The Shufflecake Project Contributors (2022) + * Copyright Contributors to the The Shufflecake Project. + * + * See the AUTHORS file at the top-level directory of this distribution and at + * + * + * This file is part of the program shufflecake-c, which is part of the + * Shufflecake Project. Shufflecake is a plausible deniability (hidden storage) + * layer for Linux. See . + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 2 of the License, or (at your option) + * any later version. This program is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. You should have received a copy of the + * GNU General Public License along with this program. + * If not, see . + */ + +#include "sflc_lite.h" +#include + + +static void sflite_write_endio(struct bio *phys_bio); + + +void sflite_write_work_fn(struct work_struct *work) +{ + struct sflite_io *sio = container_of(work, struct sflite_io, work); + struct sflite_volume *svol = sio->svol; + struct sflite_device *sdev = svol->sdev; + struct bio *orig_bio = sio->orig_bio; + struct bio_vec bvl = bio_iovec(orig_bio); + struct bio *phys_bio; + struct page *page; + u32 lsi = sio->lsi; + u32 block_offset = sio->block_offset; + u32 psi; + int err; + +// DMWARN("WRITE: dequeued. Sector = %llu", orig_bio->bi_iter.bi_sector); +// msleep(100); + + + /* Read existing mapping, or create new one */ + if (mutex_lock_interruptible(&svol->posmap_lock)) { + orig_bio->bi_status = BLK_STS_IOERR; + goto endio; + } + psi = svol->posmap[lsi]; + /* If LSI unmapped, create new mapping, while holding the lock */ + if (psi == SFLITE_PSI_INVALID) { +// DMWARN("WRITE: unmapped LSI %u, sampling PSI", lsi); +// msleep(100); + + err = sflite_create_persistent_slice_mapping(svol, lsi, &psi); + if (err){ + DMERR("Could not create slice mapping; error %d", err); + mutex_unlock(&svol->posmap_lock); + orig_bio->bi_status = BLK_STS_IOERR; + goto endio; + } +// DMWARN("WRITE: sampled PSI %u for LSI %u", psi, lsi); +// msleep(100); + } + mutex_unlock(&svol->posmap_lock); + sio->psi = psi; + + /* Allocate physical bio */ + phys_bio = bio_alloc_bioset(svol->dm_dev->bdev, 1, orig_bio->bi_opf, + GFP_NOIO, &sdev->bioset); + if (!phys_bio) { + DMERR("Could not allocate physical bio"); + orig_bio->bi_status = BLK_STS_IOERR; + goto endio; + } + /* Insert in the I/O struct */ + sio->phys_bio = phys_bio; + + /* Physical bio needs its own page */ + page = alloc_pages(GFP_NOIO, 0); + if (!page) { + DMERR("Could not allocate page for physical bio"); + orig_bio->bi_status = BLK_STS_IOERR; + goto bad_alloc_page; + } + + /* Remap sector */ + phys_bio->bi_iter.bi_sector = SFLITE_PHYS_BIO_SECTOR(sdev, psi, block_offset); + /* Encrypt */ + err = sflite_crypt_block_page(svol->tfm, bvl.bv_page, page, + phys_bio->bi_iter.bi_sector >> SFLITE_BLOCK_SHIFT, WRITE); + if (err) { + DMERR("Could not encrypt bio; error %d", err); + orig_bio->bi_status = BLK_STS_IOERR; + goto bad_encrypt; + } + + /* Add page to bio */ + __bio_add_page(phys_bio, page, SFLITE_BLOCK_SIZE, 0); + /* Set fields for the endio */ + phys_bio->bi_private = sio; + phys_bio->bi_end_io = sflite_write_endio; + /* Submit */ + dm_submit_bio_remap(orig_bio, phys_bio); + + return; + + +bad_encrypt: + __free_page(page); +bad_alloc_page: + bio_put(phys_bio); +endio: + bio_endio(orig_bio); + return; +} + +static void sflite_write_endio(struct bio *phys_bio) +{ + struct sflite_io *sio = phys_bio->bi_private; + struct bio *orig_bio = sio->orig_bio; + + /* If physical bio failed, then fail-fast */ + if (phys_bio->bi_status != BLK_STS_OK) { + orig_bio->bi_status = phys_bio->bi_status; + DMWARN("WRITE ENDIO: phys_bio failed"); + goto endio; + } + + /* Advance original bio by one block */ + bio_advance(orig_bio, SFLITE_BLOCK_SIZE); + orig_bio->bi_status = BLK_STS_OK; + +endio: + /* Free the physical bio and its page */ + bio_free_pages(phys_bio); + bio_put(phys_bio); + /* End original bio */ + bio_endio(orig_bio); + + return; +} + diff --git a/dm-sflc/src/sflc.c b/dm-sflc/src/sflc.c new file mode 100644 index 0000000..1a7e802 --- /dev/null +++ b/dm-sflc/src/sflc.c @@ -0,0 +1,293 @@ +/* + * Copyright The Shufflecake Project Authors (2022) + * Copyright The Shufflecake Project Contributors (2022) + * Copyright Contributors to the The Shufflecake Project. + * + * See the AUTHORS file at the top-level directory of this distribution and at + * + * + * This file is part of the program shufflecake-c, which is part of the + * Shufflecake Project. Shufflecake is a plausible deniability (hidden storage) + * layer for Linux. See . + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 2 of the License, or (at your option) + * any later version. This program is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. You should have received a copy of the + * GNU General Public License along with this program. + * If not, see . + */ + +#include +#include +#include + +#include "sflc.h" +#include "legacy/sflc_legacy.h" +#include "lite/sflc_lite.h" + +#include + + +// Global variables +DEFINE_MUTEX(sflc_alldevs_lock); +struct sflc_device **sflc_alldevs = NULL; +u32 sflc_free_devid = 0; /* The lowest free devID */ + + +/* Add a device to the global array, and advance next_dev_id */ +static int sflc_add_device_global(u32 dev_id, struct sflc_device *sdev) +{ + int i; + + if (mutex_lock_interruptible(&sflc_alldevs_lock)) + return -ERESTARTSYS; + + /* Check for dev_id conflict, possible because a read() to next_dev_id + * in sysfs can return the same value to two processes */ + if (sflc_alldevs[dev_id]) { + mutex_unlock(&sflc_alldevs_lock); + DMERR("A device with this ID already exists. Retry"); + return -EINVAL; + } + // Add to the global array, and advance free_devid + sflc_alldevs[dev_id] = sdev; + for (i = sflc_free_devid; i < SFLC_MAX_DEVS && sflc_alldevs[i]; i++); + sflc_free_devid = i; + + mutex_unlock(&sflc_alldevs_lock); + + return 0; +} + +/* Remove a device from the global array, and update next_dev_id */ +static void sflc_remove_device_global(u32 dev_id) +{ + if (mutex_lock_interruptible(&sflc_alldevs_lock)) + return; + sflc_alldevs[dev_id] = NULL; + if (dev_id < sflc_free_devid) + sflc_free_devid = dev_id; + mutex_unlock(&sflc_alldevs_lock); +} + + +/* + * Create volume and, if not existent, the underlying device. + * Arguments: + * argv[0]: Shufflecake mode: legacy/lite + * argv[1]: Shufflecake-unique device ID + * argv[2]: path to underlying physical device + * argv[3]: volume index within the device + * argv[4:]: mode-specific parameters + */ +static int sflc_ctr(struct dm_target *ti, unsigned int argc, char **argv) +{ + u32 dev_id; + u32 vol_idx; + struct sflc_device *sdev; + struct sflc_volume *svol; + int err; + + /* Parse arguments */ + if (argc < 4) { + ti->error = "Invalid argument count"; + return -EINVAL; + } + if (sscanf(argv[1], "%u", &dev_id) != 1) { + ti->error = "Could not decode device ID"; + return -EINVAL; + } + if (sscanf(argv[3], "%u", &vol_idx) != 1) { + ti->error = "Could not decode volume index"; + return -EINVAL; + } + /* Sanity checks */ + if (dev_id >= SFLC_MAX_DEVS) { + ti->error = "Device ID out of bounds"; + return -EINVAL; + } + if (vol_idx >= SFLC_DEV_MAX_VOLUMES) { + ti->error = "Volume index out of bounds"; + return -EINVAL; + } + + /* Create device, if this is the first volume, otherwise retrieve it */ + if (vol_idx == 0) { + sdev = sflc_dev_create(ti, argc, argv); + if (IS_ERR(sdev)) { + ti->error = "Could not instantiate device"; + return PTR_ERR(sdev); + } + /* Insert in global array */ + err = sflc_add_device_global(dev_id, sdev); + if (err) { + ti->error = "Could not add device to global array"; + goto bad_dev_global; + } + } else { + if (mutex_lock_interruptible(&sflc_alldevs_lock)) + return -ERESTARTSYS; + sdev = sflc_alldevs[dev_id]; + mutex_unlock(&sflc_alldevs_lock); + + if (!sdev) { + ti->error = "Could not find device with specified ID"; + return -EINVAL; + } + } + + /* Create volume */ + svol = sflc_vol_create(sdev, ti, argc, argv); + if (IS_ERR(svol)) { + ti->error = "Could not instantiate volume"; + err = PTR_ERR(svol); + goto bad_vol_create; + } + /* We expect ->ctr() calls to be strictly sequential, so we don't need locking */ + sdev->nr_volumes++; + + ti->private = svol; + + return 0; + + +bad_vol_create: + if (vol_idx == 0) { + sflc_remove_device_global(dev_id); +bad_dev_global: + sflc_dev_destroy(sdev); + } + return err; +} + + +/* Destroy volume and, if needed, the underlying device */ +static void sflc_dtr(struct dm_target *ti) +{ + struct sflc_volume *svol = ti->private; + struct sflc_device *sdev = svol->sdev; + + sflc_vol_destroy(svol); + /* We expect ->dtr() calls to be strictly sequential, so we don't need locking */ + sdev->nr_volumes--; + + if (sdev->nr_volumes == 0) { + sflc_remove_device_global(sdev->dev_id); + sflc_dev_destroy(sdev); + } + + return; +} + + +static int sflc_map(struct dm_target *ti, struct bio *bio) +{ + struct sflc_volume *svol = ti->private; + return svol->tt->map(ti, bio); +} + +static void sflc_io_hints(struct dm_target *ti, struct queue_limits *limits) +{ + struct sflc_volume *svol = ti->private; + svol->tt->io_hints(ti, limits); + return; +} + +static int sflc_iterate_devices(struct dm_target *ti, iterate_devices_callout_fn fn, void *data) +{ + struct sflc_volume *svol = ti->private; + return svol->tt->iterate_devices(ti, fn, data); +} + + +/* + *---------------------------- + * Kernel module + *---------------------------- + */ + +static struct target_type sflc_target_type = { + .name = SFLC_TARGET_NAME, + .version = {SFLC_VER_MAJOR, SFLC_VER_MINOR, SFLC_VER_REVISION}, + .module = THIS_MODULE, + .ctr = sflc_ctr, + .dtr = sflc_dtr, + .map = sflc_map, + .io_hints = sflc_io_hints, + .iterate_devices = sflc_iterate_devices, +}; + + +/* Module entry point */ +static int sflc_init(void) +{ + int ret; + + sflc_alldevs = vzalloc(SFLC_MAX_DEVS * sizeof(*sflc_alldevs)); + if (!sflc_alldevs) { + DMERR("Could not allocate sflc_alldevs"); + ret = -ENOMEM; + goto bad_alldevs_alloc; + } + + /* Create the first sysfs entries */ + ret = sflc_sysfs_init(); + if (ret) + goto err_sysfs; + + /* Init the Legacy module */ + ret = sflegc_init(); + if (ret) + goto err_sflegc; + + /* Init the Lite module */ + ret = sflite_init(); + if (ret) + goto err_sflite; + + /* Register the DM callbacks */ + ret = dm_register_target(&sflc_target_type); + if (ret < 0) + goto err_dm; + + DMINFO("loaded"); + return 0; + + +err_dm: + sflite_exit(); +err_sflite: + sflegc_exit(); +err_sflegc: + sflc_sysfs_exit(); +err_sysfs: + vfree(sflc_alldevs); +bad_alldevs_alloc: + DMERR("not loaded"); + return ret; +} + + +/* Module exit point */ +static void sflc_exit(void) +{ + dm_unregister_target(&sflc_target_type); + sflegc_exit(); + sflite_exit(); + sflc_sysfs_exit(); + vfree(sflc_alldevs); + + DMINFO("unloaded"); + return; +} + + +module_init(sflc_init); +module_exit(sflc_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Toninov"); diff --git a/dm-sflc/src/sflc.h b/dm-sflc/src/sflc.h new file mode 100644 index 0000000..1ff8499 --- /dev/null +++ b/dm-sflc/src/sflc.h @@ -0,0 +1,120 @@ +/* + * Copyright The Shufflecake Project Authors (2022) + * Copyright The Shufflecake Project Contributors (2022) + * Copyright Contributors to the The Shufflecake Project. + * + * See the AUTHORS file at the top-level directory of this distribution and at + * + * + * This file is part of the program shufflecake-c, which is part of the + * Shufflecake Project. Shufflecake is a plausible deniability (hidden storage) + * layer for Linux. See . + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 2 of the License, or (at your option) + * any later version. This program is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. You should have received a copy of the + * GNU General Public License along with this program. + * If not, see . + */ + +#ifndef _SFLC_H +#define _SFLC_H + + +#include + +#include "sflc_constants.h" +#include "legacy/sflc_legacy.h" +#include "lite/sflc_lite.h" + + +/* + *---------------------------- + * Structs + *---------------------------- + */ + +struct sflc_device +{ + /* Shufflecake-unique device ID */ + u32 dev_id; + /* : */ + char name[16]; + /* Number of volumes */ + u32 nr_volumes; + + /* Mode-specific device struct */ + int mode; + union { + sflegc_Device *sflegc_dev; + struct sflite_device *sflite_dev; + }; + + /* Sysfs */ + struct kobject kobj; + struct completion kobj_released; +}; + +struct sflc_volume +{ + /* Backing device */ + struct sflc_device *sdev; + /* Volume name: sflc__ */ + char name[32]; + + /* Mode-specific volume struct */ + int mode; + union { + sflegc_Volume *sflegc_vol; + struct sflite_volume *sflite_vol; + }; + /* Pointers to concrete, mode-specific callbacks */ + struct target_type *tt; + + /* Sysfs */ + struct kobject kobj; + struct completion kobj_released; +}; + + +/* + *---------------------------- + * Global variables + *---------------------------- + */ + +extern struct mutex sflc_alldevs_lock; +extern struct sflc_device **sflc_alldevs; +/* Next free device id */ +extern u32 sflc_free_devid; /* The lowest free devID */ + + +/* + *---------------------------- + * Functions + *---------------------------- + */ + +/* Device */ +struct sflc_device *sflc_dev_create(struct dm_target *ti, int argc, char **argv); +void sflc_dev_destroy(struct sflc_device *sdev); + +/* Volume */ +struct sflc_volume *sflc_vol_create(struct sflc_device *sdev, struct dm_target *ti, + int argc, char **argv); +void sflc_vol_destroy(struct sflc_volume *svol); + +/* Sysfs */ +int sflc_sysfs_init(void); +void sflc_sysfs_exit(void); +int sflc_sysfs_register_device(struct sflc_device *sdev); +void sflc_sysfs_unregister_device(struct sflc_device *sdev); +int sflc_sysfs_register_volume(struct sflc_volume *svol); +void sflc_sysfs_unregister_volume(struct sflc_volume *svol); + + +#endif /* _SFLC_H */ diff --git a/dm-sflc/sflc_constants.h b/dm-sflc/src/sflc_constants.h similarity index 65% rename from dm-sflc/sflc_constants.h rename to dm-sflc/src/sflc_constants.h index a425d88..c978796 100644 --- a/dm-sflc/sflc_constants.h +++ b/dm-sflc/src/sflc_constants.h @@ -21,17 +21,20 @@ * If not, see . */ -/***************************************************** - * PLACEHOLDER * - *****************************************************/ +/* Here we gather Shufflecake-wide constants, independent of the mode (legacy/lite) */ -/* This is just a placeholder for defining constants and parameters that must be the same across shufflecake components (kernel module, userland tool, etc) such as block size, slice size etc */ +#ifndef _SFLC_CONSTANTS_H_ +#define _SFLC_CONSTANTS_H_ + + +#define SFLC_TARGET_NAME "shufflecake" +#define DM_MSG_PREFIX "sflc" #define SFLC_VER_MAJOR 0 -#define SFLC_VER_MINOR 4 -#define SFLC_VER_REVISION 5 -#define SFLC_VER_SPECIAL "" +#define SFLC_VER_MINOR 5 +#define SFLC_VER_REVISION 0 +#define SFLC_VER_SPECIAL "rc1" #define STRINGIFY0(s) # s #define STRINGIFY(s) STRINGIFY0(s) @@ -39,3 +42,20 @@ #define SFLC_VERSION STRINGIFY(SFLC_VER_MAJOR)"."STRINGIFY(SFLC_VER_MINOR)"."STRINGIFY(SFLC_VER_REVISION)""SFLC_VER_SPECIAL +/* Each device can be formatted and used with a mode of choice, irrespective of the other devices */ +#define SFLC_MODE_LEGACY 0 +#define SFLC_MODE_LITE 1 + + +/* Max number of volumes per device */ +#define SFLC_DEV_MAX_VOLUMES 15 +/* Max number of open devices at any given time */ +#define SFLC_MAX_DEVS 1024 + + +/* Sysfs entries under /sys/module/dm_sflc/ */ +#define SFLC_SYSFS_BDEVS "bdevs" +#define SFLC_SYSFS_DEVID "next_dev_id" + + +#endif /* _SFLC_CONSTANTS_H_ */ diff --git a/dm-sflc/src/sysfs.c b/dm-sflc/src/sysfs.c new file mode 100644 index 0000000..2ef402d --- /dev/null +++ b/dm-sflc/src/sysfs.c @@ -0,0 +1,203 @@ +/* + * Copyright The Shufflecake Project Authors (2022) + * Copyright The Shufflecake Project Contributors (2022) + * Copyright Contributors to the The Shufflecake Project. + * + * See the AUTHORS file at the top-level directory of this distribution and at + * + * + * This file is part of the program shufflecake-c, which is part of the + * Shufflecake Project. Shufflecake is a plausible deniability (hidden storage) + * layer for Linux. See . + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 2 of the License, or (at your option) + * any later version. This program is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. You should have received a copy of the + * GNU General Public License along with this program. + * If not, see . + */ + +#include "sflc.h" + +#include + +/* + *---------------------------- + * Top-level entries + *---------------------------- + */ + +static ssize_t next_dev_id_show(struct module_attribute *mattr, struct module_kobject *mkobj, char *buf) +{ + ssize_t ret; + + if (mutex_lock_interruptible(&sflc_alldevs_lock)) + return -ERESTARTSYS; + ret = sysfs_emit(buf, "%u\n", sflc_free_devid); + mutex_unlock(&sflc_alldevs_lock); + + return ret; +} + +static struct kset *bdevs_kset; +static struct module_attribute devid_mattr = __ATTR_RO(next_dev_id); + +int sflc_sysfs_init() +{ + int err; + + bdevs_kset = kset_create_and_add(SFLC_SYSFS_BDEVS, NULL, &THIS_MODULE->mkobj.kobj); + if (!bdevs_kset) { + err = -ENOMEM; + DMERR("Could not create %s kset", SFLC_SYSFS_BDEVS); + goto bad_bdevs; + } + + err = sysfs_create_file(&THIS_MODULE->mkobj.kobj, &devid_mattr.attr); + if (err) { + DMERR("Could not create %s file", SFLC_SYSFS_DEVID); + goto bad_devid; + } + + return 0; + + +bad_devid: + kset_unregister(bdevs_kset); +bad_bdevs: + return err; +} + +void sflc_sysfs_exit() +{ + sysfs_remove_file(&THIS_MODULE->mkobj.kobj, &devid_mattr.attr); + kset_unregister(bdevs_kset); +} + + +/* + *---------------------------- + * Device entries + *---------------------------- + */ + +static ssize_t dev_id_show(struct kobject *kobj, struct kobj_attribute *kattr, char *buf) +{ + struct sflc_device *sdev = container_of(kobj, struct sflc_device, kobj); + + return sysfs_emit(buf, "%u\n", sdev->dev_id); +} + +static ssize_t volumes_show(struct kobject *kobj, struct kobj_attribute *kattr, char *buf) +{ + struct sflc_device *sdev = container_of(kobj, struct sflc_device, kobj); + + return sysfs_emit(buf, "%u\n", sdev->nr_volumes); +} + + +static struct kobj_attribute dev_id_kattr = __ATTR_RO(dev_id); +static struct kobj_attribute volumes_kattr = __ATTR_RO(volumes); +static struct attribute *sflc_device_default_attrs[] = { + &dev_id_kattr.attr, + &volumes_kattr.attr, + NULL +}; +ATTRIBUTE_GROUPS(sflc_device_default); + +static void sflc_device_kobj_release(struct kobject *kobj) +{ + struct sflc_device *sdev = container_of(kobj, struct sflc_device, kobj); + complete(&sdev->kobj_released); +} + +static struct kobj_type sflc_device_ktype = { + .release = sflc_device_kobj_release, + .sysfs_ops = &kobj_sysfs_ops, + .default_groups = sflc_device_default_groups +}; + +int sflc_sysfs_register_device(struct sflc_device *sdev) +{ + int err; + + /* Completion */ + init_completion(&sdev->kobj_released); + + /* Register directory :/ under bdevs/ */ + sdev->kobj.kset = bdevs_kset; + err = kobject_init_and_add(&sdev->kobj, &sflc_device_ktype, NULL, + "%s", sdev->name); + if (err) + goto bad; + /* Emit uevent */ + kobject_uevent(&sdev->kobj, KOBJ_ADD); + + return 0; + + +bad: + kobject_put(&sdev->kobj); + wait_for_completion(&sdev->kobj_released); + return err; +} + +void sflc_sysfs_unregister_device(struct sflc_device *sdev) +{ + kobject_put(&sdev->kobj); + wait_for_completion(&sdev->kobj_released); +} + + +/* + *---------------------------- + * Volume entries + *---------------------------- + */ + +static void sflc_volume_kobj_release(struct kobject *kobj) +{ + struct sflc_volume *svol = container_of(kobj, struct sflc_volume, kobj); + + complete(&svol->kobj_released); +} + +static struct kobj_type sflc_volume_ktype = { + .release = sflc_volume_kobj_release, + .sysfs_ops = &kobj_sysfs_ops, +}; + +int sflc_sysfs_register_volume(struct sflc_volume *svol) +{ + int err; + + /* Completion */ + init_completion(&svol->kobj_released); + + /* Register directory name>/ under device directory */ + err = kobject_init_and_add(&svol->kobj, &sflc_volume_ktype, &svol->sdev->kobj, + "%s", svol->name); + if (err) + goto bad; + + /* Emit uevent */ + kobject_uevent(&svol->kobj, KOBJ_ADD); + + return 0; + + +bad: + kobject_put(&svol->kobj); + wait_for_completion(&svol->kobj_released); + return err; +} + +void sflc_sysfs_unregister_volume(struct sflc_volume *svol) +{ + kobject_put(&svol->kobj); + wait_for_completion(&svol->kobj_released); +} diff --git a/dm-sflc/sysfs/devices.c b/dm-sflc/sysfs/devices.c deleted file mode 100644 index 7729145..0000000 --- a/dm-sflc/sysfs/devices.c +++ /dev/null @@ -1,301 +0,0 @@ -/* - * Copyright The Shufflecake Project Authors (2022) - * Copyright The Shufflecake Project Contributors (2022) - * Copyright Contributors to the The Shufflecake Project. - * - * See the AUTHORS file at the top-level directory of this distribution and at - * - * - * This file is part of the program shufflecake-c, which is part of the - * Shufflecake Project. Shufflecake is a plausible deniability (hidden storage) - * layer for Linux. See . - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation, either version 2 of the License, or (at your option) - * any later version. This program is distributed in the hope that it will be - * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General - * Public License for more details. You should have received a copy of the - * GNU General Public License along with this program. - * If not, see . - */ - -/***************************************************** - * INCLUDE SECTION * - *****************************************************/ - -#include "sysfs.h" -#include "utils/string.h" -#include "log/log.h" - - -/***************************************************** - * CONSTANTS * - *****************************************************/ - -#define SFLC_SYSFS_DEV_VOLUMES_ATTR_NAME "volumes" -#define SFLC_SYSFS_DEV_TOT_SLICES_ATTR_NAME "tot_slices" -#define SFLC_SYSFS_DEV_FREE_SLICES_ATTR_NAME "free_slices" - - -/***************************************************** - * PRIVATE FUNCTIONS PROTOTYPES * - *****************************************************/ - -/* Functions that will go in the sysfs_ops */ -static ssize_t sflc_sysfs_devShow(struct kobject * kobj, struct attribute * attr, char * buf); -static ssize_t sflc_sysfs_devStore(struct kobject * kobj, struct attribute * attr, const char * buf, size_t len); - -/* Concrete file showers */ -static ssize_t sflc_sysfs_showDeviceVolumes(struct kobject * kobj, struct attribute * attr, char * buf); -static ssize_t sflc_sysfs_showDeviceTotSlices(struct kobject * kobj, struct attribute * attr, char * buf); -static ssize_t sflc_sysfs_showDeviceFreeSlices(struct kobject * kobj, struct attribute * attr, char * buf); - -/* Release function for the sysfs_Device */ -static void sflc_sysfs_releaseDev(struct kobject * kobj); - - -/***************************************************** - * PRIVATE VARIABLES DEFINITIONS * - *****************************************************/ - -/* The attribute representing the volumes file */ -static const struct attribute sflc_sysfs_devVolumesAttr = { - .name = SFLC_SYSFS_DEV_VOLUMES_ATTR_NAME, - .mode = 0444 -}; - -/* The attribute representing the tot_slices file */ -static const struct attribute sflc_sysfs_devTotSlicesAttr = { - .name = SFLC_SYSFS_DEV_TOT_SLICES_ATTR_NAME, - .mode = 0444 -}; - -/* The attribute representing the free_slices file */ -static const struct attribute sflc_sysfs_devFreeSlicesAttr = { - .name = SFLC_SYSFS_DEV_FREE_SLICES_ATTR_NAME, - .mode = 0444 -}; - -/* The sysfs_ops struct encapsulating the access methods */ -static const struct sysfs_ops sflc_sysfs_devSysfsOps = { - .show = sflc_sysfs_devShow, - .store = sflc_sysfs_devStore -}; - -/* The type for our sysfs_Device */ -static struct kobj_type sflc_sysfs_devType = { - .release = sflc_sysfs_releaseDev, - .sysfs_ops = &sflc_sysfs_devSysfsOps, -}; - - -/***************************************************** - * PUBLIC FUNCTIONS DEFINITIONS * - *****************************************************/ - -/* Creates and registers a sysfs_Device instance. Return ERR_PTR() on error. */ -sflc_sysfs_Device * sflc_sysfs_devCreateAndAdd(sflc_Device * pdev) -{ - sflc_sysfs_Device * dev; - int err; - - /* Allocate outer structure */ - dev = kzalloc(sizeof(sflc_sysfs_Device), GFP_KERNEL); - if (!dev) { - err = -ENOMEM; - pr_err("Could not allocate sysfs_Device\n"); - goto err_dev_alloc; - } - - /* Set device */ - dev->pdev = pdev; - - /* Allocate inner string */ - dev->dirname = kzalloc(strlen(pdev->bdev_path) + 1, GFP_KERNEL); - if (!dev->dirname) { - err = -ENOMEM; - pr_err("Could not allocate dirname\n"); - goto err_dirname_alloc; - } - - /* Copy it and substitute slashes with underscores */ - strcpy(dev->dirname, pdev->bdev_path); - sflc_str_replaceAll(dev->dirname, '/', '_'); - - /* Init and add kobject */ - err = kobject_init_and_add(&dev->kobj, &sflc_sysfs_devType, - sflc_sysfs_bdevs, dev->dirname); - if (err) { - pr_err("Could not init and add internal kobject; error %d\n", err); - goto err_kobj_init_add; - } - - /* Create the volumes file */ - err = sysfs_create_file(&dev->kobj, &sflc_sysfs_devVolumesAttr); - if (err) { - pr_err("Could not add volumes file; error %d\n", err); - goto err_vol_file; - } - /* Create the tot_slices file */ - err = sysfs_create_file(&dev->kobj, &sflc_sysfs_devTotSlicesAttr); - if (err) { - pr_err("Could not add tot_slices file; error %d\n", err); - goto err_tot_slices_file; - } - /* Create the volumes file */ - err = sysfs_create_file(&dev->kobj, &sflc_sysfs_devFreeSlicesAttr); - if (err) { - pr_err("Could not add free_slices file; error %d\n", err); - goto err_free_slices_file; - } - - return dev; - - -err_free_slices_file: -err_tot_slices_file: -err_vol_file: - kobject_put(&dev->kobj); -err_kobj_init_add: - kfree(dev->dirname); -err_dirname_alloc: - kfree(dev); -err_dev_alloc: - return ERR_PTR(err); -} - -/* Releases a reference to a sysfs_Device instance */ -void sflc_sysfs_putDev(sflc_sysfs_Device * dev) -{ - kobject_put(&dev->kobj); -} - -/* Creates a symlink inside the device's directory (under /sys/modules/dm_sflc/bdevs/) - * pointing to the volume's directory (under /sys/devices/sflc/) */ -int sflc_sysfs_addVolumeToDevice(sflc_sysfs_Device * dev, sflc_sysfs_Volume * vol) -{ - return sysfs_create_link(&dev->kobj, &vol->kdev.kobj, vol->kdev.kobj.name); -} - -/* Removes the symlink created before */ -void sflc_sysfs_removeVolumeFromDevice(sflc_sysfs_Device * dev, sflc_sysfs_Volume * vol) -{ - sysfs_remove_link(&dev->kobj, vol->kdev.kobj.name); -} - - -/***************************************************** - * PRIVATE FUNCTIONS PROTOTYPES * - *****************************************************/ - -/* Dispatch to the right shower */ -static ssize_t sflc_sysfs_devShow(struct kobject * kobj, struct attribute * attr, char * buf) -{ - /* Dispatch based on name */ - if (strcmp(attr->name, SFLC_SYSFS_DEV_VOLUMES_ATTR_NAME) == 0) { - return sflc_sysfs_showDeviceVolumes(kobj, attr, buf); - } - if (strcmp(attr->name, SFLC_SYSFS_DEV_TOT_SLICES_ATTR_NAME) == 0) { - return sflc_sysfs_showDeviceTotSlices(kobj, attr, buf); - } - if (strcmp(attr->name, SFLC_SYSFS_DEV_FREE_SLICES_ATTR_NAME) == 0) { - return sflc_sysfs_showDeviceFreeSlices(kobj, attr, buf); - } - - /* Else, error */ - pr_err("Error, unknown attribute %s\n", attr->name); - return -EIO; -} - -/* Do nothing */ -static ssize_t sflc_sysfs_devStore(struct kobject * kobj, struct attribute * attr, const char * buf, size_t len) -{ - return -EIO; -} - -/* Show the list of mounted volumes */ -static ssize_t sflc_sysfs_showDeviceVolumes(struct kobject * kobj, struct attribute * attr, char * buf) -{ - sflc_sysfs_Device * dev; - sflc_Device * pdev; - ssize_t ret; - - /* Cast to a sysfs_Device */ - dev = container_of(kobj, sflc_sysfs_Device, kobj); - /* Get the device */ - pdev = dev->pdev; - - /* File contents */ - ret = 0; - ssize_t written; - /* Write the volume count */ - written = sprintf(buf, "%d", pdev->vol_cnt); - ret += written; - buf += written; - /* And all the volume names, space-separated */ - int i; - for (i = 0; i < pdev->vol_cnt; i++) { - written = sprintf(buf, " %s", pdev->vol[i]->vol_name); - ret += written; - buf += written; - } - /* Add newline */ - written = sprintf(buf, "\n"); - ret += written; - buf += written; - - return ret; -} - -/* Show the number of slices */ -static ssize_t sflc_sysfs_showDeviceTotSlices(struct kobject * kobj, struct attribute * attr, char * buf) -{ - sflc_sysfs_Device * dev; - sflc_Device * pdev; - ssize_t ret; - - /* Cast to a DeviceKobject */ - dev = container_of(kobj, sflc_sysfs_Device, kobj); - /* Get the device */ - pdev = dev->pdev; - - /* Write the tot_slices */ - ret = sprintf(buf, "%u\n", pdev->tot_slices); - - return ret; -} - -/* Show the number of free slices */ -static ssize_t sflc_sysfs_showDeviceFreeSlices(struct kobject * kobj, struct attribute * attr, char * buf) -{ - sflc_sysfs_Device * dev; - sflc_Device * pdev; - ssize_t ret; - - /* Cast to a DeviceKobject */ - dev = container_of(kobj, sflc_sysfs_Device, kobj); - /* Get the device */ - pdev = dev->pdev; - - /* Write the free_slices */ - ret = sprintf(buf, "%u\n", pdev->free_slices); - - return ret; -} - -/* Release function for the DeviceKobject */ -static void sflc_sysfs_releaseDev(struct kobject * kobj) -{ - sflc_sysfs_Device * dev; - - /* Cast to a DeviceKobject */ - dev = container_of(kobj, sflc_sysfs_Device, kobj); - - /* Free everything */ - kfree(dev->dirname); - kfree(dev); - - return; -} diff --git a/dm-sflc/sysfs/sysfs.c b/dm-sflc/sysfs/sysfs.c deleted file mode 100644 index a5854c4..0000000 --- a/dm-sflc/sysfs/sysfs.c +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright The Shufflecake Project Authors (2022) - * Copyright The Shufflecake Project Contributors (2022) - * Copyright Contributors to the The Shufflecake Project. - * - * See the AUTHORS file at the top-level directory of this distribution and at - * - * - * This file is part of the program shufflecake-c, which is part of the - * Shufflecake Project. Shufflecake is a plausible deniability (hidden storage) - * layer for Linux. See . - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation, either version 2 of the License, or (at your option) - * any later version. This program is distributed in the hope that it will be - * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General - * Public License for more details. You should have received a copy of the - * GNU General Public License along with this program. - * If not, see . - */ - -/***************************************************** - * INCLUDE SECTION * - *****************************************************/ - -#include - -#include "sysfs.h" -#include "log/log.h" - - -/***************************************************** - * CONSTANTS * - *****************************************************/ - -#define SFLC_SYSFS_BDEVS_ENTRY_NAME "bdevs" -#define SFLC_SYSFS_ROOT_DEVICE_NAME "sflc" -#define SFLC_SYSFS_NEXT_DEV_ID_ATTR_NAME next_dev_id - - -/***************************************************** - * PUBLIC VARIABLES DEFINITIONS * - *****************************************************/ - -/* Kobject associated to the /sys/module/dm_sflc/bdevs entry */ -struct kobject * sflc_sysfs_bdevs; - -/* Root device that will be every volume's parent */ -struct device * sflc_sysfs_root; - - -/***************************************************** - * PRIVATE FUNCTIONS PROTOTYPES * - *****************************************************/ - -static ssize_t sflc_sysfs_showNextDevId(struct device *kdev, struct device_attribute *attr, char *buf); - - -/***************************************************** - * PRIVATE VARIABLES DEFINITIONS * - *****************************************************/ - -/* Attribute showing the next device ID */ -static const struct device_attribute sflc_sysfs_nextDevIdAttr = __ATTR( - SFLC_SYSFS_NEXT_DEV_ID_ATTR_NAME, - 0444, - sflc_sysfs_showNextDevId, - NULL -); - - -/***************************************************** - * PUBLIC FUNCTIONS DEFINITIONS * - *****************************************************/ - -/* Called on module load */ -int sflc_sysfs_init(void) -{ - int err; - - /* Create the bdevs entry under /sys/module/dm_sflc */ - sflc_sysfs_bdevs = kobject_create_and_add(SFLC_SYSFS_BDEVS_ENTRY_NAME, &THIS_MODULE->mkobj.kobj); - if (!sflc_sysfs_bdevs) { - err = -ENOMEM; - pr_err("Could not create bdevs kobject\n"); - goto err_realdevs; - } - - /* Create the root sflc device */ - sflc_sysfs_root = root_device_register(SFLC_SYSFS_ROOT_DEVICE_NAME); - if (IS_ERR(sflc_sysfs_root)) { - err = PTR_ERR(sflc_sysfs_root); - pr_err("Could not register sflc root device; error %d\n", err); - goto err_rootdev; - } - - /* Add next_dev_id attribute to it */ - err = device_create_file(sflc_sysfs_root, &sflc_sysfs_nextDevIdAttr); - if (err) { - pr_err("Could not create mapped_slices device file; error %d\n", err); - goto err_dev_create_file; - } - - return 0; - -err_dev_create_file: - root_device_unregister(sflc_sysfs_root); -err_rootdev: - kobject_put(sflc_sysfs_bdevs); -err_realdevs: - return err; -} - -/* Called on module unload */ -void sflc_sysfs_exit(void) -{ - root_device_unregister(sflc_sysfs_root); - kobject_put(sflc_sysfs_bdevs); -} - - -/***************************************************** - * PRIVATE FUNCTIONS DEFINITIONS * - *****************************************************/ - -static ssize_t sflc_sysfs_showNextDevId(struct device *kdev, struct device_attribute *attr, char *buf) -{ - return sprintf(buf, "%lu\n", sflc_dev_nextId); -} - diff --git a/dm-sflc/sysfs/sysfs.h b/dm-sflc/sysfs/sysfs.h deleted file mode 100644 index 62fc014..0000000 --- a/dm-sflc/sysfs/sysfs.h +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright The Shufflecake Project Authors (2022) - * Copyright The Shufflecake Project Contributors (2022) - * Copyright Contributors to the The Shufflecake Project. - * - * See the AUTHORS file at the top-level directory of this distribution and at - * - * - * This file is part of the program shufflecake-c, which is part of the - * Shufflecake Project. Shufflecake is a plausible deniability (hidden storage) - * layer for Linux. See . - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation, either version 2 of the License, or (at your option) - * any later version. This program is distributed in the hope that it will be - * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General - * Public License for more details. You should have received a copy of the - * GNU General Public License along with this program. - * If not, see . - */ - -/* - * Sysfs functions - */ - -#ifndef _SFLC_SYSFS_SYSFS_H_ -#define _SFLC_SYSFS_SYSFS_H_ - - -/***************************************************** - * TYPES FORWARD DECLARATIONS * - *****************************************************/ - -/* Necessary since device.h, volume.h, and sysfs.h all include each other */ - -typedef struct sflc_sysfs_device_s sflc_sysfs_Device; -typedef struct sflc_sysfs_volume_s sflc_sysfs_Volume; - - -/***************************************************** - * INCLUDE SECTION * - *****************************************************/ - -#include -#include - -#include "device/device.h" -#include "volume/volume.h" - - -/***************************************************** - * TYPES * - *****************************************************/ - -/* This embeds a struct kobject */ -struct sflc_sysfs_device_s -{ - /* The Device it represents */ - sflc_Device * pdev; - /* The name of this device's subdirectoy under realdevs */ - char * dirname; - - /* The embedded kobject */ - struct kobject kobj; -}; - -/* This embeds a struct device */ -struct sflc_sysfs_volume_s -{ - /* The Volume it represents */ - sflc_Volume * pvol; - - /* The embedded device */ - struct device kdev; -}; - - -/***************************************************** - * PUBLIC VARIABLES DECLARATIONS * - *****************************************************/ - -/* Kobject associated to the /sys/module/dm_sflc/bdevs entry */ -extern struct kobject * sflc_sysfs_bdevs; - -/* Root device (/sys/devices/sflc) that will be every volume's parent. - A bit overkill to have a sflc root device, but it does the trick. */ -extern struct device * sflc_sysfs_root; - - -/***************************************************** - * PUBLIC FUNCTIONS PROTOTYPES * - *****************************************************/ - -/* Called on module load/unload */ -int sflc_sysfs_init(void); -void sflc_sysfs_exit(void); - - -/* Device-related functions */ - -/* Creates and registers a sysfs_Device instance. Returns ERR_PTR() on error. */ -sflc_sysfs_Device * sflc_sysfs_devCreateAndAdd(sflc_Device * pdev); - -/* Releases a reference to a sysfs_Device instance */ -void sflc_sysfs_putDev(sflc_sysfs_Device * dev); - -/* Creates a symlink inside the device's subdirectory pointing to the volume's subdirectory */ -int sflc_sysfs_addVolumeToDevice(sflc_sysfs_Device * dev, sflc_sysfs_Volume * vol); - -/* Removes the symlink created before */ -void sflc_sysfs_removeVolumeFromDevice(sflc_sysfs_Device * dev, sflc_sysfs_Volume * vol); - - -/* Volume-related functions */ - -/* Creates and registers a sysfs_Volume instance. Returns ERR_PTR() on error. */ -sflc_sysfs_Volume * sflc_sysfs_volCreateAndAdd(sflc_Volume * pvol); - -/* Releases a reference to a sysfs_Volume instance */ -void sflc_sysfs_putVol(sflc_sysfs_Volume * vol); - - -#endif /* _SFLC_SYSFS_SYSFS_H_ */ diff --git a/dm-sflc/sysfs/volumes.c b/dm-sflc/sysfs/volumes.c deleted file mode 100644 index 2ca2e7f..0000000 --- a/dm-sflc/sysfs/volumes.c +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright The Shufflecake Project Authors (2022) - * Copyright The Shufflecake Project Contributors (2022) - * Copyright Contributors to the The Shufflecake Project. - * - * See the AUTHORS file at the top-level directory of this distribution and at - * - * - * This file is part of the program shufflecake-c, which is part of the - * Shufflecake Project. Shufflecake is a plausible deniability (hidden storage) - * layer for Linux. See . - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation, either version 2 of the License, or (at your option) - * any later version. This program is distributed in the hope that it will be - * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General - * Public License for more details. You should have received a copy of the - * GNU General Public License along with this program. - * If not, see . - */ - -/***************************************************** - * INCLUDE SECTION * - *****************************************************/ - -#include "sysfs.h" -#include "utils/string.h" -#include "log/log.h" - - -/***************************************************** - * CONSTANTS * - *****************************************************/ - -#define SFLC_SYSFS_VOL_NR_SLICES_ATTR_NAME mapped_slices - - -/***************************************************** - * PRIVATE FUNCTIONS PROTOTYPES * - *****************************************************/ - -static void sflc_sysfs_volRelease(struct device * kdev); -static ssize_t sflc_sysfs_showVolNrSlices(struct device * dev, struct device_attribute * attr, char * buf); - - -/***************************************************** - * PRIVATE VARIABLES DEFINITIONS * - *****************************************************/ - -/* Attribute showing the number of slices utilised by the volume */ -static const struct device_attribute sflc_sysfs_volNrSlicesAttr = __ATTR( - SFLC_SYSFS_VOL_NR_SLICES_ATTR_NAME, - 0444, - sflc_sysfs_showVolNrSlices, - NULL -); - - -/***************************************************** - * PUBLIC FUNCTIONS DEFINITIONS * - *****************************************************/ - -/* Creates and registers a sysfs_Volume instance. Returns ERR_PTR() on error. */ -sflc_sysfs_Volume * sflc_sysfs_volCreateAndAdd(sflc_Volume * pvol) -{ - sflc_sysfs_Volume * vol; - int err; - - /* Allocate device */ - vol = kzalloc(sizeof(sflc_sysfs_Volume), GFP_KERNEL); - if (!vol) { - err = -ENOMEM; - pr_err("Could not allocate sysfs_Volume\n"); - goto err_vol_alloc; - } - - /* Set volume */ - vol->pvol = pvol; - - /* Set name */ - err = dev_set_name(&vol->kdev, "%s", pvol->vol_name); - if (err) { - pr_err("Could not set device name %s; error %d\n", pvol->vol_name, err); - goto err_dev_set_name; - } - - /* Set destructor */ - vol->kdev.release = sflc_sysfs_volRelease; - /* Set parent */ - vol->kdev.parent = sflc_sysfs_root; - - /* Register */ - err = device_register(&vol->kdev); - if (err) { - pr_err("Could not register volume %s; error %d\n", pvol->vol_name, err); - goto err_dev_register; - } - - /* Add mapped_slices attribute */ - err = device_create_file(&vol->kdev, &sflc_sysfs_volNrSlicesAttr); - if (err) { - pr_err("Could not create mapped_slices device file; error %d\n", err); - goto err_dev_create_file; - } - - return vol; - - -err_dev_create_file: - device_unregister(&vol->kdev); -err_dev_register: - put_device(&vol->kdev); -err_dev_set_name: - kfree(vol); -err_vol_alloc: - return ERR_PTR(err); -} - -/* Releases a reference to a sysfs_Device instance */ -void sflc_sysfs_putVol(sflc_sysfs_Volume * vol) -{ - device_unregister(&vol->kdev); -} - - -/***************************************************** - * PRIVATE FUNCTIONS PROTOTYPES * - *****************************************************/ - -static ssize_t sflc_sysfs_showVolNrSlices(struct device * kdev, struct device_attribute * attr, char * buf) -{ - sflc_sysfs_Volume * vol = container_of(kdev, sflc_sysfs_Volume, kdev); - sflc_Volume * pvol = vol->pvol; - - return sprintf(buf, "%u\n", pvol->mapped_slices); -} - -static void sflc_sysfs_volRelease(struct device * kdev) -{ - sflc_sysfs_Volume * vol; - - /* Cast */ - vol = container_of(kdev, sflc_sysfs_Volume, kdev); - - /* Just free */ - kfree(vol); - - return; -} diff --git a/dm-sflc/target/target.c b/dm-sflc/target/target.c deleted file mode 100644 index afb143a..0000000 --- a/dm-sflc/target/target.c +++ /dev/null @@ -1,280 +0,0 @@ -/* - * Copyright The Shufflecake Project Authors (2022) - * Copyright The Shufflecake Project Contributors (2022) - * Copyright Contributors to the The Shufflecake Project. - * - * See the AUTHORS file at the top-level directory of this distribution and at - * - * - * This file is part of the program shufflecake-c, which is part of the - * Shufflecake Project. Shufflecake is a plausible deniability (hidden storage) - * layer for Linux. See . - * - * This program is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation, either version 2 of the License, or (at your option) - * any later version. This program is distributed in the hope that it will be - * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General - * Public License for more details. You should have received a copy of the - * GNU General Public License along with this program. - * If not, see . - */ - -/* - * Methods of our DM target - */ - -/***************************************************** - * INCLUDE SECTION * - *****************************************************/ - -#include "target.h" -#include "device/device.h" -#include "volume/volume.h" -#include "utils/bio.h" -#include "utils/string.h" -#include "log/log.h" - -/***************************************************** - * CONSTANTS * - *****************************************************/ - -/***************************************************** - * PRIVATE FUNCTIONS PROTOTYPES * - *****************************************************/ - -static int sflc_tgt_ctr(struct dm_target *ti, unsigned int argc, char **argv); -static void sflc_tgt_dtr(struct dm_target *ti); -static int sflc_tgt_map(struct dm_target *ti, struct bio *bio); -static void sflc_tgt_ioHints(struct dm_target *ti, struct queue_limits *limits); -static int sflc_tgt_iterateDevices(struct dm_target *ti, iterate_devices_callout_fn fn, - void *data); - -/***************************************************** - * PUBLIC VARIABLES DEFINITIONS * - *****************************************************/ - -struct target_type sflc_target = { - .name = "shufflecake", - .version = {1, 0, 0}, - .module = THIS_MODULE, - .ctr = sflc_tgt_ctr, - .dtr = sflc_tgt_dtr, - .map = sflc_tgt_map, - .status = NULL, - .io_hints = sflc_tgt_ioHints, - .iterate_devices = sflc_tgt_iterateDevices, -}; - -/***************************************************** - * PRIVATE FUNCTIONS DEFINITIONS * - *****************************************************/ - -/* Called every time we create a volume with the userland tool */ -static int sflc_tgt_ctr(struct dm_target *ti, unsigned int argc, char **argv) -{ - char * bdev_path; - int vol_idx; - char * enckey_hex; - u8 enckey[SFLC_SK_KEY_LEN]; - u32 tot_slices; - sflc_Device * dev; - sflc_Volume * vol; - int err; - - /* - * Parse arguments. - * - * argv[0]: underlying block device path - * argv[1]: volume index within the device - * argv[2]: number of 1 MB slices in the underlying device - * argv[3]: 32-byte encryption key (hex-encoded) - */ - if (argc != 4) { - ti->error = "Invalid argument count"; - return -EINVAL; - } - bdev_path = argv[0]; - sscanf(argv[1], "%d", &vol_idx); - sscanf(argv[2], "%u", &tot_slices); - enckey_hex = argv[3]; - - /* Decode the encryption key */ - if (strlen(enckey_hex) != 2 * SFLC_SK_KEY_LEN) { - pr_err("Hexadecimal key (length %lu): %s\n", strlen(enckey_hex), enckey_hex); - ti->error = "Invalid key length"; - return -EINVAL; - } - err = sflc_str_hexDecode(enckey_hex, enckey); - if (err) { - ti->error = "Could not decode hexadecimal encryption key"; - return err; - } - - /* Acquire the big device lock */ - if (down_interruptible(&sflc_dev_mutex)) { - ti->error = "Interrupted while waiting for access to Device"; - return -EINTR; - } - - /* Check if we already have a Device for this bdev */ - dev = sflc_dev_lookupByPath(bdev_path); - if (IS_ERR(dev)) { - ti->error = "Could not look up device by path (interrupted)"; - up(&sflc_dev_mutex); - return PTR_ERR(dev); - } - - /* Otherwise create it (also adds it to the device list) */ - if (!dev) { - pr_notice("Device for %s didn't exist before, going to create it\n", bdev_path); - dev = sflc_dev_create(ti, bdev_path, tot_slices); - } else { - pr_notice("Device on %s already existed\n", bdev_path); - } - - /* Check for device creation errors */ - if (IS_ERR(dev)) { - ti->error = "Could not create device"; - up(&sflc_dev_mutex); - return PTR_ERR(dev); - } - - /* Create the volume (also adds it to the device) */ - vol = sflc_vol_create(ti, dev, vol_idx, enckey); - if (IS_ERR(vol)) { - ti->error = "Error creating volume"; - up(&sflc_dev_mutex); - return PTR_ERR(vol); - } - pr_debug("Now %d volumes are linked to device %s\n", dev->vol_cnt, bdev_path); - - /* Release the big device lock */ - up(&sflc_dev_mutex); - - /* Tell DM we want one SFLC sector at a time */ - ti->max_io_len = SFLC_DEV_SECTOR_SCALE; - /* Enable REQ_OP_FLUSH bios */ - ti->num_flush_bios = 1; - /* Disable REQ_OP_WRITE_ZEROES and REQ_OP_SECURE_ERASE (can't be passed through as - they would break deniability, and they would be too complicated to handle individually) */ - ti->num_secure_erase_bios = 0; - ti->num_write_zeroes_bios = 0; - /* Momentarily disable REQ_OP_DISCARD_BIOS - TODO: will need to support them to release slice mappings */ - ti->num_discard_bios = 0; - /* When we receive a ->map call, we won't need to take the device lock anymore */ - ti->private = vol; - - return 0; -} - -/* Called every time we destroy a volume with the userland tool */ -static void sflc_tgt_dtr(struct dm_target *ti) -{ - sflc_Volume * vol = ti->private; - sflc_Device * dev = vol->dev; - - pr_debug("Destroying volume \"%s\"\n", vol->vol_name); - - /* We do need to take the device lock here, as we'll be modifying the device */ - if (down_interruptible(&sflc_dev_mutex)) { - pr_err("Interrupted while waiting to destroy volume\n"); - return; - } - - /* Destroy volume (also decreases refcount in device) */ - sflc_vol_destroy(ti, vol); - - /* Destroy the device */ - if (dev->vol_cnt == 0) { - pr_notice("Removed the last volume from device\n"); - sflc_dev_destroy(ti, dev); - } - - /* End of critical section */ - up(&sflc_dev_mutex); - - return; -} - -/* Callback for every bio submitted to our virtual block device */ -static int sflc_tgt_map(struct dm_target *ti, struct bio *bio) -{ - int err; - sflc_Volume * vol = ti->private; - - /* If no data, just quickly remap the sector and the block device (no crypto) */ - /* TODO: this is dangerous for deniability, will need more filtering */ - if (unlikely(!bio_has_data(bio))) { - pr_debug("No-data bio: bio_op = %d", bio_op(bio)); - err = sflc_vol_remapBioFast(vol, bio); - if (err) { - pr_err("Could not remap bio; error %d\n", err); - return DM_MAPIO_KILL; - } - return DM_MAPIO_REMAPPED; - } - - /* At this point, the bio has data. Do a few sanity checks */ - /* TODO: I think we can get rid of all of them */ - - /* Check that it is properly aligned and it doesn't cross vector boundaries */ - if (unlikely(!sflc_bio_isAligned(bio))) { - pr_err("Unaligned bio!\n"); - return DM_MAPIO_KILL; - } - /* If it contains more than one SFLC sector, complain with the DM layer and continue */ - if (unlikely(bio->bi_iter.bi_size > SFLC_DEV_SECTOR_SIZE)) { - pr_notice("Large bio of size %u\n", bio->bi_iter.bi_size); - dm_accept_partial_bio(bio, SFLC_DEV_SECTOR_SCALE); - } - /* Check that it contains exactly one SFLC sector */ - if (unlikely(bio->bi_iter.bi_size != SFLC_DEV_SECTOR_SIZE)) { - pr_err("Wrong length (%u) of bio\n", bio->bi_iter.bi_size); - return DM_MAPIO_KILL; - } - - /* Now it is safe, process it */ - err = sflc_vol_processBio(vol, bio); - if (err) { - pr_err("Could not enqueue bio\n"); - return DM_MAPIO_KILL; - } - - return DM_MAPIO_SUBMITTED; -} - -/* Callback executed to inform the DM about our 4096-byte sector size */ -static void sflc_tgt_ioHints(struct dm_target *ti, struct queue_limits *limits) -{ - sflc_Volume * vol = ti->private; - - pr_info("Called io_hints on volume \"%s\"\n", vol->vol_name); - - limits->logical_block_size = SFLC_DEV_SECTOR_SIZE; - limits->physical_block_size = SFLC_DEV_SECTOR_SIZE; - - limits->io_min = SFLC_DEV_SECTOR_SIZE; - limits->io_opt = SFLC_DEV_SECTOR_SIZE; - - return; -} - -/* Callback needed for God knows what, otherwise io_hints never gets called */ -static int sflc_tgt_iterateDevices(struct dm_target *ti, iterate_devices_callout_fn fn, - void *data) -{ - sflc_Volume * vol = ti->private; - sflc_Device * dev = vol->dev; - - pr_debug("Called iterate_devices on volume \"%s\"\n", vol->vol_name); - - if (!fn) { - return -EINVAL; - } - return fn(ti, vol->dev->bdev, 0, - (dev->dev_header_size + dev->tot_slices * SFLC_DEV_PHYS_SLICE_SIZE) * SFLC_DEV_SECTOR_SCALE, - data); -} diff --git a/resources/images/badges/badge_community_jabber_chat.png b/resources/images/badges/badge_community_jabber_chat.png new file mode 100644 index 0000000..b7bb37c Binary files /dev/null and b/resources/images/badges/badge_community_jabber_chat.png differ diff --git a/resources/images/badges/badge_version_0.4.5.png b/resources/images/badges/badge_version_0.4.5.png deleted file mode 100644 index 14a5825..0000000 Binary files a/resources/images/badges/badge_version_0.4.5.png and /dev/null differ diff --git a/resources/images/badges/badge_version_0.5.0.png b/resources/images/badges/badge_version_0.5.0.png new file mode 100644 index 0000000..869a324 Binary files /dev/null and b/resources/images/badges/badge_version_0.5.0.png differ diff --git a/resources/images/badges/badges.svg b/resources/images/badges/badges.svg index eadd2c3..254bb97 100644 --- a/resources/images/badges/badges.svg +++ b/resources/images/badges/badges.svg @@ -29,12 +29,12 @@ inkscape:document-units="mm" showgrid="false" inkscape:zoom="2.7438272" - inkscape:cx="200.26771" - inkscape:cy="241.99775" + inkscape:cx="234.16198" + inkscape:cy="198.26321" inkscape:window-width="1920" - inkscape:window-height="979" + inkscape:window-height="975" inkscape:window-x="0" - inkscape:window-y="0" + inkscape:window-y="32" inkscape:window-maximized="1" inkscape:current-layer="layer1" /> @@ -223,38 +223,38 @@ xml:space="preserve" style="font-size:4.39831px;line-height:1.25;font-family:FreeSans;-inkscape-font-specification:FreeSans;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke-width:0.183262" x="63.241447" - y="53.516087" + y="60.878864" id="text1131">web + y="60.878864">web + y="57.0406" /> shufflecake.net + y="60.878864">shufflecake.net @@ -262,38 +262,38 @@ xml:space="preserve" style="font-size:4.39831px;line-height:1.25;font-family:FreeSans;-inkscape-font-specification:FreeSans;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke-width:0.183262" x="63.241447" - y="61.032242" + y="68.39502" id="text1143">docs + y="68.39502">docs + y="64.556755" /> Research Paper + y="68.39502">Research Paper @@ -301,69 +301,108 @@ xml:space="preserve" style="font-size:4.39831px;line-height:1.25;font-family:FreeSans;-inkscape-font-specification:FreeSans;letter-spacing:0px;word-spacing:0px;fill:#ffffff;fill-opacity:1;stroke-width:0.183262" x="63.241447" - y="68.44519" + y="75.807968" id="text1155">license + y="75.807968">license + y="71.969704" /> GPLv2+ + y="75.807968">GPLv2+ version + y="83.4077">version + y="79.569435" /> 0.4.5 + y="83.4077">0.5.0 + + community + + Jabber Chat diff --git a/resources/images/headers.png b/resources/images/headers.png deleted file mode 100644 index 562702c..0000000 Binary files a/resources/images/headers.png and /dev/null differ diff --git a/resources/images/headers_legacy.png b/resources/images/headers_legacy.png new file mode 100644 index 0000000..2192b21 Binary files /dev/null and b/resources/images/headers_legacy.png differ diff --git a/resources/images/headers.svg b/resources/images/headers_legacy.svg similarity index 95% rename from resources/images/headers.svg rename to resources/images/headers_legacy.svg index d637326..081c1a0 100644 --- a/resources/images/headers.svg +++ b/resources/images/headers_legacy.svg @@ -8,7 +8,7 @@ version="1.1" id="svg2909" inkscape:version="1.2.2 (b0a8486541, 2022-12-01)" - sodipodi:docname="headers.svg" + sodipodi:docname="headers_legacy.svg" inkscape:export-filename="headers.png" inkscape:export-xdpi="200" inkscape:export-ydpi="200" @@ -27,13 +27,13 @@ inkscape:deskcolor="#d1d1d1" inkscape:document-units="mm" showgrid="false" - inkscape:zoom="1.3719136" - inkscape:cx="466.13723" - inkscape:cy="319.991" + inkscape:zoom="1.9401788" + inkscape:cx="383.72752" + inkscape:cy="239.15322" inkscape:window-width="1920" - inkscape:window-height="979" + inkscape:window-height="975" inkscape:window-x="0" - inkscape:window-y="0" + inkscape:window-y="32" inkscape:window-maximized="1" inkscape:current-layer="layer1" /> Device / Cake Header Encrypted Slices + IVs 0 . . . 1 1 14 1 14 VMB VMB POS 1 1 1 salt 0 Shufflecake v0.4.x + + y="37.286942">Shufflecake "Legacy" v0.4.x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + DMB + + Header + Device / Cake + + + Header + + + + Encrypted Slices + + + + + VMB + 0 + + + + EncryptedPosMap + 0 + + . . . + + + VMB + 1 + + + + EncryptedPosMap + 1 + + + + VMB + 14 + + + + EncryptedPosMap + 14 + + DMB + . . . + + + IV + 14 + + + + ctxt + 14 + + Password + Argon2 + + KEK + AES-GCM + + + + + VMK + 1 + + AES-XTS + + 1 + 1 + AES-XTS + + + Data I/O + + + VEK + VMK + 0 + NumSlices + Metadata + | + | + | + | + | + | + 1 + 1 + + + + AES-XTS + + + PSI + 0 + PSI + 1 + | + | + PSI + NumSlices-1 + . . . + | + | + | + | + + + IV + 1 + + IV + 1 + + + + ctxt + 1 + + ctxt + 1 + + + + salt + + salt + + + + IV + 1 + + IV + 0 + + + + ctxt + 1 + + ctxt + 0 + + + Shufflecake "Lite" v0.5.x+ + Structure of disk and headers + Example where a password for volume 1unlocks volume 1 and recursively alsovolume 0 (dotted arrow). + + + + . . . + + + + + + diff --git a/shufflecake-userland/Makefile.sources b/shufflecake-userland/Makefile.sources index 0e2a80b..d2313c8 100644 --- a/shufflecake-userland/Makefile.sources +++ b/shufflecake-userland/Makefile.sources @@ -28,9 +28,9 @@ #### PROJ_SRCS := $(addprefix utils/,crypto.c disk.c dm.c file.c string.c input.c) -PROJ_SRCS += $(addprefix header/,position_map.c volume_master_block.c device_master_block.c) -PROJ_SRCS += $(addprefix operations/,volume_header.c devmapper.c dmb.c) -PROJ_SRCS += $(addprefix commands/,init.c open.c close.c test_pwd.c change_pwd.c) +PROJ_SRCS += $(addprefix header/,position_map_legacy.c position_map_lite.c volume_master_block_legacy.c volume_master_block_lite.c device_master_block.c) +PROJ_SRCS += $(addprefix operations/,volume_header_legacy.c volume_header_lite.c devmapper_legacy.c devmapper_lite.c dmb.c) +PROJ_SRCS += $(addprefix commands/,init_legacy.c init_lite.c open_legacy.c open_lite.c close.c test_pwd.c change_pwd.c) PROJ_SRCS += $(addprefix cli/,dispatch.c init.c open.c close.c testpwd.c changepwd.c) PROJ_SRCS += main.c diff --git a/shufflecake-userland/include/cli.h b/shufflecake-userland/include/cli.h index 838f618..1c53043 100644 --- a/shufflecake-userland/include/cli.h +++ b/shufflecake-userland/include/cli.h @@ -49,9 +49,9 @@ int sflc_cli_dispatch(int argc, char **argv); /* Initializes device and create empty volumes */ -int sflc_cli_init(char *block_device, int num_volumes, int skip_randfill); +int sflc_cli_init(char *block_device, int sflc_mode, int num_volumes, int skip_randfill); /* Open volumes */ -int sflc_cli_open(char *block_device); +int sflc_cli_open(char *block_device, int sflc_mode); /* Close volumes */ int sflc_cli_close(char *block_device); /* Test password */ diff --git a/shufflecake-userland/include/commands.h b/shufflecake-userland/include/commands.h index 68a14ac..aed2c45 100644 --- a/shufflecake-userland/include/commands.h +++ b/shufflecake-userland/include/commands.h @@ -50,13 +50,13 @@ typedef struct { /* Underlying block device */ char *bdev_path; - + /* Shufflecake mode */ + int sflc_mode; /* Number of volumes */ size_t nr_vols; /* Volumes' passwords */ char **pwds; size_t *pwd_lens; - /* Option to skip random filling */ bool no_randfill; @@ -68,7 +68,8 @@ typedef struct { /* Underlying block device */ char *bdev_path; - + /* Shufflecake mode */ + int sflc_mode; /* The only password provided */ char *pwd; size_t pwd_len; @@ -79,10 +80,10 @@ typedef struct { /* Underlying block device */ char *bdev_path; - + /* Shufflecake mode (legacy,lite,full) */ + int sflc_mode; /* Content of the DMB cell */ sflc_DmbCell *dmb_cell; - /* The new password */ char *new_pwd; size_t new_pwd_len; @@ -94,11 +95,15 @@ typedef struct * PUBLIC FUNCTIONS PROTOTYPES * *****************************************************/ -/* Create N volumes (only formats the device header, does not open the volumes) */ -int sflc_cmd_initVolumes(sflc_cmd_InitArgs *args); +/* Create N volumes (only formats the device header, does not open the volumes). LITE version */ +int sflite_cmd_initVolumes(sflc_cmd_InitArgs *args); +/* Create N volumes (only formats the device header, does not open the volumes). LEGACY version */ +int sflegc_cmd_initVolumes(sflc_cmd_InitArgs *args); -/* Open M volumes, from the first down to the one whose pwd is provided */ -int sflc_cmd_openVolumes(sflc_cmd_OpenArgs *args); +/* Open M volumes, from the first down to the one whose pwd is provided. LITE version */ +int sflite_cmd_openVolumes(sflc_cmd_OpenArgs *args); +/* Open M volumes, from the first down to the one whose pwd is provided. LEGACY version */ +int sflegc_cmd_openVolumes(sflc_cmd_OpenArgs *args); /* Close all volumes on the device (reads the list from sysfs) */ int sflc_cmd_closeVolumes(char *bdev_path); diff --git a/shufflecake-userland/include/header.h b/shufflecake-userland/include/header.h index 869b868..bd77fd3 100644 --- a/shufflecake-userland/include/header.h +++ b/shufflecake-userland/include/header.h @@ -33,6 +33,7 @@ #include #include "utils/crypto.h" +#include "utils/math.h" /***************************************************** @@ -40,18 +41,18 @@ *****************************************************/ /* The DMB contains one IV + one VMB key + one MAC for each volume */ -#define SFLC_DMB_CELL_SIZE (SFLC_AESGCM_PADDED_IVLEN + SFLC_CRYPTO_KEYLEN + SFLC_AESGCM_TAGLEN) +#define SFLC_DMB_CELL_SIZE (SFLC_AESGCM_PADDED_IVLEN + SFLC_STANDARD_KEYLEN + SFLC_AESGCM_TAGLEN) /* Let us enforce that the one DMB can fit cells for all volumes */ -#if SFLC_ARGON_SALTLEN + (SFLC_DEV_MAX_VOLUMES * SFLC_DMB_CELL) > SFLC_SECTOR_SIZE -#error "Invalid combination of parameters: probably SFLC_DEV_MAX_VOLUMES is too big" +#if SFLC_ARGON_SALTLEN + (SFLC_DEV_MAX_VOLUMES * SFLC_DMB_CELL_SIZE) > SFLC_BLOCK_SIZE +#error "Invalid combination of parameters: probably SFLITE_DEV_MAX_VOLUMES is too big" #endif // The VMB cleartext occupies the last 4064 bytes on-disk (4096 bytes minus IV and MAC) -#define SFLC_CLEAR_VMB_LEN (SFLC_SECTOR_SIZE - \ - SFLC_AESGCM_PADDED_IVLEN - \ - SFLC_AESGCM_TAGLEN) +#define SFLC_CLEAR_VMB_LEN (SFLC_BLOCK_SIZE - \ + SFLC_AESGCM_PADDED_IVLEN - \ + SFLC_AESGCM_TAGLEN) @@ -66,21 +67,20 @@ */ typedef struct { // Each volume's VMB key - char vmb_keys[SFLC_DEV_MAX_VOLUMES][SFLC_CRYPTO_KEYLEN]; + char vmb_keys[SFLC_DEV_MAX_VOLUMES][SFLC_STANDARD_KEYLEN]; // How many of these need actually be encrypted size_t nr_vols; } sflc_Dmb; - /** * When unsealing a DMB, only one VMB key can be unlocked with a password. * An invalid value for vol_idx means no VMB key could be unlocked (wrong pwd) */ typedef struct { // The unlocked VMB key - char vmb_key[SFLC_CRYPTO_KEYLEN]; + char vmb_key[SFLC_STANDARD_KEYLEN]; // The index of the volume opened by this VMB key size_t vol_idx; @@ -94,20 +94,24 @@ typedef struct { * only contains the useful info, in the clear. */ typedef struct { + int mode; + // The key that encrypts the volume's data section - char volume_key[SFLC_CRYPTO_KEYLEN]; + union { + char volume_key_lite[SFLC_AESXTS_KEYLEN]; + char volume_key_legacy[SFLC_STANDARD_KEYLEN]; + }; // The key that encrypts the previous volume's master block - char prev_vmb_key[SFLC_CRYPTO_KEYLEN]; + char prev_vmb_key[SFLC_STANDARD_KEYLEN]; // The total number of logical slices virtually available to this volume size_t nr_slices; } sflc_Vmb; - /** - * This struct represents an encrypted empty position map. + * This struct represents an encrypted empty position map. LEGACY version. * On-disk, the layout interleaves one IV block with 256 PosMap blocks (each * encrypted by an IV in the IV block). Many such "runs" can be concatenated, * until the position map is big enough to index the desired number of slices. @@ -132,7 +136,21 @@ typedef struct { // The number of PosMapBlocks in the last array size_t nr_last_pmbs; -} sflc_EncPosMap; +} sflegc_EncPosMap; + + +/***************************************************** + * INLINE FUNCTIONS * + *****************************************************/ + + +// Starting block of a volume's position map. LITE version +static inline uint64_t sflite_pmStartBlock(size_t vol_idx, size_t nr_slices) +{ + return 1 + + SFLC_DEV_MAX_VOLUMES + + vol_idx*ceil(nr_slices, SFLC_SLICE_IDX_PER_BLOCK); +} /***************************************************** @@ -147,15 +165,22 @@ int sflc_dmb_unseal(char *disk_block, char *pwd, size_t pwd_len, sflc_DmbCell *d int sflc_dmb_setCell(char *disk_block, sflc_DmbCell *dmb_cell, char *pwd, size_t pwd_len); -/* "Encrypt" a VMB with a VMB key, so it's ready to be written on-disk */ -int sflc_vmb_seal(sflc_Vmb *vmb, char *vmb_key, char *disk_block); -/* "Decrypt" a VMB coming from the disk, directly using its key */ -int sflc_vmb_unseal(char *disk_block, char *vmb_key, sflc_Vmb *vmb); +/* "Encrypt" a VMB with a VMB key, so it's ready to be written on-disk. LITE version */ +int sflite_vmb_seal(sflc_Vmb *vmb, char *vmb_key, char *disk_block); +/* "Decrypt" a VMB coming from the disk, directly using its key. LITE version */ +int sflite_vmb_unseal(char *disk_block, char *vmb_key, sflc_Vmb *vmb); + +/* "Encrypt" a VMB with a VMB key, so it's ready to be written on-disk. LEGACY version */ +int sflegc_vmb_seal(sflc_Vmb *vmb, char *vmb_key, char *disk_block); +/* "Decrypt" a VMB coming from the disk, directly using its key. LEGACY version */ +int sflegc_vmb_unseal(char *disk_block, char *vmb_key, sflc_Vmb *vmb); -/* Create an encrypted empty position map for the given number of slices (allocates memory) */ -int sflc_epm_create(size_t nr_slices, char *volume_key, sflc_EncPosMap *epm); +/* Create an encrypted empty position map for the given number of slices (allocates memory). LITE version */ +void *sflite_epm_create(size_t nr_slices, size_t vol_idx, char *volume_key); +/* Create an encrypted empty position map for the given number of slices (allocates memory). LEGACY version */ +int sflegc_epm_create(size_t nr_slices, char *volume_key, sflegc_EncPosMap *epm); #endif /* _HEADER_H_ */ diff --git a/shufflecake-userland/include/operations.h b/shufflecake-userland/include/operations.h index 8de9ab6..c1c9fd6 100644 --- a/shufflecake-userland/include/operations.h +++ b/shufflecake-userland/include/operations.h @@ -41,22 +41,22 @@ * INLINE FUNCTIONS * *****************************************************/ -// Size, in 4096-byte blocks, of a whole volume header (VMB+PM) -static inline size_t sflc_volHeaderSize(size_t nr_slices) +// Size, in 4096-byte blocks, of a whole volume header (VMB+PM). LEGACY version +static inline size_t sflegc_volHeaderSize(size_t nr_slices) { // Each PosMapBlock holds up to 1024 PSIs (Physical Slice Index) size_t nr_pmbs = ceil(nr_slices, SFLC_SLICE_IDX_PER_BLOCK); // Each array holds up to 256 PosMapBlocks - size_t nr_arrays = ceil(nr_pmbs, SFLC_BLOCKS_PER_LOG_SLICE); + size_t nr_arrays = ceil(nr_pmbs, SFLC_SLICE_SCALE); // 1 VMB, the PMBs, and the IV blocks return 1 + nr_pmbs + nr_arrays; } -// Position of the VMB for the given volume -static inline uint64_t sflc_vmbPosition(size_t vol_idx, size_t nr_slices) +// Position of the VMB for the given volume. LEGACY version +static inline uint64_t sflegc_vmbPosition(size_t vol_idx, size_t nr_slices) { - return 1 + ((uint64_t) vol_idx) * ((uint64_t) sflc_volHeaderSize(nr_slices)); + return 1 + ((uint64_t) vol_idx) * ((uint64_t) sflegc_volHeaderSize(nr_slices)); } @@ -71,14 +71,26 @@ int sflc_ops_readDmb(char *bdev_path, char *pwd, size_t pwd_len, sflc_DmbCell *d /* Reads the DMB from disk, changes the relevant DMB cell, and writes it back */ int sflc_ops_rewriteDmbCell(char *bdev_path, sflc_DmbCell *dmb_cell, char *new_pwd, size_t new_pwd_len); -/* Encrypts and writes a volume header (VMB+PM) on-disk */ -int sflc_ops_writeVolumeHeader(char *bdev_path, char *vmb_key, sflc_Vmb *vmb, size_t vol_idx); -/* Reads a VMB from disk and unlocks it */ -int sflc_ops_readVmb(char *bdev_path, char *vmb_key, size_t nr_slices, size_t vol_idx, sflc_Vmb *vmb); -/* Build parameter list for ctor in dm_sflc, and send DM ioctl to create virtual block device */ -int sflc_ops_openVolume(char *bdev_path, size_t dev_id, size_t vol_idx, sflc_Vmb *vmb); -/* Close the volume via the appropriate ioctl to DM */ -int sflc_ops_closeVolume(char *label); +/* Encrypts and writes a volume header (VMB+PM) on-disk. LITE version */ +int sflite_ops_writeVolumeHeader(char *bdev_path, char *vmb_key, sflc_Vmb *vmb, size_t vol_idx); +/* Reads a VMB from disk and unlocks it. LITE version */ +int sflite_ops_readVmb(char *bdev_path, char *vmb_key, size_t nr_slices, size_t vol_idx, sflc_Vmb *vmb); + +/* Encrypts and writes a volume header (VMB+PM) on-disk. LEGACY version */ +int sflegc_ops_writeVolumeHeader(char *bdev_path, char *vmb_key, sflc_Vmb *vmb, size_t vol_idx); +/* Reads a VMB from disk and unlocks it. LEGACY version */ +int sflegc_ops_readVmb(char *bdev_path, char *vmb_key, size_t nr_slices, size_t vol_idx, sflc_Vmb *vmb); + + +/* Build parameter list for ctor in dm_sflc, and send DM ioctl to create virtual block device. LITE version */ +int sflite_ops_openVolume(char *bdev_path, size_t dev_id, size_t vol_idx, sflc_Vmb *vmb); +/* Close the volume via the appropriate ioctl to DM. LITE version */ +int sflite_ops_closeVolume(char *label); + +/* Build parameter list for ctor in dm_sflc, and send DM ioctl to create virtual block device. LEGACY version */ +int sflegc_ops_openVolume(char *bdev_path, size_t dev_id, size_t vol_idx, sflc_Vmb *vmb); +/* Close the volume via the appropriate ioctl to DM. LEGACY version */ +int sflegc_ops_closeVolume(char *label); #endif /* _OPERATIONS_H_ */ diff --git a/shufflecake-userland/include/sflc-constants.h b/shufflecake-userland/include/sflc-constants.h new file mode 120000 index 0000000..3a95dcc --- /dev/null +++ b/shufflecake-userland/include/sflc-constants.h @@ -0,0 +1 @@ +../../dm-sflc/src/sflc_constants.h \ No newline at end of file diff --git a/shufflecake-userland/include/sflc_constants.h b/shufflecake-userland/include/sflc_constants.h deleted file mode 120000 index fab9e42..0000000 --- a/shufflecake-userland/include/sflc_constants.h +++ /dev/null @@ -1 +0,0 @@ -../../dm-sflc/sflc_constants.h \ No newline at end of file diff --git a/shufflecake-userland/include/utils/crypto.h b/shufflecake-userland/include/utils/crypto.h index 15ac111..8366134 100644 --- a/shufflecake-userland/include/utils/crypto.h +++ b/shufflecake-userland/include/utils/crypto.h @@ -41,20 +41,21 @@ *****************************************************/ // Key length, for input into AES-CTR and AES-GCM, and for output from Argon -#define SFLC_CRYPTO_KEYLEN 32 /* bytes */ +#define SFLC_STANDARD_KEYLEN 32 /* bytes */ +// Key length for AES-XTS +#define SFLC_AESXTS_KEYLEN 64 /* bytes */ // IV length for AES-CTR #define SFLC_AESCTR_IVLEN 16 /* bytes */ +// IV length for AES-XTS +#define SFLC_AESXTS_IVLEN 16 /* bytes */ // IV length for AES-GCM #define SFLC_AESGCM_IVLEN 12 /* bytes */ - // IVs occupy 16 bytes on-disk, but only the *FIRST* 12 are used for AES-GCM #define SFLC_AESGCM_PADDED_IVLEN 16 /* bytes */ - // MAC length for AES-GCM #define SFLC_AESGCM_TAGLEN 16 /* bytes */ - // Content of output plaintext upon MAC verification failure #define SFLC_AESGCM_POISON_PT 0xFF @@ -81,9 +82,9 @@ * PUBLIC FUNCTIONS PROTOTYPES * *****************************************************/ -/* Get slow, true random bytes (suited for keys) */ +/* Get slow, strong random bytes (suited for keys) */ int sflc_rand_getStrongBytes(char *buf, size_t buflen); -/* Get fast, pseudo random bytes (suited for IVs and padding) */ +/* Get fast, weak(er) random bytes (suited for IVs and padding) */ int sflc_rand_getWeakBytes(char *buf, size_t buflen); /* AES256-CTR encryption, does not touch the IV. Set ct = NULL for in-place. */ @@ -91,6 +92,10 @@ int sflc_aes256ctr_encrypt(char *key, char *pt, size_t pt_len, char *iv, char *c /* AES256-CTR decryption, does not touch the IV. Set pt = NULL for in-place. */ int sflc_aes256ctr_decrypt(char *key, char *ct, size_t ct_len, char *iv, char *pt); +/* AES256-XTS encryption. Set ct = NULL for in-place. + * The IV is intepreted as a little-endian "sector number" */ +int sflc_aes256xts_encrypt(char *key, char *pt, size_t pt_len, char *iv, char *ct); + /* AES256-GCM encryption, does not touch the IV */ int sflc_aes256gcm_encrypt(char *key, char *pt, size_t pt_len, char *iv, char *ct, char *tag); /* AES256-GCM decryption, does not touch the IV (only decrypts if MAC is valid) */ diff --git a/shufflecake-userland/include/utils/disk.h b/shufflecake-userland/include/utils/disk.h index 7666609..3bb1033 100644 --- a/shufflecake-userland/include/utils/disk.h +++ b/shufflecake-userland/include/utils/disk.h @@ -35,6 +35,7 @@ #include #include +#include "utils/math.h" #include "utils/sflc.h" @@ -43,65 +44,60 @@ *****************************************************/ /** - * Max slices for given disk size (in 4096-byte blocks). - * - * The bigger a disk is, the more slices it can host. However, the more slices we format it with, - * the bigger the position map needed to index them: the header size grows with the number of slices, - * taking up part of the space that's supposed to host those slices. - * To settle the matter, let us derive an upper bound on the header size, yielding a "safe" value - * for the number of slices (given a disk size). - * - * To index s slices, we need pm := ceil(s/1024) <= s/1024 + 1 PosMap blocks, since each PosMap - * block (4096 bytes) can host 1024 slice indices (4 bytes each). - * - * To encrypt those PosMap blocks, we need iv := ceil(pm/256) <= pm IV blocks, since each IV block - * (4096 bytes) can encrypt 256 data blocks (IVs are 16 bytes). - * - * Therefore, a position map indexing s slices occupies pm+iv <= 2*pm <= 2*s/1024 + 2 blocks. - * - * A single volume's header contains the Volume Master Block and the position map, therefore it - * occupies 1+pm+iv <= 2*s/1024 + 3 blocks. - * - * The entire device's header simply contains 15 volume headers of the same size, therefore it - * occupies h := 15 * (1+pm+iv) <= 15*2*s/1024 + 3*15 <= s + 3*15 blocks. - * The last inequality follows from 15*2/1024 <= 1 (we need to enforce this on the symbolic values). - * - * To actually host the s slices, the data section needs 257*s blocks (256 data blocks + 1 IV block - * per slice). - * - * Therefore, in order to format a disk with s slices, we need at most (s + 3*15) + 257*s = - * = (1 + 257)*s + 3*15 blocks. - * - * If we are given d blocks on the disk, a safe value for s is one that satisfies - * (1 + 257)*s + 3*15 <= d <==> s <= (d - 3*15) / (1 + 257) + * Max slices for given disk size (in 4096-byte blocks). LITE version */ -#define sflc_disk_maxSlices(size) (size - 3*SFLC_DEV_MAX_VOLUMES) / (1 + SFLC_BLOCKS_PER_PHYS_SLICE) +static inline uint32_t sflite_disk_maxSlices(uint64_t size) { + uint64_t nr_slices; + // Start from upper bound + nr_slices = size / SFLC_SLICE_SCALE; + while(true) { + if (nr_slices == 0) + break; -/* Let us enforce, on the symbolic values, the inequality used in the previous bound */ + // Stop when this nr_slices can fit in size, including the header + uint64_t posmap_blocks = ceil(nr_slices, SFLC_SLICE_IDX_PER_BLOCK); + uint64_t header_size = 1 + SFLC_DEV_MAX_VOLUMES * (1 + posmap_blocks); + if (header_size + nr_slices*SFLC_SLICE_SCALE <= size) + break; + + nr_slices--; + } + + return nr_slices > SFLC_MAX_SLICES ? SFLC_MAX_SLICES : (uint32_t) nr_slices; +} + +/* LEGACY version */ +#define sflegc_disk_maxSlices(size) (size - 3*SFLC_DEV_MAX_VOLUMES) / (1 + SFLEGC_BLOCKS_PER_PHYS_SLICE) +/* We need this inequality to hold, in order for the previous bound to be true */ #if SFLC_DEV_MAX_VOLUMES * 2 > SFLC_SLICE_IDX_PER_BLOCK #error "Invalid combination of parameters, probably SFLC_DEV_MAX_VOLUMES is too big" #endif + + /***************************************************** * PUBLIC FUNCTIONS PROTOTYPES * *****************************************************/ +/* Returns a malloc'ed string formatted as : */ +char *sflc_disk_getDeviceName(char *bdev_path); + /* Checks whether the given path points to a block device */ bool sflc_disk_isBlockDevice(char *path); /* Returns the size in 4096-byte sectors (or < 0 if error) */ -int64_t sflc_disk_getSize(char * bdev_path); +int64_t sflc_disk_getSize(char *bdev_path); -/* Reads a single 4096-byte sector from the disk */ -int sflc_disk_readSector(char * bdev_path, uint64_t sector, char * buf); +/* Reads a single 4096-byte block from the disk */ +int sflc_disk_readBlock(char *bdev_path, uint64_t bnum, char *buf); -/* Writes a single 4096-byte sector to the disk */ -int sflc_disk_writeSector(char * bdev_path, uint64_t sector, char * buf); +/* Writes many 4096-byte blocks to the disk */ +int sflc_disk_writeManyBlocks(char *bdev_path, uint64_t bnum, char *buf, size_t num_blocks); -/* Writes many 4096-byte sectors to the disk */ -int sflc_disk_writeManySectors(char * bdev_path, uint64_t sector, char * buf, size_t num_sectors); +/* Writes a single 4096-byte block to the disk */ +#define sflc_disk_writeBlock(bdev_path, bnum, buf) sflc_disk_writeManyBlocks(bdev_path, bnum, buf, 1) #endif /* _UTILS_DISK_H_ */ diff --git a/shufflecake-userland/include/utils/input.h b/shufflecake-userland/include/utils/input.h index 9463999..52e07fb 100644 --- a/shufflecake-userland/include/utils/input.h +++ b/shufflecake-userland/include/utils/input.h @@ -43,4 +43,4 @@ int sflc_safeReadLine(char *buf, size_t bufsize); /* Reads a password or passphrase (discarding the newline) from stdin in a secure way (no echo) */ int sflc_safeReadPassphrase(char *buf, size_t bufsize); -#endif /* _UTILS_FILE_H_ */ +#endif /* _UTILS_INPUT_H_ */ diff --git a/shufflecake-userland/include/utils/log.h b/shufflecake-userland/include/utils/log.h index 2088fbb..0fd35d7 100644 --- a/shufflecake-userland/include/utils/log.h +++ b/shufflecake-userland/include/utils/log.h @@ -120,13 +120,13 @@ static inline void sflc_log_hex(char *str, size_t len) for (i = 0; i < len; i++) { printf("%02x ", s[i]); // Nice aligned wrapping - if (i % 16 == 15) { + if (i % 32 == 31) { printf("\n"); } } // Always end with a newline - if (i % 16 != 0) { + if (i % 32 != 0) { printf("\n"); } diff --git a/shufflecake-userland/include/utils/sflc.h b/shufflecake-userland/include/utils/sflc.h index e8135e4..285dde3 100644 --- a/shufflecake-userland/include/utils/sflc.h +++ b/shufflecake-userland/include/utils/sflc.h @@ -41,10 +41,20 @@ /* Name of the DM target in the kernel */ #define SFLC_DM_TARGET_NAME "shufflecake" -/* Disk constants */ -#define SFLC_SECTOR_SIZE 4096 /* bytes */ -#define KERNEL_SECTOR_SIZE 512 /* bytes */ -#define SFLC_SECTOR_SCALE (SFLC_SECTOR_SIZE / KERNEL_SECTOR_SIZE) +/* Modes */ +#define SFLC_MODE_LEGACY 0 +#define SFLC_MODE_LITE 1 +#define SFLC_MODE_FULL 2 + +/* Sizes */ +#define KERNEL_SECTOR_SIZE 512 /* bytes */ +#define SFLC_BLOCK_SIZE 4096 /* bytes */ +#define SFLC_BLOCK_SCALE (SFLC_BLOCK_SIZE / KERNEL_SECTOR_SIZE) +#define SFLC_SLICE_SCALE 256 /* blocks in a slice */ +#define SFLC_MAX_SLICES (UINT32_MAX - 1) /* 0xFFFFFFFF is reserved */ + +/* For legacy */ +#define SFLEGC_BLOCKS_PER_PHYS_SLICE (SFLC_SLICE_SCALE + 1) /* Max number of volumes in a device */ #define SFLC_DEV_MAX_VOLUMES 15 @@ -57,27 +67,20 @@ /* A slice index is represented over 32 bits */ #define SFLC_SLICE_IDX_WIDTH 4 /* bytes */ /* A position map block contains 1024 slice indices */ -#define SFLC_SLICE_IDX_PER_BLOCK (SFLC_SECTOR_SIZE / SFLC_SLICE_IDX_WIDTH) +#define SFLC_SLICE_IDX_PER_BLOCK (SFLC_BLOCK_SIZE / SFLC_SLICE_IDX_WIDTH) -// IV length for AES-CTR -#define SFLC_AESCTR_IVLEN 16 /* bytes */ - -/* An IV block can encrypt 256 data blocks */ -#define SFLC_DATA_BLOCKS_PER_IV_BLOCK (SFLC_SECTOR_SIZE / SFLC_AESCTR_IVLEN) -/* A logical slice spans 256 blocks of data (1 MiB) */ -#define SFLC_BLOCKS_PER_LOG_SLICE SFLC_DATA_BLOCKS_PER_IV_BLOCK -/* A physical slice also includes the IV block */ -#define SFLC_BLOCKS_PER_PHYS_SLICE (1 + SFLC_BLOCKS_PER_LOG_SLICE) /* A PSI of 0xFFFFFFFF indicates an unassigned LSI */ #define SFLC_EPM_FILLER 0xFF /* The sysfs file containing the next available device ID */ -#define SFLC_SYSFS_NEXTDEVID "/sys/devices/sflc/next_dev_id" +#define SFLC_SYSFS_NEXTDEVID "/sys/module/dm_sflc/next_dev_id" /* The sysfs directory containing a subdir for each (underlying) block device */ #define SFLC_SYSFS_BDEVS_DIR "/sys/module/dm_sflc/bdevs" -/* Within each bdev's subdir, this file lists its open volumes */ +/* Within each bdev's subdir, this file shows its number of open volumes */ #define SFLC_SYSFS_OPENVOLUMES_FILENAME "volumes" +/* Within each bdev's subdir, this file shows its Shufflecake device ID */ +#define SFLC_SYSFS_DEVID_FILENAME "dev_id" /* TODO: reasonable? */ #define SFLC_BDEV_PATH_MAX_LEN 1024 diff --git a/shufflecake-userland/src/cli/close.c b/shufflecake-userland/src/cli/close.c index fdbaa28..da4c02f 100644 --- a/shufflecake-userland/src/cli/close.c +++ b/shufflecake-userland/src/cli/close.c @@ -47,14 +47,14 @@ */ int sflc_cli_close(char *block_device) { // Requires: block_device is a correct block device path -// char bdev_path[SFLC_BDEV_PATH_MAX_LEN + 2]; +// char bdev_path[SFLITE_BDEV_PATH_MAX_LEN + 2]; // int err; // /* Gather (absolute) path to underlying block device */ // printf("Enter the absolute path to the underlying block device containing the Shufflecake volumes to close: "); -// err = sflc_safeReadLine(bdev_path, SFLC_BDEV_PATH_MAX_LEN + 2); +// err = sflite_safeReadLine(bdev_path, SFLITE_BDEV_PATH_MAX_LEN + 2); // if (err) { -// sflc_log_error("Could not read path to underlying block device; error %d", err); +// sflite_log_error("Could not read path to underlying block device; error %d", err); // return err; // } // /* Check that it is absolute */ @@ -66,7 +66,7 @@ int sflc_cli_close(char *block_device) /* Actually perform the command */ -// return sflc_cmd_closeVolumes(bdev_path); +// return sflite_cmd_closeVolumes(bdev_path); return sflc_cmd_closeVolumes(block_device); diff --git a/shufflecake-userland/src/cli/dispatch.c b/shufflecake-userland/src/cli/dispatch.c index 01da250..f5e3e17 100644 --- a/shufflecake-userland/src/cli/dispatch.c +++ b/shufflecake-userland/src/cli/dispatch.c @@ -35,7 +35,6 @@ #include "utils/sflc.h" #include "utils/disk.h" #include "utils/log.h" -#include "sflc_constants.h" /***************************************************** @@ -43,13 +42,14 @@ *****************************************************/ /* Used by argp to provide the automatic "-V" option */ -const char *argp_program_version = SFLC_VERSION; +const char *argp_program_version = "0.5.0"; // Temporary hack /* Used by argp to provide the automatic "--help" option */ const char *argp_program_bug_address = ""; /* Signed integer values representing a handle for each option */ #define SFLC_OPT_NUMVOLS_KEY 'n' // Positive and printable: also serves as short command-line option #define SFLC_OPT_SKIPRAND_KEY (-'r') // Negative, because we don't want a short option available for this +#define SFLC_OPT_LEGACY_KEY (-'l') /***************************************************** @@ -67,6 +67,7 @@ enum sflc_cli_action { struct sflc_cli_arguments { enum sflc_cli_action act; char *block_device; + int sflc_mode; int num_volumes; bool skip_randfill; }; @@ -86,8 +87,8 @@ static error_t _parseArgpKey(int key, char *arg, struct argp_state *state); /* Doc strings */ static char args_doc[] = "ACTION "; static char doc[] = - "Shufflecake is a plausible deniability (hidden storage) layer for Linux.\n" - "See official website at for more info.\n" + "\nShufflecake is a plausible deniability (hidden storage) layer for Linux.\n" + "See official website at for more info.\n\n" "Possible values for mandatory ACTION are:\n\n" "\tinit:\t\tInitialise a block device for Shufflecake use, formatting\n" @@ -96,7 +97,7 @@ static char doc[] = "\topen:\t\tOpen a hierarchy of Shufflecake volumes within a device by\n" "\t\t\tasking a single user password. Virtual devices will appear\n" - "\t\t\tin /dev/mapper. Notice: freshly created device must be\n" + "\t\t\tin /dev/mapper. Notice: freshly created devices must be\n" "\t\t\tuser-formatted and mounted in order to be used.\n\n" "\tclose:\t\tClose all open Shufflecake volumes supported by given\n" @@ -115,6 +116,7 @@ static struct argp_option options[] = { "Specify number of volumes to be created with `init'. Must be an integer between 1 and 15.", 0 }, // TODO: define MAX_VOLS instead of hardcoding 15 {"skip-randfill", SFLC_OPT_SKIPRAND_KEY, 0, 0, "Skip pre-overwriting block device with random data, only valid with `init'. Faster but less secure. Use only for debugging or testing."}, + {"legacy", SFLC_OPT_LEGACY_KEY, 0, 0, "Use the old (pre-v0.5.0) Shufflecake format. Only valid with `init` and `open'. This mode is less secure and error-prone, use of this option is not recommended, it is provided for backward-compatibility only. This mode is going to be deprecated in the future."}, {0} }; @@ -141,6 +143,7 @@ int sflc_cli_dispatch(int argc, char **argv) { arguments.act = -1; arguments.block_device = NULL; + arguments.sflc_mode = SFLC_MODE_LITE; arguments.num_volumes = 0; arguments.skip_randfill = false; @@ -153,6 +156,13 @@ int sflc_cli_dispatch(int argc, char **argv) { return EINVAL; } /* Check options consistency */ + if (arguments.sflc_mode == SFLC_MODE_LEGACY && + arguments.act != SFLC_ACT_INIT && + arguments.act != SFLC_ACT_OPEN) { + printf("Error: --legacy (-l) can only be combined with `init' or 'open'.\n"); + return EINVAL; + } + /* Check options consistency */ if (arguments.skip_randfill && arguments.act != SFLC_ACT_INIT) { printf("Error: --skip-randfill can only be combined with `init'.\n"); return EINVAL; @@ -165,10 +175,10 @@ int sflc_cli_dispatch(int argc, char **argv) { /* Dispatch to specific command */ if (arguments.act == SFLC_ACT_INIT) { - return sflc_cli_init(arguments.block_device, arguments.num_volumes, arguments.skip_randfill); + return sflc_cli_init(arguments.block_device, arguments.sflc_mode, arguments.num_volumes, arguments.skip_randfill); } if (arguments.act == SFLC_ACT_OPEN) { - return sflc_cli_open(arguments.block_device); + return sflc_cli_open(arguments.block_device, arguments.sflc_mode); } if (arguments.act == SFLC_ACT_CLOSE) { return sflc_cli_close(arguments.block_device); @@ -225,6 +235,9 @@ static error_t _parseArgpKey(int key, char *arg, struct argp_state *state) { case SFLC_OPT_NUMVOLS_KEY: arguments->num_volumes = atoi(arg); break; + case SFLC_OPT_LEGACY_KEY: + arguments->sflc_mode = SFLC_MODE_LEGACY; + break; case SFLC_OPT_SKIPRAND_KEY: arguments->skip_randfill = true; break; diff --git a/shufflecake-userland/src/cli/init.c b/shufflecake-userland/src/cli/init.c index 302a96d..36a9bd7 100644 --- a/shufflecake-userland/src/cli/init.c +++ b/shufflecake-userland/src/cli/init.c @@ -45,7 +45,7 @@ * * @return Error code, 0 on success */ -int sflc_cli_init(char *block_device, int num_volumes, int skip_randfill) +int sflc_cli_init(char *block_device, int sflc_mode, int num_volumes, int skip_randfill) { // Requires: block_device is a correct block device path sflc_cmd_InitArgs args; char str_nrvols[SFLC_BIGBUFSIZE]; @@ -54,6 +54,7 @@ int sflc_cli_init(char *block_device, int num_volumes, int skip_randfill) int err; args.bdev_path = block_device; + args.sflc_mode = sflc_mode; // Check if number of volumes was nonzero passed by command line already if (num_volumes) { @@ -114,5 +115,15 @@ int sflc_cli_init(char *block_device, int num_volumes, int skip_randfill) args.no_randfill = skip_randfill; /* Actually perform the command */ - return sflc_cmd_initVolumes(&args); + switch(sflc_mode) + { + case SFLC_MODE_LEGACY: + return sflegc_cmd_initVolumes(&args); + case SFLC_MODE_LITE: + return sflite_cmd_initVolumes(&args); + default: + sflc_log_error("WTF, sflc_mode out of bounds!"); + return ENOTRECOVERABLE; + } + } diff --git a/shufflecake-userland/src/cli/open.c b/shufflecake-userland/src/cli/open.c index 45464c9..b2d963f 100644 --- a/shufflecake-userland/src/cli/open.c +++ b/shufflecake-userland/src/cli/open.c @@ -45,7 +45,7 @@ * * @return Error code, 0 on success */ -int sflc_cli_open(char *block_device) +int sflc_cli_open(char *block_device, int sflc_mode) { // Requires: block_device is a correct block device path sflc_cmd_OpenArgs args; char pwd[SFLC_BIGBUFSIZE]; @@ -73,5 +73,15 @@ int sflc_cli_open(char *block_device) args.pwd_len = pwd_len; /* Actually perform the command */ - return sflc_cmd_openVolumes(&args); + /* Actually perform the command */ + switch(sflc_mode) + { + case SFLC_MODE_LEGACY: + return sflegc_cmd_openVolumes(&args); + case SFLC_MODE_LITE: + return sflite_cmd_openVolumes(&args); + default: + sflc_log_error("WTF, sflc_mode out of bounds!"); + return ENOTRECOVERABLE; + } } diff --git a/shufflecake-userland/src/commands/change_pwd.c b/shufflecake-userland/src/commands/change_pwd.c index 2ef64e0..b823662 100644 --- a/shufflecake-userland/src/commands/change_pwd.c +++ b/shufflecake-userland/src/commands/change_pwd.c @@ -53,6 +53,6 @@ */ int sflc_cmd_changePwd(sflc_cmd_ChangePwdArgs *args) { - /* Delegate entirely to the function reading the DMB */ + /* Delegate entirely to the function rewriting the DMB */ return sflc_ops_rewriteDmbCell(args->bdev_path, args->dmb_cell, args->new_pwd, args->new_pwd_len); } diff --git a/shufflecake-userland/src/commands/close.c b/shufflecake-userland/src/commands/close.c index 4c180f6..28e63d4 100644 --- a/shufflecake-userland/src/commands/close.c +++ b/shufflecake-userland/src/commands/close.c @@ -35,6 +35,7 @@ #include "utils/crypto.h" #include "utils/string.h" #include "utils/file.h" +#include "utils/disk.h" #include "utils/log.h" @@ -43,7 +44,7 @@ *****************************************************/ /* Reads the list of volumes from sysfs */ -static int _readVolumesList(char *bdev_path, char **labels, size_t *nr_vols); +static int _buildVolumesList(char *bdev_path, char **labels, size_t *nr_vols); /* Close them all (in reverse order of opening) */ static int _closeVolumes(char **labels, size_t nr_vols); @@ -77,7 +78,7 @@ int sflc_cmd_closeVolumes(char *bdev_path) } /* Read them */ - err = _readVolumesList(bdev_path, labels, &nr_vols); + err = _buildVolumesList(bdev_path, labels, &nr_vols); if (err) { sflc_log_error("Could not read volume list from sysfs; error %d", err); goto out; @@ -106,31 +107,50 @@ out: * PRIVATE FUNCTIONS PROTOTYPES * *****************************************************/ -/* Reads the list of volumes from sysfs */ -static int _readVolumesList(char *bdev_path, char **labels, size_t *nr_vols) +/* Reads from sysfs to build the volumes list */ +static int _buildVolumesList(char *bdev_path, char **labels, size_t *nr_vols) { - char bdev_path_noslash[SFLC_BDEV_PATH_MAX_LEN + 1]; - char openvolumes_path[SFLC_BIGBUFSIZE]; - char *str_openvolumes; + char *bdev_name; + char devid_path[SFLC_BIGBUFSIZE]; + char *str_devid; + size_t dev_id; + char nrvolumes_path[SFLC_BIGBUFSIZE]; + char *str_nrvolumes; - /* Remove the slashes from the bdev_path (replace with underscores) */ - strcpy(bdev_path_noslash, bdev_path); - sflc_str_replaceAll(bdev_path_noslash, '/', '_'); - /* Build path to sysfsy file containing open volumes list */ - sprintf(openvolumes_path, "%s/%s/%s", SFLC_SYSFS_BDEVS_DIR, bdev_path_noslash, SFLC_SYSFS_OPENVOLUMES_FILENAME); + /* Get device name as : */ + bdev_name = sflc_disk_getDeviceName(bdev_path); + if(!bdev_name) { + sflc_log_error("Could not allocate device name"); + return ENOMEM; + } + /* Build path to sysfs file containing device ID */ + sprintf(devid_path, "%s/%s/%s", SFLC_SYSFS_BDEVS_DIR, bdev_name, SFLC_SYSFS_DEVID_FILENAME); + /* Build path to sysfs file containing number of open volumes */ + sprintf(nrvolumes_path, "%s/%s/%s", SFLC_SYSFS_BDEVS_DIR, bdev_name, SFLC_SYSFS_OPENVOLUMES_FILENAME); - /* Read the sysfs file */ - str_openvolumes = sflc_readFile(openvolumes_path); - if (!str_openvolumes) { - sflc_log_error("Could not read file %s", openvolumes_path); + /* Read the device ID */ + str_devid = sflc_readFile(devid_path); + if (!str_devid) { + sflc_log_error("Could not read file %s", devid_path); + return EBADF; + } + /* Parse the device ID */ + if (sscanf(str_devid, "%lu", &dev_id) != 1) { + sflc_log_error("Could not parse device ID:\n%s", str_devid); return EBADF; } + /* Read the number of volumes */ + str_nrvolumes = sflc_readFile(nrvolumes_path); + if (!str_nrvolumes) { + sflc_log_error("Could not read file %s", nrvolumes_path); + return EBADF; + } /* Parse the number of volumes */ - char *endptr; - *nr_vols = strtoul(str_openvolumes, &endptr, 10); - /* Skip past the number of volumes (lands on a whitespace before the first label) */ - str_openvolumes = endptr; + if (sscanf(str_nrvolumes, "%lu", nr_vols) != 1) { + sflc_log_error("Could not parse number of volumes:\n%s", str_nrvolumes); + return EBADF; + } /* Just to be sure */ if (*nr_vols > SFLC_DEV_MAX_VOLUMES) { @@ -138,18 +158,10 @@ static int _readVolumesList(char *bdev_path, char **labels, size_t *nr_vols) return EBADF; } - /* Read labels */ + /* Build labels */ size_t i; for (i = 0; i < *nr_vols; i++) { - /* Trust the content of the sysfs file */ - if (sscanf(str_openvolumes, " %s", labels[i]) != 1) { - sflc_log_error("Could not read volume label %lu. Sysfs content:\n%s", i, str_openvolumes); - return EBADF; - } - sflc_log_debug("Label %lu to close: %s", i, labels[i]); - - /* Skip past the whitespace and the label */ - str_openvolumes += 1 + strlen(labels[i]); + sprintf(labels[i], "sflc_%lu_%lu", dev_id, i); } return 0; @@ -164,7 +176,7 @@ static int _closeVolumes(char **labels, size_t nr_vols) /* Eazy peazy */ int i; for (i = nr_vols-1; i >= 0; i--) { - err = sflc_ops_closeVolume(labels[i]); + err = sflite_ops_closeVolume(labels[i]); if (err) { sflc_log_error("Could not close volume %s; error %d", labels[i], err); return err; diff --git a/shufflecake-userland/src/commands/init_legacy.c b/shufflecake-userland/src/commands/init_legacy.c new file mode 100644 index 0000000..b258267 --- /dev/null +++ b/shufflecake-userland/src/commands/init_legacy.c @@ -0,0 +1,202 @@ +/* + * Copyright The Shufflecake Project Authors (2022) + * Copyright The Shufflecake Project Contributors (2022) + * Copyright Contributors to the The Shufflecake Project. + * + * See the AUTHORS file at the top-level directory of this distribution and at + * + * + * This file is part of the program shufflecake-c, which is part of the + * Shufflecake Project. Shufflecake is a plausible deniability (hidden storage) + * layer for Linux. See . + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 2 of the License, or (at your option) + * any later version. This program is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. You should have received a copy of the + * GNU General Public License along with this program. + * If not, see . + */ + +/***************************************************** + * INCLUDE SECTION * + *****************************************************/ + +#include +#include +#include + +#include "commands.h" +#include "operations.h" +#include "utils/sflc.h" +#include "utils/disk.h" +#include "utils/crypto.h" +#include "utils/log.h" + + +/***************************************************** + * CONSTANTS * + *****************************************************/ + +/* The device is randomised in chunks of 1024 blocks (arbitrary number) */ +#define SFLC_BLOCKS_IN_RAND_CHUNK 1024 +/* That's 4 MiB */ +#define SFLC_RAND_CHUNK_SIZE (SFLC_BLOCKS_IN_RAND_CHUNK * SFLC_BLOCK_SIZE) + + +/***************************************************** + * PRIVATE FUNCTIONS PROTOTYPES * + *****************************************************/ + +/* Fill the device with random data */ +static int _fillDiskWithRandom(char *bdev_path, uint64_t dev_size); + + +/***************************************************** + * PUBLIC FUNCTIONS DEFINITIONS * + *****************************************************/ + +/** + * Create N volumes (only formats the device header, does not open the volumes). + * Creates them in order from 0 to N-1, so as to induce a back-linked list on the device. + * + * @param args->bdev_path The path to the underlying block device + * @param args->nr_vols The number of volumes to create + * @param args->pwds The array of passwords for the various volumes + * @param args->pwd_lens The length of each password + * @param args->no_randfill A boolean switch indicating that the volume should not + * be filled entirely with random data prior to formatting. + * + * @return Error code, 0 on success + */ +int sflegc_cmd_initVolumes(sflc_cmd_InitArgs *args) +{ + sflc_Dmb dmb; + sflc_Vmb vmb; + int64_t dev_size; + size_t nr_slices; + int err; + + /* Sanity check */ + if (args->nr_vols > SFLC_DEV_MAX_VOLUMES) { + sflc_log_error("Cannot create %lu volumes on a single device", args->nr_vols); + return EINVAL; + } + + /* Get device size */ + dev_size = sflc_disk_getSize(args->bdev_path); + if (dev_size < 0) { + err = -dev_size; + sflc_log_error("Could not get device size for %s; error %d", args->bdev_path, err); + return err; + } + /* Convert to number of slices */ + nr_slices = sflegc_disk_maxSlices(dev_size); + sflc_log_debug("Device %s has %ld blocks, corresponding to %lu logical slices", args->bdev_path, dev_size, nr_slices); + + /* Fill disk with random bytes, if requested */ + if (!args->no_randfill) { + err = _fillDiskWithRandom(args->bdev_path, (uint64_t) dev_size); + if (err) { + sflc_log_error("Could not fill device %s with random bytes; error %d", args->bdev_path, err); + return err; + } + } + + /* Fill the DMB */ + dmb.nr_vols = args->nr_vols; + /* Sample the VMB keys */ + size_t i; + for (i = 0; i < dmb.nr_vols; i++) { + err = sflc_rand_getStrongBytes(dmb.vmb_keys[i], SFLC_STANDARD_KEYLEN); + if (err) { + sflc_log_error("Could not sample VMB key number %lu; error %d", i , err); + return err; + } + } + /* And write (encrypted) to disk */ + err = sflc_ops_writeDmb(args->bdev_path, args->pwds, args->pwd_lens, &dmb); + if (err) { + sflc_log_error("Could not create DMB and write it to disk; error %d", err); + return err; + } + + /* Write the volume headers */ + vmb.nr_slices = nr_slices; + for (i = 0; i < args->nr_vols; i++) { + /* This volume's prev_vmb_key */ + if (i > 0) { + memcpy(vmb.prev_vmb_key, dmb.vmb_keys[i-1], SFLC_STANDARD_KEYLEN); + } + /* Sample this volume's VEK */ + sflc_rand_getStrongBytes(vmb.volume_key_legacy, SFLC_STANDARD_KEYLEN); + + /* Write complete volume header (VMB + PM) */ + err = sflegc_ops_writeVolumeHeader(args->bdev_path, dmb.vmb_keys[i], &vmb, i); + if (err) { + sflc_log_error("Error writing volume header %lu on device %s; error %d", i, args->bdev_path, err); + return err; + } + } + printf("Created %lu volumes on device %s\n", args->nr_vols, args->bdev_path); + + return 0; +} + + +/***************************************************** + * PRIVATE FUNCTIONS PROTOTYPES * + *****************************************************/ + +/* Fill the device with random data */ +static int _fillDiskWithRandom(char *bdev_path, uint64_t dev_size) +{ + char *rand_chunk; + int err; + + /* Allocate chunk */ + rand_chunk = malloc(SFLC_RAND_CHUNK_SIZE); + if (!rand_chunk) { + sflc_log_error("Could not allocate %d bytes for chunk of random data", SFLC_RAND_CHUNK_SIZE); + return ENOMEM; + } + + /* Loop to write random data in chunks */ + uint64_t blocks_remaining = dev_size; + uint64_t sector = 0; + while (blocks_remaining > 0) { + uint64_t blocks_to_write = + (blocks_remaining > SFLC_BLOCKS_IN_RAND_CHUNK) ? SFLC_BLOCKS_IN_RAND_CHUNK : blocks_remaining; + uint64_t bytes_to_write = blocks_to_write * SFLC_BLOCK_SIZE; + + /* Sample random bytes */ + err = sflc_rand_getWeakBytes(rand_chunk, bytes_to_write); + if (err) { + sflc_log_error("Could not sample %lu random bytes to write on disk; error %d", bytes_to_write, err); + goto out; + } + + /* Write on disk */ + err = sflc_disk_writeManyBlocks(bdev_path, sector, rand_chunk, blocks_to_write); + if (err) { + sflc_log_error("Could not write random bytes on disk; error %d", err); + goto out; + } + + /* Advance loop */ + sector += blocks_to_write; + blocks_remaining -= blocks_to_write; + } + + /* No prob */ + err = 0; + + +out: + free(rand_chunk); + return err; +} + diff --git a/shufflecake-userland/src/commands/init.c b/shufflecake-userland/src/commands/init_lite.c similarity index 90% rename from shufflecake-userland/src/commands/init.c rename to shufflecake-userland/src/commands/init_lite.c index cd21b03..f65d1b6 100644 --- a/shufflecake-userland/src/commands/init.c +++ b/shufflecake-userland/src/commands/init_lite.c @@ -44,7 +44,7 @@ /* The device is randomised in chunks of 1024 blocks (arbitrary number) */ #define SFLC_BLOCKS_IN_RAND_CHUNK 1024 /* That's 4 MiB */ -#define SFLC_RAND_CHUNK_SIZE (SFLC_BLOCKS_IN_RAND_CHUNK * SFLC_SECTOR_SIZE) +#define SFLC_RAND_CHUNK_SIZE (SFLC_BLOCKS_IN_RAND_CHUNK * SFLC_BLOCK_SIZE) /***************************************************** @@ -72,7 +72,7 @@ static int _fillDiskWithRandom(char *bdev_path, uint64_t dev_size); * * @return Error code, 0 on success */ -int sflc_cmd_initVolumes(sflc_cmd_InitArgs *args) +int sflite_cmd_initVolumes(sflc_cmd_InitArgs *args) { sflc_Dmb dmb; sflc_Vmb vmb; @@ -94,7 +94,7 @@ int sflc_cmd_initVolumes(sflc_cmd_InitArgs *args) return err; } /* Convert to number of slices */ - nr_slices = sflc_disk_maxSlices(dev_size); + nr_slices = sflite_disk_maxSlices(dev_size); sflc_log_debug("Device %s has %ld blocks, corresponding to %lu logical slices", args->bdev_path, dev_size, nr_slices); /* Fill disk with random bytes, if requested */ @@ -111,7 +111,7 @@ int sflc_cmd_initVolumes(sflc_cmd_InitArgs *args) /* Sample the VMB keys */ size_t i; for (i = 0; i < dmb.nr_vols; i++) { - err = sflc_rand_getStrongBytes(dmb.vmb_keys[i], SFLC_CRYPTO_KEYLEN); + err = sflc_rand_getStrongBytes(dmb.vmb_keys[i], SFLC_STANDARD_KEYLEN); if (err) { sflc_log_error("Could not sample VMB key number %lu; error %d", i , err); return err; @@ -129,13 +129,13 @@ int sflc_cmd_initVolumes(sflc_cmd_InitArgs *args) for (i = 0; i < args->nr_vols; i++) { /* This volume's prev_vmb_key */ if (i > 0) { - memcpy(vmb.prev_vmb_key, dmb.vmb_keys[i-1], SFLC_CRYPTO_KEYLEN); + memcpy(vmb.prev_vmb_key, dmb.vmb_keys[i-1], SFLC_STANDARD_KEYLEN); } /* Sample this volume's VEK */ - sflc_rand_getStrongBytes(vmb.volume_key, SFLC_CRYPTO_KEYLEN); + sflc_rand_getStrongBytes(vmb.volume_key_lite, SFLC_AESXTS_KEYLEN); /* Write complete volume header (VMB + PM) */ - err = sflc_ops_writeVolumeHeader(args->bdev_path, dmb.vmb_keys[i], &vmb, i); + err = sflite_ops_writeVolumeHeader(args->bdev_path, dmb.vmb_keys[i], &vmb, i); if (err) { sflc_log_error("Error writing volume header %lu on device %s; error %d", i, args->bdev_path, err); return err; @@ -170,7 +170,7 @@ static int _fillDiskWithRandom(char *bdev_path, uint64_t dev_size) while (blocks_remaining > 0) { uint64_t blocks_to_write = (blocks_remaining > SFLC_BLOCKS_IN_RAND_CHUNK) ? SFLC_BLOCKS_IN_RAND_CHUNK : blocks_remaining; - uint64_t bytes_to_write = blocks_to_write * SFLC_SECTOR_SIZE; + uint64_t bytes_to_write = blocks_to_write * SFLC_BLOCK_SIZE; /* Sample random bytes */ err = sflc_rand_getWeakBytes(rand_chunk, bytes_to_write); @@ -180,7 +180,7 @@ static int _fillDiskWithRandom(char *bdev_path, uint64_t dev_size) } /* Write on disk */ - err = sflc_disk_writeManySectors(bdev_path, sector, rand_chunk, blocks_to_write); + err = sflc_disk_writeManyBlocks(bdev_path, sector, rand_chunk, blocks_to_write); if (err) { sflc_log_error("Could not write random bytes on disk; error %d", err); goto out; diff --git a/shufflecake-userland/src/commands/open.c b/shufflecake-userland/src/commands/open_legacy.c similarity index 89% rename from shufflecake-userland/src/commands/open.c rename to shufflecake-userland/src/commands/open_legacy.c index da0c4f0..44ab82f 100644 --- a/shufflecake-userland/src/commands/open.c +++ b/shufflecake-userland/src/commands/open_legacy.c @@ -65,7 +65,7 @@ static int _getNextDevId(size_t *next_dev_id); * * @return Error code (also if no volume could be opened), 0 on success */ -int sflc_cmd_openVolumes(sflc_cmd_OpenArgs *args) +int sflegc_cmd_openVolumes(sflc_cmd_OpenArgs *args) { int64_t dev_size; size_t nr_slices; @@ -73,18 +73,19 @@ int sflc_cmd_openVolumes(sflc_cmd_OpenArgs *args) sflc_Vmb vmbs[SFLC_DEV_MAX_VOLUMES]; size_t dev_id; int err; - char bdev_path_noslash[SFLC_BDEV_PATH_MAX_LEN + 1]; + char *bdev_name; char opendev_path[SFLC_BIGBUFSIZE]; DIR* opendev_dir; /* Check if device is already opened and abort if so. */ - /* Step 1: rebuild sysfs directory name of device to be checked. */ - /* TODO: this is duplicate code from close.c we might want to modularize it. */ - /* Remove the slashes from the bdev_path (replace with underscores). */ - strcpy(bdev_path_noslash, args->bdev_path); - sflc_str_replaceAll(bdev_path_noslash, '/', '_'); + /* Get device name as : */ + bdev_name = sflc_disk_getDeviceName(args->bdev_path); + if(!bdev_name) { + sflc_log_error("Could not allocate device name"); + return ENOMEM; + } /* Build sysfs path of opened device */ - sprintf(opendev_path, "%s/%s", SFLC_SYSFS_BDEVS_DIR, bdev_path_noslash); + sprintf(opendev_path, "%s/%s", SFLC_SYSFS_BDEVS_DIR, bdev_name); /* Step 2: check if directory exists. */ opendev_dir = opendir(opendev_path); if (opendev_dir) { @@ -102,7 +103,7 @@ int sflc_cmd_openVolumes(sflc_cmd_OpenArgs *args) sflc_log_error("Could not read device size for %s; error %d", args->bdev_path, err); return err; } - nr_slices = sflc_disk_maxSlices(dev_size); + nr_slices = sflegc_disk_maxSlices(dev_size); /* Find volume opened by the pwd */ err = sflc_ops_readDmb(args->bdev_path, args->pwd, args->pwd_len, &dmb_cell); @@ -131,7 +132,7 @@ int sflc_cmd_openVolumes(sflc_cmd_OpenArgs *args) } /* Read and unlock VMB */ - err = sflc_ops_readVmb(args->bdev_path, vmb_key, nr_slices, (size_t) i, &vmbs[i]); + err = sflegc_ops_readVmb(args->bdev_path, vmb_key, nr_slices, (size_t) i, &vmbs[i]); if (err) { sflc_log_error("Could not read VMB %d on device %s; error %d", i, args->bdev_path, err); @@ -149,7 +150,7 @@ int sflc_cmd_openVolumes(sflc_cmd_OpenArgs *args) /* Open volumes "in order" */ for (i = 0; i <= dmb_cell.vol_idx; i++) { - err = sflc_ops_openVolume(args->bdev_path, dev_id, (size_t) i, &vmbs[i]); + err = sflegc_ops_openVolume(args->bdev_path, dev_id, (size_t) i, &vmbs[i]); if (err) { sflc_log_error("Could not open volume %d; error %d. " "Previous volumes on the device might have already " diff --git a/shufflecake-userland/src/commands/open_lite.c b/shufflecake-userland/src/commands/open_lite.c new file mode 100644 index 0000000..4604719 --- /dev/null +++ b/shufflecake-userland/src/commands/open_lite.c @@ -0,0 +1,206 @@ +/* + * Copyright The Shufflecake Project Authors (2022) + * Copyright The Shufflecake Project Contributors (2022) + * Copyright Contributors to the The Shufflecake Project. + * + * See the AUTHORS file at the top-level directory of this distribution and at + * + * + * This file is part of the program shufflecake-c, which is part of the + * Shufflecake Project. Shufflecake is a plausible deniability (hidden storage) + * layer for Linux. See . + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 2 of the License, or (at your option) + * any later version. This program is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. You should have received a copy of the + * GNU General Public License along with this program. + * If not, see . + */ + +/***************************************************** + * INCLUDE SECTION * + *****************************************************/ + +#include +#include +#include +#include + +#include "commands.h" +#include "operations.h" +#include "utils/sflc.h" +#include "utils/crypto.h" +#include "utils/disk.h" +#include "utils/file.h" +#include "utils/log.h" + + +/***************************************************** + * PRIVATE FUNCTIONS PROTOTYPES * + *****************************************************/ + +/* Read the next device ID in sysfs */ +static int _getNextDevId(size_t *next_dev_id); + + +/***************************************************** + * PUBLIC FUNCTIONS DEFINITIONS * + *****************************************************/ + +/** + * Open M volumes, from the first one down to the one whose pwd is provided. + * Scans the DMB cells to find which one is unlocked by the provided pwd; then, + * using the decrypted VMB key, unlocks the M-th VMB; then, iteratively using + * the prev_vmb_key field, unlocks all the previous VMBs; then, using the + * decrypted VMB keys, opens the volumes "in order" from 1 to M. + * + * @param args->bdev_path The underlying block device + * @param args->pwd The password + * @param args->pwd_len The password length + * + * @return Error code (also if no volume could be opened), 0 on success + */ +int sflite_cmd_openVolumes(sflc_cmd_OpenArgs *args) +{ + int64_t dev_size; + size_t nr_slices; + sflc_DmbCell dmb_cell; + sflc_Vmb vmbs[SFLC_DEV_MAX_VOLUMES]; + size_t dev_id; + char *bdev_name; + char opendev_path[SFLC_BIGBUFSIZE]; + DIR* opendev_dir; + int err; + + /* Check if device is already opened and abort if so. */ + /* Get device name as : */ + bdev_name = sflc_disk_getDeviceName(args->bdev_path); + if(!bdev_name) { + sflc_log_error("Could not allocate device name"); + return ENOMEM; + } + /* Build sysfs path of opened device */ + sprintf(opendev_path, "%s/%s", SFLC_SYSFS_BDEVS_DIR, bdev_name); + /* Step 2: check if directory exists. */ + opendev_dir = opendir(opendev_path); + if (opendev_dir) { + /* Directory exists. */ + closedir(opendev_dir); + err = EEXIST; + sflc_log_error("Device %s seems to be already open; error %d", args->bdev_path, err); + return err; + } + + /* Get number of slices */ + dev_size = sflc_disk_getSize(args->bdev_path); + if (dev_size < 0) { + err = -dev_size; + sflc_log_error("Could not read device size for %s; error %d", args->bdev_path, err); + return err; + } + nr_slices = sflite_disk_maxSlices(dev_size); + + /* Find volume opened by the pwd */ + err = sflc_ops_readDmb(args->bdev_path, args->pwd, args->pwd_len, &dmb_cell); + if (err) { + sflc_log_error("Could not read DMB; error %d", err); + return err; + } + /* Was there one? */ + if (dmb_cell.vol_idx >= SFLC_DEV_MAX_VOLUMES) { + sflc_log_error("The provided password opens no volume on the device"); + return EINVAL; + } + printf("Password is correct! Opening volumes...\n"); + + /* Unlock VMBs "backwards" */ + int i; // Needs sign, because loop ends on i>=0 + for (i = dmb_cell.vol_idx; i >= 0; i--) { + /* Which VMB key to use? */ + char *vmb_key; + if (i == dmb_cell.vol_idx) { + // The one unlocked by pwd + vmb_key = dmb_cell.vmb_key; + } else { + // Or the prev_vmb_key from last iteration + vmb_key = vmbs[i+1].prev_vmb_key; + } + + /* Read and unlock VMB */ + err = sflite_ops_readVmb(args->bdev_path, vmb_key, nr_slices, (size_t) i, &vmbs[i]); + if (err) { + sflc_log_error("Could not read VMB %d on device %s; error %d", + i, args->bdev_path, err); + return err; + } + } + + /* Get the ID that will be assigned to the block device */ + err = _getNextDevId(&dev_id); + if (err) { + sflc_log_error("Could not get next device ID; error %d", err); + return err; + } + sflc_log_debug("Next device ID is %lu", dev_id); + + /* Open volumes "in order" */ + for (i = 0; i <= dmb_cell.vol_idx; i++) { + err = sflite_ops_openVolume(args->bdev_path, dev_id, (size_t) i, &vmbs[i]); + if (err) { + sflc_log_error("Could not open volume %d; error %d. " + "Previous volumes on the device might have already " + "been opened, it's recommended you close them", + i, err); + return err; + } + sflc_log_debug("Successfully opened volume %d with VMB key", i); + printf("Opened volume /dev/mapper/sflc_%lu_%d\n", dev_id, i); + } + + return 0; +} + + +/***************************************************** + * PRIVATE FUNCTIONS PROTOTYPES * + *****************************************************/ + +/* Read the next device ID in sysfs */ +static int _getNextDevId(size_t *next_dev_id) +{ + char *str_nextdevid; + int err; + + /* Read sysfs entry */ + str_nextdevid = sflc_readFile(SFLC_SYSFS_NEXTDEVID); + if (!str_nextdevid) { + sflc_log_error("Could not read sysfs entry %s", SFLC_SYSFS_NEXTDEVID); + return EINVAL; + } + + /* Parse integer */ + if (sscanf(str_nextdevid, "%lu", next_dev_id) != 1) { + sflc_log_error("Error parsing content of file %s", SFLC_SYSFS_NEXTDEVID); + err = EINVAL; + goto err_devid; + } + /* Sanity check */ + if (*next_dev_id >= SFLC_TOT_MAX_DEVICES) { + sflc_log_error("There are already %d open devices, this is the maximum allowed", SFLC_TOT_MAX_DEVICES); + err = E2BIG; + goto err_devid; + } + + /* All good */ + err = 0; + + +err_devid: + free(str_nextdevid); + return err; +} + diff --git a/shufflecake-userland/src/header/device_master_block.c b/shufflecake-userland/src/header/device_master_block.c index cdd1f8c..1cfcd9b 100644 --- a/shufflecake-userland/src/header/device_master_block.c +++ b/shufflecake-userland/src/header/device_master_block.c @@ -72,7 +72,7 @@ int sflc_dmb_seal(sflc_Dmb *dmb, char **pwds, size_t *pwd_lens, char *disk_block } /* Randomise whole block */ - err = sflc_rand_getWeakBytes(disk_block, SFLC_SECTOR_SIZE); + err = sflc_rand_getWeakBytes(disk_block, SFLC_BLOCK_SIZE); if (err) { sflc_log_error("Could not randomise DMB; error %d", err); return err; @@ -115,9 +115,9 @@ int sflc_dmb_unseal(char *disk_block, char *pwd, size_t pwd_len, sflc_DmbCell *d // KDF salt char *salt; // The KDF-derived key - char kek[SFLC_CRYPTO_KEYLEN]; + char kek[SFLC_STANDARD_KEYLEN]; // The unlocked VMB key - char vmb_key[SFLC_CRYPTO_KEYLEN]; + char vmb_key[SFLC_STANDARD_KEYLEN]; // Error code int err; @@ -149,7 +149,7 @@ int sflc_dmb_unseal(char *disk_block, char *pwd, size_t pwd_len, sflc_DmbCell *d if (match) { sflc_log_debug("The provided password unlocks volume %lu", i); dmb_cell->vol_idx = i; - memcpy(dmb_cell->vmb_key, vmb_key, SFLC_CRYPTO_KEYLEN); + memcpy(dmb_cell->vmb_key, vmb_key, SFLC_STANDARD_KEYLEN); } } @@ -160,7 +160,7 @@ int sflc_dmb_unseal(char *disk_block, char *pwd, size_t pwd_len, sflc_DmbCell *d bad_decrypt: bad_kdf: /* Always wipe the key from memory, even on success */ - memset(kek, 0, SFLC_CRYPTO_KEYLEN); + memset(kek, 0, SFLC_STANDARD_KEYLEN); return err; } @@ -211,9 +211,9 @@ static int _encryptVmbKeyWithPwd(char *salt, char *pwd, size_t pwd_len, char *vm // Pointers inside the block char *iv = dmb_cell; char *enc_vmb_key = iv + SFLC_AESGCM_PADDED_IVLEN; - char *mac = enc_vmb_key + SFLC_CRYPTO_KEYLEN; + char *mac = enc_vmb_key + SFLC_STANDARD_KEYLEN; // Key-encryption-key derived from KDF - char kek[SFLC_CRYPTO_KEYLEN]; + char kek[SFLC_STANDARD_KEYLEN]; // Error code int err; @@ -234,7 +234,7 @@ static int _encryptVmbKeyWithPwd(char *salt, char *pwd, size_t pwd_len, char *vm sflc_log_debug("Successfully sampled prologue IV"); /* Encrypt the VMB key */ - err = sflc_aes256gcm_encrypt(kek, vmb_key, SFLC_CRYPTO_KEYLEN, iv, enc_vmb_key, mac); + err = sflc_aes256gcm_encrypt(kek, vmb_key, SFLC_STANDARD_KEYLEN, iv, enc_vmb_key, mac); if (err) { sflc_log_error("Could not encrypt the VMB key: error %d", err); goto bad_encrypt; @@ -249,7 +249,7 @@ bad_encrypt: bad_sample_iv: bad_kdf: /* Always wipe the key from memory, even on success */ - memset(kek, 0, SFLC_CRYPTO_KEYLEN); + memset(kek, 0, SFLC_STANDARD_KEYLEN); return err; } @@ -259,12 +259,12 @@ static int _decryptVmbKeyWithPwd(char *dmb_cell, char *kek, char *vmb_key, bool // Pointers inside the block char *iv = dmb_cell; char *enc_vmb_key = iv + SFLC_AESGCM_PADDED_IVLEN; - char *mac = enc_vmb_key + SFLC_CRYPTO_KEYLEN; + char *mac = enc_vmb_key + SFLC_STANDARD_KEYLEN; // Error code int err; /* Decrypt the VMB key */ - err = sflc_aes256gcm_decrypt(kek, enc_vmb_key, SFLC_CRYPTO_KEYLEN, mac, iv, vmb_key, match); + err = sflc_aes256gcm_decrypt(kek, enc_vmb_key, SFLC_STANDARD_KEYLEN, mac, iv, vmb_key, match); if (err) { sflc_log_error("Error while decrypting VMB key: error %d", err); return err; diff --git a/shufflecake-userland/src/header/position_map.c b/shufflecake-userland/src/header/position_map_legacy.c similarity index 88% rename from shufflecake-userland/src/header/position_map.c rename to shufflecake-userland/src/header/position_map_legacy.c index f2b8144..6aab1c7 100644 --- a/shufflecake-userland/src/header/position_map.c +++ b/shufflecake-userland/src/header/position_map_legacy.c @@ -50,7 +50,7 @@ * @param epm The EncPosMap struct to be initialised. * * @return Error code, 0 on success */ -int sflc_epm_create(size_t nr_slices, char *volume_key, sflc_EncPosMap *epm) +int sflegc_epm_create(size_t nr_slices, char *volume_key, sflegc_EncPosMap *epm) { size_t nr_pmbs; size_t nr_arrays; @@ -59,12 +59,12 @@ int sflc_epm_create(size_t nr_slices, char *volume_key, sflc_EncPosMap *epm) // Each PosMapBlock holds up to 1024 PSIs (Physical Slice Index) nr_pmbs = ceil(nr_slices, SFLC_SLICE_IDX_PER_BLOCK); // Each array holds up to 256 PosMapBlocks - nr_arrays = ceil(nr_pmbs, SFLC_BLOCKS_PER_LOG_SLICE); + nr_arrays = ceil(nr_pmbs, SFLC_SLICE_SCALE); // Fill the EPM numeric fields epm->nr_arrays = nr_arrays; // All arrays are full except the last one - epm->nr_last_pmbs = nr_pmbs - (SFLC_BLOCKS_PER_LOG_SLICE * (nr_arrays - 1)); + epm->nr_last_pmbs = nr_pmbs - (SFLC_SLICE_SCALE * (nr_arrays - 1)); // Allocate array of IV blocks epm->iv_blocks = malloc(nr_arrays * sizeof(char *)); @@ -85,13 +85,13 @@ int sflc_epm_create(size_t nr_slices, char *volume_key, sflc_EncPosMap *epm) int i; for (i = 0; i < nr_arrays; i++) { // The last PMB array might be smaller - size_t nr_pmbs_here = ((i == nr_arrays - 1) ? epm->nr_last_pmbs : SFLC_BLOCKS_PER_LOG_SLICE); - size_t pmb_array_size = SFLC_SECTOR_SIZE * nr_pmbs_here; + size_t nr_pmbs_here = ((i == nr_arrays - 1) ? epm->nr_last_pmbs : SFLC_SLICE_SCALE); + size_t pmb_array_size = SFLC_BLOCK_SIZE * nr_pmbs_here; char *iv_block; char *pmb_array; // Allocate IV block - epm->iv_blocks[i] = malloc(SFLC_SECTOR_SIZE); + epm->iv_blocks[i] = malloc(SFLC_BLOCK_SIZE); if (!epm->iv_blocks[i]) { sflc_log_error("Could not allocate IV block number %d", i); err = ENOMEM; @@ -109,7 +109,7 @@ int sflc_epm_create(size_t nr_slices, char *volume_key, sflc_EncPosMap *epm) pmb_array = epm->pmb_arrays[i]; // Fill the IV block with random data (can ignore return value) - sflc_rand_getWeakBytes(iv_block, SFLC_SECTOR_SIZE); + sflc_rand_getWeakBytes(iv_block, SFLC_BLOCK_SIZE); // Fill the PMB array with 0xFF memset(pmb_array, SFLC_EPM_FILLER, pmb_array_size); @@ -117,10 +117,10 @@ int sflc_epm_create(size_t nr_slices, char *volume_key, sflc_EncPosMap *epm) int j; for (j = 0; j < nr_pmbs_here; j++) { char *iv = iv_block + (j * SFLC_AESCTR_IVLEN); - char *pmb = pmb_array + (j * SFLC_SECTOR_SIZE); + char *pmb = pmb_array + (j * SFLC_BLOCK_SIZE); // Encrypt in-place - err = sflc_aes256ctr_encrypt(volume_key, pmb, SFLC_SECTOR_SIZE, iv, NULL); + err = sflc_aes256ctr_encrypt(volume_key, pmb, SFLC_BLOCK_SIZE, iv, NULL); if (err) { sflc_log_error("Could not encrypt PMB %d of array %d", j, i); goto out; diff --git a/shufflecake-userland/src/header/position_map_lite.c b/shufflecake-userland/src/header/position_map_lite.c new file mode 100644 index 0000000..ae2b48a --- /dev/null +++ b/shufflecake-userland/src/header/position_map_lite.c @@ -0,0 +1,97 @@ +/* + * Copyright The Shufflecake Project Authors (2022) + * Copyright The Shufflecake Project Contributors (2022) + * Copyright Contributors to the The Shufflecake Project. + * + * See the AUTHORS file at the top-level directory of this distribution and at + * + * + * This file is part of the program shufflecake-c, which is part of the + * Shufflecake Project. Shufflecake is a plausible deniability (hidden storage) + * layer for Linux. See . + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 2 of the License, or (at your option) + * any later version. This program is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. You should have received a copy of the + * GNU General Public License along with this program. + * If not, see . + */ + +/***************************************************** + * INCLUDE SECTION * + *****************************************************/ + +#include +#include +#include +#include + +#include "header.h" +#include "utils/sflc.h" +#include "utils/crypto.h" +#include "utils/math.h" +#include "utils/log.h" + + +/***************************************************** + * PUBLIC FUNCTIONS DEFINITIONS * + *****************************************************/ + +/* Create an encrypted empty position map for the given number of slices. + * Allocates the memory (whole number of blocks) needed to host it. + * + * @param nr_slices The number of slices the device will be composed of. + * @param volume_key The volume's data section encryption key, used to encrypt the + * position map as well. + * + * @return The memory buffer containing the position map */ +void *sflite_epm_create(size_t nr_slices, size_t vol_idx, char *volume_key) +{ + char pmb[SFLC_BLOCK_SIZE]; + char iv[SFLC_AESXTS_IVLEN]; + void *epm; + size_t nr_pmbs; + uint64_t pblk_num; + int err; + + // Each PosMapBlock holds up to 1024 PSIs (Physical Slice Index) + nr_pmbs = ceil(nr_slices, SFLC_SLICE_IDX_PER_BLOCK); + + // Allocate EPM + epm = malloc(nr_pmbs * SFLC_BLOCK_SIZE); + if (!epm) { + sflc_log_error("Could not malloc EPM"); + return NULL; + } + + // Fill cleartext PMB with 0xFF + memset(pmb, SFLC_EPM_FILLER, SFLC_BLOCK_SIZE); + // First physical block number + pblk_num = sflite_pmStartBlock(vol_idx, nr_slices); + + // Loop to encrypt each PMB + int i; + for (i = 0; i < nr_pmbs; i++) { + // Set IV + memset(iv, 0, SFLC_AESXTS_IVLEN); + *((uint64_t*)iv) = htole64(pblk_num); + + // Encrypt + err = sflc_aes256xts_encrypt(volume_key, pmb, SFLC_BLOCK_SIZE, iv, + epm + i*SFLC_BLOCK_SIZE); + if (err) { + sflc_log_error("Could not encrypt %d-th block of PosMap; error %d", i , err); + free(epm); + return NULL; + } + + // Increment block number + pblk_num++; + } + + return epm; +} diff --git a/shufflecake-userland/src/header/volume_master_block_legacy.c b/shufflecake-userland/src/header/volume_master_block_legacy.c new file mode 100644 index 0000000..ec6cc70 --- /dev/null +++ b/shufflecake-userland/src/header/volume_master_block_legacy.c @@ -0,0 +1,223 @@ +/* + * Copyright The Shufflecake Project Authors (2022) + * Copyright The Shufflecake Project Contributors (2022) + * Copyright Contributors to the The Shufflecake Project. + * + * See the AUTHORS file at the top-level directory of this distribution and at + * + * + * This file is part of the program shufflecake-c, which is part of the + * Shufflecake Project. Shufflecake is a plausible deniability (hidden storage) + * layer for Linux. See . + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 2 of the License, or (at your option) + * any later version. This program is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. You should have received a copy of the + * GNU General Public License along with this program. + * If not, see . + */ + +/***************************************************** + * INCLUDE SECTION * + *****************************************************/ + +#include +#include +#include +#include // Network byte order + +#include "header.h" +#include "utils/crypto.h" +#include "utils/string.h" +#include "utils/log.h" + + +/***************************************************** + * PRIVATE FUNCTIONS PROTOTYPES * + *****************************************************/ + +/* Serialise the VMB before encrypting it */ +static void _serialiseVmb(sflc_Vmb *vmb, char *clear_vmb); + +/* Deserialise the VMB after decrypting it */ +static int _deserialiseVmb(char *clear_vmb, sflc_Vmb *vmb); + + +/***************************************************** + * PUBLIC FUNCTIONS DEFINITIONS * + *****************************************************/ + +/** + * Builds the on-disk master block (indistinguishable from random). + * + * @param vmb The useful information stored in this volume master block + * @param vmb_key The key encrypting the VMB + * @param disk_block The 4096-byte buffer that will contain the random-looking + * bytes to be written on-disk + * + * @return The error code, 0 on success + */ +int sflegc_vmb_seal(sflc_Vmb *vmb, char *vmb_key, char *disk_block) +{ + // Pointers inside the block + char *iv = disk_block; + char *enc_vmb = iv + SFLC_AESCTR_IVLEN; + // Serialised VMB (dynamically allocated), to be encrypted + char *clear_vmb; + // Error code + int err; + + /* Allocate large buffer on the heap */ + clear_vmb = malloc(SFLC_CLEAR_VMB_LEN); + if (!clear_vmb) { + sflc_log_error("Could not allocate %d bytes for VMB cleartext", SFLC_CLEAR_VMB_LEN); + err = ENOMEM; + goto bad_clear_alloc; + } + sflc_log_debug("Successfully allocated %d bytes for VMB cleartext", SFLC_CLEAR_VMB_LEN); + + /* Serialise the struct */ + _serialiseVmb(vmb, clear_vmb); + sflc_log_debug("Serialised VMB struct"); + + /* Sample VMB IV */ + err = sflc_rand_getWeakBytes(iv, SFLC_AESGCM_PADDED_IVLEN); + if (err) { + sflc_log_error("Could not sample VMB IV: error %d", err); + goto bad_sample_iv; + } + sflc_log_debug("Successfully sampled VMB IV"); + + /* Encrypt the VMB */ + err = sflc_aes256ctr_encrypt(vmb_key, clear_vmb, SFLC_CLEAR_VMB_LEN, iv, enc_vmb); + if (err) { + sflc_log_error("Could not encrypt VMB: error %d", err); + goto bad_encrypt; + } + sflc_log_debug("Successfully encrypted VMB"); + + // No prob + err = 0; + + +bad_encrypt: +bad_sample_iv: + /* Always wipe and free the cleartext VMB, even on success */ + memset(clear_vmb, 0, SFLC_CLEAR_VMB_LEN); + free(clear_vmb); +bad_clear_alloc: + return err; +} + + +/** + * Decrypt the VMB payload using the VMB key. + * + * @param disk_block The content of the on-disk encrypted VMB + * @param vmb_key The proposed VMB key to unseal its payload + * @param vmb A pointer to the output struct that will contain all the VMB fields + * + * @return An error code, 0 on success + */ +int sflegc_vmb_unseal(char *disk_block, char *vmb_key, sflc_Vmb *vmb) +{ + // Pointers inside the block + char *iv = disk_block; + char *enc_vmb = iv + SFLC_AESCTR_IVLEN; + // Decrypted VMB (dynamically allocated), to be deserialised + char *clear_vmb; + // Error code + int err; + + /* Allocate large buffer on the heap */ + clear_vmb = malloc(SFLC_CLEAR_VMB_LEN); + if (!clear_vmb) { + sflc_log_error("Could not allocate %d bytes for VMB cleartext", SFLC_CLEAR_VMB_LEN); + err = ENOMEM; + goto bad_clear_alloc; + } + sflc_log_debug("Successfully allocated %d bytes for VMB cleartext", SFLC_CLEAR_VMB_LEN); + + /* Decrypt the VMB */ + err = sflc_aes256ctr_decrypt(vmb_key, enc_vmb, SFLC_CLEAR_VMB_LEN, iv, clear_vmb); + if (err) { + sflc_log_error("Error while decrypting VMB: error %d", err); + goto bad_decrypt; + } + sflc_log_debug("Successfully decrypted VMB"); + + /* Deserialise the struct */ + err = _deserialiseVmb(clear_vmb, vmb); + if (err) { + sflc_log_error("Error while deserialising VMB: error %d", err); + goto bad_deserialise; + } + sflc_log_debug("Deserialised VMB struct"); + + // No prob + err = 0; + + +bad_deserialise: +bad_decrypt: + /* Always wipe and free the VMB cleartext, even on success */ + memset(clear_vmb, 0, SFLC_CLEAR_VMB_LEN); + free(clear_vmb); +bad_clear_alloc: + return err; +} + + +/***************************************************** + * PRIVATE FUNCTIONS PROTOTYPES * + *****************************************************/ + +/* Serialise the payload before encrypting it */ +static void _serialiseVmb(sflc_Vmb *vmb, char *clear_vmb) +{ + // Pointers inside the VMB + char *p_vol_key = clear_vmb; + char *p_prev_vmb_key = p_vol_key + SFLC_STANDARD_KEYLEN; + char *p_nr_slices = p_prev_vmb_key + SFLC_STANDARD_KEYLEN; + + /* Copy the volume key */ + memcpy(p_vol_key, vmb->volume_key_legacy, SFLC_STANDARD_KEYLEN); + + /* Copy the previous volume's VMB key */ + memcpy(p_prev_vmb_key, vmb->prev_vmb_key, SFLC_STANDARD_KEYLEN); + + /* Write the number of slices (network byte order) */ + *((uint32_t *) p_nr_slices) = htonl(vmb->nr_slices); + + // Leave the rest uninitialised + + return; +} + + +/* Deserialise the VMB after decrypting it */ +static int _deserialiseVmb(char *clear_vmb, sflc_Vmb *vmb) +{ + // Pointers inside the VMB + char *p_vol_key = clear_vmb; + char *p_prev_vmb_key = p_vol_key + SFLC_STANDARD_KEYLEN; + char *p_nr_slices = p_prev_vmb_key + SFLC_STANDARD_KEYLEN; + + /* Copy the volume key */ + memcpy(vmb->volume_key_legacy, p_vol_key, SFLC_STANDARD_KEYLEN); + + /* Copy the previous volume's VMB key */ + memcpy(vmb->prev_vmb_key, p_prev_vmb_key, SFLC_STANDARD_KEYLEN); + + /* Read number of slices (network byte order) */ + vmb->nr_slices = ntohl( *((uint32_t *) p_nr_slices) ); + + // Ignore the rest + + return 0; +} + diff --git a/shufflecake-userland/src/header/volume_master_block.c b/shufflecake-userland/src/header/volume_master_block_lite.c similarity index 90% rename from shufflecake-userland/src/header/volume_master_block.c rename to shufflecake-userland/src/header/volume_master_block_lite.c index 9347582..d61099f 100644 --- a/shufflecake-userland/src/header/volume_master_block.c +++ b/shufflecake-userland/src/header/volume_master_block_lite.c @@ -61,7 +61,7 @@ static int _deserialiseVmb(char *clear_vmb, sflc_Vmb *vmb); * * @return The error code, 0 on success */ -int sflc_vmb_seal(sflc_Vmb *vmb, char *vmb_key, char *disk_block) +int sflite_vmb_seal(sflc_Vmb *vmb, char *vmb_key, char *disk_block) { // Pointers inside the block char *iv = disk_block; @@ -123,7 +123,7 @@ bad_clear_alloc: * * @return An error code, 0 on success */ -int sflc_vmb_unseal(char *disk_block, char *vmb_key, sflc_Vmb *vmb) +int sflite_vmb_unseal(char *disk_block, char *vmb_key, sflc_Vmb *vmb) { // Pointers inside the block char *iv = disk_block; @@ -181,14 +181,14 @@ static void _serialiseVmb(sflc_Vmb *vmb, char *clear_vmb) { // Pointers inside the VMB char *p_vol_key = clear_vmb; - char *p_prev_vmb_key = p_vol_key + SFLC_CRYPTO_KEYLEN; - char *p_nr_slices = p_prev_vmb_key + SFLC_CRYPTO_KEYLEN; + char *p_prev_vmb_key = p_vol_key + SFLC_AESXTS_KEYLEN; + char *p_nr_slices = p_prev_vmb_key + SFLC_STANDARD_KEYLEN; /* Copy the volume key */ - memcpy(p_vol_key, vmb->volume_key, SFLC_CRYPTO_KEYLEN); + memcpy(p_vol_key, vmb->volume_key_lite, SFLC_AESXTS_KEYLEN); /* Copy the previous volume's VMB key */ - memcpy(p_prev_vmb_key, vmb->prev_vmb_key, SFLC_CRYPTO_KEYLEN); + memcpy(p_prev_vmb_key, vmb->prev_vmb_key, SFLC_STANDARD_KEYLEN); /* Write the number of slices (network byte order) */ *((uint32_t *) p_nr_slices) = htonl(vmb->nr_slices); @@ -204,14 +204,14 @@ static int _deserialiseVmb(char *clear_vmb, sflc_Vmb *vmb) { // Pointers inside the VMB char *p_vol_key = clear_vmb; - char *p_prev_vmb_key = p_vol_key + SFLC_CRYPTO_KEYLEN; - char *p_nr_slices = p_prev_vmb_key + SFLC_CRYPTO_KEYLEN; + char *p_prev_vmb_key = p_vol_key + SFLC_AESXTS_KEYLEN; + char *p_nr_slices = p_prev_vmb_key + SFLC_STANDARD_KEYLEN; /* Copy the volume key */ - memcpy(vmb->volume_key, p_vol_key, SFLC_CRYPTO_KEYLEN); + memcpy(vmb->volume_key_lite, p_vol_key, SFLC_AESXTS_KEYLEN); /* Copy the previous volume's VMB key */ - memcpy(vmb->prev_vmb_key, p_prev_vmb_key, SFLC_CRYPTO_KEYLEN); + memcpy(vmb->prev_vmb_key, p_prev_vmb_key, SFLC_STANDARD_KEYLEN); /* Read number of slices (network byte order) */ vmb->nr_slices = ntohl( *((uint32_t *) p_nr_slices) ); diff --git a/shufflecake-userland/src/operations/devmapper.c b/shufflecake-userland/src/operations/devmapper_legacy.c similarity index 88% rename from shufflecake-userland/src/operations/devmapper.c rename to shufflecake-userland/src/operations/devmapper_legacy.c index 99a66a2..5fe3bb3 100644 --- a/shufflecake-userland/src/operations/devmapper.c +++ b/shufflecake-userland/src/operations/devmapper_legacy.c @@ -56,7 +56,7 @@ * * @return Error code, 0 on success */ -int sflc_ops_openVolume(char *bdev_path, size_t dev_id, size_t vol_idx, sflc_Vmb *vmb) +int sflegc_ops_openVolume(char *bdev_path, size_t dev_id, size_t vol_idx, sflc_Vmb *vmb) { char label[SFLC_BIGBUFSIZE]; char *hex_key; @@ -68,7 +68,7 @@ int sflc_ops_openVolume(char *bdev_path, size_t dev_id, size_t vol_idx, sflc_Vmb sprintf(label, "sflc_%lu_%lu", dev_id, vol_idx); /* Get the hex version of the volume's data section key */ - hex_key = sflc_toHex(vmb->volume_key, SFLC_CRYPTO_KEYLEN); + hex_key = sflc_toHex(vmb->volume_key_legacy, SFLC_STANDARD_KEYLEN); if (!hex_key) { sflc_log_error("Could not encode volume key to hexadecimal"); err = ENOMEM; @@ -76,10 +76,10 @@ int sflc_ops_openVolume(char *bdev_path, size_t dev_id, size_t vol_idx, sflc_Vmb } /* Get the number of logical 512-byte sectors composing the volume */ - num_sectors = ((uint64_t) vmb->nr_slices) * SFLC_BLOCKS_PER_LOG_SLICE * SFLC_SECTOR_SCALE; + num_sectors = ((uint64_t) vmb->nr_slices) * SFLC_SLICE_SCALE * SFLC_BLOCK_SCALE; /* Build param list */ - sprintf(params, "%s %lu %lu %s", bdev_path, vol_idx, vmb->nr_slices, hex_key); + sprintf(params, "%d %lu %s %lu %lu %s", SFLC_MODE_LEGACY, dev_id, bdev_path, vol_idx, vmb->nr_slices, hex_key); /* Issue ioctl */ err = sflc_dm_create(label, num_sectors, params); @@ -104,7 +104,7 @@ err_hexkey: * * @return Error code, 0 on success */ -int sflc_ops_closeVolume(char *label) +int sflegc_ops_closeVolume(char *label) { /* Issue ioctl */ return sflc_dm_destroy(label); diff --git a/shufflecake-userland/src/operations/devmapper_lite.c b/shufflecake-userland/src/operations/devmapper_lite.c new file mode 100644 index 0000000..5dc610b --- /dev/null +++ b/shufflecake-userland/src/operations/devmapper_lite.c @@ -0,0 +1,112 @@ +/* + * Copyright The Shufflecake Project Authors (2022) + * Copyright The Shufflecake Project Contributors (2022) + * Copyright Contributors to the The Shufflecake Project. + * + * See the AUTHORS file at the top-level directory of this distribution and at + * + * + * This file is part of the program shufflecake-c, which is part of the + * Shufflecake Project. Shufflecake is a plausible deniability (hidden storage) + * layer for Linux. See . + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 2 of the License, or (at your option) + * any later version. This program is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. You should have received a copy of the + * GNU General Public License along with this program. + * If not, see . + */ + +/***************************************************** + * INCLUDE SECTION * + *****************************************************/ + +#include +#include +#include +#include +#include + +#include "header.h" +#include "operations.h" +#include "utils/sflc.h" +#include "utils/crypto.h" +#include "utils/file.h" +#include "utils/string.h" +#include "utils/dm.h" +#include "utils/log.h" + + +/***************************************************** + * PUBLIC FUNCTIONS DEFINITIONS * + *****************************************************/ + +/** + * Build parameter list for ctor in dm_sflc, and send DM ioctl to create + * virtual block device. + * + * @param bdev_path The path to the underlying device + * @param dev_id The ID of the underlying block device + * @param vol_idx The index of the volume within the device + * @param vmb Volume metadata + * + * @return Error code, 0 on success + */ +int sflite_ops_openVolume(char *bdev_path, size_t dev_id, size_t vol_idx, sflc_Vmb *vmb) +{ + char label[SFLC_BIGBUFSIZE]; + char *hex_key; + char params[SFLC_BIGBUFSIZE]; + uint64_t num_sectors; + int err; + + /* Build volume label */ + sprintf(label, "sflc_%lu_%lu", dev_id, vol_idx); + + /* Get the hex version of the volume's data section key */ + hex_key = sflc_toHex(vmb->volume_key_lite, SFLC_AESXTS_KEYLEN); + if (!hex_key) { + sflc_log_error("Could not encode volume key to hexadecimal"); + err = ENOMEM; + goto err_hexkey; + } + + /* Get the number of logical 512-byte sectors composing the volume */ + num_sectors = ((uint64_t) vmb->nr_slices) * SFLC_SLICE_SCALE * SFLC_BLOCK_SCALE; + + /* Build param list */ + sprintf(params, "%d %lu %s %lu %lu %s", SFLC_MODE_LITE, dev_id, bdev_path, vol_idx, vmb->nr_slices, hex_key); + + /* Issue ioctl */ + err = sflc_dm_create(label, num_sectors, params); + if (err) { + sflc_log_error("Could not issue ioctl CREATE command to device mapper; error %d", err); + goto err_dmcreate; + } + err = 0; + + +err_dmcreate: + memset(hex_key, 0, strlen(hex_key)); + free(hex_key); +err_hexkey: + return err; +} + + +/** + * Close the volume by issuing the appropriate ioctl to the DM. + * + * @param label The only needed parameter: the ID of the volume. + * + * @return Error code, 0 on success + */ +int sflite_ops_closeVolume(char *label) +{ + /* Issue ioctl */ + return sflc_dm_destroy(label); +} diff --git a/shufflecake-userland/src/operations/dmb.c b/shufflecake-userland/src/operations/dmb.c index d529966..662742e 100644 --- a/shufflecake-userland/src/operations/dmb.c +++ b/shufflecake-userland/src/operations/dmb.c @@ -57,7 +57,7 @@ int sflc_ops_writeDmb(char *bdev_path, char **pwds, size_t *pwd_lens, sflc_Dmb *dmb) { /* On-disk DMB */ - char enc_dmb[SFLC_SECTOR_SIZE]; + char enc_dmb[SFLC_BLOCK_SIZE]; /* Error code */ int err; @@ -75,7 +75,7 @@ int sflc_ops_writeDmb(char *bdev_path, char **pwds, size_t *pwd_lens, sflc_Dmb * } /* Write it to disk (at sector 0) */ - err = sflc_disk_writeSector(bdev_path, 0, enc_dmb); + err = sflc_disk_writeBlock(bdev_path, 0, enc_dmb); if (err) { sflc_log_error("Could not write DMB to disk; error %d", err); return err; @@ -99,11 +99,11 @@ int sflc_ops_writeDmb(char *bdev_path, char **pwds, size_t *pwd_lens, sflc_Dmb * */ int sflc_ops_readDmb(char *bdev_path, char *pwd, size_t pwd_len, sflc_DmbCell *dmb) { - char enc_dmb[SFLC_SECTOR_SIZE]; + char enc_dmb[SFLC_BLOCK_SIZE]; int err; /* Read DMB from disk (at sector 0) */ - err = sflc_disk_readSector(bdev_path, 0, enc_dmb); + err = sflc_disk_readBlock(bdev_path, 0, enc_dmb); if (err) { sflc_log_error("Could not read DMB from disk; error %d", err); return err; @@ -131,7 +131,7 @@ int sflc_ops_readDmb(char *bdev_path, char *pwd, size_t pwd_len, sflc_DmbCell *d */ int sflc_ops_rewriteDmbCell(char *bdev_path, sflc_DmbCell *dmb_cell, char *new_pwd, size_t new_pwd_len) { - char enc_dmb[SFLC_SECTOR_SIZE]; + char enc_dmb[SFLC_BLOCK_SIZE]; int err; /* Sanity check */ @@ -141,7 +141,7 @@ int sflc_ops_rewriteDmbCell(char *bdev_path, sflc_DmbCell *dmb_cell, char *new_p } /* Read DMB from disk (at sector 0) */ - err = sflc_disk_readSector(bdev_path, 0, enc_dmb); + err = sflc_disk_readBlock(bdev_path, 0, enc_dmb); if (err) { sflc_log_error("Could not read DMB from disk; error %d", err); return err; @@ -155,7 +155,7 @@ int sflc_ops_rewriteDmbCell(char *bdev_path, sflc_DmbCell *dmb_cell, char *new_p } /* Write it to disk (at sector 0) */ - err = sflc_disk_writeSector(bdev_path, 0, enc_dmb); + err = sflc_disk_writeBlock(bdev_path, 0, enc_dmb); if (err) { sflc_log_error("Could not write DMB to disk; error %d", err); return err; diff --git a/shufflecake-userland/src/operations/volume_header.c b/shufflecake-userland/src/operations/volume_header_legacy.c similarity index 83% rename from shufflecake-userland/src/operations/volume_header.c rename to shufflecake-userland/src/operations/volume_header_legacy.c index 1088290..41bc54a 100644 --- a/shufflecake-userland/src/operations/volume_header.c +++ b/shufflecake-userland/src/operations/volume_header_legacy.c @@ -53,23 +53,23 @@ * * @return Error code, 0 on success */ -int sflc_ops_writeVolumeHeader(char *bdev_path, char *vmb_key, sflc_Vmb *vmb, size_t vol_idx) +int sflegc_ops_writeVolumeHeader(char *bdev_path, char *vmb_key, sflc_Vmb *vmb, size_t vol_idx) { - char enc_vmb[SFLC_SECTOR_SIZE]; - sflc_EncPosMap epm; + char enc_vmb[SFLC_BLOCK_SIZE]; + sflegc_EncPosMap epm; uint64_t sector; int err; // Encrypt VMB - err = sflc_vmb_seal(vmb, vmb_key, enc_vmb); + err = sflegc_vmb_seal(vmb, vmb_key, enc_vmb); if (err) { sflc_log_error("Could not seal VMB; error %d", err); goto out; } // Write it to disk - sector = sflc_vmbPosition(vol_idx, vmb->nr_slices); - err = sflc_disk_writeSector(bdev_path, sector, enc_vmb); + sector = sflegc_vmbPosition(vol_idx, vmb->nr_slices); + err = sflc_disk_writeBlock(bdev_path, sector, enc_vmb); if (err) { sflc_log_error("Could not write VMB to disk; error %d", err); goto out; @@ -77,7 +77,7 @@ int sflc_ops_writeVolumeHeader(char *bdev_path, char *vmb_key, sflc_Vmb *vmb, si sector += 1; // Create encrypted empty position map - err = sflc_epm_create(vmb->nr_slices, vmb->volume_key, &epm); + err = sflegc_epm_create(vmb->nr_slices, vmb->volume_key_legacy, &epm); if (err) { sflc_log_error("Could not create encrypted empty position map; error %d", err); goto out; @@ -88,10 +88,10 @@ int sflc_ops_writeVolumeHeader(char *bdev_path, char *vmb_key, sflc_Vmb *vmb, si for (i = 0; i < epm.nr_arrays; i++) { char *iv_block = epm.iv_blocks[i]; char *pmb_array = epm.pmb_arrays[i]; - size_t nr_pmbs = ((i == epm.nr_arrays-1) ? epm.nr_last_pmbs : SFLC_BLOCKS_PER_LOG_SLICE); + size_t nr_pmbs = ((i == epm.nr_arrays-1) ? epm.nr_last_pmbs : SFLC_SLICE_SCALE); // First write the IV block - err = sflc_disk_writeSector(bdev_path, sector, iv_block); + err = sflc_disk_writeBlock(bdev_path, sector, iv_block); if (err) { sflc_log_error("Could not write IV block to disk; error %d", err); goto out; @@ -99,7 +99,7 @@ int sflc_ops_writeVolumeHeader(char *bdev_path, char *vmb_key, sflc_Vmb *vmb, si sector += 1; // Then the whole PMB array - err = sflc_disk_writeManySectors(bdev_path, sector, pmb_array, nr_pmbs); + err = sflc_disk_writeManyBlocks(bdev_path, sector, pmb_array, nr_pmbs); if (err) { sflc_log_error("Could not write PMB array to disk; error %d", err); goto out; @@ -133,22 +133,22 @@ out: * * @return Error code, 0 on success */ -int sflc_ops_readVmb(char *bdev_path, char *vmb_key, size_t nr_slices, size_t vol_idx, sflc_Vmb *vmb) +int sflegc_ops_readVmb(char *bdev_path, char *vmb_key, size_t nr_slices, size_t vol_idx, sflc_Vmb *vmb) { - char enc_vmb[SFLC_SECTOR_SIZE]; + char enc_vmb[SFLC_BLOCK_SIZE]; uint64_t sector; int err; /* Read encrypted VMB from disk */ - sector = sflc_vmbPosition(vol_idx, nr_slices); - err = sflc_disk_readSector(bdev_path, sector, enc_vmb); + sector = sflegc_vmbPosition(vol_idx, nr_slices); + err = sflc_disk_readBlock(bdev_path, sector, enc_vmb); if (err) { sflc_log_error("Could not read VMB from disk; error %d", err); return err; } /* Unseal it */ - err = sflc_vmb_unseal(enc_vmb, vmb_key, vmb); + err = sflegc_vmb_unseal(enc_vmb, vmb_key, vmb); if (err) { sflc_log_error("Could not unseal VMB; error %d", err); return err; diff --git a/shufflecake-userland/src/operations/volume_header_lite.c b/shufflecake-userland/src/operations/volume_header_lite.c new file mode 100644 index 0000000..ce649ab --- /dev/null +++ b/shufflecake-userland/src/operations/volume_header_lite.c @@ -0,0 +1,142 @@ +/* + * Copyright The Shufflecake Project Authors (2022) + * Copyright The Shufflecake Project Contributors (2022) + * Copyright Contributors to the The Shufflecake Project. + * + * See the AUTHORS file at the top-level directory of this distribution and at + * + * + * This file is part of the program shufflecake-c, which is part of the + * Shufflecake Project. Shufflecake is a plausible deniability (hidden storage) + * layer for Linux. See . + * + * This program is free software: you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation, either version 2 of the License, or (at your option) + * any later version. This program is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General + * Public License for more details. You should have received a copy of the + * GNU General Public License along with this program. + * If not, see . + */ + +/***************************************************** + * INCLUDE SECTION * + *****************************************************/ + +#include +#include +#include +#include + +#include "header.h" +#include "header.h" +#include "operations.h" +#include "utils/sflc.h" +#include "utils/disk.h" +#include "utils/crypto.h" +#include "utils/log.h" + + +/***************************************************** + * PUBLIC FUNCTIONS DEFINITIONS * + *****************************************************/ + +/** + * Writes a volume header (VMB+PM) on-disk. + * + * @param bdev_path The underlying block device to write the volume header + * @param vmb_key The key to encrypt the VMB + * @param vmb The VMB to encrypt + * @param vol_idx The index of the volume within the device + * + * @return Error code, 0 on success + */ +int sflite_ops_writeVolumeHeader(char *bdev_path, char *vmb_key, sflc_Vmb *vmb, size_t vol_idx) +{ + char enc_vmb[SFLC_BLOCK_SIZE]; + void *epm; + uint64_t sector; + int err; + + // Encrypt VMB + err = sflite_vmb_seal(vmb, vmb_key, enc_vmb); + if (err) { + sflc_log_error("Could not seal VMB; error %d", err); + goto out; + } + + // Write it to disk + sector = 1 + vol_idx; + err = sflc_disk_writeBlock(bdev_path, sector, enc_vmb); + if (err) { + sflc_log_error("Could not write VMB to disk; error %d", err); + goto out; + } + + // Create encrypted empty position map + epm = sflite_epm_create(vmb->nr_slices, vol_idx, vmb->volume_key_lite); + if (!epm) { + sflc_log_error("Could not create encrypted empty position map."); + err = ENOMEM; + goto out; + } + + // Write to disk + sector = sflite_pmStartBlock(vol_idx, vmb->nr_slices); + err = sflc_disk_writeManyBlocks(bdev_path, sector, epm, + ceil(vmb->nr_slices, SFLC_SLICE_IDX_PER_BLOCK)); + if (err) { + sflc_log_error("Could not write encrypted PosMap; error %d", err); + } + free(epm); + + +out: + return err; +} + + +/** + * Reads a VMB from disk and unlocks it + * + * @param bdev_path The underlying block device + * @param vmb_key The key to decrypt the VMB + * @param nr_slices The number of slices in the device + * @param vol_idx The index of the volume within the device + * + * @output vmb The decrypted VMB + * + * @return Error code, 0 on success + */ +int sflite_ops_readVmb(char *bdev_path, char *vmb_key, size_t nr_slices, size_t vol_idx, sflc_Vmb *vmb) +{ + char enc_vmb[SFLC_BLOCK_SIZE]; + uint64_t sector; + int err; + + /* Read encrypted VMB from disk */ + sector = 1 + vol_idx; + err = sflc_disk_readBlock(bdev_path, sector, enc_vmb); + if (err) { + sflc_log_error("Could not read VMB from disk; error %d", err); + return err; + } + + /* Unseal it */ + err = sflite_vmb_unseal(enc_vmb, vmb_key, vmb); + if (err) { + sflc_log_error("Could not unseal VMB; error %d", err); + return err; + } + + /* Compare the number of slices */ + if (nr_slices != vmb->nr_slices) { + sflc_log_error("Incompatible header size: the device size was different when the volumes" + "were created. Did you resize the device %s since last time?", bdev_path); + return EINVAL; + } + + return 0; +} diff --git a/shufflecake-userland/src/utils/crypto.c b/shufflecake-userland/src/utils/crypto.c index b42f50f..4494dd1 100644 --- a/shufflecake-userland/src/utils/crypto.c +++ b/shufflecake-userland/src/utils/crypto.c @@ -95,7 +95,7 @@ int sflc_aes256ctr_encrypt(char *key, char *pt, size_t pt_len, char *iv, char *c sflc_log_debug("Successfully instantiated AES256-CTR cipher handle"); // Set the key - err = gcry_cipher_setkey(hd, key, SFLC_CRYPTO_KEYLEN); + err = gcry_cipher_setkey(hd, key, SFLC_STANDARD_KEYLEN); if (err) { sflc_log_error("Could not set AES key: error %d", err); goto bad_setkey; @@ -163,7 +163,7 @@ int sflc_aes256ctr_decrypt(char *key, char *ct, size_t ct_len, char *iv, char *p sflc_log_debug("Successfully instantiated AES256-CTR cipher handle"); // Set the key - err = gcry_cipher_setkey(hd, key, SFLC_CRYPTO_KEYLEN); + err = gcry_cipher_setkey(hd, key, SFLC_STANDARD_KEYLEN); if (err) { sflc_log_error("Could not set AES key: error %d", err); goto bad_setkey; @@ -205,6 +205,76 @@ bad_open: } +/** + * AES256-XTS encryption. Set ct = NULL for in-place. + * The IV is intepreted as a little-endian "sector number". + * + * @param key The 64-byte AES-XTS key + * @param pt The plaintext + * @param pt_len The length of the plaintext, must be a multiple of the AES + * block size (16 bytes) + * @param iv The 16-byte AES-XTS IV + * @param ct A caller-allocated buffer that will contain the output ciphertext, + * cannot overlap with pt. If NULL, in-place encryption. + * + * @return The error code (0 on success) + */ +int sflc_aes256xts_encrypt(char *key, char *pt, size_t pt_len, char *iv, char *ct) +{ + gcry_cipher_hd_t hd; + gcry_error_t err; + + // Instantiate the handle + err = gcry_cipher_open(&hd, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_XTS, GCRY_CIPHER_SECURE); + if (err) { + sflc_log_error("Could not instantiate AES256-XTS cipher handle: error %d", err); + goto bad_open; + } + sflc_log_debug("Successfully instantiated AES256-XTS cipher handle"); + + // Set the key + err = gcry_cipher_setkey(hd, key, SFLC_AESXTS_KEYLEN); + if (err) { + sflc_log_error("Could not set AES-XTS key: error %d", err); + goto bad_setkey; + } + sflc_log_debug("Successfully set the AES-XTS key"); + + // Set the IV (not a counter, as per Gcrypt docs) + err = gcry_cipher_setiv(hd, iv, SFLC_AESXTS_IVLEN); + if (err) { + sflc_log_error("Could not set AES-XTS IV: error %d", err); + goto bad_setiv; + } + sflc_log_debug("Successfully set the IV"); + + // Encrypt + if (ct == NULL) { // In-place + err = gcry_cipher_encrypt(hd, pt, pt_len, NULL, 0); + } + else { // Out-of-place + err = gcry_cipher_encrypt(hd, ct, pt_len, pt, pt_len); + } + // Error check + if (err) { + sflc_log_error("Could not encrypt: error %d", err); + goto bad_encrypt; + } + sflc_log_debug("Successfully encrypted"); + + // No prob? + err = 0; + + +bad_encrypt: +bad_setiv: +bad_setkey: + gcry_cipher_close(hd); +bad_open: + return err; +} + + /** *AES-GCM encryption, does not touch the IV. * @@ -233,7 +303,7 @@ int sflc_aes256gcm_encrypt(char *key, char *pt, size_t pt_len, char *iv, char *c sflc_log_debug("Successfully instantiated AES256-GCM cipher handle"); // Set the key - err = gcry_cipher_setkey(hd, key, SFLC_CRYPTO_KEYLEN); + err = gcry_cipher_setkey(hd, key, SFLC_STANDARD_KEYLEN); if (err) { sflc_log_error("Could not set AES key: error %d", err); goto bad_setkey; @@ -308,7 +378,7 @@ int sflc_aes256gcm_decrypt(char *key, char *ct, size_t ct_len, char *tag, char * sflc_log_debug("Successfully instantiated AES256-GCM cipher handle"); // Set the key - err = gcry_cipher_setkey(hd, key, SFLC_CRYPTO_KEYLEN); + err = gcry_cipher_setkey(hd, key, SFLC_STANDARD_KEYLEN); if (err) { sflc_log_error("Could not set AES key: error %d", err); goto bad_setkey; @@ -378,7 +448,7 @@ int sflc_argon2id_derive(char *pwd, size_t pwd_len, char *salt, char *hash) { gcry_kdf_hd_t hd; const unsigned long argon_params[4] = - {SFLC_CRYPTO_KEYLEN, SFLC_ARGON_T, SFLC_ARGON_M, SFLC_ARGON_P}; + {SFLC_STANDARD_KEYLEN, SFLC_ARGON_T, SFLC_ARGON_M, SFLC_ARGON_P}; gcry_error_t err; // Instantiate Argon2id handle @@ -405,7 +475,7 @@ int sflc_argon2id_derive(char *pwd, size_t pwd_len, char *salt, char *hash) sflc_log_debug("Successfully run Argon2id computation"); // Finalise hash - err = gcry_kdf_final(hd, SFLC_CRYPTO_KEYLEN, hash); + err = gcry_kdf_final(hd, SFLC_STANDARD_KEYLEN, hash); if (err) { sflc_log_error("Could not finalise Argon2id hash: error %d", err); goto bad_final; diff --git a/shufflecake-userland/src/utils/disk.c b/shufflecake-userland/src/utils/disk.c index 2f78598..7da8c86 100644 --- a/shufflecake-userland/src/utils/disk.c +++ b/shufflecake-userland/src/utils/disk.c @@ -30,11 +30,13 @@ *****************************************************/ #include +#include #include #include #include #include #include +#include #include #include @@ -47,6 +49,30 @@ *****************************************************/ +/** + * Returns a malloc'ed string formatted as : + * + * @param bdev_path The path to the block device + * + * @return A string version of the device ID + */ +char *sflc_disk_getDeviceName(char *bdev_path) +{ + struct stat sb; + char *dev_name; + + if (stat(bdev_path, &sb) != 0) + return NULL; + dev_name = malloc(SFLC_BIGBUFSIZE); + if (!dev_name) + return NULL; + + sprintf(dev_name, "%u:%u", major(sb.st_rdev), minor(sb.st_rdev)); + + return dev_name; +} + + /** * Checks whether the given path points to a block device. * @@ -96,7 +122,7 @@ int64_t sflc_disk_getSize(char * bdev_path) sflc_log_debug("Size of %s is %lu bytes", bdev_path, size_bytes); /* Compute size in SFLC sectors */ - ret = (size_bytes / SFLC_SECTOR_SIZE); + ret = (size_bytes / SFLC_BLOCK_SIZE); bad_ioctl: close(fd); @@ -114,7 +140,7 @@ bad_open: * * @return The error code (0 on success) */ -int sflc_disk_readSector(char * bdev_path, uint64_t sector, char * buf) +int sflc_disk_readBlock(char * bdev_path, uint64_t sector, char * buf) { int fd; int err; @@ -130,7 +156,7 @@ int sflc_disk_readSector(char * bdev_path, uint64_t sector, char * buf) sflc_log_debug("Opened file %s", bdev_path); /* Set offset in bytes */ - if (lseek(fd, sector * SFLC_SECTOR_SIZE, SEEK_SET) < 0) { + if (lseek(fd, sector * SFLC_BLOCK_SIZE, SEEK_SET) < 0) { sflc_log_error("Could not lseek file %s to sector %lu", bdev_path, sector); perror("Cause: "); err = errno; @@ -139,7 +165,7 @@ int sflc_disk_readSector(char * bdev_path, uint64_t sector, char * buf) sflc_log_debug("Successful lseek on file %s to sector %lu", bdev_path, sector); /* Read in a loop */ - size_t bytes_to_read = SFLC_SECTOR_SIZE; + size_t bytes_to_read = SFLC_BLOCK_SIZE; while (bytes_to_read > 0) { /* Read syscall */ ssize_t bytes_read = read(fd, buf, bytes_to_read); @@ -172,22 +198,6 @@ bad_open: } -/** - * Writes a single 4096-byte sector to the disk. - * - * @param bdev_path The path of the block device - * @param sector The index of the desired sector - * @param The caller-allocated buffer (must hold 4096 bytes) where the data - * comes from - * - * @return The error code (0 on success) - */ -int sflc_disk_writeSector(char * bdev_path, uint64_t sector, char * buf) -{ - return sflc_disk_writeManySectors(bdev_path, sector, buf, 1); -} - - /** * Writes many 4096-byte sectors to the disk. * @@ -199,7 +209,7 @@ int sflc_disk_writeSector(char * bdev_path, uint64_t sector, char * buf) * * @return The error code (0 on success) */ -int sflc_disk_writeManySectors(char * bdev_path, uint64_t sector, char * buf, size_t num_sectors) +int sflc_disk_writeManyBlocks(char * bdev_path, uint64_t sector, char * buf, size_t num_sectors) { int fd; int err; @@ -215,7 +225,7 @@ int sflc_disk_writeManySectors(char * bdev_path, uint64_t sector, char * buf, si sflc_log_debug("Opened file %s", bdev_path); /* Set offset in bytes */ - if (lseek(fd, sector * SFLC_SECTOR_SIZE, SEEK_SET) < 0) { + if (lseek(fd, sector * SFLC_BLOCK_SIZE, SEEK_SET) < 0) { sflc_log_error("Could not lseek file %s to sector %lu", bdev_path, sector); perror("Cause: "); err = errno; @@ -224,7 +234,7 @@ int sflc_disk_writeManySectors(char * bdev_path, uint64_t sector, char * buf, si sflc_log_debug("Successful lseek on file %s to sector %lu", bdev_path, sector); /* Write in a loop */ - size_t bytes_to_write = SFLC_SECTOR_SIZE * num_sectors; + size_t bytes_to_write = SFLC_BLOCK_SIZE * num_sectors; while (bytes_to_write > 0) { /* Write syscall */ ssize_t bytes_written = write(fd, buf, bytes_to_write); diff --git a/shufflecake-userland/src/utils/dm.c b/shufflecake-userland/src/utils/dm.c index 6c2d054..275d61e 100644 --- a/shufflecake-userland/src/utils/dm.c +++ b/shufflecake-userland/src/utils/dm.c @@ -35,6 +35,7 @@ #include #include "utils/dm.h" +#include "utils/sflc.h" #include "utils/log.h" diff --git a/shufflecake-userland/test/crypto/test_aes256ctr.c b/shufflecake-userland/test/crypto/test_aes256ctr.c index 700a910..ce2676b 100644 --- a/shufflecake-userland/test/crypto/test_aes256ctr.c +++ b/shufflecake-userland/test/crypto/test_aes256ctr.c @@ -56,10 +56,10 @@ char *test_aes256ctr_encrypt_inplace() char iv[] = AES256CTR_TEST_IV; int err; - sflc_log_blue("Testing AES256-CTR encryption in-place"); + sflite_log_blue("Testing AES256-CTR encryption in-place"); // Encrypt in-place - err = sflc_aes256ctr_encrypt(key, msg, msg_len, iv, NULL); + err = sflite_aes256ctr_encrypt(key, msg, msg_len, iv, NULL); // Check error mu_assert("Error while encrypting", !err); @@ -73,7 +73,7 @@ char *test_aes256ctr_encrypt_inplace() // Check IV untouched mu_assert("IV changed", memcmp(iv, IV, sizeof(iv)) == 0); - sflc_log_green("OK"); + sflite_log_green("OK"); return NULL; } @@ -87,10 +87,10 @@ char *test_aes256ctr_encrypt_outofplace() char iv[] = AES256CTR_TEST_IV; int err; - sflc_log_blue("Testing AES256-CTR encryption out-of-place"); + sflite_log_blue("Testing AES256-CTR encryption out-of-place"); // Encrypt out-of-place - err = sflc_aes256ctr_encrypt(key, msg, msg_len, iv, ct); + err = sflite_aes256ctr_encrypt(key, msg, msg_len, iv, ct); // Check error mu_assert("Error while encrypting", !err); @@ -107,7 +107,7 @@ char *test_aes256ctr_encrypt_outofplace() // Check IV untouched mu_assert("IV changed", memcmp(iv, IV, sizeof(iv)) == 0); - sflc_log_green("OK"); + sflite_log_green("OK"); return NULL; } @@ -120,10 +120,10 @@ char *test_aes256ctr_decrypt_inplace() char iv[] = AES256CTR_TEST_IV; int err; - sflc_log_blue("Testing AES256-CTR decryption in-place"); + sflite_log_blue("Testing AES256-CTR decryption in-place"); // Decrypt in-place - err = sflc_aes256ctr_decrypt(key, msg, msg_len, iv, NULL); + err = sflite_aes256ctr_decrypt(key, msg, msg_len, iv, NULL); // Check error mu_assert("Error while decrypting", !err); @@ -137,7 +137,7 @@ char *test_aes256ctr_decrypt_inplace() // Check IV untouched mu_assert("IV changed", memcmp(iv, IV, sizeof(iv)) == 0); - sflc_log_green("OK"); + sflite_log_green("OK"); return NULL; } @@ -151,10 +151,10 @@ char *test_aes256ctr_decrypt_outofplace() char iv[] = AES256CTR_TEST_IV; int err; - sflc_log_blue("Testing AES256-CTR decryption out-of-place"); + sflite_log_blue("Testing AES256-CTR decryption out-of-place"); // Decrypt out-of-place - err = sflc_aes256ctr_decrypt(key, msg, msg_len, iv, pt); + err = sflite_aes256ctr_decrypt(key, msg, msg_len, iv, pt); // Check error mu_assert("Error while decrypting", !err); @@ -171,7 +171,7 @@ char *test_aes256ctr_decrypt_outofplace() // Check IV untouched mu_assert("IV changed", memcmp(iv, IV, sizeof(iv)) == 0); - sflc_log_green("OK"); + sflite_log_green("OK"); return NULL; } diff --git a/shufflecake-userland/test/crypto/test_aes256gcm.c b/shufflecake-userland/test/crypto/test_aes256gcm.c index b332c51..da5458a 100644 --- a/shufflecake-userland/test/crypto/test_aes256gcm.c +++ b/shufflecake-userland/test/crypto/test_aes256gcm.c @@ -56,20 +56,20 @@ char *test_aes256gcm_encrypt() char key[] = AES256GCM_TEST_KEY; char iv[] = AES256GCM_TEST_IV; char ct[sizeof(pt)]; - char tag[SFLC_AESGCM_TAGLEN]; + char tag[SFLITE_AESGCM_TAGLEN]; int err; - sflc_log_blue("Testing AES256-GCM encryption"); + sflite_log_blue("Testing AES256-GCM encryption"); // Encrypt - err = sflc_aes256gcm_encrypt(key, pt, pt_len, iv, ct, tag); + err = sflite_aes256gcm_encrypt(key, pt, pt_len, iv, ct, tag); // Check error mu_assert("Error while encrypting", !err); // Check outcome mu_assert("Ciphertext mismatch", memcmp(ct, CT, pt_len) == 0); - mu_assert("MAC mismatch", memcmp(tag, TAG, SFLC_AESGCM_TAGLEN) == 0); + mu_assert("MAC mismatch", memcmp(tag, TAG, SFLITE_AESGCM_TAGLEN) == 0); // Check key untouched mu_assert("Key changed", memcmp(key, KEY, sizeof(key)) == 0); @@ -77,7 +77,7 @@ char *test_aes256gcm_encrypt() // Check IV untouched mu_assert("IV changed", memcmp(iv, IV, sizeof(iv)) == 0); - sflc_log_green("OK"); + sflite_log_green("OK"); return NULL; } @@ -93,10 +93,10 @@ char *test_aes256gcm_decrypt_good() char pt[sizeof(ct)]; int err; - sflc_log_blue("Testing AES256-GCM decryption with the proper MAC"); + sflite_log_blue("Testing AES256-GCM decryption with the proper MAC"); // Decrypt - err = sflc_aes256gcm_decrypt(key, ct, ct_len, tag, iv, pt, &match); + err = sflite_aes256gcm_decrypt(key, ct, ct_len, tag, iv, pt, &match); // Check error mu_assert("Error while decrypting", !err); @@ -114,7 +114,7 @@ char *test_aes256gcm_decrypt_good() // Check MAC untouched mu_assert("MAC changed", memcmp(tag, TAG, sizeof(tag)) == 0); - sflc_log_green("OK"); + sflite_log_green("OK"); return NULL; } @@ -130,13 +130,13 @@ char *test_aes256gcm_decrypt_fail() char pt[sizeof(ct)]; int err; - sflc_log_blue("Testing AES256-GCM decryption without the proper MAC"); + sflite_log_blue("Testing AES256-GCM decryption without the proper MAC"); // Corrupt the MAC tag[0] += 1; // Decrypt - err = sflc_aes256gcm_decrypt(key, ct, ct_len, tag, iv, pt, &match); + err = sflite_aes256gcm_decrypt(key, ct, ct_len, tag, iv, pt, &match); // Check error mu_assert("Error while decrypting", !err); @@ -154,7 +154,7 @@ char *test_aes256gcm_decrypt_fail() mu_assert("Tail of MAC changed", memcmp(tag+1, TAG+1, sizeof(tag)-1) == 0); mu_assert("Head of MAC changed", tag[0] == TAG[0]+1); - sflc_log_green("OK"); + sflite_log_green("OK"); return NULL; } diff --git a/shufflecake-userland/test/crypto/test_argon2id.c b/shufflecake-userland/test/crypto/test_argon2id.c index 0ded58b..b50bf3e 100644 --- a/shufflecake-userland/test/crypto/test_argon2id.c +++ b/shufflecake-userland/test/crypto/test_argon2id.c @@ -39,7 +39,7 @@ * CONSTANT VARIABLES * *****************************************************/ -char SALT[SFLC_ARGON_SALTLEN+1] = "Poor Petrol Pump"; +char SALT[SFLITE_ARGON_SALTLEN+1] = "Poor Petrol Pump"; /***************************************************** @@ -48,17 +48,17 @@ char SALT[SFLC_ARGON_SALTLEN+1] = "Poor Petrol Pump"; char *test_argon2id() { - char pwd[SFLC_BIGBUFSIZE]; - char key[SFLC_CRYPTO_KEYLEN]; + char pwd[SFLITE_BIGBUFSIZE]; + char key[SFLITE_STANDARD_KEYLEN]; int err; - sflc_log_blue("Testing Argon2id interactively with a fixed salt"); + sflite_log_blue("Testing Argon2id interactively with a fixed salt"); // Loop until user breaks out while (true) { /* Collect password */ printf("Choose password to hash (empty to skip): "); - err = sflc_safeReadLine(pwd, SFLC_BIGBUFSIZE); + err = sflite_safeReadLine(pwd, SFLITE_BIGBUFSIZE); mu_assert("Could not read password", !err); /* Check if empty */ @@ -67,15 +67,15 @@ char *test_argon2id() } /* Hash it */ - err = sflc_argon2id_derive(pwd, strlen(pwd), SALT, key); + err = sflite_argon2id_derive(pwd, strlen(pwd), SALT, key); mu_assert("Could not hash password", !err); /* Print it */ printf("Salt used ASCII: \"%s\". Hex:\n", SALT); - sflc_log_hex(SALT, SFLC_ARGON_SALTLEN); + sflite_log_hex(SALT, SFLITE_ARGON_SALTLEN); printf("Argon2id hash (m = %d, t = %d, p = %d):\n", - SFLC_ARGON_M, SFLC_ARGON_T, SFLC_ARGON_P); - sflc_log_hex(key, SFLC_CRYPTO_KEYLEN); + SFLITE_ARGON_M, SFLITE_ARGON_T, SFLITE_ARGON_P); + sflite_log_hex(key, SFLITE_STANDARD_KEYLEN); printf("Go check the result online\n\n"); } diff --git a/shufflecake-userland/test/main.c b/shufflecake-userland/test/main.c index 565aa2c..1f3a506 100644 --- a/shufflecake-userland/test/main.c +++ b/shufflecake-userland/test/main.c @@ -49,10 +49,10 @@ int main() char *result = all_tests(); if (result != NULL) { - sflc_log_red("\nTEST FAILED: %s", result); + sflite_log_red("\nTEST FAILED: %s", result); } else { - sflc_log_green("\nALL TESTS PASSED"); + sflite_log_green("\nALL TESTS PASSED"); } return result != NULL; @@ -65,7 +65,7 @@ int main() static char *all_tests() { - sflc_log_yellow("Running crypto tests"); + sflite_log_yellow("Running crypto tests"); mu_run_test(test_aes256ctr_encrypt_inplace); mu_run_test(test_aes256ctr_encrypt_outofplace); mu_run_test(test_aes256ctr_decrypt_inplace);