mirror of
https://github.com/Fishwaldo/linux-bl808.git
synced 2025-03-19 05:24:11 +00: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
|
- nr_open
|
||||||
- overflowuid
|
- overflowuid
|
||||||
- overflowgid
|
- overflowgid
|
||||||
|
- pipe-user-pages-hard
|
||||||
|
- pipe-user-pages-soft
|
||||||
- protected_hardlinks
|
- protected_hardlinks
|
||||||
- protected_symlinks
|
- protected_symlinks
|
||||||
- suid_dumpable
|
- 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:
|
protected_hardlinks:
|
||||||
|
|
||||||
A long-standing class of security issues is the hardlink-based
|
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;
|
return -EINVAL;
|
||||||
|
|
||||||
kbuf = memdup_user_nul(buf, count);
|
kbuf = memdup_user_nul(buf, count);
|
||||||
if (!IS_ERR(kbuf))
|
if (IS_ERR(kbuf))
|
||||||
return PTR_ERR(kbuf);
|
return PTR_ERR(kbuf);
|
||||||
|
|
||||||
if (check_version(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)
|
static struct file_system_type **find_filesystem(const char *name, unsigned len)
|
||||||
{
|
{
|
||||||
struct file_system_type **p;
|
struct file_system_type **p;
|
||||||
for (p=&file_systems; *p; p=&(*p)->next)
|
for (p = &file_systems; *p; p = &(*p)->next)
|
||||||
if (strlen((*p)->name) == len &&
|
if (strncmp((*p)->name, name, len) == 0 &&
|
||||||
strncmp((*p)->name, name, len) == 0)
|
!(*p)->name[len])
|
||||||
break;
|
break;
|
||||||
return p;
|
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;
|
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
|
* We use a start+len construction, which provides full use of the
|
||||||
* allocated memory.
|
* allocated memory.
|
||||||
|
@ -583,20 +589,49 @@ pipe_fasync(int fd, struct file *filp, int on)
|
||||||
return retval;
|
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 *alloc_pipe_info(void)
|
||||||
{
|
{
|
||||||
struct pipe_inode_info *pipe;
|
struct pipe_inode_info *pipe;
|
||||||
|
|
||||||
pipe = kzalloc(sizeof(struct pipe_inode_info), GFP_KERNEL);
|
pipe = kzalloc(sizeof(struct pipe_inode_info), GFP_KERNEL);
|
||||||
if (pipe) {
|
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) {
|
if (pipe->bufs) {
|
||||||
init_waitqueue_head(&pipe->wait);
|
init_waitqueue_head(&pipe->wait);
|
||||||
pipe->r_counter = pipe->w_counter = 1;
|
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);
|
mutex_init(&pipe->mutex);
|
||||||
return pipe;
|
return pipe;
|
||||||
}
|
}
|
||||||
|
free_uid(user);
|
||||||
kfree(pipe);
|
kfree(pipe);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -607,6 +642,8 @@ void free_pipe_info(struct pipe_inode_info *pipe)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
account_pipe_buffers(pipe, pipe->buffers, 0);
|
||||||
|
free_uid(pipe->user);
|
||||||
for (i = 0; i < pipe->buffers; i++) {
|
for (i = 0; i < pipe->buffers; i++) {
|
||||||
struct pipe_buffer *buf = pipe->bufs + i;
|
struct pipe_buffer *buf = pipe->bufs + i;
|
||||||
if (buf->ops)
|
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));
|
memcpy(bufs + head, pipe->bufs, tail * sizeof(struct pipe_buffer));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
account_pipe_buffers(pipe, pipe->buffers, nr_pages);
|
||||||
pipe->curbuf = 0;
|
pipe->curbuf = 0;
|
||||||
kfree(pipe->bufs);
|
kfree(pipe->bufs);
|
||||||
pipe->bufs = 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) {
|
if (!capable(CAP_SYS_RESOURCE) && size > pipe_max_size) {
|
||||||
ret = -EPERM;
|
ret = -EPERM;
|
||||||
goto out;
|
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);
|
ret = pipe_set_size(pipe, nr_pages);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -42,6 +42,7 @@ struct pipe_buffer {
|
||||||
* @fasync_readers: reader side fasync
|
* @fasync_readers: reader side fasync
|
||||||
* @fasync_writers: writer side fasync
|
* @fasync_writers: writer side fasync
|
||||||
* @bufs: the circular array of pipe buffers
|
* @bufs: the circular array of pipe buffers
|
||||||
|
* @user: the user who created this pipe
|
||||||
**/
|
**/
|
||||||
struct pipe_inode_info {
|
struct pipe_inode_info {
|
||||||
struct mutex mutex;
|
struct mutex mutex;
|
||||||
|
@ -57,6 +58,7 @@ struct pipe_inode_info {
|
||||||
struct fasync_struct *fasync_readers;
|
struct fasync_struct *fasync_readers;
|
||||||
struct fasync_struct *fasync_writers;
|
struct fasync_struct *fasync_writers;
|
||||||
struct pipe_buffer *bufs;
|
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 *);
|
void pipe_double_lock(struct pipe_inode_info *, struct pipe_inode_info *);
|
||||||
|
|
||||||
extern unsigned int pipe_max_size, pipe_min_size;
|
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 *);
|
int pipe_proc_fn(struct ctl_table *, int, void __user *, size_t *, loff_t *);
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -835,6 +835,7 @@ struct user_struct {
|
||||||
#endif
|
#endif
|
||||||
unsigned long locked_shm; /* How many pages of mlocked shm ? */
|
unsigned long locked_shm; /* How many pages of mlocked shm ? */
|
||||||
unsigned long unix_inflight; /* How many files in flight in unix sockets */
|
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
|
#ifdef CONFIG_KEYS
|
||||||
struct key *uid_keyring; /* UID specific keyring */
|
struct key *uid_keyring; /* UID specific keyring */
|
||||||
|
|
|
@ -1757,6 +1757,20 @@ static struct ctl_table fs_table[] = {
|
||||||
.proc_handler = &pipe_proc_fn,
|
.proc_handler = &pipe_proc_fn,
|
||||||
.extra1 = &pipe_min_size,
|
.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…
Add table
Reference in a new issue