diff options
author | Mikulas Patocka <mpatocka@redhat.com> | 2013-03-01 17:45:44 -0500 |
---|---|---|
committer | Alasdair G Kergon <agk@redhat.com> | 2013-03-01 17:45:44 -0500 |
commit | fd7c092e711ebab55b2688d3859d95dfd0301f73 (patch) | |
tree | 3cc99f96f4a2de8e22347feb86b0ecd5dd7200d0 /drivers/md/dm-ioctl.c | |
parent | 16245bdc9d3e22d1460341a655c8b5288953bc14 (diff) |
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>
Diffstat (limited to 'drivers/md/dm-ioctl.c')
-rw-r--r-- | drivers/md/dm-ioctl.c | 14 |
1 files changed, 9 insertions, 5 deletions
diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c index 0666b5d14b88..eee353da3742 100644 --- a/drivers/md/dm-ioctl.c +++ b/drivers/md/dm-ioctl.c | |||
@@ -1067,6 +1067,7 @@ static void retrieve_status(struct dm_table *table, | |||
1067 | num_targets = dm_table_get_num_targets(table); | 1067 | num_targets = dm_table_get_num_targets(table); |
1068 | for (i = 0; i < num_targets; i++) { | 1068 | for (i = 0; i < num_targets; i++) { |
1069 | struct dm_target *ti = dm_table_get_target(table, i); | 1069 | struct dm_target *ti = dm_table_get_target(table, i); |
1070 | size_t l; | ||
1070 | 1071 | ||
1071 | remaining = len - (outptr - outbuf); | 1072 | remaining = len - (outptr - outbuf); |
1072 | if (remaining <= sizeof(struct dm_target_spec)) { | 1073 | if (remaining <= sizeof(struct dm_target_spec)) { |
@@ -1093,14 +1094,17 @@ static void retrieve_status(struct dm_table *table, | |||
1093 | if (ti->type->status) { | 1094 | if (ti->type->status) { |
1094 | if (param->flags & DM_NOFLUSH_FLAG) | 1095 | if (param->flags & DM_NOFLUSH_FLAG) |
1095 | status_flags |= DM_STATUS_NOFLUSH_FLAG; | 1096 | status_flags |= DM_STATUS_NOFLUSH_FLAG; |
1096 | if (ti->type->status(ti, type, status_flags, outptr, remaining)) { | 1097 | ti->type->status(ti, type, status_flags, outptr, remaining); |
1097 | param->flags |= DM_BUFFER_FULL_FLAG; | ||
1098 | break; | ||
1099 | } | ||
1100 | } else | 1098 | } else |
1101 | outptr[0] = '\0'; | 1099 | outptr[0] = '\0'; |
1102 | 1100 | ||
1103 | outptr += strlen(outptr) + 1; | 1101 | l = strlen(outptr) + 1; |
1102 | if (l == remaining) { | ||
1103 | param->flags |= DM_BUFFER_FULL_FLAG; | ||
1104 | break; | ||
1105 | } | ||
1106 | |||
1107 | outptr += l; | ||
1104 | used = param->data_start + (outptr - outbuf); | 1108 | used = param->data_start + (outptr - outbuf); |
1105 | 1109 | ||
1106 | outptr = align_ptr(outptr); | 1110 | outptr = align_ptr(outptr); |