aboutsummaryrefslogtreecommitdiffstats
path: root/arch/m68k
diff options
context:
space:
mode:
authorGeert Uytterhoeven <geert@linux-m68k.org>2011-04-03 08:00:10 -0400
committerGeert Uytterhoeven <geert@linux-m68k.org>2011-05-19 12:19:09 -0400
commitf82a519f1262963d6ab30fa238721463fad2e0c8 (patch)
treec7808cc9a265b923a20d96d5a9aff2c2f1669d4a /arch/m68k
parent359c47ea71be21c1105ae474e8c90ec3e988bbdf (diff)
m68k: bitops - Never step beyond the end of the bitmap
find_next bitops on m68k (find_next_zero_bit, find_next_bit, and find_next_bit_le) may cause out of bounds memory access when the bitmap size in bits % 32 != 0 and offset (the bitnumber to start searching at) is very close to the bitmap size. For example, unsigned long bitmap[2] = { 0, 0 }; find_next_bit(bitmap, 63, 62); 1. find_next_bit() tries to find any set bits in bitmap[1], but no bits set. 2. Then find_first_bit(bimap + 2, -1) 3. Unfortunately find_first_bit() takes unsigned int as the size argument. 4. find_first_bit will access bitmap[2~] until it find any set bits. Add missing tests for stepping beyond the end of the bitmap to all find_{first,next}_*() functions, and make sure they never return a value larger than the bitmap size. Reported-by: Akinobu Mita <akinobu.mita@gmail.com> Cc: Andreas Schwab <schwab@linux-m68k.org> Signed-off-by: Geert Uytterhoeven <geert@linux-m68k.org>
Diffstat (limited to 'arch/m68k')
-rw-r--r--arch/m68k/include/asm/bitops_mm.h81
1 files changed, 55 insertions, 26 deletions
diff --git a/arch/m68k/include/asm/bitops_mm.h b/arch/m68k/include/asm/bitops_mm.h
index 5bd3afadeafa..e9020f88a748 100644
--- a/arch/m68k/include/asm/bitops_mm.h
+++ b/arch/m68k/include/asm/bitops_mm.h
@@ -181,14 +181,15 @@ static inline int find_first_zero_bit(const unsigned long *vaddr,
181{ 181{
182 const unsigned long *p = vaddr; 182 const unsigned long *p = vaddr;
183 int res = 32; 183 int res = 32;
184 unsigned int words;
184 unsigned long num; 185 unsigned long num;
185 186
186 if (!size) 187 if (!size)
187 return 0; 188 return 0;
188 189
189 size = (size + 31) >> 5; 190 words = (size + 31) >> 5;
190 while (!(num = ~*p++)) { 191 while (!(num = ~*p++)) {
191 if (!--size) 192 if (!--words)
192 goto out; 193 goto out;
193 } 194 }
194 195
@@ -196,7 +197,8 @@ static inline int find_first_zero_bit(const unsigned long *vaddr,
196 : "=d" (res) : "d" (num & -num)); 197 : "=d" (res) : "d" (num & -num));
197 res ^= 31; 198 res ^= 31;
198out: 199out:
199 return ((long)p - (long)vaddr - 4) * 8 + res; 200 res += ((long)p - (long)vaddr - 4) * 8;
201 return res < size ? res : size;
200} 202}
201 203
202static inline int find_next_zero_bit(const unsigned long *vaddr, int size, 204static inline int find_next_zero_bit(const unsigned long *vaddr, int size,
@@ -215,9 +217,14 @@ static inline int find_next_zero_bit(const unsigned long *vaddr, int size,
215 /* Look for zero in first longword */ 217 /* Look for zero in first longword */
216 __asm__ __volatile__ ("bfffo %1{#0,#0},%0" 218 __asm__ __volatile__ ("bfffo %1{#0,#0},%0"
217 : "=d" (res) : "d" (num & -num)); 219 : "=d" (res) : "d" (num & -num));
218 if (res < 32) 220 if (res < 32) {
219 return offset + (res ^ 31); 221 offset += res ^ 31;
222 return offset < size ? offset : size;
223 }
220 offset += 32; 224 offset += 32;
225
226 if (offset >= size)
227 return size;
221 } 228 }
222 /* No zero yet, search remaining full bytes for a zero */ 229 /* No zero yet, search remaining full bytes for a zero */
223 return offset + find_first_zero_bit(p, size - offset); 230 return offset + find_first_zero_bit(p, size - offset);
@@ -227,14 +234,15 @@ static inline int find_first_bit(const unsigned long *vaddr, unsigned size)
227{ 234{
228 const unsigned long *p = vaddr; 235 const unsigned long *p = vaddr;
229 int res = 32; 236 int res = 32;
237 unsigned int words;
230 unsigned long num; 238 unsigned long num;
231 239
232 if (!size) 240 if (!size)
233 return 0; 241 return 0;
234 242
235 size = (size + 31) >> 5; 243 words = (size + 31) >> 5;
236 while (!(num = *p++)) { 244 while (!(num = *p++)) {
237 if (!--size) 245 if (!--words)
238 goto out; 246 goto out;
239 } 247 }
240 248
@@ -242,7 +250,8 @@ static inline int find_first_bit(const unsigned long *vaddr, unsigned size)
242 : "=d" (res) : "d" (num & -num)); 250 : "=d" (res) : "d" (num & -num));
243 res ^= 31; 251 res ^= 31;
244out: 252out:
245 return ((long)p - (long)vaddr - 4) * 8 + res; 253 res += ((long)p - (long)vaddr - 4) * 8;
254 return res < size ? res : size;
246} 255}
247 256
248static inline int find_next_bit(const unsigned long *vaddr, int size, 257static inline int find_next_bit(const unsigned long *vaddr, int size,
@@ -261,9 +270,14 @@ static inline int find_next_bit(const unsigned long *vaddr, int size,
261 /* Look for one in first longword */ 270 /* Look for one in first longword */
262 __asm__ __volatile__ ("bfffo %1{#0,#0},%0" 271 __asm__ __volatile__ ("bfffo %1{#0,#0},%0"
263 : "=d" (res) : "d" (num & -num)); 272 : "=d" (res) : "d" (num & -num));
264 if (res < 32) 273 if (res < 32) {
265 return offset + (res ^ 31); 274 offset += res ^ 31;
275 return offset < size ? offset : size;
276 }
266 offset += 32; 277 offset += 32;
278
279 if (offset >= size)
280 return size;
267 } 281 }
268 /* No one yet, search remaining full bytes for a one */ 282 /* No one yet, search remaining full bytes for a one */
269 return offset + find_first_bit(p, size - offset); 283 return offset + find_first_bit(p, size - offset);
@@ -364,23 +378,25 @@ static inline int test_bit_le(int nr, const void *vaddr)
364static inline int find_first_zero_bit_le(const void *vaddr, unsigned size) 378static inline int find_first_zero_bit_le(const void *vaddr, unsigned size)
365{ 379{
366 const unsigned long *p = vaddr, *addr = vaddr; 380 const unsigned long *p = vaddr, *addr = vaddr;
367 int res; 381 int res = 0;
382 unsigned int words;
368 383
369 if (!size) 384 if (!size)
370 return 0; 385 return 0;
371 386
372 size = (size >> 5) + ((size & 31) > 0); 387 words = (size >> 5) + ((size & 31) > 0);
373 while (*p++ == ~0UL) 388 while (*p++ == ~0UL) {
374 { 389 if (--words == 0)
375 if (--size == 0) 390 goto out;
376 return (p - addr) << 5;
377 } 391 }
378 392
379 --p; 393 --p;
380 for (res = 0; res < 32; res++) 394 for (res = 0; res < 32; res++)
381 if (!test_bit_le(res, p)) 395 if (!test_bit_le(res, p))
382 break; 396 break;
383 return (p - addr) * 32 + res; 397out:
398 res += (p - addr) * 32;
399 return res < size ? res : size;
384} 400}
385 401
386static inline unsigned long find_next_zero_bit_le(const void *addr, 402static inline unsigned long find_next_zero_bit_le(const void *addr,
@@ -398,10 +414,15 @@ static inline unsigned long find_next_zero_bit_le(const void *addr,
398 offset -= bit; 414 offset -= bit;
399 /* Look for zero in first longword */ 415 /* Look for zero in first longword */
400 for (res = bit; res < 32; res++) 416 for (res = bit; res < 32; res++)
401 if (!test_bit_le(res, p)) 417 if (!test_bit_le(res, p)) {
402 return offset + res; 418 offset += res;
419 return offset < size ? offset : size;
420 }
403 p++; 421 p++;
404 offset += 32; 422 offset += 32;
423
424 if (offset >= size)
425 return size;
405 } 426 }
406 /* No zero yet, search remaining full bytes for a zero */ 427 /* No zero yet, search remaining full bytes for a zero */
407 return offset + find_first_zero_bit_le(p, size - offset); 428 return offset + find_first_zero_bit_le(p, size - offset);
@@ -410,22 +431,25 @@ static inline unsigned long find_next_zero_bit_le(const void *addr,
410static inline int find_first_bit_le(const void *vaddr, unsigned size) 431static inline int find_first_bit_le(const void *vaddr, unsigned size)
411{ 432{
412 const unsigned long *p = vaddr, *addr = vaddr; 433 const unsigned long *p = vaddr, *addr = vaddr;
413 int res; 434 int res = 0;
435 unsigned int words;
414 436
415 if (!size) 437 if (!size)
416 return 0; 438 return 0;
417 439
418 size = (size >> 5) + ((size & 31) > 0); 440 words = (size >> 5) + ((size & 31) > 0);
419 while (*p++ == 0UL) { 441 while (*p++ == 0UL) {
420 if (--size == 0) 442 if (--words == 0)
421 return (p - addr) << 5; 443 goto out;
422 } 444 }
423 445
424 --p; 446 --p;
425 for (res = 0; res < 32; res++) 447 for (res = 0; res < 32; res++)
426 if (test_bit_le(res, p)) 448 if (test_bit_le(res, p))
427 break; 449 break;
428 return (p - addr) * 32 + res; 450out:
451 res += (p - addr) * 32;
452 return res < size ? res : size;
429} 453}
430 454
431static inline unsigned long find_next_bit_le(const void *addr, 455static inline unsigned long find_next_bit_le(const void *addr,
@@ -443,10 +467,15 @@ static inline unsigned long find_next_bit_le(const void *addr,
443 offset -= bit; 467 offset -= bit;
444 /* Look for one in first longword */ 468 /* Look for one in first longword */
445 for (res = bit; res < 32; res++) 469 for (res = bit; res < 32; res++)
446 if (test_bit_le(res, p)) 470 if (test_bit_le(res, p)) {
447 return offset + res; 471 offset += res;
472 return offset < size ? offset : size;
473 }
448 p++; 474 p++;
449 offset += 32; 475 offset += 32;
476
477 if (offset >= size)
478 return size;
450 } 479 }
451 /* No set bit yet, search remaining full bytes for a set bit */ 480 /* No set bit yet, search remaining full bytes for a set bit */
452 return offset + find_first_bit_le(p, size - offset); 481 return offset + find_first_bit_le(p, size - offset);