dm: fix truncated status strings
Avoid returning a truncated table or status string instead of setting the DM_BUFFER_FULL_FLAG when the last target of a table fills the buffer. When processing a table or status request, the function retrieve_status calls ti->type->status. If ti->type->status returns non-zero, retrieve_status assumes that the buffer overflowed and sets DM_BUFFER_FULL_FLAG. However, targets don't return non-zero values from their status method on overflow. Most targets returns always zero. If a buffer overflow happens in a target that is not the last in the table, it gets noticed during the next iteration of the loop in retrieve_status; but if a buffer overflow happens in the last target, it goes unnoticed and erroneously truncated data is returned. In the current code, the targets behave in the following way: * dm-crypt returns -ENOMEM if there is not enough space to store the key, but it returns 0 on all other overflows. * dm-thin returns errors from the status method if a disk error happened. This is incorrect because retrieve_status doesn't check the error code, it assumes that all non-zero values mean buffer overflow. * all the other targets always return 0. This patch changes the ti->type->status function to return void (because most targets don't use the return code). Overflow is detected in retrieve_status: if the status method fills up the remaining space completely, it is assumed that buffer overflow happened. Cc: stable@vger.kernel.org Signed-off-by: Mikulas Patocka <mpatocka@redhat.com> Signed-off-by: Alasdair G Kergon <agk@redhat.com>
This commit is contained in:

committed by
Alasdair G Kergon

parent
16245bdc9d
commit
fd7c092e71
@@ -1067,6 +1067,7 @@ static void retrieve_status(struct dm_table *table,
|
||||
num_targets = dm_table_get_num_targets(table);
|
||||
for (i = 0; i < num_targets; i++) {
|
||||
struct dm_target *ti = dm_table_get_target(table, i);
|
||||
size_t l;
|
||||
|
||||
remaining = len - (outptr - outbuf);
|
||||
if (remaining <= sizeof(struct dm_target_spec)) {
|
||||
@@ -1093,14 +1094,17 @@ static void retrieve_status(struct dm_table *table,
|
||||
if (ti->type->status) {
|
||||
if (param->flags & DM_NOFLUSH_FLAG)
|
||||
status_flags |= DM_STATUS_NOFLUSH_FLAG;
|
||||
if (ti->type->status(ti, type, status_flags, outptr, remaining)) {
|
||||
param->flags |= DM_BUFFER_FULL_FLAG;
|
||||
break;
|
||||
}
|
||||
ti->type->status(ti, type, status_flags, outptr, remaining);
|
||||
} else
|
||||
outptr[0] = '\0';
|
||||
|
||||
outptr += strlen(outptr) + 1;
|
||||
l = strlen(outptr) + 1;
|
||||
if (l == remaining) {
|
||||
param->flags |= DM_BUFFER_FULL_FLAG;
|
||||
break;
|
||||
}
|
||||
|
||||
outptr += l;
|
||||
used = param->data_start + (outptr - outbuf);
|
||||
|
||||
outptr = align_ptr(outptr);
|
||||
|
Reference in New Issue
Block a user