Beispiel #1
0
ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos)
{
   struct inode *inode = file->f_dentry->d_inode;
   ssize_t ret;

   if (!(file->f_mode & FMODE_READ))
      return -EBADF;
   if (!file->f_op || (!file->f_op->read && !file->f_op->aio_read))
      return -EINVAL;

   ret = locks_verify_area(FLOCK_VERIFY_READ, inode, file, *pos, count);
   if (!ret) {
      ret = security_file_permission (file, MAY_READ);
      if (!ret) {
         if (file->f_op->read)
            ret = file->f_op->read(file, buf, count, pos);
         else
            ret = do_sync_read(file, buf, count, pos);
         if (ret > 0)
            dnotify_parent(file->f_dentry, DN_ACCESS);
      }
   }

   return ret;
}
Beispiel #2
0
/**
 * sysfs_update_file - update the modified timestamp on an object attribute.
 * @kobj: object we're acting for.
 * @attr: attribute descriptor.
 *
 * Also call dnotify for the dentry, which lots of userspace programs
 * use.
 */
int sysfs_update_file(struct kobject * kobj, const struct attribute * attr)
{
	struct dentry * dir = kobj->dentry;
	struct dentry * victim;
	int res = -ENOENT;

	down(&dir->d_inode->i_sem);
	victim = sysfs_get_dentry(dir, attr->name);
	if (!IS_ERR(victim)) {
		/* make sure dentry is really there */
		if (victim->d_inode && 
		    (victim->d_parent->d_inode == dir->d_inode)) {
			victim->d_inode->i_mtime = CURRENT_TIME;
			dnotify_parent(victim, DN_MODIFY);

			/**
			 * Drop reference from initial sysfs_get_dentry().
			 */
			dput(victim);
			res = 0;
		}
		
		/**
		 * Drop the reference acquired from sysfs_get_dentry() above.
		 */
		dput(victim);
	}
	up(&dir->d_inode->i_sem);

	return res;
}
Beispiel #3
0
ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_t *pos)
{
   struct inode *inode = file->f_dentry->d_inode;
   ssize_t ret;

   if (!(file->f_mode & FMODE_WRITE))
      return -EBADF;
   if (!file->f_op || (!file->f_op->write && !file->f_op->aio_write))
      return -EINVAL;

   ret = locks_verify_area(FLOCK_VERIFY_WRITE, inode, file, *pos, count);
   if (!ret) {
      ret = security_file_permission (file, MAY_WRITE);
      if (!ret) {
         if (file->f_op->write)
            ret = file->f_op->write(file, buf, count, pos);
         else
            ret = do_sync_write(file, buf, count, pos);
         if (ret > 0)
            dnotify_parent(file->f_dentry, DN_MODIFY);
      }
   }

   return ret;
}
Beispiel #4
0
asmlinkage ssize_t sys_pread(unsigned int fd, char * buf,
			     size_t count, loff_t pos)
{
	ssize_t ret;
	struct file * file;
	ssize_t (*read)(struct file *, char *, size_t, loff_t *);

	ret = -EBADF;
	file = fget(fd);
	if (!file)
		goto bad_file;
	if (!(file->f_mode & FMODE_READ))
		goto out;
	ret = locks_verify_area(FLOCK_VERIFY_READ, file->f_dentry->d_inode,
				file, pos, count);
	if (ret)
		goto out;
	ret = -EINVAL;
	if (!file->f_op || !(read = file->f_op->read))
		goto out;
	if (pos < 0)
		goto out;
	ret = read(file, buf, count, &pos);
	if (ret > 0)
		dnotify_parent(file->f_dentry, DN_ACCESS);
out:
	fput(file);
bad_file:
	return ret;
}
Beispiel #5
0
asmlinkage ssize_t sys_pwrite(unsigned int fd, const char * buf,
			      size_t count, loff_t pos)
{
	ssize_t ret;
	struct file * file;
	ssize_t (*write)(struct file *, const char *, size_t, loff_t *);

	ret = -EBADF;
	file = fget(fd);
	if (!file)
		goto bad_file;
	if (!(file->f_mode & FMODE_WRITE))
		goto out;
	ret = locks_verify_area(FLOCK_VERIFY_WRITE, file->f_dentry->d_inode,
				file, pos, count);
	if (ret)
		goto out;
	ret = -EINVAL;
	if (!file->f_op || !(write = file->f_op->write))
		goto out;
	if (pos < 0)
		goto out;

	ret = write(file, buf, count, &pos);
	if (ret > 0)
		dnotify_parent(file->f_dentry, DN_MODIFY);
out:
	fput(file);
bad_file:
	return ret;
}
Beispiel #6
0
asmlinkage ssize_t sys_write(unsigned int fd, const char * buf, size_t count)
{
	ssize_t ret;
	struct file * file;

	ret = -EBADF;
	file = fget(fd);
	if (file) {
		if (file->f_mode & FMODE_WRITE) {
			struct inode *inode = file->f_dentry->d_inode;
			ret = locks_verify_area(FLOCK_VERIFY_WRITE, inode, file,
				file->f_pos, count);
			if (!ret) {
				ssize_t (*write)(struct file *, const char *, size_t, loff_t *);
				ret = -EINVAL;
				if (file->f_op && (write = file->f_op->write) != NULL)
					ret = write(file, buf, count, &file->f_pos);
			}
		}
		if (ret > 0)
			dnotify_parent(file->f_dentry, DN_MODIFY);
		fput(file);
	}
	return ret;
}
Beispiel #7
0
/*
 * Flush all pending data to disk.  This operation will block.
 */
