crypt_reboot 0.1.1 → 0.2.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ca95c9301674a1698f766dbfa5dfd06adc99e91a286c32b7eaa77d8611e21762
4
- data.tar.gz: 5403a4ed739f8b5901451e3e413598e85acfee1765266a66d85257c708904399
3
+ metadata.gz: ee0a1d8c466f902cc47c84b3310c899046ae2d2cacc952f184baa76463add807
4
+ data.tar.gz: 6fc17834b241d0822848b84e36fa2277b47a998c77659740a82d0e49d83a16e6
5
5
  SHA512:
6
- metadata.gz: d633a85afa5dc298f39c144d700347cb20ae4bc03e5865ba3a92c2a1ae0ec9bc679393b612f7c18838d35578f583db8f791aab223f896a1ed3fce8bcfd78c6e8
7
- data.tar.gz: 59442b7e7106a5d2892def87930503472315dbc45da8d9bf8919d29fc7fc998edcb2dfe69b3bc4ea0306c173bc1dc305fa5be42954bb706eb35f4104531933a3
6
+ metadata.gz: 030a74f06349d21c91b05a7ac297ffb927309faad863689a8cd632521587e47059c38995b377e199e5337819f447999796f65aa6dfa17345f7aaca0821458a23
7
+ data.tar.gz: 2f16596ee0b871ecec49b9687da65d3086c66daa41b48e3090d43317452755752443996f5ef5887ac4a73f50f31bd4307ab08254b2869e3219970117ddfcbeee
data/CHANGELOG.md CHANGED
@@ -1,3 +1,12 @@
1
+ ## [0.1.2] - 2023-07-22
2
+
3
+ - Lock memory to prevent secrets leaking to swap
4
+ - Use `ramfs` instead of `tmpfs` for the same reason
5
+
6
+ ## [0.1.1] - 2023-07-13
7
+
8
+ - Standardize passphrase prompt
9
+
1
10
  ## [0.1.0] - 2023-07-09
2
11
 
3
12
  - Initial release
data/README.md CHANGED
@@ -28,13 +28,16 @@ Debian, Ubuntu, Linux Mint, Pop!_OS, etc.
28
28
  On the other hand, do not expect it to work on other distributions now.
29
29
  But support for them may come in upcoming versions.
30
30
 
