mirror of
https://github.com/systemd/systemd-stable.git
synced 2024-12-22 13:33:56 +03:00
Implement --luks-sector-size for homed
This commit is contained in:
parent
b25e08a752
commit
fd83c98e8a
@ -500,6 +500,10 @@ memory cost for the PBKDF operation, when LUKS storage is used, in bytes.
|
||||
`luksPbkdfParallelThreads` → An unsigned 64bit integer, indicating the intended
|
||||
required parallel threads for the PBKDF operation, when LUKS storage is used.
|
||||
|
||||
`luksSectorSize` → An unsigned 64bit integer, indicating the sector size to
|
||||
use for the LUKS storage mechanism, in bytes. Must be a power of two between
|
||||
512 and 4096.
|
||||
|
||||
`autoResizeMode` → A string, one of `off`, `grow`, `shrink-and-grow`. Unless
|
||||
set to `off`, controls whether the home area shall be grown automatically to
|
||||
the size configured in `diskSize` automatically at login time. If set to
|
||||
@ -734,7 +738,7 @@ that may be used in this section are identical to the equally named ones in the
|
||||
`fileSystemUuid`, `luksDiscard`, `luksOfflineDiscard`, `luksCipher`,
|
||||
`luksCipherMode`, `luksVolumeKeySize`, `luksPbkdfHashAlgorithm`,
|
||||
`luksPbkdfType`, `luksPbkdfTimeCostUSec`, `luksPbkdfMemoryCost`,
|
||||
`luksPbkdfParallelThreads`, `autoResizeMode`, `rebalanceWeight`,
|
||||
`luksPbkdfParallelThreads`, `luksSectorSize`, `autoResizeMode`, `rebalanceWeight`,
|
||||
`rateLimitIntervalUSec`, `rateLimitBurst`, `enforcePasswordPolicy`,
|
||||
`autoLogin`, `stopDelayUSec`, `killProcesses`, `passwordChangeMinUSec`,
|
||||
`passwordChangeMaxUSec`, `passwordChangeWarnUSec`,
|
||||
|
@ -692,6 +692,7 @@
|
||||
<term><option>--luks-pbkdf-time-cost=</option><replaceable>SECONDS</replaceable></term>
|
||||
<term><option>--luks-pbkdf-memory-cost=</option><replaceable>BYTES</replaceable></term>
|
||||
<term><option>--luks-pbkdf-parallel-threads=</option><replaceable>THREADS</replaceable></term>
|
||||
<term><option>--luks-sector-size=</option><replaceable>BYTES</replaceable></term>
|
||||
|
||||
<listitem><para>Configures various cryptographic parameters for the LUKS2 storage mechanism. See
|
||||
<citerefentry
|
||||
|
@ -96,6 +96,7 @@ _homectl() {
|
||||
--luks-pbkdf-time-cost
|
||||
--luks-pbkdf-memory-cost
|
||||
--luks-pbkdf-parallel-threads
|
||||
--luks-sector-size
|
||||
--nosuid
|
||||
--nodev
|
||||
--noexec
|
||||
|
@ -1797,6 +1797,26 @@ static int parse_disk_size(const char *t, uint64_t *ret) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int parse_sector_size(const char *t, uint64_t *ret) {
|
||||
int r;
|
||||
|
||||
assert(t);
|
||||
assert(ret);
|
||||
|
||||
uint64_t ss;
|
||||
|
||||
r = safe_atou64(t, &ss);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to parse sector size parameter %s", t);
|
||||
if (ss < 512 || ss > 4096) /* Allow up to 4K due to dm-crypt support and 4K alignment by the homed LUKS backend */
|
||||
return log_error_errno(SYNTHETIC_ERRNO(ERANGE), "Sector size not between 512 and 4096: %s", t);
|
||||
if (!ISPOWEROF2(ss))
|
||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Sector size not power of 2: %s", t);
|
||||
|
||||
*ret = ss;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int resize_home(int argc, char *argv[], void *userdata) {
|
||||
_cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
|
||||
_cleanup_(user_record_unrefp) UserRecord *secret = NULL;
|
||||
@ -2291,6 +2311,8 @@ static int help(int argc, char *argv[], void *userdata) {
|
||||
" Memory cost for PBKDF in bytes\n"
|
||||
" --luks-pbkdf-parallel-threads=NUMBER\n"
|
||||
" Number of parallel threads for PKBDF\n"
|
||||
" --luks-sector-size=BYTES\n"
|
||||
" Sector size for LUKS encryption in bytes\n"
|
||||
" --luks-extra-mount-options=OPTIONS\n"
|
||||
" LUKS extra mount options\n"
|
||||
" --auto-resize-mode=MODE Automatically grow/shrink home on login/logout\n"
|
||||
@ -2372,6 +2394,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
ARG_LUKS_PBKDF_TIME_COST,
|
||||
ARG_LUKS_PBKDF_MEMORY_COST,
|
||||
ARG_LUKS_PBKDF_PARALLEL_THREADS,
|
||||
ARG_LUKS_SECTOR_SIZE,
|
||||
ARG_RATE_LIMIT_INTERVAL,
|
||||
ARG_RATE_LIMIT_BURST,
|
||||
ARG_STOP_DELAY,
|
||||
@ -2452,6 +2475,7 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
{ "luks-pbkdf-time-cost", required_argument, NULL, ARG_LUKS_PBKDF_TIME_COST },
|
||||
{ "luks-pbkdf-memory-cost", required_argument, NULL, ARG_LUKS_PBKDF_MEMORY_COST },
|
||||
{ "luks-pbkdf-parallel-threads", required_argument, NULL, ARG_LUKS_PBKDF_PARALLEL_THREADS },
|
||||
{ "luks-sector-size", required_argument, NULL, ARG_LUKS_SECTOR_SIZE },
|
||||
{ "nosuid", required_argument, NULL, ARG_NOSUID },
|
||||
{ "nodev", required_argument, NULL, ARG_NODEV },
|
||||
{ "noexec", required_argument, NULL, ARG_NOEXEC },
|
||||
@ -3095,6 +3119,28 @@ static int parse_argv(int argc, char *argv[]) {
|
||||
break;
|
||||
}
|
||||
|
||||
case ARG_LUKS_SECTOR_SIZE: {
|
||||
uint64_t ss;
|
||||
|
||||
if (isempty(optarg)) {
|
||||
r = drop_from_identity("luksSectorSize");
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
r = parse_sector_size(optarg, &ss);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = json_variant_set_field_unsigned(&arg_identity_extra, "luksSectorSize", ss);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to set sector size field: %m");
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case ARG_UMASK: {
|
||||
mode_t m;
|
||||
|
||||
|
@ -1378,7 +1378,7 @@ int home_setup_luks(
|
||||
return r;
|
||||
}
|
||||
|
||||
r = loop_device_make(setup->image_fd, O_RDWR, offset, size, 0, LOCK_UN, &setup->loop);
|
||||
r = loop_device_make(setup->image_fd, O_RDWR, offset, size, user_record_luks_sector_size(h), 0, LOCK_UN, &setup->loop);
|
||||
if (r == -ENOENT) {
|
||||
log_error_errno(r, "Loopback block device support is not available on this system.");
|
||||
return -ENOLINK; /* make recognizable */
|
||||
@ -1761,7 +1761,7 @@ static int luks_format(
|
||||
&(struct crypt_params_luks2) {
|
||||
.label = label,
|
||||
.subsystem = "systemd-home",
|
||||
.sector_size = 512U,
|
||||
.sector_size = user_record_luks_sector_size(hr),
|
||||
.pbkdf = &good_pbkdf,
|
||||
});
|
||||
if (r < 0)
|
||||
@ -2299,7 +2299,7 @@ int home_create_luks(
|
||||
|
||||
log_info("Writing of partition table completed.");
|
||||
|
||||
r = loop_device_make(setup->image_fd, O_RDWR, partition_offset, partition_size, 0, LOCK_EX, &setup->loop);
|
||||
r = loop_device_make(setup->image_fd, O_RDWR, partition_offset, partition_size, user_record_luks_sector_size(h), 0, LOCK_EX, &setup->loop);
|
||||
if (r < 0) {
|
||||
if (r == -ENOENT) { /* this means /dev/loop-control doesn't exist, i.e. we are in a container
|
||||
* or similar and loopback bock devices are not available, return a
|
||||
|
@ -3176,7 +3176,7 @@ static int context_copy_blocks(Context *context) {
|
||||
assert_se((whole_fd = fdisk_get_devfd(context->fdisk_context)) >= 0);
|
||||
|
||||
if (p->encrypt != ENCRYPT_OFF) {
|
||||
r = loop_device_make(whole_fd, O_RDWR, p->offset, p->new_size, 0, LOCK_EX, &d);
|
||||
r = loop_device_make(whole_fd, O_RDWR, p->offset, p->new_size, 0, 0, LOCK_EX, &d);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to make loopback device of future partition %" PRIu64 ": %m", p->partno);
|
||||
|
||||
@ -3477,7 +3477,7 @@ static int context_mkfs(Context *context) {
|
||||
/* Loopback block devices are not only useful to turn regular files into block devices, but
|
||||
* also to cut out sections of block devices into new block devices. */
|
||||
|
||||
r = loop_device_make(fd, O_RDWR, p->offset, p->new_size, 0, LOCK_EX, &d);
|
||||
r = loop_device_make(fd, O_RDWR, p->offset, p->new_size, 0, 0, LOCK_EX, &d);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to make loopback device of future partition %" PRIu64 ": %m", p->partno);
|
||||
|
||||
@ -3646,13 +3646,13 @@ static int context_verity_hash(Context *context) {
|
||||
if (fd < 0)
|
||||
assert_se((fd = fdisk_get_devfd(context->fdisk_context)) >= 0);
|
||||
|
||||
r = loop_device_make(fd, O_RDONLY, dp->offset, dp->new_size, 0, LOCK_EX, &data_device);
|
||||
r = loop_device_make(fd, O_RDONLY, dp->offset, dp->new_size, 0, 0, LOCK_EX, &data_device);
|
||||
if (r < 0)
|
||||
return log_error_errno(r,
|
||||
"Failed to make loopback device of verity data partition %" PRIu64 ": %m",
|
||||
p->partno);
|
||||
|
||||
r = loop_device_make(fd, O_RDWR, p->offset, p->new_size, 0, LOCK_EX, &hash_device);
|
||||
r = loop_device_make(fd, O_RDWR, p->offset, p->new_size, 0, 0, LOCK_EX, &hash_device);
|
||||
if (r < 0)
|
||||
return log_error_errno(r,
|
||||
"Failed to make loopback device of verity hash partition %" PRIu64 ": %m",
|
||||
|
@ -123,6 +123,17 @@ static int loop_configure_verify(int fd, const struct loop_config *c) {
|
||||
assert(fd >= 0);
|
||||
assert(c);
|
||||
|
||||
if (c->block_size != 0) {
|
||||
int z;
|
||||
|
||||
if (ioctl(fd, BLKSSZGET, &z) < 0)
|
||||
return -errno;
|
||||
|
||||
assert(z >= 0);
|
||||
if ((uint32_t) z != c->block_size)
|
||||
log_debug("LOOP_CONFIGURE didn't honour requested block size %u, got %i instead. Ignoring.", c->block_size, z);
|
||||
}
|
||||
|
||||
if (c->info.lo_sizelimit != 0) {
|
||||
/* Kernel 5.8 vanilla doesn't properly propagate the size limit into the
|
||||
* block device. If it's used, let's immediately check if it had the desired
|
||||
@ -133,7 +144,7 @@ static int loop_configure_verify(int fd, const struct loop_config *c) {
|
||||
return -errno;
|
||||
|
||||
if (z != c->info.lo_sizelimit) {
|
||||
log_debug("LOOP_CONFIGURE is broken, doesn't honour .lo_sizelimit. Falling back to LOOP_SET_STATUS64.");
|
||||
log_debug("LOOP_CONFIGURE is broken, doesn't honour .info.lo_sizelimit. Falling back to LOOP_SET_STATUS64.");
|
||||
broken = true;
|
||||
}
|
||||
}
|
||||
@ -171,7 +182,7 @@ static int loop_configure_fallback(int fd, const struct loop_config *c) {
|
||||
info_copy.lo_flags &= LOOP_SET_STATUS_SETTABLE_FLAGS;
|
||||
|
||||
/* Since kernel commit 5db470e229e22b7eda6e23b5566e532c96fb5bc3 (kernel v5.0) the LOOP_SET_STATUS64
|
||||
* ioctl can return EAGAIN in case we change the lo_offset field, if someone else is accessing the
|
||||
* ioctl can return EAGAIN in case we change the info.lo_offset field, if someone else is accessing the
|
||||
* block device while we try to reconfigure it. This is a pretty common case, since udev might
|
||||
* instantly start probing the device as soon as we attach an fd to it. Hence handle it in two ways:
|
||||
* first, let's take the BSD lock to ensure that udev will not step in between the point in
|
||||
@ -391,6 +402,7 @@ static int loop_device_make_internal(
|
||||
int open_flags,
|
||||
uint64_t offset,
|
||||
uint64_t size,
|
||||
uint32_t block_size,
|
||||
uint32_t loop_flags,
|
||||
int lock_op,
|
||||
LoopDevice **ret) {
|
||||
@ -463,6 +475,7 @@ static int loop_device_make_internal(
|
||||
|
||||
config = (struct loop_config) {
|
||||
.fd = fd,
|
||||
.block_size = block_size,
|
||||
.info = {
|
||||
/* Use the specified flags, but configure the read-only flag from the open flags, and force autoclear */
|
||||
.lo_flags = (loop_flags & ~LO_FLAGS_READ_ONLY) | ((open_flags & O_ACCMODE) == O_RDONLY ? LO_FLAGS_READ_ONLY : 0) | LO_FLAGS_AUTOCLEAR,
|
||||
@ -546,6 +559,7 @@ int loop_device_make(
|
||||
int open_flags,
|
||||
uint64_t offset,
|
||||
uint64_t size,
|
||||
uint32_t block_size,
|
||||
uint32_t loop_flags,
|
||||
int lock_op,
|
||||
LoopDevice **ret) {
|
||||
@ -559,6 +573,7 @@ int loop_device_make(
|
||||
open_flags,
|
||||
offset,
|
||||
size,
|
||||
block_size,
|
||||
loop_flags_mangle(loop_flags),
|
||||
lock_op,
|
||||
ret);
|
||||
@ -622,7 +637,7 @@ int loop_device_make_by_path(
|
||||
direct ? "enabled" : "disabled",
|
||||
direct != (direct_flags != 0) ? " (O_DIRECT was requested but not supported)" : "");
|
||||
|
||||
return loop_device_make_internal(path, fd, open_flags, 0, 0, loop_flags, lock_op, ret);
|
||||
return loop_device_make_internal(path, fd, open_flags, 0, 0, 0, loop_flags, lock_op, ret);
|
||||
}
|
||||
|
||||
static LoopDevice* loop_device_free(LoopDevice *d) {
|
||||
|
@ -28,7 +28,7 @@ struct LoopDevice {
|
||||
/* Returns true if LoopDevice object is not actually a loopback device but some other block device we just wrap */
|
||||
#define LOOP_DEVICE_IS_FOREIGN(d) ((d)->nr < 0)
|
||||
|
||||
int loop_device_make(int fd, int open_flags, uint64_t offset, uint64_t size, uint32_t loop_flags, int lock_op, LoopDevice **ret);
|
||||
int loop_device_make(int fd, int open_flags, uint64_t offset, uint64_t size, uint32_t block_size, uint32_t loop_flags, int lock_op, LoopDevice **ret);
|
||||
int loop_device_make_by_path(const char *path, int open_flags, uint32_t loop_flags, int lock_op, LoopDevice **ret);
|
||||
int loop_device_open(sd_device *dev, int open_flags, int lock_op, LoopDevice **ret);
|
||||
int loop_device_open_from_fd(int fd, int open_flags, int lock_op, LoopDevice **ret);
|
||||
|
@ -321,6 +321,8 @@ void user_record_show(UserRecord *hr, bool show_full_group_info) {
|
||||
|
||||
if (hr->luks_pbkdf_parallel_threads != UINT64_MAX)
|
||||
printf("PBKDF Thread: %" PRIu64 "\n", hr->luks_pbkdf_parallel_threads);
|
||||
if (hr->luks_sector_size != UINT64_MAX)
|
||||
printf(" Sector Size: %" PRIu64 "\n", hr->luks_sector_size);
|
||||
|
||||
} else if (storage == USER_CIFS) {
|
||||
|
||||
|
@ -58,6 +58,7 @@ UserRecord* user_record_new(void) {
|
||||
.luks_pbkdf_time_cost_usec = UINT64_MAX,
|
||||
.luks_pbkdf_memory_cost = UINT64_MAX,
|
||||
.luks_pbkdf_parallel_threads = UINT64_MAX,
|
||||
.luks_sector_size = UINT64_MAX,
|
||||
.disk_usage = UINT64_MAX,
|
||||
.disk_free = UINT64_MAX,
|
||||
.disk_ceiling = UINT64_MAX,
|
||||
@ -1215,6 +1216,7 @@ static int dispatch_per_machine(const char *name, JsonVariant *variant, JsonDisp
|
||||
{ "luksPbkdfTimeCostUSec", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, luks_pbkdf_time_cost_usec), 0 },
|
||||
{ "luksPbkdfMemoryCost", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, luks_pbkdf_memory_cost), 0 },
|
||||
{ "luksPbkdfParallelThreads", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, luks_pbkdf_parallel_threads), 0 },
|
||||
{ "luksSectorSize", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, luks_sector_size), 0 },
|
||||
{ "luksExtraMountOptions", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, luks_extra_mount_options), 0 },
|
||||
{ "dropCaches", JSON_VARIANT_BOOLEAN, json_dispatch_tristate, offsetof(UserRecord, drop_caches), 0 },
|
||||
{ "autoResizeMode", _JSON_VARIANT_TYPE_INVALID, dispatch_auto_resize_mode, offsetof(UserRecord, auto_resize_mode), 0 },
|
||||
@ -1567,6 +1569,7 @@ int user_record_load(UserRecord *h, JsonVariant *v, UserRecordLoadFlags load_fla
|
||||
{ "luksPbkdfTimeCostUSec", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, luks_pbkdf_time_cost_usec), 0 },
|
||||
{ "luksPbkdfMemoryCost", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, luks_pbkdf_memory_cost), 0 },
|
||||
{ "luksPbkdfParallelThreads", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, luks_pbkdf_parallel_threads), 0 },
|
||||
{ "luksSectorSize", JSON_VARIANT_UNSIGNED, json_dispatch_uint64, offsetof(UserRecord, luks_sector_size), 0 },
|
||||
{ "luksExtraMountOptions", JSON_VARIANT_STRING, json_dispatch_string, offsetof(UserRecord, luks_extra_mount_options), 0 },
|
||||
{ "dropCaches", JSON_VARIANT_BOOLEAN, json_dispatch_tristate, offsetof(UserRecord, drop_caches), 0 },
|
||||
{ "autoResizeMode", _JSON_VARIANT_TYPE_INVALID, dispatch_auto_resize_mode, offsetof(UserRecord, auto_resize_mode), 0 },
|
||||
@ -1871,6 +1874,16 @@ uint64_t user_record_luks_pbkdf_parallel_threads(UserRecord *h) {
|
||||
return MIN(h->luks_pbkdf_parallel_threads, UINT32_MAX);
|
||||
}
|
||||
|
||||
uint64_t user_record_luks_sector_size(UserRecord *h) {
|
||||
assert(h);
|
||||
|
||||
if (h->luks_sector_size == UINT64_MAX)
|
||||
return 512;
|
||||
|
||||
/* Allow up to 4K due to dm-crypt support and 4K alignment by the homed LUKS backend */
|
||||
return CLAMP(UINT64_C(1) << (63 - __builtin_clzl(h->luks_sector_size)), 512U, 4096U);
|
||||
}
|
||||
|
||||
const char *user_record_luks_pbkdf_hash_algorithm(UserRecord *h) {
|
||||
assert(h);
|
||||
|
||||
|
@ -312,6 +312,7 @@ typedef struct UserRecord {
|
||||
uint64_t luks_pbkdf_time_cost_usec;
|
||||
uint64_t luks_pbkdf_memory_cost;
|
||||
uint64_t luks_pbkdf_parallel_threads;
|
||||
uint64_t luks_sector_size;
|
||||
char *luks_extra_mount_options;
|
||||
|
||||
uint64_t disk_usage;
|
||||
@ -396,6 +397,7 @@ const char* user_record_luks_pbkdf_type(UserRecord *h);
|
||||
usec_t user_record_luks_pbkdf_time_cost_usec(UserRecord *h);
|
||||
uint64_t user_record_luks_pbkdf_memory_cost(UserRecord *h);
|
||||
uint64_t user_record_luks_pbkdf_parallel_threads(UserRecord *h);
|
||||
uint64_t user_record_luks_sector_size(UserRecord *h);
|
||||
const char *user_record_luks_pbkdf_hash_algorithm(UserRecord *h);
|
||||
gid_t user_record_gid(UserRecord *h);
|
||||
UserDisposition user_record_disposition(UserRecord *h);
|
||||
|
@ -62,7 +62,7 @@ static void* thread_func(void *ptr) {
|
||||
|
||||
assert_se(mkdtemp_malloc(NULL, &mounted) >= 0);
|
||||
|
||||
r = loop_device_make(fd, O_RDONLY, 0, UINT64_MAX, LO_FLAGS_PARTSCAN, LOCK_SH, &loop);
|
||||
r = loop_device_make(fd, O_RDONLY, 0, UINT64_MAX, 0, LO_FLAGS_PARTSCAN, LOCK_SH, &loop);
|
||||
if (r < 0)
|
||||
log_error_errno(r, "Failed to allocate loopback device: %m");
|
||||
assert_se(r >= 0);
|
||||
@ -217,7 +217,7 @@ static int run(int argc, char *argv[]) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
assert_se(loop_device_make(fd, O_RDWR, 0, UINT64_MAX, LO_FLAGS_PARTSCAN, LOCK_EX, &loop) >= 0);
|
||||
assert_se(loop_device_make(fd, O_RDWR, 0, UINT64_MAX, 0, LO_FLAGS_PARTSCAN, LOCK_EX, &loop) >= 0);
|
||||
|
||||
#if HAVE_BLKID
|
||||
assert_se(dissect_loop_device(loop, NULL, NULL, 0, &dissected) >= 0);
|
||||
|
Loading…
Reference in New Issue
Block a user