|
@@ -161,17 +161,19 @@ static struct loop_func_table *xfer_funcs[MAX_LO_CRYPT] = {
|
|
&xor_funcs
|
|
&xor_funcs
|
|
};
|
|
};
|
|
|
|
|
|
-static loff_t get_loop_size(struct loop_device *lo, struct file *file)
|
|
|
|
|
|
+static loff_t get_size(loff_t offset, loff_t sizelimit, struct file *file)
|
|
{
|
|
{
|
|
- loff_t size, offset, loopsize;
|
|
|
|
|
|
+ loff_t size, loopsize;
|
|
|
|
|
|
/* Compute loopsize in bytes */
|
|
/* Compute loopsize in bytes */
|
|
size = i_size_read(file->f_mapping->host);
|
|
size = i_size_read(file->f_mapping->host);
|
|
- offset = lo->lo_offset;
|
|
|
|
loopsize = size - offset;
|
|
loopsize = size - offset;
|
|
- if (lo->lo_sizelimit > 0 && lo->lo_sizelimit < loopsize)
|
|
|
|
- loopsize = lo->lo_sizelimit;
|
|
|
|
|
|
+ /* offset is beyond i_size, wierd but possible */
|
|
|
|
+ if (loopsize < 0)
|
|
|
|
+ return 0;
|
|
|
|
|
|
|
|
+ if (sizelimit > 0 && sizelimit < loopsize)
|
|
|
|
+ loopsize = sizelimit;
|
|
/*
|
|
/*
|
|
* Unfortunately, if we want to do I/O on the device,
|
|
* Unfortunately, if we want to do I/O on the device,
|
|
* the number of 512-byte sectors has to fit into a sector_t.
|
|
* the number of 512-byte sectors has to fit into a sector_t.
|
|
@@ -179,17 +181,25 @@ static loff_t get_loop_size(struct loop_device *lo, struct file *file)
|
|
return loopsize >> 9;
|
|
return loopsize >> 9;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static loff_t get_loop_size(struct loop_device *lo, struct file *file)
|
|
|
|
+{
|
|
|
|
+ return get_size(lo->lo_offset, lo->lo_sizelimit, file);
|
|
|
|
+}
|
|
|
|
+
|
|
static int
|
|
static int
|
|
-figure_loop_size(struct loop_device *lo)
|
|
|
|
|
|
+figure_loop_size(struct loop_device *lo, loff_t offset, loff_t sizelimit)
|
|
{
|
|
{
|
|
- loff_t size = get_loop_size(lo, lo->lo_backing_file);
|
|
|
|
|
|
+ loff_t size = get_size(offset, sizelimit, lo->lo_backing_file);
|
|
sector_t x = (sector_t)size;
|
|
sector_t x = (sector_t)size;
|
|
|
|
|
|
if (unlikely((loff_t)x != size))
|
|
if (unlikely((loff_t)x != size))
|
|
return -EFBIG;
|
|
return -EFBIG;
|
|
-
|
|
|
|
|
|
+ if (lo->lo_offset != offset)
|
|
|
|
+ lo->lo_offset = offset;
|
|
|
|
+ if (lo->lo_sizelimit != sizelimit)
|
|
|
|
+ lo->lo_sizelimit = sizelimit;
|
|
set_capacity(lo->lo_disk, x);
|
|
set_capacity(lo->lo_disk, x);
|
|
- return 0;
|
|
|
|
|
|
+ return 0;
|
|
}
|
|
}
|
|
|
|
|
|
static inline int
|
|
static inline int
|
|
@@ -1059,9 +1069,7 @@ loop_set_status(struct loop_device *lo, const struct loop_info64 *info)
|
|
|
|
|
|
if (lo->lo_offset != info->lo_offset ||
|
|
if (lo->lo_offset != info->lo_offset ||
|
|
lo->lo_sizelimit != info->lo_sizelimit) {
|
|
lo->lo_sizelimit != info->lo_sizelimit) {
|
|
- lo->lo_offset = info->lo_offset;
|
|
|
|
- lo->lo_sizelimit = info->lo_sizelimit;
|
|
|
|
- if (figure_loop_size(lo))
|
|
|
|
|
|
+ if (figure_loop_size(lo, info->lo_offset, info->lo_sizelimit))
|
|
return -EFBIG;
|
|
return -EFBIG;
|
|
}
|
|
}
|
|
loop_config_discard(lo);
|
|
loop_config_discard(lo);
|
|
@@ -1247,7 +1255,7 @@ static int loop_set_capacity(struct loop_device *lo, struct block_device *bdev)
|
|
err = -ENXIO;
|
|
err = -ENXIO;
|
|
if (unlikely(lo->lo_state != Lo_bound))
|
|
if (unlikely(lo->lo_state != Lo_bound))
|
|
goto out;
|
|
goto out;
|
|
- err = figure_loop_size(lo);
|
|
|
|
|
|
+ err = figure_loop_size(lo, lo->lo_offset, lo->lo_sizelimit);
|
|
if (unlikely(err))
|
|
if (unlikely(err))
|
|
goto out;
|
|
goto out;
|
|
sec = get_capacity(lo->lo_disk);
|
|
sec = get_capacity(lo->lo_disk);
|
|
@@ -1285,13 +1293,19 @@ static int lo_ioctl(struct block_device *bdev, fmode_t mode,
|
|
goto out_unlocked;
|
|
goto out_unlocked;
|
|
break;
|
|
break;
|
|
case LOOP_SET_STATUS:
|
|
case LOOP_SET_STATUS:
|
|
- err = loop_set_status_old(lo, (struct loop_info __user *) arg);
|
|
|
|
|
|
+ err = -EPERM;
|
|
|
|
+ if ((mode & FMODE_WRITE) || capable(CAP_SYS_ADMIN))
|
|
|
|
+ err = loop_set_status_old(lo,
|
|
|
|
+ (struct loop_info __user *)arg);
|
|
break;
|
|
break;
|
|
case LOOP_GET_STATUS:
|
|
case LOOP_GET_STATUS:
|
|
err = loop_get_status_old(lo, (struct loop_info __user *) arg);
|
|
err = loop_get_status_old(lo, (struct loop_info __user *) arg);
|
|
break;
|
|
break;
|
|
case LOOP_SET_STATUS64:
|
|
case LOOP_SET_STATUS64:
|
|
- err = loop_set_status64(lo, (struct loop_info64 __user *) arg);
|
|
|
|
|
|
+ err = -EPERM;
|
|
|
|
+ if ((mode & FMODE_WRITE) || capable(CAP_SYS_ADMIN))
|
|
|
|
+ err = loop_set_status64(lo,
|
|
|
|
+ (struct loop_info64 __user *) arg);
|
|
break;
|
|
break;
|
|
case LOOP_GET_STATUS64:
|
|
case LOOP_GET_STATUS64:
|
|
err = loop_get_status64(lo, (struct loop_info64 __user *) arg);
|
|
err = loop_get_status64(lo, (struct loop_info64 __user *) arg);
|