tools headers UAPI: Sync drm/i915_drm.h with the kernel sources
[linux-2.6-microblaze.git] / fs / anon_inodes.c
index 8971430..a280156 100644 (file)
@@ -55,61 +55,79 @@ static struct file_system_type anon_inode_fs_type = {
        .kill_sb        = kill_anon_super,
 };
 
-/**
- * anon_inode_getfile - creates a new file instance by hooking it up to an
- *                      anonymous inode, and a dentry that describe the "class"
- *                      of the file
- *
- * @name:    [in]    name of the "class" of the new file
- * @fops:    [in]    file operations for the new file
- * @priv:    [in]    private data for the new file (will be file's private_data)
- * @flags:   [in]    flags
- *
- * Creates a new file by hooking it on a single inode. This is useful for files
- * that do not need to have a full-fledged inode in order to operate correctly.
- * All the files created with anon_inode_getfile() will share a single inode,
- * hence saving memory and avoiding code duplication for the file/inode/dentry
- * setup.  Returns the newly created file* or an error pointer.
- */
-struct file *anon_inode_getfile(const char *name,
-                               const struct file_operations *fops,
-                               void *priv, int flags)
+static struct inode *anon_inode_make_secure_inode(
+       const char *name,
+       const struct inode *context_inode)
 {
-       struct file *file;
+       struct inode *inode;
+       const struct qstr qname = QSTR_INIT(name, strlen(name));
+       int error;
+
+       inode = alloc_anon_inode(anon_inode_mnt->mnt_sb);
+       if (IS_ERR(inode))
+               return inode;
+       inode->i_flags &= ~S_PRIVATE;
+       error = security_inode_init_security_anon(inode, &qname, context_inode);
+       if (error) {
+               iput(inode);
+               return ERR_PTR(error);
+       }
+       return inode;
+}
 
