crypt_reboot 0.1.2 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +9 -0
- data/README.md +47 -5
- data/lib/basic_loader.rb +1 -1
- data/lib/crypt_reboot/cli/params/definition.rb +6 -0
- data/lib/crypt_reboot/cli/params_parsing_executor.rb +2 -2
- data/lib/crypt_reboot/elastic_memory_locker.rb +35 -0
- data/lib/crypt_reboot/instantiable_config.rb +4 -1
- data/lib/crypt_reboot/version.rb +1 -1
- metadata +13 -13
- data/lib/crypt_reboot/memory_locker.rb +0 -33
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6ec1b79f3b99fddc49e170693df471d0eebc44af064787cb29b2694985a91418
|
4
|
+
data.tar.gz: e3fa5ac025fc7ea7544a6e4c6d9db1f5894a0da44b6c39d07689a7594c0fc714
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8aebba8307469fc4cba898f0c3427b4c6242e7f90dea985b33a72e89e13ee7e0854b232870b1afaea518c92eee03dca8c32d4c1f956a6da2e6cd55adae67f07e
|
7
|
+
data.tar.gz: 56d86831971b547b4d1856b426dafac2a77bffa23fd8ced861908902ce969186be52710e92dd50ec01242c77133d77439a088a651626dd9e8ce2977ce136483a
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
## [0.2.1] - 2023-11-12
|
2
|
+
|
3
|
+
- use new MemoryLocker without a need for FFI compilation step
|
4
|
+
|
5
|
+
## [0.2.0] - 2023-07-29
|
6
|
+
|
7
|
+
- Make memory locking optional with `--insecure-memory` command line option
|
8
|
+
- Remove FFI gem dependency
|
9
|
+
|
1
10
|
## [0.1.2] - 2023-07-22
|
2
11
|
|
3
12
|
- Lock memory to prevent secrets leaking to swap
|
data/README.md
CHANGED
@@ -7,7 +7,8 @@ Convenient reboot for Linux systems with encrypted root partition.
|
|
7
7
|
> Just type `cryptreboot` instead of `reboot`.
|
8
8
|
|
9
9
|
It asks for a passphrase and reboots the system afterward, automatically
|
10
|
-
unlocking the drive on startup using
|
10
|
+
unlocking the drive on startup using
|
11
|
+
[in-memory initramfs patching and kexec](https://blog.pawelpokrywka.com/p/rebooting-linux-with-encrypted-disk).
|
11
12
|
Without explicit consent, no secrets are stored on disk, even temporarily.
|
12
13
|
|
13
14
|
Useful when unlocking the drive at startup is difficult, such as on headless
|
@@ -36,7 +37,8 @@ Following distributions were tested by the author on the AMD64 machine:
|
|
36
37
|
- Ubuntu 22.04 LTS
|
37
38
|
- Ubuntu 20.04 LTS needs tiny adjustments to system settings,
|
38
39
|
specifically [changing compression](#lz4-initramfs-compression) and
|
39
|
-
[fixing systemd kexec support](#staged-kernel-not-being-executed-by-systemd)
|
40
|
+
[fixing systemd kexec support](#staged-kernel-not-being-executed-by-systemd), but still
|
41
|
+
[sometimes](#unable-to-kexec-on-reboot-using-old-systemd) reboot experience may be suboptimal
|
40
42
|
- ~~Ubuntu 18.04 LTS~~ is not supported (initramfs uses *pre-crypttab* format)
|
41
43
|
|
42
44
|
If you have successfully run cryptreboot on another distribution,
|
@@ -71,6 +73,10 @@ Make sure the required software is installed, then install the gem system-wide b
|
|
71
73
|
|
72
74
|
$ sudo gem install crypt_reboot
|
73
75
|
|
76
|
+
To upgrade run:
|
77
|
+
|
78
|
+
$ sudo gem update crypt_reboot
|
79
|
+
|
74
80
|
## Usage
|
75
81
|
|
76
82
|
Cryptreboot performs operations normally only available to the root user,
|
@@ -84,7 +90,7 @@ To see the usage, run:
|
|
84
90
|
|
85
91
|
$ cryptreboot --help
|
86
92
|
|
87
|
-
##
|
93
|
+
## Troubleshooting
|
88
94
|
|
89
95
|
### LZ4 initramfs compression
|
90
96
|
|
@@ -140,9 +146,9 @@ To cancel the change, remove the file:
|
|
140
146
|
|
141
147
|
$ sudo rm /etc/systemd/system/systemd-kexec.service.d/override.conf
|
142
148
|
|
143
|
-
### No symlinks to most recent kernel and initramfs
|
149
|
+
### No symlinks to the most recent kernel and initramfs
|
144
150
|
|
145
|
-
By default cryptreboot looks for kernel in `/boot/vmlinuz` and for initramfs
|
151
|
+
By default, cryptreboot looks for kernel in `/boot/vmlinuz` and for initramfs
|
146
152
|
in `/boot/initrd.img`. If those files are missing in your Linux distribution,
|
147
153
|
cryptreboot will fail, unless you use `--kernel` and `--initramfs` command line
|
148
154
|
options.
|
@@ -160,6 +166,42 @@ Unfortunately, you need to rerun it after each kernel upgrade, otherwise,
|
|
160
166
|
cryptreboot is going to boot the old kernel.
|
161
167
|
Upcoming versions of cryptreboot will offer better solutions.
|
162
168
|
|
169
|
+
### Problems with memory locking
|
170
|
+
|
171
|
+
If you get:
|
172
|
+
|
173
|
+
> Locking error: Failed to lock memory
|
174
|
+
|
175
|
+
it means there was an error while locking memory to prevent a risk of sensitive data ending in a swap space.
|
176
|
+
|
177
|
+
Make sure you have permission to lock memory. Root users have.
|
178
|
+
If permissions are ok, then please report a bug describing your setup.
|
179
|
+
|
180
|
+
The solution of last resort is to use `--insecure-memory` flag, which disables memory locking completely.
|
181
|
+
|
182
|
+
### Unable to kexec on reboot using old systemd
|
183
|
+
|
184
|
+
Ubuntu 20.04 ships with `systemd` which may fall back to standard reboot instead of using `kexec`, because this utility
|
185
|
+
is located on a filesystem being unmounted during the shutdown sequence.
|
186
|
+
|
187
|
+
As a result, using cryptreboot would feel like using normal reboot.
|
188
|
+
|
189
|
+
To tell if your system is affected, you have to check messages printed to the console after you run cryptreboot.
|
190
|
+
This message happens just before reboot, so you will have just a few milliseconds to notice it on screen:
|
191
|
+
|
192
|
+
> shutdown[1]: (sd-kexec) failed with exit status 1
|
193
|
+
|
194
|
+
[There is a fix](https://bugs.launchpad.net/ubuntu/+source/systemd/+bug/1969365) waiting to be included in
|
195
|
+
a stable release update to `systemd` since 2023-07-21.
|
196
|
+
|
197
|
+
In the meantime, as a workaround, you can use `kexec` directly. **Warning: it will skip the standard shutdown procedure. Filesystems won't be unmounted, services won't be stopped, etc. It is like hitting `reset` button**.
|
198
|
+
However, when you use a decent filesystem with journalling the risk of things going bad should not be high.
|
199
|
+
|
200
|
+
Given the above warning, to reboot skipping the shutdown procedure, run:
|
201
|
+
|
202
|
+
$ sudo cryptreboot -p
|
203
|
+
$ sudo kexec -e # will skip proper shutdown sequence
|
204
|
+
|
163
205
|
## Development
|
164
206
|
|
165
207
|
After checking out the repo, run `bundle install` to install
|
data/lib/basic_loader.rb
CHANGED
@@ -8,13 +8,13 @@ require 'crypt_reboot/cli'
|
|
8
8
|
require 'crypt_reboot/concatenator'
|
9
9
|
require 'crypt_reboot/instantiable_config'
|
10
10
|
require 'crypt_reboot/config'
|
11
|
+
require 'crypt_reboot/elastic_memory_locker'
|
11
12
|
require 'crypt_reboot/files_generator'
|
12
13
|
require 'crypt_reboot/files_writer'
|
13
14
|
require 'crypt_reboot/gziper'
|
14
15
|
require 'crypt_reboot/initramfs_patch_squeezer'
|
15
16
|
require 'crypt_reboot/kexec_patching_loader'
|
16
17
|
require 'crypt_reboot/lazy_config'
|
17
|
-
require 'crypt_reboot/memory_locker'
|
18
18
|
require 'crypt_reboot/passphrase_asker'
|
19
19
|
require 'crypt_reboot/patched_initramfs_generator'
|
20
20
|
require 'crypt_reboot/rebooter'
|
@@ -90,6 +90,12 @@ module CryptReboot
|
|
90
90
|
'algorithm to a more robust one.'
|
91
91
|
end
|
92
92
|
|
93
|
+
flag :insecure_memory do
|
94
|
+
short '-s'
|
95
|
+
long '--insecure-memory'
|
96
|
+
desc 'Do not lock memory. WARNING: there is a risk your secrets will leak to swap.'
|
97
|
+
end
|
98
|
+
|
93
99
|
flag :debug do
|
94
100
|
short '-d'
|
95
101
|
long '--debug'
|
@@ -5,7 +5,6 @@ module CryptReboot
|
|
5
5
|
# Interprets parameters, executes everything and returns callable object
|
6
6
|
class ParamsParsingExecutor
|
7
7
|
def call(raw_params)
|
8
|
-
locker.call
|
9
8
|
params = parser.call(raw_params)
|
10
9
|
handle_action_params!(params) or configure_and_exec(params)
|
11
10
|
rescue StandardError, Interrupt => e
|
@@ -22,6 +21,7 @@ module CryptReboot
|
|
22
21
|
|
23
22
|
def configure_and_exec(params)
|
24
23
|
config_updater.call(**params)
|
24
|
+
locker.call
|
25
25
|
loader.call
|
26
26
|
rebooter
|
27
27
|
end
|
@@ -58,7 +58,7 @@ module CryptReboot
|
|
58
58
|
rebooter: Rebooter.new,
|
59
59
|
happy_exiter_class: HappyExiter,
|
60
60
|
sad_exiter_class: SadExiter,
|
61
|
-
locker:
|
61
|
+
locker: ElasticMemoryLocker.new)
|
62
62
|
@parser = parser
|
63
63
|
@config_updater = config_updater
|
64
64
|
@loader = loader
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'memory_locker' unless defined? MemoryLocker # MemoryLocker is mocked in tests
|
4
|
+
|
5
|
+
module CryptReboot
|
6
|
+
# Try to lock memory if configuration allows it
|
7
|
+
class ElasticMemoryLocker
|
8
|
+
LockingError = Class.new StandardError
|
9
|
+
|
10
|
+
def call
|
11
|
+
return if skip_locking?
|
12
|
+
|
13
|
+
locker.call
|
14
|
+
nil
|
15
|
+
rescue locking_error => e
|
16
|
+
raise LockingError, 'Failed to lock memory', cause: e
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def skip_locking?
|
22
|
+
insecure_memory_checker.call
|
23
|
+
end
|
24
|
+
|
25
|
+
attr_reader :insecure_memory_checker, :locker, :locking_error
|
26
|
+
|
27
|
+
def initialize(insecure_memory_checker: LazyConfig.insecure_memory,
|
28
|
+
locker: MemoryLocker,
|
29
|
+
locking_error: MemoryLocker::Error)
|
30
|
+
@insecure_memory_checker = insecure_memory_checker
|
31
|
+
@locker = locker
|
32
|
+
@locking_error = locking_error
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -8,7 +8,7 @@ module CryptReboot
|
|
8
8
|
attr_reader :initramfs, :cmdline, :kernel, :patch_save_path, :cat_path, :cpio_path,
|
9
9
|
:unmkinitramfs_path, :kexec_path, :cryptsetup_path, :reboot_path,
|
10
10
|
:mount_path, :umount_path, :strace_path, :grep_path,
|
11
|
-
:debug, :prepare_only, :skip_lz4_check
|
11
|
+
:debug, :prepare_only, :skip_lz4_check, :insecure_memory
|
12
12
|
|
13
13
|
def update!(**settings)
|
14
14
|
settings.each do |name, value|
|
@@ -25,6 +25,7 @@ module CryptReboot
|
|
25
25
|
end
|
26
26
|
|
27
27
|
# rubocop:disable Metrics/MethodLength
|
28
|
+
# rubocop:disable Metrics/AbcSize
|
28
29
|
def initialize
|
29
30
|
# Options
|
30
31
|
@initramfs = '/boot/initrd.img'
|
@@ -46,7 +47,9 @@ module CryptReboot
|
|
46
47
|
@debug = false
|
47
48
|
@prepare_only = false
|
48
49
|
@skip_lz4_check = false
|
50
|
+
@insecure_memory = false
|
49
51
|
end
|
52
|
+
# rubocop:enable Metrics/AbcSize
|
50
53
|
# rubocop:enable Metrics/MethodLength
|
51
54
|
end
|
52
55
|
end
|
data/lib/crypt_reboot/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: crypt_reboot
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1
|
4
|
+
version: 0.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Paweł Pokrywka
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-11-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: tty-command
|
@@ -39,20 +39,20 @@ dependencies:
|
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0.3'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
42
|
+
name: memory_locker
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - "
|
45
|
+
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: 1.0.
|
47
|
+
version: 1.0.3
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- - "
|
52
|
+
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: 1.0.
|
55
|
-
description:
|
54
|
+
version: 1.0.3
|
55
|
+
description:
|
56
56
|
email:
|
57
57
|
- pepawel@users.noreply.github.com
|
58
58
|
executables:
|
@@ -85,6 +85,7 @@ files:
|
|
85
85
|
- lib/crypt_reboot/crypt_tab/keyfile_locator.rb
|
86
86
|
- lib/crypt_reboot/crypt_tab/luks_to_plain_converter.rb
|
87
87
|
- lib/crypt_reboot/crypt_tab/serializer.rb
|
88
|
+
- lib/crypt_reboot/elastic_memory_locker.rb
|
88
89
|
- lib/crypt_reboot/files_generator.rb
|
89
90
|
- lib/crypt_reboot/files_writer.rb
|
90
91
|
- lib/crypt_reboot/gziper.rb
|
@@ -107,7 +108,6 @@ files:
|
|
107
108
|
- lib/crypt_reboot/luks/dumper/luks_v2_parser.rb
|
108
109
|
- lib/crypt_reboot/luks/key_fetcher.rb
|
109
110
|
- lib/crypt_reboot/luks/version_detector.rb
|
110
|
-
- lib/crypt_reboot/memory_locker.rb
|
111
111
|
- lib/crypt_reboot/passphrase_asker.rb
|
112
112
|
- lib/crypt_reboot/patched_initramfs_generator.rb
|
113
113
|
- lib/crypt_reboot/rebooter.rb
|
@@ -131,7 +131,7 @@ metadata:
|
|
131
131
|
source_code_uri: https://github.com/phantom-node/cryptreboot
|
132
132
|
changelog_uri: https://github.com/phantom-node/cryptreboot/blob/master/CHANGELOG.md
|
133
133
|
rubygems_mfa_required: 'true'
|
134
|
-
post_install_message:
|
134
|
+
post_install_message:
|
135
135
|
rdoc_options: []
|
136
136
|
require_paths:
|
137
137
|
- lib
|
@@ -146,8 +146,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
146
146
|
- !ruby/object:Gem::Version
|
147
147
|
version: '0'
|
148
148
|
requirements: []
|
149
|
-
rubygems_version: 3.
|
150
|
-
signing_key:
|
149
|
+
rubygems_version: 3.2.22
|
150
|
+
signing_key:
|
151
151
|
specification_version: 4
|
152
152
|
summary: Linux utility for automatic and secure unlocking of encrypted disks on reboot
|
153
153
|
test_files: []
|
@@ -1,33 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'ffi'
|
4
|
-
|
5
|
-
module CryptReboot
|
6
|
-
# Lock process memory, so it won't be swapped by the kernel.
|
7
|
-
# It is implemented as a one-way operation: there is no unlock.
|
8
|
-
# That's because it's hard to properly clean memory in Ruby.
|
9
|
-
class MemoryLocker
|
10
|
-
Error = Class.new StandardError
|
11
|
-
|
12
|
-
def call
|
13
|
-
return if Libc.mlockall(Libc::MCL_CURRENT | Libc::MCL_FUTURE).zero?
|
14
|
-
|
15
|
-
raise Error, "Failed to lock memory: #{FFI.errno}"
|
16
|
-
end
|
17
|
-
|
18
|
-
# Low level interface to libc
|
19
|
-
module Libc
|
20
|
-
extend FFI::Library
|
21
|
-
ffi_lib 'libc.so.6'
|
22
|
-
|
23
|
-
# define mlockall constants
|
24
|
-
MCL_CURRENT = 1
|
25
|
-
MCL_FUTURE = 2
|
26
|
-
MCL_ONFAULT = 4
|
27
|
-
|
28
|
-
# declare mlockall function
|
29
|
-
attach_function :mlockall, [:int], :int
|
30
|
-
end
|
31
|
-
private_constant :Libc
|
32
|
-
end
|
33
|
-
end
|