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
|
@ -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