* [RFC PATCH] dm: Check for device sector overflow if CONFIG_LBDAF is not set @ 2018-11-04 13:42 Milan Broz 2018-11-05 18:35 ` Mikulas Patocka 0 siblings, 1 reply; 6+ messages in thread From: Milan Broz @ 2018-11-04 13:42 UTC (permalink / raw) To: dm-devel; +Cc: mpatocka, Milan Broz, snitzer Reference to a device in device-mapper table contains offset in sectors. If the sector_t is 32bit integer (CONFIG_LBDAF is not set), then several device-mapper targets can overflow this offset and validity check is then performad on wrong offset and wrong table is activated. See for example (on 32bit without CONFIG_LBDAF) this overflow: # dmsetup create test --table "0 2048 linear /dev/sdg 4294967297" # dmsetup table test 0 2048 linear 8:96 1 In this patch I tried to add check for this problem to dm-linear and dm-crypt, but I am sure there are more places and I am not sure this is the proper way. Should we use uint64_t in DM internally for device offset instead? There are probably some internal calculations in dm-table.c that can overflow as well. NOTE: it is a RFC patch that is incomplete (more targets need fixes). Signed-off-by: Milan Broz <gmazyland@gmail.com> --- drivers/md/dm-crypt.c | 4 ++++ drivers/md/dm-linear.c | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index 49be7a6a2e81..008fc40ef84b 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c @@ -2786,6 +2786,10 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) goto bad; } cc->start = tmpll; + if (sizeof(cc->start) < sizeof(tmpll) && cc->start != tmpll) { + ti->error = "Device sector overflow"; + goto bad; + } if (crypt_integrity_aead(cc) || cc->integrity_iv_size) { ret = crypt_integrity_ctr(cc, ti); diff --git a/drivers/md/dm-linear.c b/drivers/md/dm-linear.c index 8d7ddee6ac4d..b5a0065d1436 100644 --- a/drivers/md/dm-linear.c +++ b/drivers/md/dm-linear.c @@ -50,6 +50,10 @@ static int linear_ctr(struct dm_target *ti, unsigned int argc, char **argv) goto bad; } lc->start = tmp; + if (sizeof(lc->start) < sizeof(tmp) && lc->start != tmp) { + ti->error = "Device sector overflow"; + goto bad; + } ret = dm_get_device(ti, argv[0], dm_table_get_mode(ti->table), &lc->dev); if (ret) { -- 2.19.1 ^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [RFC PATCH] dm: Check for device sector overflow if CONFIG_LBDAF is not set 2018-11-04 13:42 [RFC PATCH] dm: Check for device sector overflow if CONFIG_LBDAF is not set Milan Broz @ 2018-11-05 18:35 ` Mikulas Patocka 2018-11-05 18:59 ` Milan Broz 0 siblings, 1 reply; 6+ messages in thread From: Mikulas Patocka @ 2018-11-05 18:35 UTC (permalink / raw) To: Milan Broz; +Cc: dm-devel, snitzer On Sun, 4 Nov 2018, Milan Broz wrote: > Reference to a device in device-mapper table contains offset in sectors. > > If the sector_t is 32bit integer (CONFIG_LBDAF is not set), then > several device-mapper targets can overflow this offset and validity > check is then performad on wrong offset and wrong table is activated. > > See for example (on 32bit without CONFIG_LBDAF) this overflow: > > # dmsetup create test --table "0 2048 linear /dev/sdg 4294967297" > # dmsetup table test > 0 2048 linear 8:96 1 > > In this patch I tried to add check for this problem to dm-linear and dm-crypt, > but I am sure there are more places and I am not sure this is the proper way. > > Should we use uint64_t in DM internally for device offset instead? > > There are probably some internal calculations in dm-table.c that > can overflow as well. > > NOTE: it is a RFC patch that is incomplete (more targets need fixes). OK. But the condition "sizeof(cc->start) < sizeof(tmpll)" could be dropped, the compiler will optimize out "cc->start != tmpll" if the types have the same width. Mikulas > Signed-off-by: Milan Broz <gmazyland@gmail.com> > --- > drivers/md/dm-crypt.c | 4 ++++ > drivers/md/dm-linear.c | 4 ++++ > 2 files changed, 8 insertions(+) > > diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c > index 49be7a6a2e81..008fc40ef84b 100644 > --- a/drivers/md/dm-crypt.c > +++ b/drivers/md/dm-crypt.c > @@ -2786,6 +2786,10 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) > goto bad; > } > cc->start = tmpll; > + if (sizeof(cc->start) < sizeof(tmpll) && cc->start != tmpll) { > + ti->error = "Device sector overflow"; > + goto bad; > + } > > if (crypt_integrity_aead(cc) || cc->integrity_iv_size) { > ret = crypt_integrity_ctr(cc, ti); > diff --git a/drivers/md/dm-linear.c b/drivers/md/dm-linear.c > index 8d7ddee6ac4d..b5a0065d1436 100644 > --- a/drivers/md/dm-linear.c > +++ b/drivers/md/dm-linear.c > @@ -50,6 +50,10 @@ static int linear_ctr(struct dm_target *ti, unsigned int argc, char **argv) > goto bad; > } > lc->start = tmp; > + if (sizeof(lc->start) < sizeof(tmp) && lc->start != tmp) { > + ti->error = "Device sector overflow"; > + goto bad; > + } > > ret = dm_get_device(ti, argv[0], dm_table_get_mode(ti->table), &lc->dev); > if (ret) { > -- > 2.19.1 > ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [RFC PATCH] dm: Check for device sector overflow if CONFIG_LBDAF is not set 2018-11-05 18:35 ` Mikulas Patocka @ 2018-11-05 18:59 ` Milan Broz 2018-11-06 21:44 ` Mikulas Patocka 0 siblings, 1 reply; 6+ messages in thread From: Milan Broz @ 2018-11-05 18:59 UTC (permalink / raw) To: Mikulas Patocka, Milan Broz; +Cc: dm-devel, snitzer On 05/11/2018 19:35, Mikulas Patocka wrote: > But the condition "sizeof(cc->start) < sizeof(tmpll)" could be dropped, > the compiler will optimize out "cc->start != tmpll" if the types have the > same width. Yes, the intention here is that in 64bit env. the whole if condition is not compiled in. If it happens without "sizeof(cc->start) < sizeof(tmpll)", then we can drop it. So, does it make sense to add this to all dm targets? Or any better idea? Milan ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [RFC PATCH] dm: Check for device sector overflow if CONFIG_LBDAF is not set 2018-11-05 18:59 ` Milan Broz @ 2018-11-06 21:44 ` Mikulas Patocka 2018-11-07 21:24 ` [PATCH v2] " Milan Broz 0 siblings, 1 reply; 6+ messages in thread From: Mikulas Patocka @ 2018-11-06 21:44 UTC (permalink / raw) To: Milan Broz; +Cc: dm-devel, snitzer On Mon, 5 Nov 2018, Milan Broz wrote: > On 05/11/2018 19:35, Mikulas Patocka wrote: > > But the condition "sizeof(cc->start) < sizeof(tmpll)" could be dropped, > > the compiler will optimize out "cc->start != tmpll" if the types have the > > same width. > > Yes, the intention here is that in 64bit env. the whole if condition > is not compiled in. If it happens without "sizeof(cc->start) < sizeof(tmpll)", > then we can drop it. > > So, does it make sense to add this to all dm targets? Or any better idea? > > Milan In the targets that I have written, I tried to protect against this: if (sscanf(argv[1], "%llu%c", &start, &dummy) != 1 || start != (sector_t)start) ic->provided_data_sectors = le64_to_cpu(ic->sb->provided_data_sectors) if (ic->provided_data_sectors != le64_to_cpu(ic->sb->provided_data_sectors)) { wc->start_sector = start_sector; if (wc->start_sector != start_sector If you find some more unprotected cases, it's OK to convert them. Mikulas ^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v2] dm: Check for device sector overflow if CONFIG_LBDAF is not set 2018-11-06 21:44 ` Mikulas Patocka @ 2018-11-07 21:24 ` Milan Broz 2018-11-15 13:20 ` Mikulas Patocka 0 siblings, 1 reply; 6+ messages in thread From: Milan Broz @ 2018-11-07 21:24 UTC (permalink / raw) To: dm-devel; +Cc: mpatocka, Milan Broz, snitzer Reference to a device in device-mapper table contains offset in sectors. If the sector_t is 32bit integer (CONFIG_LBDAF is not set), then several device-mapper targets can overflow this offset and validity check is then performed on a wrong offset and a wrong table is activated. See for example (on 32bit without CONFIG_LBDAF) this overflow: # dmsetup create test --table "0 2048 linear /dev/sdg 4294967297" # dmsetup table test 0 2048 linear 8:96 1 This patch adds explicit check for overflow if the offset is sector_t type. Signed-off-by: Milan Broz <gmazyland@gmail.com> --- drivers/md/dm-crypt.c | 2 +- drivers/md/dm-delay.c | 2 +- drivers/md/dm-flakey.c | 2 +- drivers/md/dm-linear.c | 2 +- drivers/md/dm-raid1.c | 3 ++- drivers/md/dm-unstripe.c | 2 +- 6 files changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c index 49be7a6a2e81..a41fe7975dc6 100644 --- a/drivers/md/dm-crypt.c +++ b/drivers/md/dm-crypt.c @@ -2781,7 +2781,7 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) } ret = -EINVAL; - if (sscanf(argv[4], "%llu%c", &tmpll, &dummy) != 1) { + if (sscanf(argv[4], "%llu%c", &tmpll, &dummy) != 1 || tmpll != (sector_t)tmpll) { ti->error = "Invalid device sector"; goto bad; } diff --git a/drivers/md/dm-delay.c b/drivers/md/dm-delay.c index 2fb7bb4304ad..fddffe251bf6 100644 --- a/drivers/md/dm-delay.c +++ b/drivers/md/dm-delay.c @@ -141,7 +141,7 @@ static int delay_class_ctr(struct dm_target *ti, struct delay_class *c, char **a unsigned long long tmpll; char dummy; - if (sscanf(argv[1], "%llu%c", &tmpll, &dummy) != 1) { + if (sscanf(argv[1], "%llu%c", &tmpll, &dummy) != 1 || tmpll != (sector_t)tmpll) { ti->error = "Invalid device sector"; return -EINVAL; } diff --git a/drivers/md/dm-flakey.c b/drivers/md/dm-flakey.c index 3cb97fa4c11d..8261aa8c7fe1 100644 --- a/drivers/md/dm-flakey.c +++ b/drivers/md/dm-flakey.c @@ -213,7 +213,7 @@ static int flakey_ctr(struct dm_target *ti, unsigned int argc, char **argv) devname = dm_shift_arg(&as); r = -EINVAL; - if (sscanf(dm_shift_arg(&as), "%llu%c", &tmpll, &dummy) != 1) { + if (sscanf(dm_shift_arg(&as), "%llu%c", &tmpll, &dummy) != 1 || tmpll != (sector_t)tmpll) { ti->error = "Invalid device sector"; goto bad; } diff --git a/drivers/md/dm-linear.c b/drivers/md/dm-linear.c index 8d7ddee6ac4d..ad980a38fb1e 100644 --- a/drivers/md/dm-linear.c +++ b/drivers/md/dm-linear.c @@ -45,7 +45,7 @@ static int linear_ctr(struct dm_target *ti, unsigned int argc, char **argv) } ret = -EINVAL; - if (sscanf(argv[1], "%llu%c", &tmp, &dummy) != 1) { + if (sscanf(argv[1], "%llu%c", &tmp, &dummy) != 1 || tmp != (sector_t)tmp) { ti->error = "Invalid device sector"; goto bad; } diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c index 79eab1071ec2..5a51151f680d 100644 --- a/drivers/md/dm-raid1.c +++ b/drivers/md/dm-raid1.c @@ -943,7 +943,8 @@ static int get_mirror(struct mirror_set *ms, struct dm_target *ti, char dummy; int ret; - if (sscanf(argv[1], "%llu%c", &offset, &dummy) != 1) { + if (sscanf(argv[1], "%llu%c", &offset, &dummy) != 1 || + offset != (sector_t)offset) { ti->error = "Invalid offset"; return -EINVAL; } diff --git a/drivers/md/dm-unstripe.c b/drivers/md/dm-unstripe.c index 954b7ab4e684..e673dacf6418 100644 --- a/drivers/md/dm-unstripe.c +++ b/drivers/md/dm-unstripe.c @@ -78,7 +78,7 @@ static int unstripe_ctr(struct dm_target *ti, unsigned int argc, char **argv) goto err; } - if (sscanf(argv[4], "%llu%c", &start, &dummy) != 1) { + if (sscanf(argv[4], "%llu%c", &start, &dummy) != 1 || start != (sector_t)start) { ti->error = "Invalid striped device offset"; goto err; } -- 2.19.1 ^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH v2] dm: Check for device sector overflow if CONFIG_LBDAF is not set 2018-11-07 21:24 ` [PATCH v2] " Milan Broz @ 2018-11-15 13:20 ` Mikulas Patocka 0 siblings, 0 replies; 6+ messages in thread From: Mikulas Patocka @ 2018-11-15 13:20 UTC (permalink / raw) To: Milan Broz; +Cc: dm-devel, snitzer On Wed, 7 Nov 2018, Milan Broz wrote: > Reference to a device in device-mapper table contains offset in sectors. > > If the sector_t is 32bit integer (CONFIG_LBDAF is not set), then > several device-mapper targets can overflow this offset and validity > check is then performed on a wrong offset and a wrong table is activated. > > See for example (on 32bit without CONFIG_LBDAF) this overflow: > > # dmsetup create test --table "0 2048 linear /dev/sdg 4294967297" > # dmsetup table test > 0 2048 linear 8:96 1 > > This patch adds explicit check for overflow if the offset is sector_t type. > > Signed-off-by: Milan Broz <gmazyland@gmail.com> Reviewed-by: Mikulas Patocka <mpatocka@redhat.com> > --- > drivers/md/dm-crypt.c | 2 +- > drivers/md/dm-delay.c | 2 +- > drivers/md/dm-flakey.c | 2 +- > drivers/md/dm-linear.c | 2 +- > drivers/md/dm-raid1.c | 3 ++- > drivers/md/dm-unstripe.c | 2 +- > 6 files changed, 7 insertions(+), 6 deletions(-) > > diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c > index 49be7a6a2e81..a41fe7975dc6 100644 > --- a/drivers/md/dm-crypt.c > +++ b/drivers/md/dm-crypt.c > @@ -2781,7 +2781,7 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv) > } > > ret = -EINVAL; > - if (sscanf(argv[4], "%llu%c", &tmpll, &dummy) != 1) { > + if (sscanf(argv[4], "%llu%c", &tmpll, &dummy) != 1 || tmpll != (sector_t)tmpll) { > ti->error = "Invalid device sector"; > goto bad; > } > diff --git a/drivers/md/dm-delay.c b/drivers/md/dm-delay.c > index 2fb7bb4304ad..fddffe251bf6 100644 > --- a/drivers/md/dm-delay.c > +++ b/drivers/md/dm-delay.c > @@ -141,7 +141,7 @@ static int delay_class_ctr(struct dm_target *ti, struct delay_class *c, char **a > unsigned long long tmpll; > char dummy; > > - if (sscanf(argv[1], "%llu%c", &tmpll, &dummy) != 1) { > + if (sscanf(argv[1], "%llu%c", &tmpll, &dummy) != 1 || tmpll != (sector_t)tmpll) { > ti->error = "Invalid device sector"; > return -EINVAL; > } > diff --git a/drivers/md/dm-flakey.c b/drivers/md/dm-flakey.c > index 3cb97fa4c11d..8261aa8c7fe1 100644 > --- a/drivers/md/dm-flakey.c > +++ b/drivers/md/dm-flakey.c > @@ -213,7 +213,7 @@ static int flakey_ctr(struct dm_target *ti, unsigned int argc, char **argv) > devname = dm_shift_arg(&as); > > r = -EINVAL; > - if (sscanf(dm_shift_arg(&as), "%llu%c", &tmpll, &dummy) != 1) { > + if (sscanf(dm_shift_arg(&as), "%llu%c", &tmpll, &dummy) != 1 || tmpll != (sector_t)tmpll) { > ti->error = "Invalid device sector"; > goto bad; > } > diff --git a/drivers/md/dm-linear.c b/drivers/md/dm-linear.c > index 8d7ddee6ac4d..ad980a38fb1e 100644 > --- a/drivers/md/dm-linear.c > +++ b/drivers/md/dm-linear.c > @@ -45,7 +45,7 @@ static int linear_ctr(struct dm_target *ti, unsigned int argc, char **argv) > } > > ret = -EINVAL; > - if (sscanf(argv[1], "%llu%c", &tmp, &dummy) != 1) { > + if (sscanf(argv[1], "%llu%c", &tmp, &dummy) != 1 || tmp != (sector_t)tmp) { > ti->error = "Invalid device sector"; > goto bad; > } > diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c > index 79eab1071ec2..5a51151f680d 100644 > --- a/drivers/md/dm-raid1.c > +++ b/drivers/md/dm-raid1.c > @@ -943,7 +943,8 @@ static int get_mirror(struct mirror_set *ms, struct dm_target *ti, > char dummy; > int ret; > > - if (sscanf(argv[1], "%llu%c", &offset, &dummy) != 1) { > + if (sscanf(argv[1], "%llu%c", &offset, &dummy) != 1 || > + offset != (sector_t)offset) { > ti->error = "Invalid offset"; > return -EINVAL; > } > diff --git a/drivers/md/dm-unstripe.c b/drivers/md/dm-unstripe.c > index 954b7ab4e684..e673dacf6418 100644 > --- a/drivers/md/dm-unstripe.c > +++ b/drivers/md/dm-unstripe.c > @@ -78,7 +78,7 @@ static int unstripe_ctr(struct dm_target *ti, unsigned int argc, char **argv) > goto err; > } > > - if (sscanf(argv[4], "%llu%c", &start, &dummy) != 1) { > + if (sscanf(argv[4], "%llu%c", &start, &dummy) != 1 || start != (sector_t)start) { > ti->error = "Invalid striped device offset"; > goto err; > } > -- > 2.19.1 > ^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2018-11-15 13:20 UTC | newest] Thread overview: 6+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2018-11-04 13:42 [RFC PATCH] dm: Check for device sector overflow if CONFIG_LBDAF is not set Milan Broz 2018-11-05 18:35 ` Mikulas Patocka 2018-11-05 18:59 ` Milan Broz 2018-11-06 21:44 ` Mikulas Patocka 2018-11-07 21:24 ` [PATCH v2] " Milan Broz 2018-11-15 13:20 ` Mikulas Patocka
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox