coredump: only charge written data against RLIMIT_CORE
[deliverable/linux.git] / fs / coredump.c
index 9ea87e9fdccf6e8c26350b7bce598562295eacb9..492c2db25dc9bd654a3fb6931dc3bdc1162ac42d 100644 (file)
@@ -32,6 +32,9 @@
 #include <linux/pipe_fs_i.h>
 #include <linux/oom.h>
 #include <linux/compat.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/path.h>
 #include <linux/timekeeping.h>
 
 #include <asm/uaccess.h>
@@ -649,6 +652,8 @@ void do_coredump(const siginfo_t *siginfo)
                }
        } else {
                struct inode *inode;
+               int open_flags = O_CREAT | O_RDWR | O_NOFOLLOW |
+                                O_LARGEFILE | O_EXCL;
 
                if (cprm.limit < binfmt->min_coredump)
                        goto fail_unlock;
@@ -687,10 +692,27 @@ void do_coredump(const siginfo_t *siginfo)
                 * what matters is that at least one of the two processes
                 * writes its coredump successfully, not which one.
                 */
-               cprm.file = filp_open(cn.corename,
-                                O_CREAT | 2 | O_NOFOLLOW |
-                                O_LARGEFILE | O_EXCL,
-                                0600);
+               if (need_suid_safe) {
+                       /*
+                        * Using user namespaces, normal user tasks can change
+                        * their current->fs->root to point to arbitrary
+                        * directories. Since the intention of the "only dump
+                        * with a fully qualified path" rule is to control where
+                        * coredumps may be placed using root privileges,
+                        * current->fs->root must not be used. Instead, use the
+                        * root directory of init_task.
+                        */
+                       struct path root;
+
+                       task_lock(&init_task);
+                       get_fs_root(init_task.fs, &root);
+                       task_unlock(&init_task);
+                       cprm.file = file_open_root(root.dentry, root.mnt,
+                               cn.corename, open_flags, 0600);
+                       path_put(&root);
+               } else {
+                       cprm.file = filp_open(cn.corename, open_flags, 0600);
+               }
                if (IS_ERR(cprm.file))
                        goto fail_unlock;
 
@@ -781,12 +803,9 @@ int dump_skip(struct coredump_params *cprm, size_t nr)
        static char zeroes[PAGE_SIZE];
        struct file *file = cprm->file;
        if (file->f_op->llseek && file->f_op->llseek != no_llseek) {
-               if (cprm->written + nr > cprm->limit)
-                       return 0;
                if (dump_interrupted() ||
                    file->f_op->llseek(file, nr, SEEK_CUR) < 0)
                        return 0;
-               cprm->written += nr;
                return 1;
        } else {
                while (nr > PAGE_SIZE) {
@@ -801,7 +820,7 @@ EXPORT_SYMBOL(dump_skip);
 
 int dump_align(struct coredump_params *cprm, int align)
 {
-       unsigned mod = cprm->written & (align - 1);
+       unsigned mod = cprm->file->f_pos & (align - 1);
        if (align & (align - 1))
                return 0;
        return mod ? dump_skip(cprm, align - mod) : 1;
This page took 0.031634 seconds and 5 git commands to generate.