31
- Following distributions were tested by the author:
31
+ Following distributions were tested by the author on the AMD64 machine:
32
+ - DappNode 0.2.75 is based on Debian 12, see below
33
+ - Debian 12 needs [symlinks for kernel and initramfs](#no-symlinks-to-most-recent-kernel-and-initramfs)
34
+ - Pop!_OS 22.04 LTS
35
+ - Ubuntu 23.04
32
36
  - Ubuntu 22.04 LTS
33
37
  - Ubuntu 20.04 LTS needs tiny adjustments to system settings,
34
38
  specifically [changing compression](#lz4-initramfs-compression) and
35
39
  [fixing systemd kexec support](#staged-kernel-not-being-executed-by-systemd)
36
40
  - ~~Ubuntu 18.04 LTS~~ is not supported (initramfs uses *pre-crypttab* format)
37
- - Pop!_OS 22.04 LTS
38
41
 
39
42
  If you have successfully run cryptreboot on another distribution,
40
43
  please contact me and I will update the list.
@@ -50,17 +53,36 @@ You need to ensure those are installed:
50
53
  If you use recent, mainstream Linux distribution, other requirements are
51
54
  probably already met:
52
55
  - `kexec` support in the kernel
53
- - `tmpfs` filesystem support in kernel
56
+ - `ramfs` filesystem support in kernel
54
57
  - `cryptsetup` (if you use disk encryption, it should be installed)
55
58
  - `systemd` or another way to guarantee staged kernel is executed on reboot
56
59
  - `strace` (not required if `--skip-lz4-check` flag is specified)
57
60
 
61
+ If you use Debian-based distribution, use this command to install required packages:
62
+
63
+ $ sudo apt install --no-install-recommends cryptsetup-initramfs kexec-tools ruby strace systemd
64
+
65
+ When asked if kexec should handle reboots, answer `yes` (however the answer probably
66
+ doesn't matter for cryptreboot to work).
67
+
68
+ ## Recommendations
69
+
70
+ To protects against saving sensitive data (passphrase, encryption keys) to swap space on a disk, it is recommended to use `memory_locker` ([Rubygems](https://rubygems.org/gems/memory_locker), [Github](https://github.com/phantom-node/memory_locker)).
71
+
72
+ $ sudo gem install memory_locker
73
+
74
+ If you don't want to install it, you will have to specify `--insecure-memory` flag when running cryptreboot.
75
+
58
76
  ## Installation
59
77
 
60
78
  Make sure the required software is installed, then install the gem system-wide by executing:
61
79
 
62
80
  $ sudo gem install crypt_reboot
63
81
 
82
+ To upgrade run:
83
+
84
+ $ sudo gem update crypt_reboot
85
+
64
86
  ## Usage
65
87
 
66
88
  Cryptreboot performs operations normally only available to the root user,
@@ -74,7 +96,7 @@ To see the usage, run:
74
96
 
75
97
  $ cryptreboot --help
76
98
 
77
- ## Resolutions for common issues
99
+ ## Troubleshooting
78
100
 
79
101
  ### LZ4 initramfs compression
80
102
 
@@ -130,6 +152,40 @@ To cancel the change, remove the file:
130
152
 
131
153
  $ sudo rm /etc/systemd/system/systemd-kexec.service.d/override.conf
132
154
 
155
+ ### No symlinks to the most recent kernel and initramfs
156
+
157
+ By default, cryptreboot looks for kernel in `/boot/vmlinuz` and for initramfs
158
+ in `/boot/initrd.img`. If those files are missing in your Linux distribution,
159
+ cryptreboot will fail, unless you use `--kernel` and `--initramfs` command line
160
+ options.
161
+
162
+ $ sudo cryptreboot --kernel /boot/vmlinuz-`uname -r` --initramfs /boot/initrd.img-`uname -r`
163
+
164
+ If you don't want to specify options every time you reboot, add symlinks to
165
+ the currently running kernel and initramfs:
166
+
167
+ $ cd /boot
168
+ $ sudo ln -sf vmlinuz-`uname -r` vmlinuz
169
+ $ sudo ln -sf initrd.img-`uname -r` initrd.img
170
+
171
+ Unfortunately, you need to rerun it after each kernel upgrade, otherwise,
172
+ cryptreboot is going to boot the old kernel.
173
+ Upcoming versions of cryptreboot will offer better solutions.
174
+
175
+ ### Problems with memory locking
176
+
177
+ If you get:
178
+
179
+ > Locking error: Failed to lock memory
180
+
181
+ it means there was an error while locking memory to prevent a risk of sensitive data ending in a swap space.
182
+
183
+ The best solution is to install `memory_locker` (see [requirements](#requirements) section).
184
+ If it still doesn't help, make sure you have permission to lock memory. Root users do.
185
+ If the problem persists, then please report a bug describing your setup.
186
+
187
+ The solution of last resort is to use `--insecure-memory` flag, which disables memory locking completely.
188
+
133
189
  ## Development
134
190
 
135
191
  After checking out the repo, run `bundle install` to install
data/lib/basic_loader.rb CHANGED
@@ -8,6 +8,7 @@ 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'
@@ -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'
@@ -7,7 +7,7 @@ module CryptReboot
7
7
  def call(raw_params)
8
8
  params = parser.call(raw_params)
9
9
  handle_action_params!(params) or configure_and_exec(params)
10
- rescue StandardError => e
10
+ rescue StandardError, Interrupt => e
11
11
  raise if debug?
12
12
 
13
13
  sad_exiter_class.new(error_message(e))
@@ -21,6 +21,7 @@ module CryptReboot
21
21
 
22
22
  def configure_and_exec(params)
23
23
  config_updater.call(**params)
24
+ locker.call
24
25
  loader.call
25
26
  rebooter
26
27
  end
@@ -45,7 +46,7 @@ module CryptReboot
45
46
 
46
47
  attr_reader :parser, :config_updater, :loader, :help_generator,
47
48
  :version_string, :debug_checker, :rebooter,
48
- :happy_exiter_class, :sad_exiter_class
49
+ :happy_exiter_class, :sad_exiter_class, :locker
49
50
 
50
51
  # rubocop:disable Metrics/ParameterLists
51
52
  def initialize(parser: Params::Parser.new,
@@ -56,7 +57,8 @@ module CryptReboot
56
57
  debug_checker: LazyConfig.debug,
57
58
  rebooter: Rebooter.new,
58
59
  happy_exiter_class: HappyExiter,
59
- sad_exiter_class: SadExiter)
60
+ sad_exiter_class: SadExiter,
61
+ locker: ElasticMemoryLocker.new)
60
62
  @parser = parser
61
63
  @config_updater = config_updater
62
64
  @loader = loader
@@ -66,6 +68,7 @@ module CryptReboot
66
68
  @rebooter = rebooter
67
69
  @happy_exiter_class = happy_exiter_class
68
70
  @sad_exiter_class = sad_exiter_class
71
+ @locker = locker
69
72
  end
70
73
  # rubocop:enable Metrics/ParameterLists
71
74
  end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module CryptReboot
4
+ # Try to lock memory if configuration allows it
5
+ class ElasticMemoryLocker
6
+ LockingError = Class.new StandardError
7
+
8
+ def call
9
+ return if skip_locking?
10
+
11
+ loader.call
12
+ locker.call
13
+ nil
14
+ rescue load_error, locking_error => e
15
+ raise LockingError, 'Failed to lock memory', cause: e
16
+ end
17
+
18
+ private
19
+
20
+ def skip_locking?
21
+ insecure_memory_checker.call
22
+ end
23
+
24
+ def locking_error
25
+ lazy_locking_error.call
26
+ end
27
+
28
+ attr_reader :insecure_memory_checker, :loader, :load_error, :locker, :lazy_locking_error
29
+
30
+ def initialize(insecure_memory_checker: LazyConfig.insecure_memory,
31
+ loader: -> { require 'memory_locker' },
32
+ load_error: LoadError,
33
+ locker: -> { MemoryLocker.call },
34
+ lazy_locking_error: -> { MemoryLocker::Error })
35
+ @insecure_memory_checker = insecure_memory_checker
36
+ @loader = loader
37
+ @load_error = load_error
38
+ @locker = locker
39
+ @lazy_locking_error = lazy_locking_error
40
+ end
41
+ end
42
+ 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
@@ -4,7 +4,7 @@ require 'tmpdir'
4
4
 
5
5
  module CryptReboot
6
6
  module SafeTemp
7
- # Create temporary directory, mounts tmpfs and yields tmp dir location.
7
+ # Create temporary directory, mounts ramfs and yields tmp dir location.
8
8
  # Make sure to cleanup afterwards.
9
9
  class Directory
10
10
  def call
@@ -2,7 +2,9 @@
2
2
 
3
3
  module CryptReboot
4
4
  module SafeTemp
5
- # Mount tmpfs at the given mount point, yield and unmount
5
+ # Mount ramfs at the given mount point, yield and unmount.
6
+ # We don't want the contents of directory to be swapped,
7
+ # therefore ramfs is used instead of tmpfs.
6
8
  class Mounter
7
9
  def call(dir, &block)
8
10
  mounter.call(dir)
@@ -21,7 +23,7 @@ module CryptReboot
21
23
 
22
24
  def initialize(runner: Runner::NoResult.new,
23
25
  mounter: lambda { |dir|
24
- runner.call(Config.mount_path, '-t', 'tmpfs', '-o', 'mode=700', 'none', dir)
26
+ runner.call(Config.mount_path, '-t', 'ramfs', '-o', 'mode=700', 'none', dir)
25
27
  },
26
28
  umounter: ->(dir) { runner.call(Config.umount_path, dir) })
27
29
  @runner = runner
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module CryptReboot
4
- VERSION = '0.1.1'
4
+ VERSION = '0.2.0'
5
5
  end
data/lib/crypt_reboot.rb CHANGED
@@ -7,6 +7,7 @@ rescue LoadError => e
7
7
 
8
8
  require 'zeitwerk'
9
9
  loader = Zeitwerk::Loader.for_gem
10
+ loader.ignore("#{__dir__}/memory_locker.rb") # stub has to be loaded manually
10
11
  loader.setup
11
12
  end
12
13
 
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.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Paweł Pokrywka
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-07-13 00:00:00.000000000 Z
11
+ date: 2023-07-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: tty-command
@@ -71,6 +71,7 @@ files:
71
71
  - lib/crypt_reboot/crypt_tab/keyfile_locator.rb
72
72
  - lib/crypt_reboot/crypt_tab/luks_to_plain_converter.rb
73
73
  - lib/crypt_reboot/crypt_tab/serializer.rb
74
+ - lib/crypt_reboot/elastic_memory_locker.rb
74
75
  - lib/crypt_reboot/files_generator.rb
75
76
  - lib/crypt_reboot/files_writer.rb
76
77
  - lib/crypt_reboot/gziper.rb