OSDN Git Service

scsi: target: pscsi: Avoid OOM in pscsi_map_sg()
authorMartin Wilck <mwilck@suse.com>
Tue, 23 Mar 2021 21:24:30 +0000 (22:24 +0100)
committerMartin K. Petersen <martin.petersen@oracle.com>
Thu, 25 Mar 2021 03:19:23 +0000 (23:19 -0400)
commit077ce028b8e0684d5ee7da573bd835b14b591546
treeaae896763bdc0588b7fe4fdeb66720a4d8be7ef6
parent3401ecf7fc1b9458a19d42c0e26a228f18ac7dda
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>
drivers/target/target_core_pscsi.c