2017-02-08 20:51:30 +03:00
# include <linux/sched/signal.h>
2012-08-23 14:43:24 +04:00
# include <linux/errno.h>
# include <linux/dcache.h>
# include <linux/path.h>
# include <linux/fdtable.h>
# include <linux/namei.h>
# include <linux/pid.h>
# include <linux/security.h>
2012-08-26 18:28:20 +04:00
# include <linux/file.h>
# include <linux/seq_file.h>
2015-04-16 22:49:38 +03:00
# include <linux/fs.h>
2012-08-23 14:43:24 +04:00
# include <linux/proc_fs.h>
2014-04-08 02:38:34 +04:00
# include "../mount.h"
2012-08-23 14:43:24 +04:00
# include "internal.h"
# include "fd.h"
2012-08-26 18:28:20 +04:00
static int seq_show ( struct seq_file * m , void * v )
2012-08-23 14:43:24 +04:00
{
struct files_struct * files = NULL ;
2012-08-26 18:28:20 +04:00
int f_flags = 0 , ret = - ENOENT ;
struct file * file = NULL ;
struct task_struct * task ;
task = get_proc_task ( m - > private ) ;
if ( ! task )
return - ENOENT ;
files = get_files_struct ( task ) ;
put_task_struct ( task ) ;
2012-08-23 14:43:24 +04:00
if ( files ) {
2016-09-02 00:42:02 +03:00
unsigned int fd = proc_fd ( m - > private ) ;
2012-08-26 18:28:20 +04:00
2012-08-23 14:43:24 +04:00
spin_lock ( & files - > file_lock ) ;
file = fcheck_files ( files , fd ) ;
if ( file ) {
2012-08-26 18:28:20 +04:00
struct fdtable * fdt = files_fdtable ( files ) ;
2012-08-23 14:43:24 +04:00
2012-08-26 19:01:04 +04:00
f_flags = file - > f_flags ;
2012-08-23 14:43:24 +04:00
if ( close_on_exec ( fd , fdt ) )
f_flags | = O_CLOEXEC ;
2012-08-26 18:28:20 +04:00
get_file ( file ) ;
ret = 0 ;
2012-08-23 14:43:24 +04:00
}
spin_unlock ( & files - > file_lock ) ;
put_files_struct ( files ) ;
}
2012-08-26 18:28:20 +04:00
2015-04-16 22:49:38 +03:00
if ( ret )
return ret ;
seq_printf ( m , " pos: \t %lli \n flags: \t 0%o \n mnt_id: \t %i \n " ,
( long long ) file - > f_pos , f_flags ,
real_mount ( file - > f_path . mnt ) - > mnt_id ) ;
show_fd_locks ( m , file , files ) ;
if ( seq_has_overflowed ( m ) )
goto out ;
if ( file - > f_op - > show_fdinfo )
file - > f_op - > show_fdinfo ( m , file ) ;
2012-08-26 18:28:20 +04:00
2015-04-16 22:49:38 +03:00
out :
fput ( file ) ;
return 0 ;
2012-08-23 14:43:24 +04:00
}
2012-08-26 18:28:20 +04:00
static int seq_fdinfo_open ( struct inode * inode , struct file * file )
{
return single_open ( file , seq_show , inode ) ;
}
static const struct file_operations proc_fdinfo_file_operations = {
. open = seq_fdinfo_open ,
. read = seq_read ,
. llseek = seq_lseek ,
. release = single_release ,
} ;
2012-08-23 14:43:24 +04:00
static int tid_fd_revalidate ( struct dentry * dentry , unsigned int flags )
{
struct files_struct * files ;
struct task_struct * task ;
struct inode * inode ;
2016-09-02 00:42:02 +03:00
unsigned int fd ;
2012-08-23 14:43:24 +04:00
if ( flags & LOOKUP_RCU )
return - ECHILD ;
2015-03-18 01:25:59 +03:00
inode = d_inode ( dentry ) ;
2012-08-23 14:43:24 +04:00
task = get_proc_task ( inode ) ;
fd = proc_fd ( inode ) ;
if ( task ) {
files = get_files_struct ( task ) ;
if ( files ) {
struct file * file ;
rcu_read_lock ( ) ;
file = fcheck_files ( files , fd ) ;
if ( file ) {
unsigned f_mode = file - > f_mode ;
rcu_read_unlock ( ) ;
put_files_struct ( files ) ;
2017-01-03 00:23:11 +03:00
task_dump_owner ( task , 0 , & inode - > i_uid , & inode - > i_gid ) ;
2012-08-23 14:43:24 +04:00
if ( S_ISLNK ( inode - > i_mode ) ) {
unsigned i_mode = S_IFLNK ;
if ( f_mode & FMODE_READ )
i_mode | = S_IRUSR | S_IXUSR ;
if ( f_mode & FMODE_WRITE )
i_mode | = S_IWUSR | S_IXUSR ;
inode - > i_mode = i_mode ;
}
security_task_to_inode ( task , inode ) ;
put_task_struct ( task ) ;
return 1 ;
}
rcu_read_unlock ( ) ;
put_files_struct ( files ) ;
}
put_task_struct ( task ) ;
}
return 0 ;
}
static const struct dentry_operations tid_fd_dentry_operations = {
. d_revalidate = tid_fd_revalidate ,
. d_delete = pid_delete_dentry ,
} ;
static int proc_fd_link ( struct dentry * dentry , struct path * path )
{
2012-08-26 18:28:20 +04:00
struct files_struct * files = NULL ;
struct task_struct * task ;
int ret = - ENOENT ;
2015-03-18 01:25:59 +03:00
task = get_proc_task ( d_inode ( dentry ) ) ;
2012-08-26 18:28:20 +04:00
if ( task ) {
files = get_files_struct ( task ) ;
put_task_struct ( task ) ;
}
if ( files ) {
2016-09-02 00:42:02 +03:00
unsigned int fd = proc_fd ( d_inode ( dentry ) ) ;
2012-08-26 18:28:20 +04:00
struct file * fd_file ;
spin_lock ( & files - > file_lock ) ;
fd_file = fcheck_files ( files , fd ) ;
if ( fd_file ) {
* path = fd_file - > f_path ;
path_get ( & fd_file - > f_path ) ;
ret = 0 ;
}
spin_unlock ( & files - > file_lock ) ;
put_files_struct ( files ) ;
}
return ret ;
2012-08-23 14:43:24 +04:00
}
2013-06-15 11:15:20 +04:00
static int
2012-08-23 14:43:24 +04:00
proc_fd_instantiate ( struct inode * dir , struct dentry * dentry ,
struct task_struct * task , const void * ptr )
{
unsigned fd = ( unsigned long ) ptr ;
struct proc_inode * ei ;
struct inode * inode ;
2016-11-11 00:18:28 +03:00
inode = proc_pid_make_inode ( dir - > i_sb , task , S_IFLNK ) ;
2012-08-23 14:43:24 +04:00
if ( ! inode )
goto out ;
ei = PROC_I ( inode ) ;
ei - > fd = fd ;
inode - > i_op = & proc_pid_link_inode_operations ;
inode - > i_size = 64 ;
ei - > op . proc_get_link = proc_fd_link ;
d_set_d_op ( dentry , & tid_fd_dentry_operations ) ;
d_add ( dentry , inode ) ;
/* Close the race of the process dying before we return the dentry */
if ( tid_fd_revalidate ( dentry , 0 ) )
2013-06-15 11:15:20 +04:00
return 0 ;
2012-08-23 14:43:24 +04:00
out :
2013-06-15 11:15:20 +04:00
return - ENOENT ;
2012-08-23 14:43:24 +04:00
}
static struct dentry * proc_lookupfd_common ( struct inode * dir ,
struct dentry * dentry ,
instantiate_t instantiate )
{
struct task_struct * task = get_proc_task ( dir ) ;
2013-06-15 11:15:20 +04:00
int result = - ENOENT ;
2014-08-09 01:21:25 +04:00
unsigned fd = name_to_int ( & dentry - > d_name ) ;
2012-08-23 14:43:24 +04:00
if ( ! task )
goto out_no_task ;
if ( fd = = ~ 0U )
goto out ;
result = instantiate ( dir , dentry , task , ( void * ) ( unsigned long ) fd ) ;
out :
put_task_struct ( task ) ;
out_no_task :
2013-06-15 11:15:20 +04:00
return ERR_PTR ( result ) ;
2012-08-23 14:43:24 +04:00
}
2013-05-16 20:07:31 +04:00
static int proc_readfd_common ( struct file * file , struct dir_context * ctx ,
instantiate_t instantiate )
2012-08-23 14:43:24 +04:00
{
2013-05-16 20:07:31 +04:00
struct task_struct * p = get_proc_task ( file_inode ( file ) ) ;
2012-08-23 14:43:24 +04:00
struct files_struct * files ;
2013-05-16 20:07:31 +04:00
unsigned int fd ;
2012-08-23 14:43:24 +04:00
if ( ! p )
2013-05-16 20:07:31 +04:00
return - ENOENT ;
2012-08-23 14:43:24 +04:00
2013-05-16 20:07:31 +04:00
if ( ! dir_emit_dots ( file , ctx ) )
goto out ;
files = get_files_struct ( p ) ;
if ( ! files )
goto out ;
rcu_read_lock ( ) ;
for ( fd = ctx - > pos - 2 ;
fd < files_fdtable ( files ) - > max_fds ;
fd + + , ctx - > pos + + ) {
char name [ PROC_NUMBUF ] ;
int len ;
if ( ! fcheck_files ( files , fd ) )
continue ;
rcu_read_unlock ( ) ;
2016-09-02 00:42:02 +03:00
len = snprintf ( name , sizeof ( name ) , " %u " , fd ) ;
2013-05-16 20:07:31 +04:00
if ( ! proc_fill_cache ( file , ctx ,
name , len , instantiate , p ,
( void * ) ( unsigned long ) fd ) )
goto out_fd_loop ;
2015-12-03 22:12:07 +03:00
cond_resched ( ) ;
2013-05-16 20:07:31 +04:00
rcu_read_lock ( ) ;
2012-08-23 14:43:24 +04:00
}
2013-05-16 20:07:31 +04:00
rcu_read_unlock ( ) ;
out_fd_loop :
put_files_struct ( files ) ;
2012-08-23 14:43:24 +04:00
out :
put_task_struct ( p ) ;
2013-05-16 20:07:31 +04:00
return 0 ;
2012-08-23 14:43:24 +04:00
}
2013-05-16 20:07:31 +04:00
static int proc_readfd ( struct file * file , struct dir_context * ctx )
2012-08-23 14:43:24 +04:00
{
2013-05-16 20:07:31 +04:00
return proc_readfd_common ( file , ctx , proc_fd_instantiate ) ;
2012-08-23 14:43:24 +04:00
}
const struct file_operations proc_fd_operations = {
. read = generic_read_dir ,
2016-04-21 00:13:54 +03:00
. iterate_shared = proc_readfd ,
. llseek = generic_file_llseek ,
2012-08-23 14:43:24 +04:00
} ;
static struct dentry * proc_lookupfd ( struct inode * dir , struct dentry * dentry ,
unsigned int flags )
{
return proc_lookupfd_common ( dir , dentry , proc_fd_instantiate ) ;
}
/*
* / proc / pid / fd needs a special permission handler so that a process can still
* access / proc / self / fd after it has executed a setuid ( ) .
*/
int proc_fd_permission ( struct inode * inode , int mask )
{
2015-11-07 03:30:06 +03:00
struct task_struct * p ;
int rv ;
rv = generic_permission ( inode , mask ) ;
2012-08-23 14:43:24 +04:00
if ( rv = = 0 )
2015-11-07 03:30:06 +03:00
return rv ;
rcu_read_lock ( ) ;
p = pid_task ( proc_pid ( inode ) , PIDTYPE_PID ) ;
if ( p & & same_thread_group ( p , current ) )
2012-08-23 14:43:24 +04:00
rv = 0 ;
2015-11-07 03:30:06 +03:00
rcu_read_unlock ( ) ;
2012-08-23 14:43:24 +04:00
return rv ;
}
const struct inode_operations proc_fd_inode_operations = {
. lookup = proc_lookupfd ,
. permission = proc_fd_permission ,
. setattr = proc_setattr ,
} ;
2013-06-15 11:15:20 +04:00
static int
2012-08-23 14:43:24 +04:00
proc_fdinfo_instantiate ( struct inode * dir , struct dentry * dentry ,
struct task_struct * task , const void * ptr )
{
unsigned fd = ( unsigned long ) ptr ;
struct proc_inode * ei ;
struct inode * inode ;
2016-11-11 00:18:28 +03:00
inode = proc_pid_make_inode ( dir - > i_sb , task , S_IFREG | S_IRUSR ) ;
2012-08-23 14:43:24 +04:00
if ( ! inode )
goto out ;
ei = PROC_I ( inode ) ;
ei - > fd = fd ;
inode - > i_fop = & proc_fdinfo_file_operations ;
d_set_d_op ( dentry , & tid_fd_dentry_operations ) ;
d_add ( dentry , inode ) ;
/* Close the race of the process dying before we return the dentry */
if ( tid_fd_revalidate ( dentry , 0 ) )
2013-06-15 11:15:20 +04:00
return 0 ;
2012-08-23 14:43:24 +04:00
out :
2013-06-15 11:15:20 +04:00
return - ENOENT ;
2012-08-23 14:43:24 +04:00
}
static struct dentry *
proc_lookupfdinfo ( struct inode * dir , struct dentry * dentry , unsigned int flags )
{
return proc_lookupfd_common ( dir , dentry , proc_fdinfo_instantiate ) ;
}
2013-05-16 20:07:31 +04:00
static int proc_readfdinfo ( struct file * file , struct dir_context * ctx )
2012-08-23 14:43:24 +04:00
{
2013-05-16 20:07:31 +04:00
return proc_readfd_common ( file , ctx ,
2012-08-23 14:43:24 +04:00
proc_fdinfo_instantiate ) ;
}
const struct inode_operations proc_fdinfo_inode_operations = {
. lookup = proc_lookupfdinfo ,
. setattr = proc_setattr ,
} ;
const struct file_operations proc_fdinfo_operations = {
. read = generic_read_dir ,
2016-04-21 00:13:54 +03:00
. iterate_shared = proc_readfdinfo ,
. llseek = generic_file_llseek ,
2012-08-23 14:43:24 +04:00
} ;