ptr += strlen("proc");
        ptr = skip_spaces(ptr);
 
-       file = file_open_root(mnt->mnt_root, mnt, ptr, O_RDONLY);
+       file = file_open_root(mnt->mnt_root, mnt, ptr, O_RDONLY, 0);
        if (IS_ERR(file)) {
                mconsole_reply(req, "Failed to open file", 1, 0);
                printk(KERN_ERR "open /proc/%s: %ld\n", ptr, PTR_ERR(file));
 
 #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>
                }
        } 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;
                 * 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;
 
 
                path_put(&path);
                return fd;
        }
-       file = file_open_root(path.dentry, path.mnt, "", open_flag);
+       file = file_open_root(path.dentry, path.mnt, "", open_flag, 0);
        if (IS_ERR(file)) {
                put_unused_fd(fd);
                retval =  PTR_ERR(file);
 
 EXPORT_SYMBOL(filp_open);
 
 struct file *file_open_root(struct dentry *dentry, struct vfsmount *mnt,
-                           const char *filename, int flags)
+                           const char *filename, int flags, umode_t mode)
 {
        struct open_flags op;
-       int err = build_open_flags(flags, 0, &op);
+       int err = build_open_flags(flags, mode, &op);
        if (err)
                return ERR_PTR(err);
-       if (flags & O_CREAT)
-               return ERR_PTR(-EINVAL);
        return do_file_open_root(dentry, mnt, filename, &op);
 }
 EXPORT_SYMBOL(file_open_root);
 
 extern struct file *file_open_name(struct filename *, int, umode_t);
 extern struct file *filp_open(const char *, int, umode_t);
 extern struct file *file_open_root(struct dentry *, struct vfsmount *,
-                                  const char *, int);
+                                  const char *, int, umode_t);
 extern struct file * dentry_open(const struct path *, int, const struct cred *);
 extern int filp_close(struct file *, fl_owner_t id);
 
 
        }
 
        mnt = task_active_pid_ns(current)->proc_mnt;
-       file = file_open_root(mnt->mnt_root, mnt, pathname, flags);
+       file = file_open_root(mnt->mnt_root, mnt, pathname, flags, 0);
        result = PTR_ERR(file);
        if (IS_ERR(file))
                goto out_putname;