base.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,839 行 · 第 1/3 页
C
1,839 行
ret = -EFAULT; break; } ret += retval; src += retval; buf += retval; count -= retval; } *ppos = src;out_put: mmput(mm);out_free: free_page((unsigned long) page);out: return ret;}#define mem_write NULL#ifndef mem_write/* This is a security hazard */static ssize_t mem_write(struct file * file, const char * buf, size_t count, loff_t *ppos){ int copied = 0; char *page; struct task_struct *task = proc_task(file->f_dentry->d_inode); unsigned long dst = *ppos; if (!MAY_PTRACE(task) || !may_ptrace_attach(task)) return -ESRCH; page = (char *)__get_free_page(GFP_USER); if (!page) return -ENOMEM; while (count > 0) { int this_len, retval; this_len = (count > PAGE_SIZE) ? PAGE_SIZE : count; if (copy_from_user(page, buf, this_len)) { copied = -EFAULT; break; } retval = access_process_vm(task, dst, page, this_len, 1); if (!retval) { if (!copied) copied = -EIO; break; } copied += retval; buf += retval; dst += retval; count -= retval; } *ppos = dst; free_page((unsigned long) page); return copied;}#endifstatic loff_t mem_lseek(struct file * file, loff_t offset, int orig){ switch (orig) { case 0: file->f_pos = offset; break; case 1: file->f_pos += offset; break; default: return -EINVAL; } force_successful_syscall_return(); return file->f_pos;}static struct file_operations proc_mem_operations = { .llseek = mem_lseek, .read = mem_read, .write = mem_write, .open = mem_open,};static struct inode_operations proc_mem_inode_operations = { .permission = proc_permission,};static int proc_pid_follow_link(struct dentry *dentry, struct nameidata *nd){ struct inode *inode = dentry->d_inode; int error = -EACCES; /* We don't need a base pointer in the /proc filesystem */ path_release(nd); if (current->fsuid != inode->i_uid && !capable(CAP_DAC_OVERRIDE)) goto out; error = proc_check_root(inode); if (error) goto out; error = PROC_I(inode)->op.proc_get_link(inode, &nd->dentry, &nd->mnt); nd->last_type = LAST_BIND;out: return error;}static int do_proc_readlink(struct dentry *dentry, struct vfsmount *mnt, char __user *buffer, int buflen){ struct inode * inode; char *tmp = (char*)__get_free_page(GFP_KERNEL), *path; int len; if (!tmp) return -ENOMEM; inode = dentry->d_inode; path = d_path(dentry, mnt, tmp, PAGE_SIZE); len = PTR_ERR(path); if (IS_ERR(path)) goto out; len = tmp + PAGE_SIZE - 1 - path; if (len > buflen) len = buflen; if (copy_to_user(buffer, path, len)) len = -EFAULT; out: free_page((unsigned long)tmp); return len;}static int proc_pid_readlink(struct dentry * dentry, char __user * buffer, int buflen){ int error = -EACCES; struct inode *inode = dentry->d_inode; struct dentry *de; struct vfsmount *mnt = NULL; lock_kernel(); if (current->fsuid != inode->i_uid && !capable(CAP_DAC_OVERRIDE)) goto out; error = proc_check_root(inode); if (error) goto out; error = PROC_I(inode)->op.proc_get_link(inode, &de, &mnt); if (error) goto out; error = do_proc_readlink(de, mnt, buffer, buflen); dput(de); mntput(mnt);out: unlock_kernel(); return error;}static struct inode_operations proc_pid_link_inode_operations = { .readlink = proc_pid_readlink, .follow_link = proc_pid_follow_link};static inline int pid_alive(struct task_struct *p){ return p->pids[PIDTYPE_PID].nr != 0;}#define NUMBUF 10static int proc_readfd(struct file * filp, void * dirent, filldir_t filldir){ struct inode *inode = filp->f_dentry->d_inode; struct task_struct *p = proc_task(inode); unsigned int fd, tid, ino; int retval; char buf[NUMBUF]; struct files_struct * files; retval = -ENOENT; if (!pid_alive(p)) goto out; retval = 0; tid = p->pid; fd = filp->f_pos; switch (fd) { case 0: if (filldir(dirent, ".", 1, 0, inode->i_ino, DT_DIR) < 0) goto out; filp->f_pos++; case 1: ino = fake_ino(tid, PROC_TID_INO); if (filldir(dirent, "..", 2, 1, ino, DT_DIR) < 0) goto out; filp->f_pos++; default: files = get_files_struct(p); if (!files) goto out; spin_lock(&files->file_lock); for (fd = filp->f_pos-2; fd < files->max_fds; fd++, filp->f_pos++) { unsigned int i,j; if (!fcheck_files(files, fd)) continue; spin_unlock(&files->file_lock); j = NUMBUF; i = fd; do { j--; buf[j] = '0' + (i % 10); i /= 10; } while (i); ino = fake_ino(tid, PROC_TID_FD_DIR + fd); if (filldir(dirent, buf+j, NUMBUF-j, fd+2, ino, DT_LNK) < 0) { spin_lock(&files->file_lock); break; } spin_lock(&files->file_lock); } spin_unlock(&files->file_lock); put_files_struct(files); }out: return retval;}static int proc_pident_readdir(struct file *filp, void *dirent, filldir_t filldir, struct pid_entry *ents, unsigned int nents){ int i; int pid; struct dentry *dentry = filp->f_dentry; struct inode *inode = dentry->d_inode; struct pid_entry *p; ino_t ino; int ret; ret = -ENOENT; if (!pid_alive(proc_task(inode))) goto out; ret = 0; pid = proc_task(inode)->pid; i = filp->f_pos; switch (i) { case 0: ino = inode->i_ino; if (filldir(dirent, ".", 1, i, ino, DT_DIR) < 0) goto out; i++; filp->f_pos++; /* fall through */ case 1: ino = parent_ino(dentry); if (filldir(dirent, "..", 2, i, ino, DT_DIR) < 0) goto out; i++; filp->f_pos++; /* fall through */ default: i -= 2; if (i >= nents) { ret = 1; goto out; } p = ents + i; while (p->name) { if (filldir(dirent, p->name, p->len, filp->f_pos, fake_ino(pid, p->type), p->mode >> 12) < 0) goto out; filp->f_pos++; p++; } } ret = 1;out: return ret;}static int proc_tgid_base_readdir(struct file * filp, void * dirent, filldir_t filldir){ return proc_pident_readdir(filp,dirent,filldir, tgid_base_stuff,ARRAY_SIZE(tgid_base_stuff));}static int proc_tid_base_readdir(struct file * filp, void * dirent, filldir_t filldir){ return proc_pident_readdir(filp,dirent,filldir, tid_base_stuff,ARRAY_SIZE(tid_base_stuff));}/* building an inode */static int task_dumpable(struct task_struct *task){ int dumpable = 0; struct mm_struct *mm; task_lock(task); mm = task->mm; if (mm) dumpable = mm->dumpable; task_unlock(task); return dumpable;}static struct inode *proc_pid_make_inode(struct super_block * sb, struct task_struct *task, int ino){ struct inode * inode; struct proc_inode *ei; /* We need a new inode */ inode = new_inode(sb); if (!inode) goto out; /* Common stuff */ ei = PROC_I(inode); ei->task = NULL; inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; inode->i_ino = fake_ino(task->pid, ino); if (!pid_alive(task)) goto out_unlock; /* * grab the reference to task. */ get_task_struct(task); ei->task = task; ei->type = ino; inode->i_uid = 0; inode->i_gid = 0; if (ino == PROC_TGID_INO || ino == PROC_TID_INO || task_dumpable(task)) { inode->i_uid = task->euid; inode->i_gid = task->egid; } security_task_to_inode(task, inode);out: return inode;out_unlock: ei->pde = NULL; iput(inode); return NULL;}/* dentry stuff *//* * Exceptional case: normally we are not allowed to unhash a busy * directory. In this case, however, we can do it - no aliasing problems * due to the way we treat inodes. * * Rewrite the inode's ownerships here because the owning task may have * performed a setuid(), etc. */static int pid_revalidate(struct dentry *dentry, struct nameidata *nd){ struct inode *inode = dentry->d_inode; struct task_struct *task = proc_task(inode); if (pid_alive(task)) { if (proc_type(inode) == PROC_TGID_INO || proc_type(inode) == PROC_TID_INO || task_dumpable(task)) { inode->i_uid = task->euid; inode->i_gid = task->egid; } else { inode->i_uid = 0; inode->i_gid = 0; } security_task_to_inode(task, inode); return 1; } d_drop(dentry); return 0;}static int tid_fd_revalidate(struct dentry *dentry, struct nameidata *nd){ struct inode *inode = dentry->d_inode; struct task_struct *task = proc_task(inode); int fd = proc_type(inode) - PROC_TID_FD_DIR; struct files_struct *files; files = get_files_struct(task); if (files) { spin_lock(&files->file_lock); if (fcheck_files(files, fd)) { spin_unlock(&files->file_lock); put_files_struct(files); if (task_dumpable(task)) { inode->i_uid = task->euid; inode->i_gid = task->egid; } else { inode->i_uid = 0; inode->i_gid = 0; } security_task_to_inode(task, inode); return 1; } spin_unlock(&files->file_lock); put_files_struct(files); } d_drop(dentry); return 0;}static void pid_base_iput(struct dentry *dentry, struct inode *inode){ struct task_struct *task = proc_task(inode); spin_lock(&task->proc_lock); if (task->proc_dentry == dentry) task->proc_dentry = NULL; spin_unlock(&task->proc_lock); iput(inode);}static int pid_delete_dentry(struct dentry * dentry){ /* Is the task we represent dead? * If so, then don't put the dentry on the lru list, * kill it immediately. */ return !pid_alive(proc_task(dentry->d_inode));}static struct dentry_operations tid_fd_dentry_operations ={ .d_revalidate = tid_fd_revalidate, .d_delete = pid_delete_dentry,};static struct dentry_operations pid_dentry_operations ={ .d_revalidate = pid_revalidate, .d_delete = pid_delete_dentry,};static struct dentry_operations pid_base_dentry_operations ={ .d_revalidate = pid_revalidate, .d_iput = pid_base_iput, .d_delete = pid_delete_dentry,};/* Lookups */static unsigned name_to_int(struct dentry *dentry){ const char *name = dentry->d_name.name; int len = dentry->d_name.len; unsigned n = 0; if (len > 1 && *name == '0') goto out; while (len-- > 0) { unsigned c = *name++ - '0'; if (c > 9) goto out; if (n >= (~0U-9)/10) goto out; n *= 10; n += c; } return n;out: return ~0U;}/* SMP-safe */static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry, struct nameidata *nd){ struct task_struct *task = proc_task(dir); unsigned fd = name_to_int(dentry); struct file * file; struct files_struct * files; struct inode *inode; struct proc_inode *ei; if (fd == ~0U) goto out; if (!pid_alive(task)) goto out; inode = proc_pid_make_inode(dir->i_sb, task, PROC_TID_FD_DIR+fd); if (!inode) goto out; ei = PROC_I(inode); files = get_files_struct(task); if (!files) goto out_unlock; inode->i_mode = S_IFLNK; spin_lock(&files->file_lock); file = fcheck_files(files, fd); if (!file) goto out_unlock2; if (file->f_mode & 1) inode->i_mode |= S_IRUSR | S_IXUSR; if (file->f_mode & 2) inode->i_mode |= S_IWUSR | S_IXUSR; spin_unlock(&files->file_lock); put_files_struct(files); inode->i_op = &proc_pid_link_inode_operations; inode->i_size = 64; ei->op.proc_get_link = proc_fd_link; dentry->d_op = &tid_fd_dentry_operations; d_add(dentry, inode); return NULL;out_unlock2: spin_unlock(&files->file_lock); put_files_struct(files);out_unlock: iput(inode);out: return ERR_PTR(-ENOENT);}static int proc_task_readdir(struct file * filp, void * dirent, filldir_t filldir);static struct dentry *proc_task_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd);static struct file_operations proc_fd_operations = { .read = generic_read_dir, .readdir = proc_readfd,};static struct file_operations proc_task_operations = { .read = generic_read_dir, .readdir = proc_task_readdir,};/* * proc directories can do almost nothing.. */static struct inode_operations proc_fd_inode_operations = { .lookup = proc_lookupfd, .permission = proc_permission,};static struct inode_operations proc_task_inode_operations = { .lookup = proc_task_lookup, .permission = proc_permission,};#ifdef CONFIG_SECURITYstatic ssize_t proc_pid_attr_read(struct file * file, char __user * buf, size_t count, loff_t *ppos){ struct inode * inode = file->f_dentry->d_inode; unsigned long page; ssize_t length; struct task_struct *task = proc_task(inode); if (count > PAGE_SIZE) count = PAGE_SIZE; if (!(page = __get_free_page(GFP_KERNEL))) return -ENOMEM; length = security_getprocattr(task, (char*)file->f_dentry->d_name.name, (void*)page, count); if (length >= 0) length = simple_read_from_buffer(buf, count, ppos, (char *)page, length); free_page(page); return length;}static ssize_t proc_pid_attr_write(struct file * file, const char __user * buf, size_t count, loff_t *ppos){ struct inode * inode = file->f_dentry->d_inode; char *page; ssize_t length; struct task_struct *task = proc_task(inode); if (count > PAGE_SIZE) count = PAGE_SIZE; if (*ppos != 0) { /* No partial writes. */ return -EINVAL; } page = (char*)__get_free_page(GFP_USER); if (!page) return -ENOMEM; length = -EFAULT; if (copy_from_user(page, buf, count)) goto out; length = security_setprocattr(task, (char*)file->f_dentry->d_name.name, (void*)page, count);out: free_page((unsigned long) page); return length;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?