loop: zero fill bio instead of return -EIO for partial read
PATCH 1/1 loop: zero fill bio instead of return -EIO for partial read
commit 8268f5a7415d914fc855a86aa2284ac819dc6b2e trying to fix the loop device partial read information leak problem. But it changed the semantics of read behavior. When we read beyond the end of the device we should get 0 bytes, which is normal behavior, we should not just return -EIO
Instead of return -EIO, zero out the bio to avoid information leak in case of partail read.
--- drivers/block/loop.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-)
drivers/block/loop.c +13 -11
@@ -357,14 +357,14 @@ lo_direct_splice_actor(struct pipe_inodereturn __splice_from_pipe (pipe, sd, lo_splice_actor); } -static int +static ssize_t do_lo_receive (struct loop_device *lo,struct bio_vec *bvec,int bsize,loff_t pos) {struct lo_read_data cookie;struct splice_desc sd;struct file *file; -long retval; +ssize_t retval; cookie.lo = lo; cookie.page = bvec->bv_page;
@@ -380,26 +380,28 @@ do_lo_receive(struct loop_device *lo, file = lo->lo_backing_file; retval =splice_direct_to_actor (file, &sd, lo_direct_splice_actor); -if (retval <0 ) -return retval; -if (retval != bvec->bv_len) -return -EIO ; -return 0 ; +return retval; }static int lo_receive (struct loop_device *lo,struct bio *bio,int bsize,loff_t pos) {struct bio_vec *bvec; -int i, ret =0 ; +ssize_t s; +int i;bio_for_each_segment (bvec, bio, i) { - ret =do_lo_receive (lo, bvec, bsize, pos); -if (ret <0 ) + s =do_lo_receive (lo, bvec, bsize, pos); +if (s <0 ) +return s; + +if (s != bvec->bv_len) { +zero_fill_bio (bio);break ; + } pos += bvec->bv_len; } -return ret; +return 0 ; }static int do_bio_filebacked (struct loop_device *lo,struct bio *bio)
Quoted 7 lines · Dave Young
commit
8268f5a7415d914fc855a86aa2284ac819dc6b2etrying to fix the loop device partial read information leak problem. But it changed the semantics of read behavior. When we read beyond the end of the device we should get 0 bytes, which is normal behavior, we should not just return-EIOInstead of return
-EIO, zero out the bio to avoid information leak in case of partail read.
I tested the patch with a program which patterns the loop device, truncates the backing file, and then performs preads from various offsets within the loop device, validates the return values and inspects the contents. With this patch, everything works as expected.
By the way, truncating the backing file for a loop device is insane. Why would you do that? Also, if you really want all of the data gone, you'll have to flush the contents of the buffer cache for the loop device first. It's quite the head scratcher the first time you truncate a file, wait a few seconds, and then witness the file size grow. ;-)
Quoted 63 lines
Signed-off-by Dave Young <[email protected]>--- drivers/block/loop.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-)drivers/block/loop.c +13
-11@@ -357,14 +357,14 @@ lo_direct_splice_actor(struct pipe_inodereturn __splice_from_pipe (pipe, sd, lo_splice_actor); } -static int +static ssize_t do_lo_receive (struct loop_device *lo,struct bio_vec *bvec,int bsize,loff_t pos) {struct lo_read_data cookie;struct splice_desc sd;struct file *file; -long retval; +ssize_t retval; cookie.lo = lo; cookie.page = bvec->bv_page;@@ -380,26 +380,28 @@ do_lo_receive(struct loop_device *lo, file = lo->lo_backing_file; retval =splice_direct_to_actor (file, &sd, lo_direct_splice_actor); -if (retval <0 ) -return retval; -if (retval != bvec->bv_len) -return -EIO ; -return 0 ; +return retval; }static int lo_receive (struct loop_device *lo,struct bio *bio,int bsize,loff_t pos) {struct bio_vec *bvec; -int i, ret =0 ; +ssize_t s; +int i;bio_for_each_segment (bvec, bio, i) { - ret =do_lo_receive (lo, bvec, bsize, pos); -if (ret <0 ) + s =do_lo_receive (lo, bvec, bsize, pos); +if (s <0 ) +return s; + +if (s != bvec->bv_len) { +zero_fill_bio (bio);break ; + } pos += bvec->bv_len; } -return ret; +return 0 ; }static int do_bio_filebacked (struct loop_device *lo,struct bio *bio)
Quoted 7 lines · Jeff Moyer
Quoted 5 lines · Dave Young
commit
8268f5a7415d914fc855a86aa2284ac819dc6b2etrying to fix the loop device partial read information leak problem. But it changed the semantics of read behavior. When we read beyond the end of the device we should get 0 bytes, which is normal behavior, we should not just return-EIO
Quoted 7 lines
Quoted 2 lines
Instead of return
-EIO, zero out the bio to avoid information leak in case of partail read.I tested the patch with a program which patterns the loop device, truncates the backing file, and then performs preads from various offsets within the loop device, validates the return values and inspects the contents. With this patch, everything works as expected.
Many thanks for review and test
Quoted 6 lines
By the way, truncating the backing file for a loop device is insane. Why would you do that? Also, if you really want all of the data gone, you'll have to flush the contents of the buffer cache for the loop device first. It's quite the head scratcher the first time you truncate a file, wait a few seconds, and then witness the file size grow. ;-)
I think nobody will intend to do that, but random operations could cause this happen..
Quoted 66 lines
Reviewed-by Jeff Moyer <[email protected]>Quoted 63 lines
Signed-off-by Dave Young <[email protected]>--- drivers/block/loop.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-)drivers/block/loop.c +13
-11@@ -357,14 +357,14 @@ lo_direct_splice_actor(struct pipe_inodereturn __splice_from_pipe (pipe, sd, lo_splice_actor); } -static int +static ssize_t do_lo_receive (struct loop_device *lo,struct bio_vec *bvec,int bsize,loff_t pos) {struct lo_read_data cookie;struct splice_desc sd;struct file *file; -long retval; +ssize_t retval; cookie.lo = lo; cookie.page = bvec->bv_page;@@ -380,26 +380,28 @@ do_lo_receive(struct loop_device *lo, file = lo->lo_backing_file; retval =splice_direct_to_actor (file, &sd, lo_direct_splice_actor); -if (retval <0 ) -return retval; -if (retval != bvec->bv_len) -return -EIO ; -return 0 ; +return retval; }static int lo_receive (struct loop_device *lo,struct bio *bio,int bsize,loff_t pos) {struct bio_vec *bvec; -int i, ret =0 ; +ssize_t s; +int i;bio_for_each_segment (bvec, bio, i) { - ret =do_lo_receive (lo, bvec, bsize, pos); -if (ret <0 ) + s =do_lo_receive (lo, bvec, bsize, pos); +if (s <0 ) +return s; + +if (s != bvec->bv_len) { +zero_fill_bio (bio);break ; + } pos += bvec->bv_len; } -return ret; +return 0 ; }static int do_bio_filebacked (struct loop_device *lo,struct bio *bio)
Signature · 2 lines
Thanks Dave
Quoted 96 lines · Dave Young
Quoted 7 lines · Jeff Moyer
Quoted 5 lines · Dave Young
commit
8268f5a7415d914fc855a86aa2284ac819dc6b2etrying to fix the loop device partial read information leak problem. But it changed the semantics of read behavior. When we read beyond the end of the device we should get 0 bytes, which is normal behavior, we should not just return-EIOQuoted 7 lines
Quoted 2 lines
Instead of return
-EIO, zero out the bio to avoid information leak in case of partail read.I tested the patch with a program which patterns the loop device, truncates the backing file, and then performs preads from various offsets within the loop device, validates the return values and inspects the contents. With this patch, everything works as expected.
Many thanks for review and test
Quoted 6 lines
By the way, truncating the backing file for a loop device is insane. Why would you do that? Also, if you really want all of the data gone, you'll have to flush the contents of the buffer cache for the loop device first. It's quite the head scratcher the first time you truncate a file, wait a few seconds, and then witness the file size grow. ;-)
I think nobody will intend to do that, but random operations could cause this happen..
Quoted 65 lines
Reviewed-by Jeff Moyer <[email protected]>Quoted 62 lines
Signed-off-by Dave Young <[email protected]>--- drivers/block/loop.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-)drivers/block/loop.c +13
-11@@ -357,14 +357,14 @@ lo_direct_splice_actor(struct pipe_inodereturn __splice_from_pipe (pipe, sd, lo_splice_actor); } -static int +static ssize_t do_lo_receive (struct loop_device *lo,struct bio_vec *bvec,int bsize,loff_t pos) {struct lo_read_data cookie;struct splice_desc sd;struct file *file; -long retval; +ssize_t retval; cookie.lo = lo; cookie.page = bvec->bv_page;@@ -380,26 +380,28 @@ do_lo_receive(struct loop_device *lo, file = lo->lo_backing_file; retval =splice_direct_to_actor (file, &sd, lo_direct_splice_actor); -if (retval <0 ) -return retval; -if (retval != bvec->bv_len) -return -EIO ; -return 0 ; +return retval; }static int lo_receive (struct loop_device *lo,struct bio *bio,int bsize,loff_t pos) {struct bio_vec *bvec; -int i, ret =0 ; +ssize_t s; +int i;bio_for_each_segment (bvec, bio, i) { - ret =do_lo_receive (lo, bvec, bsize, pos); -if (ret <0 ) + s =do_lo_receive (lo, bvec, bsize, pos); +if (s <0 ) +return s; + +if (s != bvec->bv_len) { +zero_fill_bio (bio);break ; + } pos += bvec->bv_len; } -return ret; +return 0 ; }
Quoted 4 lines
Quoted 1 line
drivers/block/loop.c do_lo_receive(struct loop_device *lo, · line 407
Quoted 1 line
drivers/block/loop.c +0
-0static int do_bio_filebacked (struct loop_device *lo,struct bio *bio)
Jens, what do you think about this patch? Could you take this?
Signature · 2 lines
Thanks Dave