static int
alq_doio(struct alq *alq)
{
	mm_segment_t oldfs;
	struct iovec aiov[2];
	struct file *fp;
	struct ale *ale;
	struct ale *alstart;
	int totlen;
	int iov;
	int err;

	fp = alq->aq_fp;
	totlen = 0;
	iov = 0;

	alstart = ale = alq->aq_entvalid;
	alq->aq_entvalid = NULL;

	memset(&aiov, 0, sizeof(aiov));

	do {
		if (aiov[iov].iov_base == NULL)
			aiov[iov].iov_base = ale->ae_data;
		aiov[iov].iov_len += alq->aq_entlen;
		totlen += alq->aq_entlen;
		/* Check to see if we're wrapping the buffer */
		if (ale->ae_data + alq->aq_entlen != ale->ae_next->ae_data)
			iov++;
		ale->ae_flags &= ~AE_VALID;
		ale = ale->ae_next;
	} while (ale->ae_flags & AE_VALID);

	alq->aq_flags |= AQ_FLUSHING;
	spin_unlock_irq(&alq->aq_lock);

	if (iov == 2 || aiov[iov].iov_base == NULL)
		iov--;

	oldfs = get_fs(); set_fs(KERNEL_DS);
	/* XXX ignore errors */
	err = fp->f_op->writev(fp, aiov, iov + 1, &fp->f_pos);
	set_fs(oldfs);
	if (err >= 0)
		dnotify_parent(fp->f_dentry, DN_MODIFY);

	spin_lock_irq(&alq->aq_lock);
	alq->aq_flags &= ~AQ_FLUSHING;

	if (alq->aq_entfree == NULL)
		alq->aq_entfree = alstart;

	if (alq->aq_flags & AQ_WANTED) {
		alq->aq_flags &= ~AQ_WANTED;
		return (1);
	}

	return(0);
}
Beispiel #8
0
int notify_change(struct dentry * dentry, struct iattr * attr)
{
	struct inode *inode = dentry->d_inode;
	int error;
	time_t now = CURRENT_TIME;
	unsigned int ia_valid = attr->ia_valid;

	if (!inode)
		BUG();

	attr->ia_ctime = now;
	if (!(ia_valid & ATTR_ATIME_SET))
		attr->ia_atime = now;
	if (!(ia_valid & ATTR_MTIME_SET))
		attr->ia_mtime = now;

	lock_kernel();
	if (inode->i_op && inode->i_op->setattr) 
		error = inode->i_op->setattr(dentry, attr);
	else {
		error = inode_change_ok(inode, attr);
		if (!error) {
			if ((ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) ||
			    (ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid))
				error = DQUOT_TRANSFER(inode, attr) ? -EDQUOT : 0;
			if (!error)
				error = inode_setattr(inode, attr);
		}
	}
	unlock_kernel();
	if (!error) {
		unsigned long dn_mask = setattr_mask(ia_valid);
		if (dn_mask)
			dnotify_parent(dentry, dn_mask);
	}
	return error;
}
Beispiel #9
0
asmlinkage ssize_t sys_read(unsigned int fd, char * buf, size_t count)
{
	ssize_t ret;
	struct file * file;

	ret = -EBADF;
	file = fget(fd);
	if (file) {
		if (file->f_mode & FMODE_READ) {
			ret = locks_verify_area(FLOCK_VERIFY_READ, file->f_dentry->d_inode,
						file, file->f_pos, count);
			if (!ret) {
				ssize_t (*read)(struct file *, char *, size_t, loff_t *);
				ret = -EINVAL;
				if (file->f_op && (read = file->f_op->read) != NULL)
					ret = read(file, buf, count, &file->f_pos);
			}
		}
		if (ret > 0)
			dnotify_parent(file->f_dentry, DN_ACCESS);
		fput(file);
	}
	return ret;
}
Beispiel #10
0
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;
   struct inode *inode;

   /*
    * 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++) {
      ssize_t len = (ssize_t)iov[seg].iov_len;

      if (len < 0)   /* size_t not fitting an ssize_t .. */
         goto out;
      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;
   }

   inode = file->f_dentry->d_inode;
   /* VERIFY_WRITE actually means a read, as we write to user space */
   ret = locks_verify_area((type == READ
             ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE),
            inode, 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)
      dnotify_parent(file->f_dentry,
            (type == READ) ? DN_ACCESS : DN_MODIFY);
   return ret;
}
Beispiel #11
0
static ssize_t do_readv_writev(int type, struct file *file,
			       const struct iovec * vector,
			       unsigned long count)
{
	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;
	ssize_t ret, i;
	iov_fn_t fnv;
	struct inode *inode;

	/*
	 * First get the "struct iovec" from user memory and
	 * verify all the pointers
	 */
	ret = 0;
	if (!count)
		goto out_nofree;
	ret = -EINVAL;
	if (count > UIO_MAXIOV)
		goto out_nofree;
	if (!file->f_op)
		goto out_nofree;
	if (count > UIO_FASTIOV) {
		ret = -ENOMEM;
		iov = kmalloc(count*sizeof(struct iovec), GFP_KERNEL);
		if (!iov)
			goto out_nofree;
	}
	ret = -EFAULT;
	if (copy_from_user(iov, vector, count*sizeof(*vector)))
		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 (i = 0 ; i < count ; i++) {
		ssize_t len = (ssize_t) iov[i].iov_len;
		if (len < 0)	/* size_t not fitting an ssize_t .. */
			goto out;
		tot_len += len;
		/* We must do this work unsigned - signed overflow is
		   undefined and gcc 3.2 now uses that fact sometimes... 
		   
		   FIXME: put in a proper limits.h for each platform */
#if BITS_PER_LONG==64
		if (tot_len > 0x7FFFFFFFFFFFFFFFUL)
#else
		if (tot_len > 0x7FFFFFFFUL)
#endif		
			goto out;
	}

	inode = file->f_dentry->d_inode;
	/* VERIFY_WRITE actually means a read, as we write to user space */
	ret = locks_verify_area((type == VERIFY_WRITE
				 ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE),
				inode, file, file->f_pos, tot_len);
	if (ret) goto out;

	fnv = (type == VERIFY_WRITE ? file->f_op->readv : file->f_op->writev);
	if (fnv) {
		ret = fnv(file, iov, count, &file->f_pos);
		goto out;
	}

	ret = fallback_readv_writev(type == VERIFY_WRITE ? READ : WRITE,
				    file, iov, count, &file->f_pos);

out:
	if (iov != iovstack)
		kfree(iov);
out_nofree:
	/* VERIFY_WRITE actually means a read, as we write to user space */
	if ((ret + (type == VERIFY_WRITE)) > 0)
		dnotify_parent(file->f_dentry,
			(type == VERIFY_WRITE) ? DN_ACCESS : DN_MODIFY);
	return ret;
}
Beispiel #12
0
int notify_change(struct dentry * dentry, struct iattr * attr)
{
	struct inode *inode = dentry->d_inode;
	mode_t mode = inode->i_mode;
	int error;
	struct timespec now = CURRENT_TIME;
	unsigned int ia_valid = attr->ia_valid;

	if (!inode)
		BUG();

	attr->ia_ctime = now;
	if (!(ia_valid & ATTR_ATIME_SET))
		attr->ia_atime = now;
	if (!(ia_valid & ATTR_MTIME_SET))
		attr->ia_mtime = now;
	if (ia_valid & ATTR_KILL_SUID) {
		attr->ia_valid &= ~ATTR_KILL_SUID;
		if (mode & S_ISUID) {
			if (!(ia_valid & ATTR_MODE)) {
				ia_valid = attr->ia_valid |= ATTR_MODE;
				attr->ia_mode = inode->i_mode;
			}
			attr->ia_mode &= ~S_ISUID;
		}
	}
	if (ia_valid & ATTR_KILL_SGID) {
		attr->ia_valid &= ~ ATTR_KILL_SGID;
		if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) {
			if (!(ia_valid & ATTR_MODE)) {
				ia_valid = attr->ia_valid |= ATTR_MODE;
				attr->ia_mode = inode->i_mode;
			}
			attr->ia_mode &= ~S_ISGID;
		}
	}
	if (!attr->ia_valid)
		return 0;

	if (inode->i_op && inode->i_op->setattr) {
		error = security_inode_setattr(dentry, attr);
		if (!error)
			error = inode->i_op->setattr(dentry, attr);
	} else {
		error = inode_change_ok(inode, attr);
		if (!error)
			error = security_inode_setattr(dentry, attr);
		if (!error) {
			if ((ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) ||
			    (ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid))
				error = DQUOT_TRANSFER(inode, attr) ? -EDQUOT : 0;
			if (!error)
				error = inode_setattr(inode, attr);
		}
	}
	if (!error) {
#ifdef CONFIG_MOT_FEAT_INOTIFY
		fsnotify_change(dentry, ia_valid);
#else
		unsigned long dn_mask = setattr_mask(ia_valid);
		if (dn_mask)
			dnotify_parent(dentry, dn_mask);
#endif
	}
	return error;
}