static int tid_fd_revalidate(struct dentry *dentry, unsigned int flags) { struct files_struct *files; struct task_struct *task; const struct cred *cred; struct inode *inode; int fd; if (flags & LOOKUP_RCU) return -ECHILD; inode = dentry->d_inode; 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); if (task_dumpable(task)) { rcu_read_lock(); cred = __task_cred(task); inode->i_uid = cred->euid; inode->i_gid = cred->egid; rcu_read_unlock(); } else { inode->i_uid = GLOBAL_ROOT_UID; inode->i_gid = GLOBAL_ROOT_GID; } 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); } d_drop(dentry); return 0; }
static long fd_link_ioctl (struct file *f, unsigned int ioctl, unsigned long arg) { void __user *argp = (void __user *) arg; struct task_struct *task_target = NULL; struct file *file; struct files_struct *files; struct fdtable *fdt; struct fd_copy fd_copy; switch (ioctl) { case FD_COPY: if (copy_from_user (&fd_copy, argp, sizeof (struct fd_copy))) return -EFAULT; /* * Find the task struct for the target pid */ task_target = pid_task (find_vpid (fd_copy.target_pid), PIDTYPE_PID); if (task_target == NULL) { printk (KERN_DEBUG "Failed to get mem ctx for target pid\n"); return -EFAULT; } files = get_files_struct (current); if (files == NULL) { printk (KERN_DEBUG "Failed to get files struct\n"); return -EFAULT; } rcu_read_lock (); file = fcheck_files (files, fd_copy.source_fd); if (file) { if (file->f_mode & FMODE_PATH || !atomic_long_inc_not_zero (&file->f_count)) file = NULL; } rcu_read_unlock (); put_files_struct (files); if (file == NULL) { printk (KERN_DEBUG "Failed to get file from source pid\n"); return 0; } /* * Release the existing fd in the source process */ spin_lock (&files->file_lock); filp_close (file, files); fdt = files_fdtable (files); fdt->fd[fd_copy.source_fd] = NULL; spin_unlock (&files->file_lock); /* * Find the file struct associated with the target fd. */ files = get_files_struct (task_target); if (files == NULL) { printk (KERN_DEBUG "Failed to get files struct\n"); return -EFAULT; } rcu_read_lock (); file = fcheck_files (files, fd_copy.target_fd); if (file) { if (file->f_mode & FMODE_PATH || !atomic_long_inc_not_zero (&file->f_count)) file = NULL; } rcu_read_unlock (); put_files_struct (files); if (file == NULL) { printk (KERN_DEBUG "Failed to get file from target pid\n"); return 0; } /* * Install the file struct from the target process into the * file desciptor of the source process, */ fd_install (fd_copy.source_fd, file); return 0; default: return -ENOIOCTLCMD; } }