remove libdss from Makefile
[GitHub/moto-9609/android_kernel_motorola_exynos9610.git] / fs / pipe.c
index 97e5be897753ef61c67b3534205f9839b715942e..8f9628494981c3bf60c19d562896f5724e3c9f19 100644 (file)
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -1,3 +1,4 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  *  linux/fs/pipe.c
  *
@@ -238,6 +239,14 @@ static const struct pipe_buf_operations anon_pipe_buf_ops = {
        .get = generic_pipe_buf_get,
 };
 
+static const struct pipe_buf_operations anon_pipe_buf_nomerge_ops = {
+       .can_merge = 0,
+       .confirm = generic_pipe_buf_confirm,
+       .release = anon_pipe_buf_release,
+       .steal = anon_pipe_buf_steal,
+       .get = generic_pipe_buf_get,
+};
+
 static const struct pipe_buf_operations packet_pipe_buf_ops = {
        .can_merge = 0,
        .confirm = generic_pipe_buf_confirm,
@@ -246,6 +255,12 @@ static const struct pipe_buf_operations packet_pipe_buf_ops = {
        .get = generic_pipe_buf_get,
 };
 
+void pipe_buf_mark_unmergeable(struct pipe_buffer *buf)
+{
+       if (buf->ops == &anon_pipe_buf_ops)
+               buf->ops = &anon_pipe_buf_nomerge_ops;
+}
+
 static ssize_t
 pipe_read(struct kiocb *iocb, struct iov_iter *to)
 {
@@ -609,12 +624,17 @@ static unsigned long account_pipe_buffers(struct user_struct *user,
 
 static bool too_many_pipe_buffers_soft(unsigned long user_bufs)
 {
-       return pipe_user_pages_soft && user_bufs >= pipe_user_pages_soft;
+       return pipe_user_pages_soft && user_bufs > pipe_user_pages_soft;
 }
 
 static bool too_many_pipe_buffers_hard(unsigned long user_bufs)
 {
-       return pipe_user_pages_hard && user_bufs >= pipe_user_pages_hard;
+       return pipe_user_pages_hard && user_bufs > pipe_user_pages_hard;
+}
+
+static bool is_unprivileged_user(void)
+{
+       return !capable(CAP_SYS_RESOURCE) && !capable(CAP_SYS_ADMIN);
 }
 
 struct pipe_inode_info *alloc_pipe_info(void)
@@ -633,12 +653,12 @@ struct pipe_inode_info *alloc_pipe_info(void)
 
        user_bufs = account_pipe_buffers(user, 0, pipe_bufs);
 
-       if (too_many_pipe_buffers_soft(user_bufs)) {
+       if (too_many_pipe_buffers_soft(user_bufs) && is_unprivileged_user()) {
                user_bufs = account_pipe_buffers(user, pipe_bufs, 1);
                pipe_bufs = 1;
        }
 
-       if (too_many_pipe_buffers_hard(user_bufs))
+       if (too_many_pipe_buffers_hard(user_bufs) && is_unprivileged_user())
                goto out_revert_acct;
 
        pipe->bufs = kcalloc(pipe_bufs, sizeof(struct pipe_buffer),
@@ -1017,13 +1037,19 @@ const struct file_operations pipefifo_fops = {
 
 /*
  * Currently we rely on the pipe array holding a power-of-2 number
- * of pages.
+ * of pages. Returns 0 on error.
  */
 static inline unsigned int round_pipe_size(unsigned int size)
 {
        unsigned long nr_pages;
 
+       if (size < pipe_min_size)
+               size = pipe_min_size;
+
        nr_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
+       if (nr_pages == 0)
+               return 0;
+
        return roundup_pow_of_two(nr_pages) << PAGE_SHIFT;
 }
 
@@ -1039,6 +1065,8 @@ static long pipe_set_size(struct pipe_inode_info *pipe, unsigned long arg)
        long ret = 0;
 
        size = round_pipe_size(arg);
+       if (size == 0)
+               return -EINVAL;
        nr_pages = size >> PAGE_SHIFT;
 
        if (!nr_pages)
@@ -1060,7 +1088,7 @@ static long pipe_set_size(struct pipe_inode_info *pipe, unsigned long arg)
        if (nr_pages > pipe->buffers &&
                        (too_many_pipe_buffers_hard(user_bufs) ||
                         too_many_pipe_buffers_soft(user_bufs)) &&
-                       !capable(CAP_SYS_RESOURCE) && !capable(CAP_SYS_ADMIN)) {
+                       is_unprivileged_user()) {
                ret = -EPERM;
                goto out_revert_acct;
        }
@@ -1122,13 +1150,18 @@ out_revert_acct:
 int pipe_proc_fn(struct ctl_table *table, int write, void __user *buf,
                 size_t *lenp, loff_t *ppos)
 {
+       unsigned int rounded_pipe_max_size;
        int ret;
 
-       ret = proc_dointvec_minmax(table, write, buf, lenp, ppos);
+       ret = proc_douintvec_minmax(table, write, buf, lenp, ppos);
        if (ret < 0 || !write)
                return ret;
 
-       pipe_max_size = round_pipe_size(pipe_max_size);
+       rounded_pipe_max_size = round_pipe_size(pipe_max_size);
+       if (rounded_pipe_max_size == 0)
+               return -EINVAL;
+
+       pipe_max_size = rounded_pipe_max_size;
        return ret;
 }