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 + -
显示快捷键?