2019-05-19 15:08:55 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2007-05-11 09:23:11 +04:00
/*
* fs / anon_inodes . c
*
* Copyright ( C ) 2007 Davide Libenzi < davidel @ xmailserver . org >
*
* Thanks to Arnd Bergmann for code review and suggestions .
* More changes for Thomas Gleixner suggestions .
*
*/
2009-10-04 16:11:37 +04:00
# include <linux/cred.h>
2007-05-11 09:23:11 +04:00
# include <linux/file.h>
# include <linux/poll.h>
2009-10-04 16:11:37 +04:00
# include <linux/sched.h>
2007-05-11 09:23:11 +04:00
# include <linux/init.h>
# include <linux/fs.h>
# include <linux/mount.h>
# include <linux/module.h>
# include <linux/kernel.h>
# include <linux/magic.h>
# include <linux/anon_inodes.h>
2019-03-25 19:38:23 +03:00
# include <linux/pseudo_fs.h>
2007-05-11 09:23:11 +04:00
2016-12-24 22:46:01 +03:00
# include <linux/uaccess.h>
2007-05-11 09:23:11 +04:00
static struct vfsmount * anon_inode_mnt __read_mostly ;
static struct inode * anon_inode_inode ;
2009-11-21 01:28:35 +03:00
/*
* anon_inodefs_dname ( ) is called from d_path ( ) .
*/
static char * anon_inodefs_dname ( struct dentry * dentry , char * buffer , int buflen )
{
return dynamic_dname ( dentry , buffer , buflen , " anon_inode:%s " ,
dentry - > d_name . name ) ;
}
2011-01-13 00:59:34 +03:00
static const struct dentry_operations anon_inodefs_dentry_operations = {
. d_dname = anon_inodefs_dname ,
} ;
2019-03-25 19:38:23 +03:00
static int anon_inodefs_init_fs_context ( struct fs_context * fc )
2012-03-17 10:52:29 +04:00
{
2019-03-25 19:38:23 +03:00
struct pseudo_fs_context * ctx = init_pseudo ( fc , ANON_INODE_FS_MAGIC ) ;
if ( ! ctx )
return - ENOMEM ;
ctx - > dops = & anon_inodefs_dentry_operations ;
return 0 ;
2012-03-17 10:52:29 +04:00
}
static struct file_system_type anon_inode_fs_type = {
. name = " anon_inodefs " ,
2019-03-25 19:38:23 +03:00
. init_fs_context = anon_inodefs_init_fs_context ,
2012-03-17 10:52:29 +04:00
. kill_sb = kill_anon_super ,
} ;
2021-01-09 01:22:21 +03:00
static struct inode * anon_inode_make_secure_inode (
const char * name ,
const struct inode * context_inode )
2007-05-11 09:23:11 +04:00
{
2021-01-09 01:22:21 +03:00
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 ;
}
2007-05-11 09:23:11 +04:00
2021-01-09 01:22:21 +03:00
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 ;
2007-05-11 09:23:11 +04:00
2008-12-02 13:16:03 +03:00
if ( fops - > owner & & ! try_module_get ( fops - > owner ) )
2009-09-23 03:43:57 +04:00
return ERR_PTR ( - ENOENT ) ;
2007-05-11 09:23:11 +04:00
2021-01-09 01:22:21 +03:00
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 ,
2018-06-09 16:58:23 +03:00
flags & ( O_ACCMODE | O_NONBLOCK ) , fops ) ;
2012-09-13 07:11:55 +04:00
if ( IS_ERR ( file ) )
2021-01-09 01:22:21 +03:00
goto err_iput ;
2018-06-09 16:58:23 +03:00
2021-01-09 01:22:21 +03:00
file - > f_mapping = inode - > i_mapping ;
2007-05-11 09:23:11 +04:00
file - > private_data = priv ;
2009-09-23 03:43:57 +04:00
return file ;
2021-01-09 01:22:21 +03:00
err_iput :
iput ( inode ) ;
2018-06-09 16:58:23 +03:00
err :
2009-09-23 03:43:57 +04:00
module_put ( fops - > owner ) ;
2012-09-13 07:11:55 +04:00
return file ;
2009-09-23 03:43:57 +04:00
}
/**
2021-01-09 01:22:21 +03:00
* 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
2009-09-23 03:43:57 +04:00
*
* @ 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 .
2021-01-09 01:22:21 +03:00
* All the files created with anon_inode_getfile ( ) will share a single inode ,
2009-09-23 03:43:57 +04:00
* hence saving memory and avoiding code duplication for the file / inode / dentry
2021-01-09 01:22:21 +03:00
* setup . Returns the newly created file * or an error pointer .
2009-09-23 03:43:57 +04:00
*/
2021-01-09 01:22:21 +03:00
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 )
2009-09-23 03:43:57 +04:00
{
int error , fd ;
struct file * file ;
error = get_unused_fd_flags ( flags ) ;
if ( error < 0 )
return error ;
fd = error ;
2021-01-09 01:22:21 +03:00
file = __anon_inode_getfile ( name , fops , priv , flags , context_inode ,
secure ) ;
2009-09-23 03:43:57 +04:00
if ( IS_ERR ( file ) ) {
error = PTR_ERR ( file ) ;
goto err_put_unused_fd ;
}
2007-05-11 09:23:11 +04:00
fd_install ( fd , file ) ;
2008-02-23 14:46:49 +03:00
return fd ;
2007-05-11 09:23:11 +04:00
err_put_unused_fd :
put_unused_fd ( fd ) ;
return error ;
}
2021-01-09 01:22:21 +03:00
/**
* 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 ) ;
}
2007-06-28 16:38:16 +04:00
EXPORT_SYMBOL_GPL ( anon_inode_getfd ) ;
2007-05-11 09:23:11 +04:00
2021-01-09 01:22:21 +03:00
/**
2021-01-15 15:03:42 +03:00
* 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 .
2021-01-09 01:22:21 +03:00
*/
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 ) ;
2007-05-11 09:23:11 +04:00
static int __init anon_inode_init ( void )
{
anon_inode_mnt = kern_mount ( & anon_inode_fs_type ) ;
2014-03-26 09:20:14 +04:00
if ( IS_ERR ( anon_inode_mnt ) )
panic ( " anon_inode_init() kernel mount failed (%ld) \n " , PTR_ERR ( anon_inode_mnt ) ) ;
2007-05-11 09:23:11 +04:00
2014-03-26 09:20:14 +04:00
anon_inode_inode = alloc_anon_inode ( anon_inode_mnt - > mnt_sb ) ;
if ( IS_ERR ( anon_inode_inode ) )
panic ( " anon_inode_init() inode allocation failed (%ld) \n " , PTR_ERR ( anon_inode_inode ) ) ;
return 0 ;
2007-05-11 09:23:11 +04:00
}
fs_initcall ( anon_inode_init ) ;