diff --git a/lib/internal.h b/lib/internal.h index 38b99d91..ba3f8b37 100644 --- a/lib/internal.h +++ b/lib/internal.h @@ -116,6 +116,7 @@ void device_disable_direct_io(struct device *device); int device_is_identical(struct device *device1, struct device *device2); int device_is_rotational(struct device *device); int device_is_dax(struct device *device); +int device_is_zoned(struct device *device); size_t device_alignment(struct device *device); int device_direct_io(const struct device *device); int device_fallocate(struct device *device, uint64_t size); @@ -166,6 +167,7 @@ int crypt_confirm(struct crypt_device *cd, const char *msg); char *crypt_lookup_dev(const char *dev_id); int crypt_dev_is_rotational(int major, int minor); int crypt_dev_is_dax(int major, int minor); +int crypt_dev_is_zoned(int major, int minor); int crypt_dev_is_partition(const char *dev_path); char *crypt_get_partition_device(const char *dev_path, uint64_t offset, uint64_t size); int crypt_dev_get_partition_number(const char *dev_path); diff --git a/lib/setup.c b/lib/setup.c index 70b2ceec..5d530061 100644 --- a/lib/setup.c +++ b/lib/setup.c @@ -1790,6 +1790,12 @@ static int _crypt_format_luks1(struct crypt_device *cd, return -EINVAL; } + if (device_is_zoned(crypt_metadata_device(cd)) > 0) { + log_err(cd, _("Zoned device %s cannot be used for LUKS header."), + device_path(crypt_metadata_device(cd))); + return -EINVAL; + } + if (params && cd->data_offset && params->data_alignment && (cd->data_offset % params->data_alignment)) { log_err(cd, _("Requested data alignment is not compatible with data offset.")); @@ -2027,6 +2033,12 @@ static int _crypt_format_luks2(struct crypt_device *cd, return -EINVAL; } + if (device_is_zoned(crypt_metadata_device(cd)) > 0) { + log_err(cd, _("Zoned device %s cannot be used for LUKS header."), + device_path(crypt_metadata_device(cd))); + return -EINVAL; + } + if (params && cd->data_offset && params->data_alignment && (cd->data_offset % params->data_alignment)) { log_err(cd, _("Requested data alignment is not compatible with data offset.")); diff --git a/lib/utils_device.c b/lib/utils_device.c index 8bc329d3..4b2b3a5e 100644 --- a/lib/utils_device.c +++ b/lib/utils_device.c @@ -1007,6 +1007,22 @@ int device_is_dax(struct device *device) return crypt_dev_is_dax(major(st.st_rdev), minor(st.st_rdev)); } +int device_is_zoned(struct device *device) +{ + struct stat st; + + if (!device) + return -EINVAL; + + if (stat(device_path(device), &st) < 0) + return -EINVAL; + + if (!S_ISBLK(st.st_mode)) + return 0; + + return crypt_dev_is_zoned(major(st.st_rdev), minor(st.st_rdev)); +} + size_t device_alignment(struct device *device) { int devfd; diff --git a/lib/utils_devpath.c b/lib/utils_devpath.c index 5e7e13ec..ff37b980 100644 --- a/lib/utils_devpath.c +++ b/lib/utils_devpath.c @@ -210,6 +210,23 @@ static int _path_get_uint64(const char *sysfs_path, uint64_t *value, const char return _read_uint64(path, value); } +static int _sysfs_get_string(int major, int minor, char *buf, size_t buf_size, const char *attr) +{ + char path[PATH_MAX]; + int fd, r; + + if (snprintf(path, sizeof(path), "/sys/dev/block/%d:%d/%s", + major, minor, attr) < 0) + return 0; + + if ((fd = open(path, O_RDONLY)) < 0) + return 0; + r = read(fd, buf, buf_size); + close(fd); + + return r < 0 ? 0 : r; +} + int crypt_dev_get_partition_number(const char *dev_path) { uint64_t partno; @@ -248,6 +265,16 @@ int crypt_dev_is_dax(int major, int minor) return val ? 1 : 0; } +int crypt_dev_is_zoned(int major, int minor) +{ + char buf[32] = {}; + + if (!_sysfs_get_string(major, minor, buf, sizeof(buf), "queue/zoned")) + return 0; /* if failed, expect non-zoned device */ + + return strncmp(buf, "none", 4) ? 1 : 0; +} + int crypt_dev_is_partition(const char *dev_path) { uint64_t val; diff --git a/tests/compat-test2 b/tests/compat-test2 index 5a5875a2..c317e8eb 100755 --- a/tests/compat-test2 +++ b/tests/compat-test2 @@ -1604,5 +1604,16 @@ dmsetup resume $DEV_NAME || fail $CRYPTSETUP -q luksClose $DEV_NAME2 || fail dmsetup remove --retry $DEV_NAME || fail +prepare "[47] Zoned device is unusable for LUKS header" wipe +add_scsi_device dev_size_mb=32 sector_size=4096 zbc=host-managed +echo $PWD1 | $CRYPTSETUP luksFormat --type luks1 $FAST_PBKDF_OPT $DEV > /dev/null 2>&1 && fail +echo $PWD1 | $CRYPTSETUP luksFormat --type luks1 $FAST_PBKDF_OPT --header $HEADER_IMG $DEV >/dev/null || fail +echo $PWD1 | $CRYPTSETUP open --header $HEADER_IMG $DEV $DEV_NAME || fail +$CRYPTSETUP close $DEV_NAME || fail +echo $PWD1 | $CRYPTSETUP luksFormat --type luks2 $FAST_PBKDF_OPT $DEV > /dev/null 2>&1 && fail +echo $PWD1 | $CRYPTSETUP luksFormat --type luks2 $FAST_PBKDF_OPT --header $HEADER_IMG $DEV >/dev/null || fail +echo $PWD1 | $CRYPTSETUP open --header $HEADER_IMG $DEV $DEV_NAME || fail +$CRYPTSETUP close $DEV_NAME || fail + remove_mapping exit 0