mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	mm/migrate: fix do_pages_move for compat pointers
do_pages_move does not handle compat pointers for the page list. correctly. Add in_compat_syscall check and appropriate get_user fetch when iterating the page list. It makes the syscall in compat mode (32-bit userspace, 64-bit kernel) work the same way as the native 32-bit syscall again, restoring the behavior before my broken commit5b1b561ba7("mm: simplify compat_sys_move_pages"). More specifically, my patch moved the parsing of the 'pages' array from the main entry point into do_pages_stat(), which left the syscall working correctly for the 'stat' operation (nodes = NULL), while the 'move' operation (nodes != NULL) is now missing the conversion and interprets 'pages' as an array of 64-bit pointers instead of the intended 32-bit userspace pointers. It is possible that nobody noticed this bug because the few applications that actually call move_pages are unlikely to run in compat mode because of their large memory requirements, but this clearly fixes a user-visible regression and should have been caught by ltp. Link: https://lkml.kernel.org/r/20231003144857.752952-1-gregory.price@memverge.com Fixes:5b1b561ba7("mm: simplify compat_sys_move_pages") Signed-off-by: Gregory Price <gregory.price@memverge.com> Reported-by: Arnd Bergmann <arnd@arndb.de> Co-developed-by: Arnd Bergmann <arnd@arndb.de> Cc: Jonathan Cameron <Jonathan.Cameron@huawei.com> Cc: <stable@vger.kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
This commit is contained in:
		
							parent
							
								
									1de195dd0e
								
							
						
					
					
						commit
						229e225376
					
				
					 1 changed files with 12 additions and 2 deletions
				
			
		
							
								
								
									
										10
									
								
								mm/migrate.c
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								mm/migrate.c
									
									
									
									
									
								
							| 
						 | 
					@ -2162,6 +2162,7 @@ static int do_pages_move(struct mm_struct *mm, nodemask_t task_nodes,
 | 
				
			||||||
			 const int __user *nodes,
 | 
								 const int __user *nodes,
 | 
				
			||||||
			 int __user *status, int flags)
 | 
								 int __user *status, int flags)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						compat_uptr_t __user *compat_pages = (void __user *)pages;
 | 
				
			||||||
	int current_node = NUMA_NO_NODE;
 | 
						int current_node = NUMA_NO_NODE;
 | 
				
			||||||
	LIST_HEAD(pagelist);
 | 
						LIST_HEAD(pagelist);
 | 
				
			||||||
	int start, i;
 | 
						int start, i;
 | 
				
			||||||
| 
						 | 
					@ -2174,8 +2175,17 @@ static int do_pages_move(struct mm_struct *mm, nodemask_t task_nodes,
 | 
				
			||||||
		int node;
 | 
							int node;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		err = -EFAULT;
 | 
							err = -EFAULT;
 | 
				
			||||||
 | 
							if (in_compat_syscall()) {
 | 
				
			||||||
 | 
								compat_uptr_t cp;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (get_user(cp, compat_pages + i))
 | 
				
			||||||
 | 
									goto out_flush;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								p = compat_ptr(cp);
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
			if (get_user(p, pages + i))
 | 
								if (get_user(p, pages + i))
 | 
				
			||||||
				goto out_flush;
 | 
									goto out_flush;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		if (get_user(node, nodes + i))
 | 
							if (get_user(node, nodes + i))
 | 
				
			||||||
			goto out_flush;
 | 
								goto out_flush;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue