Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

mm: Make copy_from_user() in migrate.c statically predictable

x86-32 has had a static test for copy_on_user() overflow for a while.
This test currently fails in mm/migrate.c resulting in an
allyesconfig/allmodconfig build failure on x86-32:

In function ‘copy_from_user’,
inlined from ‘do_pages_stat’ at
/home/hpa/kernel/git/mm/migrate.c:1012:
/home/hpa/kernel/git/arch/x86/include/asm/uaccess_32.h:212: error:
call to ‘copy_from_user_overflow’ declared

Make the logic more explicit and therefore easier for gcc to
understand.

v2: rewrite the loop entirely using a more normal structure for a
chunked-data loop (Linus Torvalds)

Reported-by: Len Brown <lenb@kernel.org>
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
Reviewed-and-Tested-by: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com>
Cc: Arjan van de Ven <arjan@linux.kernel.org>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Christoph Lameter <cl@linux-foundation.org>
Cc: Hugh Dickins <hugh.dickins@tiscali.co.uk>
Cc: Rik van Riel <riel@redhat.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

H. Peter Anvin and committed by
Linus Torvalds
87b8d1ad aea187c4

+15 -21
+15 -21
mm/migrate.c
··· 1002 1002 #define DO_PAGES_STAT_CHUNK_NR 16 1003 1003 const void __user *chunk_pages[DO_PAGES_STAT_CHUNK_NR]; 1004 1004 int chunk_status[DO_PAGES_STAT_CHUNK_NR]; 1005 - unsigned long i, chunk_nr = DO_PAGES_STAT_CHUNK_NR; 1006 - int err; 1007 1005 1008 - for (i = 0; i < nr_pages; i += chunk_nr) { 1009 - if (chunk_nr > nr_pages - i) 1010 - chunk_nr = nr_pages - i; 1006 + while (nr_pages) { 1007 + unsigned long chunk_nr; 1011 1008 1012 - err = copy_from_user(chunk_pages, &pages[i], 1013 - chunk_nr * sizeof(*chunk_pages)); 1014 - if (err) { 1015 - err = -EFAULT; 1016 - goto out; 1017 - } 1009 + chunk_nr = nr_pages; 1010 + if (chunk_nr > DO_PAGES_STAT_CHUNK_NR) 1011 + chunk_nr = DO_PAGES_STAT_CHUNK_NR; 1012 + 1013 + if (copy_from_user(chunk_pages, pages, chunk_nr * sizeof(*chunk_pages))) 1014 + break; 1018 1015 1019 1016 do_pages_stat_array(mm, chunk_nr, chunk_pages, chunk_status); 1020 1017 1021 - err = copy_to_user(&status[i], chunk_status, 1022 - chunk_nr * sizeof(*chunk_status)); 1023 - if (err) { 1024 - err = -EFAULT; 1025 - goto out; 1026 - } 1027 - } 1028 - err = 0; 1018 + if (copy_to_user(status, chunk_status, chunk_nr * sizeof(*status))) 1019 + break; 1029 1020 1030 - out: 1031 - return err; 1021 + pages += chunk_nr; 1022 + status += chunk_nr; 1023 + nr_pages -= chunk_nr; 1024 + } 1025 + return nr_pages ? -EFAULT : 0; 1032 1026 } 1033 1027 1034 1028 /*