mirror of
				https://github.com/torvalds/linux.git
				synced 2025-10-31 00:28:52 +02:00 
			
		
		
		
	Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull more vfs updates from Al Viro: "Embarrassing braino fix + pipe page accounting + fixing an eyesore in find_filesystem() (checking that s1 is equal to prefix of s2 of given length can be done in many ways, but "compare strlen(s1) with length and then do strncmp()" is not a good one...)" * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: [regression] fix braino in fs/dlm/user.c pipe: limit the per-user amount of pages allocated in pipes find_filesystem(): simplify comparison
This commit is contained in:
		
						commit
						eadee0ce6f
					
				
					 7 changed files with 91 additions and 6 deletions
				
			
		|  | @ -32,6 +32,8 @@ Currently, these files are in /proc/sys/fs: | |||
| - nr_open | ||||
| - overflowuid | ||||
| - overflowgid | ||||
| - pipe-user-pages-hard | ||||
| - pipe-user-pages-soft | ||||
| - protected_hardlinks | ||||
| - protected_symlinks | ||||
| - suid_dumpable | ||||
|  | @ -159,6 +161,27 @@ The default is 65534. | |||
| 
 | ||||
| ============================================================== | ||||
| 
 | ||||
| pipe-user-pages-hard: | ||||
| 
 | ||||
| Maximum total number of pages a non-privileged user may allocate for pipes. | ||||
| Once this limit is reached, no new pipes may be allocated until usage goes | ||||
| below the limit again. When set to 0, no limit is applied, which is the default | ||||
| setting. | ||||
| 
 | ||||
| ============================================================== | ||||
| 
 | ||||
| pipe-user-pages-soft: | ||||
| 
 | ||||
| Maximum total number of pages a non-privileged user may allocate for pipes | ||||
| before the pipe size gets limited to a single page. Once this limit is reached, | ||||
| new pipes will be limited to a single page in size for this user in order to | ||||
| limit total memory usage, and trying to increase them using fcntl() will be | ||||
| denied until usage goes below the limit again. The default value allows to | ||||
| allocate up to 1024 pipes at their default size. When set to 0, no limit is | ||||
| applied. | ||||
| 
 | ||||
| ============================================================== | ||||
| 
 | ||||
| protected_hardlinks: | ||||
| 
 | ||||
