ret = security_file_permission(file, type == READ ? MAY_READ : MAY_WRITE); if (ret) goto out; 
static ssize_t do_readv_writev(int type, struct file *file,			       const struct iovec __user * uvector,			       unsigned long nr_segs, loff_t *pos){	typedef ssize_t (*io_fn_t)(struct file *, char __user *, size_t, loff_t *);	typedef ssize_t (*iov_fn_t)(struct file *, const struct iovec *, unsigned long, loff_t *);	size_t tot_len;	struct iovec iovstack[UIO_FASTIOV];	struct iovec *iov=iovstack, *vector;	ssize_t ret;	int seg;	io_fn_t fn;	iov_fn_t fnv;	/*	 * SuS says "The readv() function *may* fail if the iovcnt argument	 * was less than or equal to 0, or greater than {IOV_MAX}.  Linux has	 * traditionally returned zero for zero segments, so...	 */	ret = 0;	if (nr_segs == 0)		goto out;	/*	 * First get the "struct iovec" from user memory and	 * verify all the pointers	 */	ret = -EINVAL;	if ((nr_segs > UIO_MAXIOV) || (nr_segs <= 0))		goto out;	if (!file->f_op)		goto out;	if (nr_segs > UIO_FASTIOV) {		ret = -ENOMEM;		iov = kmalloc(nr_segs*sizeof(struct iovec), GFP_KERNEL);		if (!iov)			goto out;	}	ret = -EFAULT;	if (copy_from_user(iov, uvector, nr_segs*sizeof(*uvector)))		goto out;	/*	 * Single unix specification:	 * We should -EINVAL if an element length is not >= 0 and fitting an	 * ssize_t.  The total length is fitting an ssize_t	 *	 * Be careful here because iov_len is a size_t not an ssize_t	 */	tot_len = 0;	ret = -EINVAL;	for (seg = 0; seg < nr_segs; seg++) {		void __user *buf = iov[seg].iov_base;		ssize_t len = (ssize_t)iov[seg].iov_len;		if (len < 0)	/* size_t not fitting an ssize_t .. */			goto out;		if (unlikely(!access_ok(vrfy_dir(type), buf, len)))			goto Efault;		tot_len += len;		if ((ssize_t)tot_len < 0) /* maths overflow on the ssize_t */			goto out;	}	if (tot_len == 0) {		ret = 0;		goto out;	}	ret = rw_verify_area(type, file, pos, tot_len);	if (ret)		goto out;	fnv = NULL;	if (type == READ) {		fn = file->f_op->read;		fnv = file->f_op->readv;	} else {		fn = (io_fn_t)file->f_op->write;		fnv = file->f_op->writev;	}	if (fnv) {		ret = fnv(file, iov, nr_segs, pos);		goto out;	}	/* Do it by hand, with file-ops */	ret = 0;	vector = iov;	while (nr_segs > 0) {		void __user * base;		size_t len;		ssize_t nr;		base = vector->iov_base;		len = vector->iov_len;		vector++;		nr_segs--;		nr = fn(file, base, len, pos);		if (nr < 0) {			if (!ret) ret = nr;			break;		}		ret += nr;		if (nr != len)			break;	}out:	if (iov != iovstack)		kfree(iov);	if ((ret + (type == READ)) > 0) {		if (type == READ)			fsnotify_access(file->f_dentry);		else			fsnotify_modify(file->f_dentry);	}	return ret;Efault:	ret = -EFAULT;	goto out;}
4520	/local/tlutelli/issta_data/temp/c/2005_temp/2005/4520/411b67b4b6a4dd1e0292a6a58dd753978179d173/read_write.c/buggy/fs/read_write.c