Commit 29681c0a authored by Milan Broz's avatar Milan Broz

Fix access to devices under non-root user.

We cannot allocate loop device early in luksFormat,
use only device access check here.
parent fdd6794c
......@@ -82,6 +82,9 @@ int device_is_rotational(struct device *device);
size_t device_alignment(struct device *device);
enum devcheck { DEV_OK = 0, DEV_EXCL = 1, DEV_SHARED = 2 };
int device_check_access(struct crypt_device *cd,
struct device *device,
enum devcheck device_check);
int device_block_adjust(struct crypt_device *cd,
struct device *device,
enum devcheck device_check,
......
......@@ -1042,7 +1042,7 @@ static int _crypt_format_luks1(struct crypt_device *cd,
if (r < 0)
return r;
r = device_block_adjust(cd, crypt_metadata_device(cd), DEV_EXCL, 0, NULL, NULL);
r = device_check_access(cd, crypt_metadata_device(cd), DEV_EXCL);
if (r < 0)
return r;
......@@ -1235,7 +1235,7 @@ static int _crypt_format_integrity(struct crypt_device *cd,
return -EINVAL;
}
r = device_block_adjust(cd, crypt_metadata_device(cd), DEV_EXCL, 0, NULL, NULL);
r = device_check_access(cd, crypt_metadata_device(cd), DEV_EXCL);
if (r < 0)
return r;
......
......@@ -396,18 +396,27 @@ out:
return r;
}
static int device_info(struct device *device,
enum devcheck device_check,
int *readonly, uint64_t *size)
static int device_info(struct crypt_device *cd,
struct device *device,
enum devcheck device_check,
int *readonly, uint64_t *size)
{
struct stat st;
int fd, r = -EINVAL, flags = 0;
int fd = -1, r, flags = 0, real_readonly;
uint64_t real_size;
*readonly = 0;
*size = 0;
if (!device) {
r = -ENOTBLK;
goto out;
}
if (stat(device->path, &st) < 0)
return -EINVAL;
real_readonly = 0;
real_size = 0;
if (stat(device->path, &st) < 0) {
r = -EINVAL;
goto out;
}
/* never wipe header on mounted device */
if (device_check == DEV_EXCL && S_ISBLK(st.st_mode))
......@@ -417,40 +426,71 @@ static int device_info(struct device *device,
/* coverity[toctou] */
fd = open(device->path, O_RDWR | flags);
if (fd == -1 && errno == EROFS) {
*readonly = 1;
real_readonly = 1;
fd = open(device->path, O_RDONLY | flags);
}
if (fd == -1 && device_check == DEV_EXCL && errno == EBUSY)
return -EBUSY;
if (fd == -1 && device_check == DEV_EXCL && errno == EBUSY) {
r = -EBUSY;
goto out;
}
if (fd == -1)
return -EINVAL;
if (fd == -1) {
r = -EINVAL;
goto out;
}
r = 0;
if (S_ISREG(st.st_mode)) {
//FIXME: add readonly check
*size = (uint64_t)st.st_size;
*size >>= SECTOR_SHIFT;
real_size = (uint64_t)st.st_size;
real_size >>= SECTOR_SHIFT;
} else {
/* If the device can be opened read-write, i.e. readonly is still 0, then
* check whether BKROGET says that it is read-only. E.g. read-only loop
* devices may be openend read-write but are read-only according to BLKROGET
*/
if (*readonly == 0 && (r = ioctl(fd, BLKROGET, readonly)) < 0)
if (real_readonly == 0 && (r = ioctl(fd, BLKROGET, &real_readonly)) < 0)
goto out;
if (ioctl(fd, BLKGETSIZE64, size) >= 0) {
*size >>= SECTOR_SHIFT;
r = 0;
r = ioctl(fd, BLKGETSIZE64, &real_size);
if (r >= 0) {
real_size >>= SECTOR_SHIFT;
goto out;
}
}
r = -EINVAL;
out:
close(fd);
if (fd != -1)
close(fd);
switch (r) {
case 0:
if (readonly)
*readonly = real_readonly;
if (size)
*size = real_size;
break;
case -EBUSY:
log_err(cd, _("Cannot use device %s which is in use "
"(already mapped or mounted).\n"), device->path);
break;
case -EACCES:
log_err(cd, _("Cannot use device %s, permission denied.\n"), device->path);
break;
default:
log_err(cd, _("Cannot get info about device %s.\n"), device->path);
}
return r;
}
int device_check_access(struct crypt_device *cd,
struct device *device,
enum devcheck device_check)
{
return device_info(cd, device, device_check, NULL, NULL);
}
static int device_internal_prepare(struct crypt_device *cd, struct device *device)
{
char *loop_device = NULL, *file_path = NULL;
......@@ -511,20 +551,9 @@ int device_block_adjust(struct crypt_device *cd,
if (r)
return r;
r = device_info(device, device_check, &real_readonly, &real_size);
if (r < 0) {
if (r == -EBUSY)
log_err(cd, _("Cannot use device %s which is in use "
"(already mapped or mounted).\n"),
device->path);
else if (r == -EACCES)
log_err(cd, _("Cannot use device %s, permission denied.\n"),
device->path);
else
log_err(cd, _("Cannot get info about device %s.\n"),
device->path);
r = device_info(cd, device, device_check, &real_readonly, &real_size);
if (r)
return r;
}
if (device_offset >= real_size) {
log_err(cd, _("Requested offset is beyond real size of device %s.\n"),
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment