forked from mirrors/linux
		
	gpiolib: Fix line event handling in syscall compatible mode
The introduced line event handling ABI in the commit61f922db72("gpio: userspace ABI for reading GPIO line events") missed the fact that 64-bit kernel may serve for 32-bit applications. In such case the very first check in the lineevent_read() will fail due to alignment differences. To workaround this introduce lineevent_get_size() helper which returns actual size of the structure in user space. Fixes:61f922db72("gpio: userspace ABI for reading GPIO line events") Suggested-by: Arnd Bergmann <arnd@arndb.de> Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Acked-by: Arnd Bergmann <arnd@arndb.de> Tested-by: Kent Gibson <warthog618@gmail.com> Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
This commit is contained in:
		
							parent
							
								
									1b02d9e770
								
							
						
					
					
						commit
						5ad284ab3a
					
				
					 1 changed files with 30 additions and 4 deletions
				
			
		|  | @ -423,6 +423,21 @@ static __poll_t lineevent_poll(struct file *file, | |||
| 	return events; | ||||
| } | ||||
| 
 | ||||
| static ssize_t lineevent_get_size(void) | ||||
| { | ||||
| #ifdef __x86_64__ | ||||
| 	/* i386 has no padding after 'id' */ | ||||
| 	if (in_ia32_syscall()) { | ||||
| 		struct compat_gpioeevent_data { | ||||
| 			compat_u64	timestamp; | ||||
| 			u32		id; | ||||
| 		}; | ||||
| 
 | ||||
| 		return sizeof(struct compat_gpioeevent_data); | ||||
| 	} | ||||
| #endif | ||||
| 	return sizeof(struct gpioevent_data); | ||||
| } | ||||
| 
 | ||||
| static ssize_t lineevent_read(struct file *file, | ||||
| 			      char __user *buf, | ||||
|  | @ -432,9 +447,20 @@ static ssize_t lineevent_read(struct file *file, | |||
| 	struct lineevent_state *le = file->private_data; | ||||
| 	struct gpioevent_data ge; | ||||
| 	ssize_t bytes_read = 0; | ||||
| 	ssize_t ge_size; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	if (count < sizeof(ge)) | ||||
| 	/*
 | ||||
| 	 * When compatible system call is being used the struct gpioevent_data, | ||||
| 	 * in case of at least ia32, has different size due to the alignment | ||||
| 	 * differences. Because we have first member 64 bits followed by one of | ||||
| 	 * 32 bits there is no gap between them. The only difference is the | ||||
| 	 * padding at the end of the data structure. Hence, we calculate the | ||||
| 	 * actual sizeof() and pass this as an argument to copy_to_user() to | ||||
| 	 * drop unneeded bytes from the output. | ||||
| 	 */ | ||||
| 	ge_size = lineevent_get_size(); | ||||
| 	if (count < ge_size) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	do { | ||||
|  | @ -470,10 +496,10 @@ static ssize_t lineevent_read(struct file *file, | |||
| 			break; | ||||
| 		} | ||||
| 
 | ||||
| 		if (copy_to_user(buf + bytes_read, &ge, sizeof(ge))) | ||||
| 		if (copy_to_user(buf + bytes_read, &ge, ge_size)) | ||||
| 			return -EFAULT; | ||||
| 		bytes_read += sizeof(ge); | ||||
| 	} while (count >= bytes_read + sizeof(ge)); | ||||
| 		bytes_read += ge_size; | ||||
| 	} while (count >= bytes_read + ge_size); | ||||
| 
 | ||||
| 	return bytes_read; | ||||
| } | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Andy Shevchenko
						Andy Shevchenko