#include <linux/atomic.h>
 #include <linux/device.h>
 #include <linux/poll.h>
+#include <linux/security.h>
 
 #include "internal.h"
 
 }
 EXPORT_SYMBOL_GPL(debugfs_file_put);
 
+/*
+ * Only permit access to world-readable files when the kernel is locked down.
+ * We also need to exclude any file that has ways to write or alter it as root
+ * can bypass the permissions check.
+ */
+static bool debugfs_is_locked_down(struct inode *inode,
+                                  struct file *filp,
+                                  const struct file_operations *real_fops)
+{
+       if ((inode->i_mode & 07777) == 0444 &&
+           !(filp->f_mode & FMODE_WRITE) &&
+           !real_fops->unlocked_ioctl &&
+           !real_fops->compat_ioctl &&
+           !real_fops->mmap)
+               return false;
+
+       return security_locked_down(LOCKDOWN_DEBUGFS);
+}
+
 static int open_proxy_open(struct inode *inode, struct file *filp)
 {
        struct dentry *dentry = F_DENTRY(filp);
                return r == -EIO ? -ENOENT : r;
 
        real_fops = debugfs_real_fops(filp);
+
+       r = debugfs_is_locked_down(inode, filp, real_fops);
+       if (r)
+               goto out;
+
        real_fops = fops_get(real_fops);
        if (!real_fops) {
                /* Huh? Module did not clean up after itself at exit? */
                return r == -EIO ? -ENOENT : r;
 
        real_fops = debugfs_real_fops(filp);
+
+       r = debugfs_is_locked_down(inode, filp, real_fops);
+       if (r)
+               goto out;
+
        real_fops = fops_get(real_fops);
        if (!real_fops) {
                /* Huh? Module did not cleanup after itself at exit? */
 
 #include <linux/parser.h>
 #include <linux/magic.h>
 #include <linux/slab.h>
+#include <linux/security.h>
 
 #include "internal.h"
 
 static int debugfs_mount_count;
 static bool debugfs_registered;
 
+/*
+ * Don't allow access attributes to be changed whilst the kernel is locked down
+ * so that we can use the file mode as part of a heuristic to determine whether
+ * to lock down individual files.
+ */
+static int debugfs_setattr(struct dentry *dentry, struct iattr *ia)
+{
+       int ret = security_locked_down(LOCKDOWN_DEBUGFS);
+
+       if (ret && (ia->ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID)))
+               return ret;
+       return simple_setattr(dentry, ia);
+}
+
+static const struct inode_operations debugfs_file_inode_operations = {
+       .setattr        = debugfs_setattr,
+};
+static const struct inode_operations debugfs_dir_inode_operations = {
+       .lookup         = simple_lookup,
+       .setattr        = debugfs_setattr,
+};
+static const struct inode_operations debugfs_symlink_inode_operations = {
+       .get_link       = simple_get_link,
+       .setattr        = debugfs_setattr,
+};
+
 static struct inode *debugfs_get_inode(struct super_block *sb)
 {
        struct inode *inode = new_inode(sb);
        inode->i_mode = mode;
        inode->i_private = data;
 
+       inode->i_op = &debugfs_file_inode_operations;
        inode->i_fop = proxy_fops;
        dentry->d_fsdata = (void *)((unsigned long)real_fops |
                                DEBUGFS_FSDATA_IS_REAL_FOPS_BIT);
                return failed_creating(dentry);
 
        inode->i_mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO;
-       inode->i_op = &simple_dir_inode_operations;
+       inode->i_op = &debugfs_dir_inode_operations;
        inode->i_fop = &simple_dir_operations;
 
        /* directory inodes start off with i_nlink == 2 (for "." entry) */
                return failed_creating(dentry);
        }
        inode->i_mode = S_IFLNK | S_IRWXUGO;
-       inode->i_op = &simple_symlink_inode_operations;
+       inode->i_op = &debugfs_symlink_inode_operations;
        inode->i_link = link;
        d_instantiate(dentry, inode);
        return end_creating(dentry);
 
        [LOCKDOWN_TIOCSSERIAL] = "reconfiguration of serial port IO",
        [LOCKDOWN_MODULE_PARAMETERS] = "unsafe module parameters",
        [LOCKDOWN_MMIOTRACE] = "unsafe mmio",
+       [LOCKDOWN_DEBUGFS] = "debugfs access",
        [LOCKDOWN_INTEGRITY_MAX] = "integrity",
        [LOCKDOWN_KCORE] = "/proc/kcore access",
        [LOCKDOWN_KPROBES] = "use of kprobes",