| A long-standing class of security issues is the hardlink-based | ||||
|  |  | |||
|  | @ -516,7 +516,7 @@ static ssize_t device_write(struct file *file, const char __user *buf, | |||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	kbuf = memdup_user_nul(buf, count); | ||||
| 	if (!IS_ERR(kbuf)) | ||||
| 	if (IS_ERR(kbuf)) | ||||
| 		return PTR_ERR(kbuf); | ||||
| 
 | ||||
| 	if (check_version(kbuf)) { | ||||
|  |  | |||
|  | @ -46,9 +46,9 @@ void put_filesystem(struct file_system_type *fs) | |||
| static struct file_system_type **find_filesystem(const char *name, unsigned len) | ||||
| { | ||||
| 	struct file_system_type **p; | ||||
| 	for (p=&file_systems; *p; p=&(*p)->next) | ||||
| 		if (strlen((*p)->name) == len && | ||||
| 		    strncmp((*p)->name, name, len) == 0) | ||||
| 	for (p = &file_systems; *p; p = &(*p)->next) | ||||
| 		if (strncmp((*p)->name, name, len) == 0 && | ||||
| 		    !(*p)->name[len]) | ||||
| 			break; | ||||
| 	return p; | ||||
| } | ||||
|  |  | |||
							
								
								
									
										47
									
								
								fs/pipe.c
									
									
									
									
									
								
							
							
						
						
									
										47
									
								
								fs/pipe.c
									
									
									
									
									
								
							|  | @ -38,6 +38,12 @@ unsigned int pipe_max_size = 1048576; | |||
|  */ | ||||
| unsigned int pipe_min_size = PAGE_SIZE; | ||||
| 
 | ||||
| /* Maximum allocatable pages per user. Hard limit is unset by default, soft
 | ||||
|  * matches default values. | ||||
|  */ | ||||
| unsigned long pipe_user_pages_hard; | ||||
| unsigned long pipe_user_pages_soft = PIPE_DEF_BUFFERS * INR_OPEN_CUR; | ||||
| 
 | ||||
| /*
 | ||||
|  * We use a start+len construction, which provides full use of the  | ||||
|  * allocated memory. | ||||
|  | @ -583,20 +589,49 @@ pipe_fasync(int fd, struct file *filp, int on) | |||
| 	return retval; | ||||
| } | ||||
| 
 | ||||
| static void account_pipe_buffers(struct pipe_inode_info *pipe, | ||||
|                                  unsigned long old, unsigned long new) | ||||
| { | ||||
| 	atomic_long_add(new - old, &pipe->user->pipe_bufs); | ||||
| } | ||||
| 
 | ||||
| static bool too_many_pipe_buffers_soft(struct user_struct *user) | ||||
| { | ||||
| 	return pipe_user_pages_soft && | ||||
| 	       atomic_long_read(&user->pipe_bufs) >= pipe_user_pages_soft; | ||||
| } | ||||
| 
 | ||||
| static bool too_many_pipe_buffers_hard(struct user_struct *user) | ||||
| { | ||||
| 	return pipe_user_pages_hard && | ||||
| 	       atomic_long_read(&user->pipe_bufs) >= pipe_user_pages_hard; | ||||
| } | ||||
| 
 | ||||
| struct pipe_inode_info *alloc_pipe_info(void) | ||||
| { | ||||
| 	struct pipe_inode_info *pipe; | ||||
| 
 | ||||
| 	pipe = kzalloc(sizeof(struct pipe_inode_info), GFP_KERNEL); | ||||
| 	if (pipe) { | ||||
| 		pipe->bufs = kzalloc(sizeof(struct pipe_buffer) * PIPE_DEF_BUFFERS, GFP_KERNEL); | ||||
| 		unsigned long pipe_bufs = PIPE_DEF_BUFFERS; | ||||
| 		struct user_struct *user = get_current_user(); | ||||
| 
 | ||||
| 		if (!too_many_pipe_buffers_hard(user)) { | ||||
| 			if (too_many_pipe_buffers_soft(user)) | ||||
| 				pipe_bufs = 1; | ||||
| 			pipe->bufs = kzalloc(sizeof(struct pipe_buffer) * pipe_bufs, GFP_KERNEL); | ||||
| 		} | ||||
| 
 | ||||
| 		if (pipe->bufs) { | ||||
| 			init_waitqueue_head(&pipe->wait); | ||||
| 			pipe->r_counter = pipe->w_counter = 1; | ||||
| 			pipe->buffers = PIPE_DEF_BUFFERS; | ||||
| 			pipe->buffers = pipe_bufs; | ||||
| 			pipe->user = user; | ||||
| 			account_pipe_buffers(pipe, 0, pipe_bufs); | ||||
| 			mutex_init(&pipe->mutex); | ||||
| 			return pipe; | ||||
| 		} | ||||
| 		free_uid(user); | ||||
| 		kfree(pipe); | ||||
| 	} | ||||
| 
 | ||||
|  | @ -607,6 +642,8 @@ void free_pipe_info(struct pipe_inode_info *pipe) | |||
| { | ||||
| 	int i; | ||||
| 
 | ||||
| 	account_pipe_buffers(pipe, pipe->buffers, 0); | ||||
| 	free_uid(pipe->user); | ||||
| 	for (i = 0; i < pipe->buffers; i++) { | ||||
| 		struct pipe_buffer *buf = pipe->bufs + i; | ||||
| 		if (buf->ops) | ||||
|  | @ -998,6 +1035,7 @@ static long pipe_set_size(struct pipe_inode_info *pipe, unsigned long nr_pages) | |||
| 			memcpy(bufs + head, pipe->bufs, tail * sizeof(struct pipe_buffer)); | ||||
| 	} | ||||
| 
 | ||||
| 	account_pipe_buffers(pipe, pipe->buffers, nr_pages); | ||||
| 	pipe->curbuf = 0; | ||||
| 	kfree(pipe->bufs); | ||||
| 	pipe->bufs = bufs; | ||||
|  | @ -1069,6 +1107,11 @@ long pipe_fcntl(struct file *file, unsigned int cmd, unsigned long arg) | |||
| 		if (!capable(CAP_SYS_RESOURCE) && size > pipe_max_size) { | ||||
| 			ret = -EPERM; | ||||
| 			goto out; | ||||
| 		} else if ((too_many_pipe_buffers_hard(pipe->user) || | ||||
| 			    too_many_pipe_buffers_soft(pipe->user)) && | ||||
| 		           !capable(CAP_SYS_RESOURCE) && !capable(CAP_SYS_ADMIN)) { | ||||
| 			ret = -EPERM; | ||||
| 			goto out; | ||||
| 		} | ||||
| 		ret = pipe_set_size(pipe, nr_pages); | ||||
| 		break; | ||||
|  |  | |||
|  | @ -42,6 +42,7 @@ struct pipe_buffer { | |||
|  *	@fasync_readers: reader side fasync | ||||
|  *	@fasync_writers: writer side fasync | ||||
|  *	@bufs: the circular array of pipe buffers | ||||
|  *	@user: the user who created this pipe | ||||
|  **/ | ||||
| struct pipe_inode_info { | ||||
| 	struct mutex mutex; | ||||
|  | @ -57,6 +58,7 @@ struct pipe_inode_info { | |||
| 	struct fasync_struct *fasync_readers; | ||||
| 	struct fasync_struct *fasync_writers; | ||||
| 	struct pipe_buffer *bufs; | ||||
| 	struct user_struct *user; | ||||
| }; | ||||
| 
 | ||||
| /*
 | ||||
|  | @ -123,6 +125,8 @@ void pipe_unlock(struct pipe_inode_info *); | |||
| void pipe_double_lock(struct pipe_inode_info *, struct pipe_inode_info *); | ||||
| 
 | ||||
| extern unsigned int pipe_max_size, pipe_min_size; | ||||
| extern unsigned long pipe_user_pages_hard; | ||||
| extern unsigned long pipe_user_pages_soft; | ||||
| int pipe_proc_fn(struct ctl_table *, int, void __user *, size_t *, loff_t *); | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -835,6 +835,7 @@ struct user_struct { | |||
| #endif | ||||
| 	unsigned long locked_shm; /* How many pages of mlocked shm ? */ | ||||
| 	unsigned long unix_inflight;	/* How many files in flight in unix sockets */ | ||||
| 	atomic_long_t pipe_bufs;  /* how many pages are allocated in pipe buffers */ | ||||
| 
 | ||||
| #ifdef CONFIG_KEYS | ||||
| 	struct key *uid_keyring;	/* UID specific keyring */ | ||||
|  |  | |||
|  | @ -1757,6 +1757,20 @@ static struct ctl_table fs_table[] = { | |||
| 		.proc_handler	= &pipe_proc_fn, | ||||
| 		.extra1		= &pipe_min_size, | ||||
| 	}, | ||||
| 	{ | ||||
| 		.procname	= "pipe-user-pages-hard", | ||||
| 		.data		= &pipe_user_pages_hard, | ||||
| 		.maxlen		= sizeof(pipe_user_pages_hard), | ||||
| 		.mode		= 0644, | ||||
| 		.proc_handler	= proc_doulongvec_minmax, | ||||
| 	}, | ||||
| 	{ | ||||
| 		.procname	= "pipe-user-pages-soft", | ||||
| 		.data		= &pipe_user_pages_soft, | ||||
| 		.maxlen		= sizeof(pipe_user_pages_soft), | ||||
| 		.mode		= 0644, | ||||
| 		.proc_handler	= proc_doulongvec_minmax, | ||||
| 	}, | ||||
| 	{ } | ||||
| }; | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Linus Torvalds
						Linus Torvalds