x86/ptrace: make genregs[32]_get/set more robust
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 17 Dec 2009 15:04:56 +0000 (07:04 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 17 Dec 2009 15:04:56 +0000 (07:04 -0800)
The loop condition is fragile: we compare an unsigned value to zero, and
then decrement it by something larger than one in the loop.  All the
callers should be passing in appropriately aligned buffer lengths, but
it's better to just not rely on it, and have some appropriate defensive
loop limits.

Acked-by: Roland McGrath <roland@redhat.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
arch/x86/kernel/ptrace.c

index 2779321046bd53e789847b10c18c99893e054e31..017d937639fef87694eea7cd3cbbf95efb163d37 100644 (file)
@@ -509,14 +509,14 @@ static int genregs_get(struct task_struct *target,
 {
        if (kbuf) {
                unsigned long *k = kbuf;
-               while (count > 0) {
+               while (count >= sizeof(*k)) {
                        *k++ = getreg(target, pos);
                        count -= sizeof(*k);
                        pos += sizeof(*k);
                }
        } else {
                unsigned long __user *u = ubuf;
-               while (count > 0) {
+               while (count >= sizeof(*u)) {
                        if (__put_user(getreg(target, pos), u++))
                                return -EFAULT;
                        count -= sizeof(*u);
@@ -535,14 +535,14 @@ static int genregs_set(struct task_struct *target,
        int ret = 0;
        if (kbuf) {
                const unsigned long *k = kbuf;
-               while (count > 0 && !ret) {
+               while (count >= sizeof(*k) && !ret) {
                        ret = putreg(target, pos, *k++);
                        count -= sizeof(*k);
                        pos += sizeof(*k);
                }
        } else {
                const unsigned long  __user *u = ubuf;
-               while (count > 0 && !ret) {
+               while (count >= sizeof(*u) && !ret) {
                        unsigned long word;
                        ret = __get_user(word, u++);
                        if (ret)
@@ -1458,14 +1458,14 @@ static int genregs32_get(struct task_struct *target,
 {
        if (kbuf) {
                compat_ulong_t *k = kbuf;
-               while (count > 0) {
+               while (count >= sizeof(*k)) {
                        getreg32(target, pos, k++);
                        count -= sizeof(*k);
                        pos += sizeof(*k);
                }
        } else {
                compat_ulong_t __user *u = ubuf;
-               while (count > 0) {
+               while (count >= sizeof(*u)) {
                        compat_ulong_t word;
                        getreg32(target, pos, &word);
                        if (__put_user(word, u++))
@@ -1486,14 +1486,14 @@ static int genregs32_set(struct task_struct *target,
        int ret = 0;
        if (kbuf) {
                const compat_ulong_t *k = kbuf;
-               while (count > 0 && !ret) {
+               while (count >= sizeof(*k) && !ret) {
                        ret = putreg32(target, pos, *k++);
                        count -= sizeof(*k);
                        pos += sizeof(*k);
                }
        } else {
                const compat_ulong_t __user *u = ubuf;
-               while (count > 0 && !ret) {
+               while (count >= sizeof(*u) && !ret) {
                        compat_ulong_t word;
                        ret = __get_user(word, u++);
                        if (ret)