| From foo@baz Mon Sep 17 12:33:31 CEST 2018 |
| From: Mauricio Faria de Oliveira <mfo@canonical.com> |
| Date: Wed, 25 Jul 2018 22:46:28 -0300 |
| Subject: partitions/aix: fix usage of uninitialized lv_info and lvname structures |
| |
| From: Mauricio Faria de Oliveira <mfo@canonical.com> |
| |
| [ Upstream commit 14cb2c8a6c5dae57ee3e2da10fa3db2b9087e39e ] |
| |
| The if-block that sets a successful return value in aix_partition() |
| uses 'lvip[].pps_per_lv' and 'n[].name' potentially uninitialized. |
| |
| For example, if 'numlvs' is zero or alloc_lvn() fails, neither is |
| initialized, but are used anyway if alloc_pvd() succeeds after it. |
| |
| So, make the alloc_pvd() call conditional on their initialization. |
| |
| This has been hit when attaching an apparently corrupted/stressed |
| AIX LUN, misleading the kernel to pr_warn() invalid data and hang. |
| |
| [...] partition (null) (11 pp's found) is not contiguous |
| [...] partition (null) (2 pp's found) is not contiguous |
| [...] partition (null) (3 pp's found) is not contiguous |
| [...] partition (null) (64 pp's found) is not contiguous |
| |
| Fixes: 6ceea22bbbc8 ("partitions: add aix lvm partition support files") |
| Signed-off-by: Mauricio Faria de Oliveira <mfo@canonical.com> |
| Signed-off-by: Jens Axboe <axboe@kernel.dk> |
| Signed-off-by: Sasha Levin <alexander.levin@microsoft.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| block/partitions/aix.c | 5 +++-- |
| 1 file changed, 3 insertions(+), 2 deletions(-) |
| |
| --- a/block/partitions/aix.c |
| +++ b/block/partitions/aix.c |
| @@ -178,7 +178,7 @@ int aix_partition(struct parsed_partitio |
| u32 vgda_sector = 0; |
| u32 vgda_len = 0; |
| int numlvs = 0; |
| - struct pvd *pvd; |
| + struct pvd *pvd = NULL; |
| struct lv_info { |
| unsigned short pps_per_lv; |
| unsigned short pps_found; |
| @@ -232,10 +232,11 @@ int aix_partition(struct parsed_partitio |
| if (lvip[i].pps_per_lv) |
| foundlvs += 1; |
| } |
| + /* pvd loops depend on n[].name and lvip[].pps_per_lv */ |
| + pvd = alloc_pvd(state, vgda_sector + 17); |
| } |
| put_dev_sector(sect); |
| } |
| - pvd = alloc_pvd(state, vgda_sector + 17); |
| if (pvd) { |
| int numpps = be16_to_cpu(pvd->pp_count); |
| int psn_part1 = be32_to_cpu(pvd->psn_part1); |