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-snap.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-snap.c')
-rw-r--r-- | drivers/md/dm-snap.c | 16 |
1 files changed, 6 insertions, 10 deletions
diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c index 10079e07edf4..6e45e3774eab 100644 --- a/drivers/md/dm-snap.c +++ b/drivers/md/dm-snap.c | |||
@@ -1836,8 +1836,8 @@ static void snapshot_merge_resume(struct dm_target *ti) | |||
1836 | start_merge(s); | 1836 | start_merge(s); |
1837 | } | 1837 | } |
1838 | 1838 | ||
1839 | static int snapshot_status(struct dm_target *ti, status_type_t type, | 1839 | static void snapshot_status(struct dm_target *ti, status_type_t type, |
1840 | unsigned status_flags, char *result, unsigned maxlen) | 1840 | unsigned status_flags, char *result, unsigned maxlen) |
1841 | { | 1841 | { |
1842 | unsigned sz = 0; | 1842 | unsigned sz = 0; |
1843 | struct dm_snapshot *snap = ti->private; | 1843 | struct dm_snapshot *snap = ti->private; |
@@ -1883,8 +1883,6 @@ static int snapshot_status(struct dm_target *ti, status_type_t type, | |||
1883 | maxlen - sz); | 1883 | maxlen - sz); |
1884 | break; | 1884 | break; |
1885 | } | 1885 | } |
1886 | |||
1887 | return 0; | ||
1888 | } | 1886 | } |
1889 | 1887 | ||
1890 | static int snapshot_iterate_devices(struct dm_target *ti, | 1888 | static int snapshot_iterate_devices(struct dm_target *ti, |
@@ -2138,8 +2136,8 @@ static void origin_resume(struct dm_target *ti) | |||
2138 | ti->max_io_len = get_origin_minimum_chunksize(dev->bdev); | 2136 | ti->max_io_len = get_origin_minimum_chunksize(dev->bdev); |
2139 | } | 2137 | } |
2140 | 2138 | ||
2141 | static int origin_status(struct dm_target *ti, status_type_t type, | 2139 | static void origin_status(struct dm_target *ti, status_type_t type, |
2142 | unsigned status_flags, char *result, unsigned maxlen) | 2140 | unsigned status_flags, char *result, unsigned maxlen) |
2143 | { | 2141 | { |
2144 | struct dm_dev *dev = ti->private; | 2142 | struct dm_dev *dev = ti->private; |
2145 | 2143 | ||
@@ -2152,8 +2150,6 @@ static int origin_status(struct dm_target *ti, status_type_t type, | |||
2152 | snprintf(result, maxlen, "%s", dev->name); | 2150 | snprintf(result, maxlen, "%s", dev->name); |
2153 | break; | 2151 | break; |
2154 | } | 2152 | } |
2155 | |||
2156 | return 0; | ||
2157 | } | 2153 | } |
2158 | 2154 | ||
2159 | static int origin_merge(struct dm_target *ti, struct bvec_merge_data *bvm, | 2155 | static int origin_merge(struct dm_target *ti, struct bvec_merge_data *bvm, |
@@ -2180,7 +2176,7 @@ static int origin_iterate_devices(struct dm_target *ti, | |||
2180 | 2176 | ||
2181 | static struct target_type origin_target = { | 2177 | static struct target_type origin_target = { |
2182 | .name = "snapshot-origin", | 2178 | .name = "snapshot-origin", |
2183 | .version = {1, 8, 0}, | 2179 | .version = {1, 8, 1}, |
2184 | .module = THIS_MODULE, | 2180 | .module = THIS_MODULE, |
2185 | .ctr = origin_ctr, | 2181 | .ctr = origin_ctr, |
2186 | .dtr = origin_dtr, | 2182 | .dtr = origin_dtr, |
@@ -2193,7 +2189,7 @@ static struct target_type origin_target = { | |||
2193 | 2189 | ||
2194 | static struct target_type snapshot_target = { | 2190 | static struct target_type snapshot_target = { |
2195 | .name = "snapshot", | 2191 | .name = "snapshot", |
2196 | .version = {1, 11, 0}, | 2192 | .version = {1, 11, 1}, |
2197 | .module = THIS_MODULE, | 2193 | .module = THIS_MODULE, |
2198 | .ctr = snapshot_ctr, | 2194 | .ctr = snapshot_ctr, |
2199 | .dtr = snapshot_dtr, | 2195 | .dtr = snapshot_dtr, |