-       if (IS_ERR(anon_inode_inode))
-               return ERR_PTR(-ENODEV);
+static struct file *__anon_inode_getfile(const char *name,
+                                        const struct file_operations *fops,
+                                        void *priv, int flags,
+                                        const struct inode *context_inode,
+                                        bool secure)
+{
+       struct inode *inode;
+       struct file *file;
 
        if (fops->owner && !try_module_get(fops->owner))
                return ERR_PTR(-ENOENT);
 
-       /*
-        * We know the anon_inode inode count is always greater than zero,
-        * so ihold() is safe.
-        */
-       ihold(anon_inode_inode);
-       file = alloc_file_pseudo(anon_inode_inode, anon_inode_mnt, name,
+       if (secure) {
+               inode = anon_inode_make_secure_inode(name, context_inode);
+               if (IS_ERR(inode)) {
+                       file = ERR_CAST(inode);
+                       goto err;
+               }
+       } else {
+               inode = anon_inode_inode;
+               if (IS_ERR(inode)) {
+                       file = ERR_PTR(-ENODEV);
+                       goto err;
+               }
+               /*
+                * We know the anon_inode inode count is always
+                * greater than zero, so ihold() is safe.
+                */
+               ihold(inode);
+       }
+
+       file = alloc_file_pseudo(inode, anon_inode_mnt, name,
                                 flags & (O_ACCMODE | O_NONBLOCK), fops);
        if (IS_ERR(file))
-               goto err;
+               goto err_iput;
 
-       file->f_mapping = anon_inode_inode->i_mapping;
+       file->f_mapping = inode->i_mapping;
 
        file->private_data = priv;
 
        return file;
 
+err_iput:
+       iput(inode);
 err:
-       iput(anon_inode_inode);
        module_put(fops->owner);
        return file;
 }
-EXPORT_SYMBOL_GPL(anon_inode_getfile);
 
 /**
- * anon_inode_getfd - creates a new file instance by hooking it up to an
- *                    anonymous inode, and a dentry that describe the "class"
- *                    of the file
+ * anon_inode_getfile - creates a new file instance by hooking it up to an
+ *                      anonymous inode, and a dentry that describe the "class"
+ *                      of the file
  *
  * @name:    [in]    name of the "class" of the new file
  * @fops:    [in]    file operations for the new file
@@ -118,12 +136,23 @@ EXPORT_SYMBOL_GPL(anon_inode_getfile);
  *
  * Creates a new file by hooking it on a single inode. This is useful for files
  * that do not need to have a full-fledged inode in order to operate correctly.
- * All the files created with anon_inode_getfd() will share a single inode,
+ * All the files created with anon_inode_getfile() will share a single inode,
  * hence saving memory and avoiding code duplication for the file/inode/dentry
- * setup.  Returns new descriptor or an error code.
+ * setup.  Returns the newly created file* or an error pointer.
  */
-int anon_inode_getfd(const char *name, const struct file_operations *fops,
-                    void *priv, int flags)
+struct file *anon_inode_getfile(const char *name,
+                               const struct file_operations *fops,
+                               void *priv, int flags)
+{
+       return __anon_inode_getfile(name, fops, priv, flags, NULL, false);
+}
+EXPORT_SYMBOL_GPL(anon_inode_getfile);
+
+static int __anon_inode_getfd(const char *name,
+                             const struct file_operations *fops,
+                             void *priv, int flags,
+                             const struct inode *context_inode,
+                             bool secure)
 {
        int error, fd;
        struct file *file;
@@ -133,7 +162,8 @@ int anon_inode_getfd(const char *name, const struct file_operations *fops,
                return error;
        fd = error;
 
-       file = anon_inode_getfile(name, fops, priv, flags);
+       file = __anon_inode_getfile(name, fops, priv, flags, context_inode,
+                                   secure);
        if (IS_ERR(file)) {
                error = PTR_ERR(file);
                goto err_put_unused_fd;
@@ -146,8 +176,55 @@ err_put_unused_fd:
        put_unused_fd(fd);
        return error;
 }
+
+/**
+ * anon_inode_getfd - creates a new file instance by hooking it up to
+ *                    an anonymous inode and a dentry that describe
+ *                    the "class" of the file
+ *
+ * @name:    [in]    name of the "class" of the new file
+ * @fops:    [in]    file operations for the new file
+ * @priv:    [in]    private data for the new file (will be file's private_data)
+ * @flags:   [in]    flags
+ *
+ * Creates a new file by hooking it on a single inode. This is
+ * useful for files that do not need to have a full-fledged inode in
+ * order to operate correctly.  All the files created with
+ * anon_inode_getfd() will use the same singleton inode, reducing
+ * memory use and avoiding code duplication for the file/inode/dentry
+ * setup.  Returns a newly created file descriptor or an error code.
+ */
+int anon_inode_getfd(const char *name, const struct file_operations *fops,
+                    void *priv, int flags)
+{
+       return __anon_inode_getfd(name, fops, priv, flags, NULL, false);
+}
 EXPORT_SYMBOL_GPL(anon_inode_getfd);
 
+/**
+ * anon_inode_getfd_secure - Like anon_inode_getfd(), but creates a new
+ * !S_PRIVATE anon inode rather than reuse the singleton anon inode, and calls
+ * the inode_init_security_anon() LSM hook. This allows the inode to have its
+ * own security context and for a LSM to reject creation of the inode.
+ *
+ * @name:    [in]    name of the "class" of the new file
+ * @fops:    [in]    file operations for the new file
+ * @priv:    [in]    private data for the new file (will be file's private_data)
+ * @flags:   [in]    flags
+ * @context_inode:
+ *           [in]    the logical relationship with the new inode (optional)
+ *
+ * The LSM may use @context_inode in inode_init_security_anon(), but a
+ * reference to it is not held.
+ */
+int anon_inode_getfd_secure(const char *name, const struct file_operations *fops,
+                           void *priv, int flags,
+                           const struct inode *context_inode)
+{
+       return __anon_inode_getfd(name, fops, priv, flags, context_inode, true);
+}
+EXPORT_SYMBOL_GPL(anon_inode_getfd_secure);
+
 static int __init anon_inode_init(void)
 {
        anon_inode_mnt = kern_mount(&anon_inode_fs_type);