Skip to content

Commit af176ed

Browse files
mattludwigsfhunleth
authored andcommitted
Add support for decrypting non-rootfs partitions
1 parent c71066f commit af176ed

5 files changed

Lines changed: 167 additions & 11 deletions

File tree

README.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,11 @@ uboot_env.modified | True if something has modified the U-Boot block and it diff
6767
uboot_env.start | The block offset of the U-Boot environment. (512 byte blocks)
6868
uboot_env.count | The number of blocks in the environment. Defaults to 256.
6969
run_repl | True to run a REPL before booting. This is useful for debug. Defaults to `false`
70+
dm_crypt.n.path | The extra encrypted filesystem path.Where `n` is the index of the extra filesystem.
71+
dm_crypt.n.cipher | The cipher used to encrypt the extra filesystem. Where `n` is the index of the extra filesystem.
72+
dm_crypt.n.secret | The secret key as hex digits for the extra filesystem. Where `n` is the index of the extra filesystem.
73+
74+
_for more information about configuring extra encrypted filesystems see [Mounting extra encrypted filesystems](#mounting-extra-encrypted-file-systems)_
7075

7176
Variables can be overridden using the Linux commandline. See your platform's
7277
bootloader documentation for how to pass options to Linux. At the end of the
@@ -218,3 +223,22 @@ This is illustrative, but obviously quite insecure. The current route to
218223
obtaining the secret key is to edit the C code to this project to integrate it
219224
with platform-specific way of keeping or hiding secrets. It is hoped that
220225
alternatives can be shared in the future.
226+
227+
### Mounting extra encrypted file systems
228+
229+
If you want to mount more encrypted file systems outside of the `rootfs` you
230+
can use the `dm_crypt` variable to configure the extra filesystems. The
231+
`dm_crypt` variable works using a number to under the `dm_crypt` variable
232+
namespace like so: `dm_crypt.n.path`.
233+
234+
Here's an example configuration file with configuration two more filesystems:
235+
236+
```config
237+
dm_crypt.1.path = "/dev/mmcblk0p3"
238+
dm_crypt.1.cipher = "aes-cbc-plain"
239+
dm_crypt.1.secret = "8e9c0780fd7f5d00c18a30812fe960cfce71f6074dd9cded6aab2897568cc856"
240+
241+
dm_crypt.1.path = "/dev/mmcblk0p4"
242+
dm_crypt.2.cipher = "aes-cbc-plain"
243+
dm_crypt.2.secret = "4e9c781fd7f5d00c18a30812fe970cfce56f6064dd9cded6aab2897575cc861"
244+
```

src/nerves_initramfs.c

Lines changed: 82 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,22 +20,31 @@
2020
#include "script.h"
2121
#include "block_device.h"
2222

23+
#define MAX_EXTRA_ENCRYPTED_DEVS 8
24+
2325
// Global U-Boot environment data
2426
struct uboot_env working_uboot_env;
2527

26-
static int losetup(int rootfs_fd)
28+
static int losetup(int rootfs_fd, int loop_ix)
2729
{
30+
char loop_devname[16];
31+
snprintf(loop_devname, sizeof(loop_devname), "/dev/loop%d", loop_ix);
32+
2833
// Assume loop0 is available since who else would be able to take it?
29-
int loop_fd = open("/dev/loop0", O_RDONLY);
34+
int loop_fd = open(loop_devname, O_RDONLY);
3035
if (loop_fd < 0)
31-
fatal("Enable CONFIG_BLK_DEV_LOOP in kernel");
36+
fatal("Enable CONFIG_BLK_DEV_LOOP in kernel and check that at least %d loop devices", loop_ix + 1);
3237

3338
OK_OR_FATAL(ioctl(loop_fd, LOOP_SET_FD, rootfs_fd), "LOOP_SET_FD failed");
3439

3540
return loop_fd;
3641
}
3742

38-
static int dm_create(off_t rootfs_size, const char *cipher, const char *secret)
43+
static int dm_create(int map_ix,
44+
const char *name,
45+
off_t rootfs_size,
46+
const char *cipher,
47+
const char *secret)
3948
{
4049
int dm_control = open("/dev/mapper/control", O_RDWR);
4150

@@ -53,8 +62,8 @@ static int dm_create(off_t rootfs_size, const char *cipher, const char *secret)
5362
dm->flags = 0;
5463
dm->event_nr = 0;
5564
dm->dev = 0;
56-
strcpy(dm->name, "rootfs");
57-
strcpy(dm->uuid, "CRYPT-PLAIN-rootfs");
65+
strcpy(dm->name, name);
66+
snprintf(dm->uuid, sizeof(dm->uuid), "CRYPT-PLAIN-%s", name);
5867

5968
OK_OR_FATAL(ioctl(dm_control, DM_DEV_CREATE, request_buffer), "Enable CONFIG_DM_CRYPT in kernel");
6069

@@ -68,13 +77,13 @@ static int dm_create(off_t rootfs_size, const char *cipher, const char *secret)
6877
dm->open_count = 0;
6978
dm->flags = DM_SECURE_DATA_FLAG;
7079
dm->dev = 0;
71-
strcpy(dm->name, "rootfs");
80+
strcpy(dm->name, name);
7281
struct dm_target_spec *target = (struct dm_target_spec *) &request_buffer[dm->data_start];
7382
memset(target, 0, sizeof(struct dm_target_spec));
7483
target->sector_start = 0;
7584
target->length = rootfs_size;
7685
strcpy(target->target_type, "crypt");
77-
sprintf((char *) &request_buffer[dm->data_start + sizeof(struct dm_target_spec)], "%s %s 0 /dev/loop0 0", cipher, secret);
86+
sprintf((char *) &request_buffer[dm->data_start + sizeof(struct dm_target_spec)], "%s %s %d /dev/loop%d 0", cipher, secret, map_ix, map_ix);
7887
OK_OR_FATAL(ioctl(dm_control, DM_TABLE_LOAD, request_buffer), "Check CONFIG_DM_CRYPT and crypto algs enabled");
7988

8089

@@ -86,7 +95,7 @@ static int dm_create(off_t rootfs_size, const char *cipher, const char *secret)
8695
dm->data_start = sizeof(struct dm_ioctl);
8796
dm->target_count = 0;
8897
dm->flags = DM_SECURE_DATA_FLAG;
89-
strcpy(dm->name, "rootfs");
98+
strcpy(dm->name, name);
9099
OK_OR_FATAL(ioctl(dm_control, DM_DEV_SUSPEND, request_buffer), "DM_DEV_SUSPEND failed");
91100

92101
close(dm_control);
@@ -203,17 +212,77 @@ static void mount_encrypted_fs(const char *rootfs, const char *rootfs_type, cons
203212
off_t rootfs_size = lseek(rootfs_fd, 0, SEEK_END);
204213
(void) lseek(rootfs_fd, 0, SEEK_SET);
205214

206-
int loop_fd = losetup(rootfs_fd);
215+
int loop_fd = losetup(rootfs_fd, 0);
207216
close(rootfs_fd);
208217

209-
dm_create(rootfs_size, cipher, secret);
218+
dm_create(0, "rootfs", rootfs_size, cipher, secret);
210219

211220
OK_OR_FATAL(mount("/dev/dm-0", "/mnt", rootfs_type, MS_RDONLY, NULL), "Expecting %s filesystem on %s(%s)", rootfs_type, rootfs, rootfs_path);
212221

213222
// It's ok to close loop_fd now that the mount happened.
214223
close(loop_fd);
215224
}
216225

226+
static void map_encrypted_device(int map_ix, const char *spec, const char *name, const char *cipher, const char *secret)
227+
{
228+
// Wait for the device to appear
229+
char path[BLOCK_DEVICE_PATH_LEN];
230+
int fd = open_block_device(spec, O_RDONLY, path);
231+
off_t size = lseek(fd, 0, SEEK_END);
232+
(void) lseek(fd, 0, SEEK_SET);
233+
234+
int loop_fd = losetup(fd, map_ix);
235+
close(fd);
236+
237+
char dm_name[16];
238+
snprintf(dm_name, sizeof(dm_name), "/dev/dm-%d", map_ix);
239+
240+
char link_name[32];
241+
snprintf(link_name, sizeof(link_name), "/dev/mapper/%s", name);
242+
243+
dm_create(map_ix, name, size, cipher, secret);
244+
245+
OK_OR_WARN(symlink(link_name, dm_name), "Could not symlink %s -> %s", link_name, dm_name);
246+
247+
// Hmmmmm.... It's ok to close loop_fd now that the mount happened.
248+
close(loop_fd);
249+
}
250+
251+
static void map_extra_encrypted_devs()
252+
{
253+
for (int ix = 1; ix <= MAX_EXTRA_ENCRYPTED_DEVS; ix++) {
254+
char base[12];
255+
snprintf(base, sizeof(base), "dm_crypt.%d", ix);
256+
257+
char path_var[20];
258+
char name_var[20];
259+
char cipher_var[20];
260+
char secret_var[20];
261+
262+
snprintf(path_var, sizeof(path_var), "%s.path", base);
263+
snprintf(name_var, sizeof(name_var), "%s.name", base);
264+
snprintf(cipher_var, sizeof(cipher_var), "%s.cipher", base);
265+
snprintf(secret_var, sizeof(secret_var), "%s.secret", base);
266+
267+
const char *path = get_variable_as_string(path_var);
268+
const char *name = get_variable_as_string(name_var);
269+
const char *cipher = get_variable_as_string(cipher_var);
270+
const char *secret = get_variable_as_string(secret_var);
271+
272+
if (*path != '\0') {
273+
if (*name == '\0' ||
274+
*cipher == '\0' ||
275+
*secret == '\0') {
276+
info("Not mapping %s. Make sure that %s.name, %s.cipher, and %s.secret are set",
277+
path, base, base, base);
278+
continue;
279+
}
280+
info("mapping other encrypted block device %s", path);
281+
map_encrypted_device(ix, path, name, cipher, secret);
282+
}
283+
}
284+
}
285+
217286
static void repl()
218287
{
219288
// Reset the terminal colors
@@ -312,6 +381,8 @@ int main(int argc, char *argv[])
312381
else
313382
mount_fs(rootfs_path, rootfs_fstype);
314383

384+
map_extra_encrypted_devs();
385+
315386
switch_root();
316387

317388
// Launch the real init. It's always /sbin/init with Buildroot.

tests/019_extra_encrypted_devices

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
#!/bin/sh
2+
3+
#
4+
# Test adding 1 or more encrypted devices
5+
#
6+
7+
cat >$CONFIG <<EOF
8+
dm_crypt.1.path = "/dev/mmcblk0p3"
9+
dm_crypt.1.name = "app"
10+
dm_crypt.1.cipher = "aes-cbc-plain"
11+
dm_crypt.1.secret = "8e9c0780fd7f5d00c18a30812fe960cfce71f6074dd9cded6aab2897568cc856"
12+
13+
dm_crypt.2.path = "/dev/mmcblk0p4"
14+
dm_crypt.2.name = "provisioning"
15+
dm_crypt.2.cipher = "aes-cbc-plain"
16+
dm_crypt.2.secret = "4e9c781fd7f5d00c18a30812fe970cfce56f6064dd9cded6aab2897575cc861"
17+
EOF
18+
19+
20+
cat >$EXPECTED <<EOF
21+
fixture: mkdir("/mnt", 755)
22+
fixture: mkdir("/dev", 755)
23+
fixture: mkdir("/sys", 555)
24+
fixture: mkdir("/proc", 555)
25+
fixture: mount("devtmpfs", "/dev", "devtmpfs", 10, data)
26+
fixture: mount("sysfs", "/sys", "sysfs", 14, data)
27+
fixture: mount("proc", "/proc", "proc", 14, data)
28+
fixture: mount("/dev/mmcblk0p2", "/mnt", "squashfs", 1, data)
29+
nerves_initramfs: mapping other encrypted block device /dev/mmcblk0p3
30+
fixture: ioctl(LOOP_SET_FD)
31+
fixture: ioctl(DM_DEV_CREATE, data_size=16384, data_start=312, target_count=0, open_count=0, flags=0, event_nr=0, dev=0x0, name=app, uuid=CRYPT-PLAIN-app
32+
fixture: ioctl(DM_TABLE_LOAD, data_size=16384, data_start=312, target_count=1, open_count=0, flags=32768, event_nr=0, dev=0x0, name=app, uuid=, target=0,393216,crypt (aes-cbc-plain 8e9c0780fd7f5d00c18a30812fe960cfce71f6074dd9cded6aab2897568cc856 1 /dev/loop1 0)
33+
fixture: ioctl(DM_DEV_SUSPEND, data_size=16384, data_start=312, target_count=0, open_count=0, flags=32768, event_nr=0, dev=0x0, name=app, uuid=
34+
fixture: symlink("/dev/mapper/app, /dev/dm-1")
35+
nerves_initramfs: mapping other encrypted block device /dev/mmcblk0p4
36+
fixture: ioctl(LOOP_SET_FD)
37+
fixture: ioctl(DM_DEV_CREATE, data_size=16384, data_start=312, target_count=0, open_count=0, flags=0, event_nr=0, dev=0x0, name=provisioning, uuid=CRYPT-PLAIN-provisioning
38+
fixture: ioctl(DM_TABLE_LOAD, data_size=16384, data_start=312, target_count=1, open_count=0, flags=32768, event_nr=0, dev=0x0, name=provisioning, uuid=, target=0,655360,crypt (aes-cbc-plain 4e9c781fd7f5d00c18a30812fe970cfce56f6064dd9cded6aab2897575cc861 2 /dev/loop2 0)
39+
fixture: ioctl(DM_DEV_SUSPEND, data_size=16384, data_start=312, target_count=0, open_count=0, flags=32768, event_nr=0, dev=0x0, name=provisioning, uuid=
40+
fixture: symlink("/dev/mapper/provisioning, /dev/dm-2")
41+
fixture: mount("/dev", "/mnt/dev", "(null)", 8192, data)
42+
fixture: umount("/sys")
43+
fixture: umount("/proc")
44+
fixture: unlinkat("bin", AT_REMOVEDIR)
45+
fixture: unlinkat("usr", AT_REMOVEDIR)
46+
fixture: rmdir("/sys")
47+
fixture: rmdir("/proc")
48+
fixture: mount(".", "/", "(null)", 8192, data)
49+
fixture: chroot(.)
50+
Hello from the chained /sbin/init
51+
EOF

tests/fixture/init_fixture.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,7 @@ OVERRIDE(int, dup2, (int oldfd, int newfd))
304304

305305
OVERRIDE(int, symlink, (const char *target, const char *linkpath))
306306
{
307+
log("symlink(\"%s, %s\")", target, linkpath);
307308
char new_target[PATH_MAX];
308309
if (fixup_path(target, new_target) < 0)
309310
return -1;

tests/init_fixture.sh

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,12 @@ ln -s "$TESTS_DIR/fake_faulty_program" "$TEST_ROOTFS/usr/bin/faulty_program"
1616

1717
# Create the device containing a root filesystem
1818
dd if=/dev/zero of="$TEST_ROOTFS/dev/mmcblk0p2" bs=512 count=0 seek=1024 2>/dev/null
19+
20+
# Create devices for other partitions
21+
dd if=/dev/zero of="$TEST_ROOTFS/dev/mmcblk0p1" bs=512 count=0 seek=512 2>/dev/null
22+
dd if=/dev/zero of="$TEST_ROOTFS/dev/mmcblk0p3" bs=512 count=0 seek=768 2>/dev/null
23+
dd if=/dev/zero of="$TEST_ROOTFS/dev/mmcblk0p4" bs=512 count=0 seek=1280 2>/dev/null
24+
1925
ln -s /dev/null "$TEST_ROOTFS/dev/null"
2026

2127
# Fake active console
@@ -28,6 +34,9 @@ ln -s "$real_tty" "$TEST_ROOTFS/dev/tty1"
2834
mkdir -p "$TEST_ROOTFS/dev/mapper"
2935
touch "$TEST_ROOTFS/dev/mapper/control"
3036
touch "$TEST_ROOTFS/dev/loop0"
37+
touch "$TEST_ROOTFS/dev/loop1"
38+
touch "$TEST_ROOTFS/dev/loop2"
39+
touch "$TEST_ROOTFS/dev/loop3"
3140

3241
# "Block" devices
3342
mkdir -p "$TEST_ROOTFS/sys/block"

0 commit comments

Comments
 (0)