diff options
author | Martin Wilck <mwilck@suse.com> | 2021-03-23 22:24:30 +0100 |
---|---|---|
committer | Martin K. Petersen <martin.petersen@oracle.com> | 2021-03-24 23:19:23 -0400 |
commit | 077ce028b8e0684d5ee7da573bd835b14b591546 (patch) | |
tree | aae896763bdc0588b7fe4fdeb66720a4d8be7ef6 /lib | |
parent | 3401ecf7fc1b9458a19d42c0e26a228f18ac7dda (diff) |
scsi: target: pscsi: Avoid OOM in pscsi_map_sg()
pscsi_map_sg() uses the variable nr_pages as a hint for bio_kmalloc() how
many vector elements to allocate. If nr_pages is < BIO_MAX_PAGES, it will
be reset to 0 after successful allocation of the bio.
If bio_add_pc_page() fails later for whatever reason, pscsi_map_sg() tries
to allocate another bio, passing nr_vecs = 0. This causes bio_add_pc_page()
to fail immediately in the next call. pci_map_sg() continues to allocate
zero-length bios until memory is exhausted and the kernel crashes with
OOM. This can be easily observed by exporting a SATA DVD drive via pscsi.
The target crashes as soon as the client tries to access the DVD LUN. In
the case I analyzed, bio_add_pc_page() would fail because the DVD device's
max_sectors_kb (128) was exceeded.
Avoid this by simply not resetting nr_pages to 0 after allocating the
bio. This way, the client receives an I/O error when it tries to send
requests exceeding the devices max_sectors_kb, and eventually gets it
right. The client must still limit max_sectors_kb e.g. by an udev rule if
(like in my case) the driver doesn't report valid block limits, otherwise
it encounters I/O errors.
Link: https://lore.kernel.org/r/20210323212431.15306-1-mwilck@suse.com
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Lee Duncan <lduncan@suse.com>
Signed-off-by: Martin Wilck <mwilck@suse.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Diffstat (limited to 'lib')
0 files changed, 0 insertions, 0 deletions