Пример #1
0
asmlinkage long sys_fchmodat(int dfd, const char __user *filename,
			     mode_t mode)
{
	struct nameidata nd;
	struct _inode * inode;
	int error;
	struct iattr newattrs;

	error = __user_walk_fd(dfd, filename, LOOKUP_FOLLOW, &nd);
	if (error)
		goto out;
	inode = d_get_inode(nd.dentry);

	error = -EROFS;
	if (IS_RDONLY(inode))
		goto dput_and_out;

	error = -EPERM;
	if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
		goto dput_and_out;

	imutex_lock(parent(inode));
	if (mode == (mode_t) -1)
		mode = inode->i_mode;
	newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
	newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
	error = notify_change(nd.dentry, &newattrs);
	imutex_unlock(parent(inode));

dput_and_out:
	path_release(&nd);
out:
	return error;
}
Пример #2
0
asmlinkage long sys_readlinkat(int dfd, const char __user *path,
				char __user *buf, int bufsiz)
{
	struct nameidata nd;
	int error;

	if (bufsiz <= 0)
		return -EINVAL;

	error = __user_walk_fd(dfd, path, 0, &nd);
	if (!error) {
		struct inode * inode = nd.dentry->d_inode;

		error = -EINVAL;
		if (inode->i_op && inode->i_op->readlink) {
			error = security_inode_readlink(nd.dentry);
			if (!error) {
				touch_atime(nd.mnt, nd.dentry);
				error = inode->i_op->readlink(nd.dentry, buf, bufsiz);
			}
		}
		path_release(&nd);
	}
	return error;
}
Пример #3
0
long link_by_fd(int file_fd, int newdfd, const char __user * newname)
{
    int error;
    int fput_needed;
    struct file *filep;
    struct nameidata nd;
    struct dentry *new_dentry;

    filep = fget_light(file_fd, &fput_needed);
    if(!filep)
        return -EBADF;
    error = __user_walk_fd(newdfd, newname, LOOKUP_PARENT, &nd);
    if(error)
        goto file_out;
    error = -EXDEV;
    if(filep->f_vfsmnt != nd.mnt)
        goto out_release;
    new_dentry = lookup_create(&nd, 0);
    error = PTR_ERR(new_dentry);
    if(!IS_ERR(new_dentry))
        {
            error = vfs_link(filep->f_dentry, nd.dentry->d_inode, new_dentry);
            dput(new_dentry);
        }
    mutex_unlock(&nd.dentry->d_inode->i_mutex);
out_release:
    path_release(&nd);
file_out:
    fput_light(filep, fput_needed);

    return error;
}
Пример #4
0
/*
 * access() needs to use the real uid/gid, not the effective uid/gid.
 * We do this by temporarily clearing all FS-related capabilities and
 * switching the fsuid/fsgid around to the real ones.
 */
asmlinkage long sys_faccessat(int dfd, const char __user *filename, int mode)
{
	struct nameidata nd;
	int old_fsuid, old_fsgid;
	kernel_cap_t old_cap;
	int res;
	const struct _inode *inode;

	if (mode & ~S_IRWXO)	/* where's F_OK, X_OK, W_OK, R_OK? */
		return -EINVAL;

	old_fsuid = current->fsuid;
	old_fsgid = current->fsgid;
	old_cap = current->cap_effective;

	current->fsuid = current->uid;
	current->fsgid = current->gid;

	/*
	 * Clear the capabilities if we switch to a non-root user
	 *
	 * FIXME: There is a race here against sys_capset.  The
	 * capabilities can change yet we will restore the old
	 * value below.  We should hold task_capabilities_lock,
	 * but we cannot because user_path_walk can sleep.
	 */
	if (current->uid)
		cap_clear(current->cap_effective);
	else
		current->cap_effective = current->cap_permitted;
	
	res = __user_walk_fd(dfd, filename, LOOKUP_FOLLOW|LOOKUP_ACCESS, &nd);
	if (res)
		goto out;

	inode = d_get_inode_ro(nd.dentry);
	res = vfs_permission(inode, &nd, mode);
	/* SuS v2 requires we report a read only fs too */
	if(res || !(mode & S_IWOTH) ||
	   special_file(inode->i_mode))
		goto out_path_release;

	if(IS_RDONLY(inode))
		res = -EROFS;

out_path_release:
	path_release(&nd);
out:
	current->fsuid = old_fsuid;
	current->fsgid = old_fsgid;
	current->cap_effective = old_cap;
	
	return res;
}
Пример #5
0
int vfs_lstat_fd(int dfd, char __user *name, struct kstat *stat)
{
	struct nameidata nd;
	int error;

	error = __user_walk_fd(dfd, name, 0, &nd);
	if (!error) {
		error = vfs_getattr(nd.mnt, nd.dentry, stat);
		path_release(&nd);
	}
	return error;
}
Пример #6
0
/* If times==NULL, set access and modification to current time,
 * must be owner or have write permission.
 * Else, update from *times, must be owner or super user.
 */
long do_utimes(int dfd, char __user *filename, struct timeval *times)
{
	int error;
	struct nameidata nd;
	struct inode * inode;
	struct iattr newattrs;

	error = __user_walk_fd(dfd, filename, LOOKUP_FOLLOW, &nd);

	if (error)
		goto out;
	inode = nd.dentry->d_inode;

	error = -EROFS;
	if (IS_RDONLY(inode))
		goto dput_and_out;

	/* Don't worry, the checks are done in inode_change_ok() */
	newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME;
	if (times) {
		error = -EPERM;
                if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
                        goto dput_and_out;

		newattrs.ia_atime.tv_sec = times[0].tv_sec;
		newattrs.ia_atime.tv_nsec = times[0].tv_usec * 1000;
		newattrs.ia_mtime.tv_sec = times[1].tv_sec;
		newattrs.ia_mtime.tv_nsec = times[1].tv_usec * 1000;
		newattrs.ia_valid |= ATTR_ATIME_SET | ATTR_MTIME_SET;
	} else {
		error = -EACCES;
                if (IS_IMMUTABLE(inode))
                        goto dput_and_out;

		if (current->fsuid != inode->i_uid &&
		    (error = vfs_permission(&nd, MAY_WRITE)) != 0)
			goto dput_and_out;
	}
	mutex_lock(&inode->i_mutex);
	error = notify_change(nd.dentry, &newattrs);
	mutex_unlock(&inode->i_mutex);
dput_and_out:
	path_release(&nd);
out:
	return error;
}
Пример #7
0
long name_to_handle_at(int dfd, const char __user * name,
                       struct file_handle __user * handle, int flag)
{

    int follow;
    long ret = -EINVAL;
    struct nameidata nd;
    struct file *file = NULL;

    if(!capable(CAP_DAC_OVERRIDE))
        {
            ret = -EPERM;
            goto err_out;
        }
    if((flag & ~AT_SYMLINK_FOLLOW) != 0)
        goto err_out;

    if(name == NULL && dfd != AT_FDCWD)
        {
            file = fget(dfd);

            if(file)
                nd.dentry = file->f_dentry;
            else
                {
                    ret = -EBADF;
                    goto err_out;
                }
        }
    else
        {
            follow = (flag & AT_SYMLINK_FOLLOW) ? LOOKUP_FOLLOW : 0;
            ret = __user_walk_fd(dfd, name, follow, &nd);
            if(ret)
                goto err_out;
        }
    ret = do_sys_name_to_handle(&nd, handle);
    if(file)
        fput(file);
    else
        path_release(&nd);

err_out:
    return ret;
}
Пример #8
0
asmlinkage long sys_fchownat(int dfd, const char __user *filename, uid_t user,
			     gid_t group, int flag)
{
	struct nameidata nd;
	int error = -EINVAL;
	int follow;

	if ((flag & ~AT_SYMLINK_NOFOLLOW) != 0)
		goto out;

	follow = (flag & AT_SYMLINK_NOFOLLOW) ? 0 : LOOKUP_FOLLOW;
	error = __user_walk_fd(dfd, filename, follow, &nd);
	if (error)
		goto out;
	error = chown_common(nd.dentry, user, group);
	path_release(&nd);
out:
	return error;
}
Пример #9
0
Файл: open.c Проект: 274914765/C
asmlinkage long sys_fchmodat(int dfd, const char __user *filename,
                 mode_t mode)
{
    struct nameidata nd;
    struct inode * inode;
    int error;
    struct iattr newattrs;

    error = __user_walk_fd(dfd, filename, LOOKUP_FOLLOW, &nd);
    if (error)
        goto out;
    inode = nd.path.dentry->d_inode;

    error = mnt_want_write(nd.path.mnt);
    if (error)
        goto dput_and_out;

    error = -EPERM;
    if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
        goto out_drop_write;

    mutex_lock(&inode->i_mutex);
    if (mode == (mode_t) -1)
        mode = inode->i_mode;
    newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO);
    newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
    error = notify_change(nd.path.dentry, &newattrs);
    mutex_unlock(&inode->i_mutex);

out_drop_write:
    mnt_drop_write(nd.path.mnt);
dput_and_out:
    path_put(&nd.path);
out:
    return error;
}
Пример #10
0
/* If times==NULL, set access and modification to current time,
 * must be owner or have write permission.
 * Else, update from *times, must be owner or super user.
 */
long do_utimes(int dfd, char __user *filename, struct timespec *times, int flags)
{
	int error;
	struct nameidata nd;
	struct dentry *dentry;
	struct inode *inode;
	struct iattr newattrs;
	struct file *f = NULL;

	error = -EINVAL;
	if (times && (!nsec_valid(times[0].tv_nsec) ||
		      !nsec_valid(times[1].tv_nsec))) {
		goto out;
	}

	if (flags & ~AT_SYMLINK_NOFOLLOW)
		goto out;

	if (filename == NULL && dfd != AT_FDCWD) {
		error = -EINVAL;
		if (flags & AT_SYMLINK_NOFOLLOW)
			goto out;

		error = -EBADF;
		f = fget(dfd);
		if (!f)
			goto out;
		dentry = f->f_path.dentry;
	} else {
		error = __user_walk_fd(dfd, filename, (flags & AT_SYMLINK_NOFOLLOW) ? 0 : LOOKUP_FOLLOW, &nd);
		if (error)
			goto out;

		dentry = nd.dentry;
	}

	inode = dentry->d_inode;

	error = -EROFS;
	if (IS_RDONLY(inode))
		goto dput_and_out;

	/* Don't worry, the checks are done in inode_change_ok() */
	newattrs.ia_valid = ATTR_CTIME | ATTR_MTIME | ATTR_ATIME;
	if (times) {
		error = -EPERM;
                if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
                        goto dput_and_out;

		if (times[0].tv_nsec == UTIME_OMIT)
			newattrs.ia_valid &= ~ATTR_ATIME;
		else if (times[0].tv_nsec != UTIME_NOW) {
			newattrs.ia_atime.tv_sec = times[0].tv_sec;
			newattrs.ia_atime.tv_nsec = times[0].tv_nsec;
			newattrs.ia_valid |= ATTR_ATIME_SET;
		}

		if (times[1].tv_nsec == UTIME_OMIT)
			newattrs.ia_valid &= ~ATTR_MTIME;
		else if (times[1].tv_nsec != UTIME_NOW) {
			newattrs.ia_mtime.tv_sec = times[1].tv_sec;
			newattrs.ia_mtime.tv_nsec = times[1].tv_nsec;
			newattrs.ia_valid |= ATTR_MTIME_SET;
		}
	} else {
		error = -EACCES;
                if (IS_IMMUTABLE(inode))
                        goto dput_and_out;

		if (!is_owner_or_cap(inode)) {
			if (f) {
				if (!(f->f_mode & FMODE_WRITE))
					goto dput_and_out;
			} else {
				error = vfs_permission(&nd, MAY_WRITE);
				if (error)
					goto dput_and_out;
			}
		}
	}
	mutex_lock(&inode->i_mutex);
	error = notify_change(dentry, &newattrs);
	mutex_unlock(&inode->i_mutex);
dput_and_out:
	if (f)
		fput(f);
	else
		path_release(&nd);
out:
	return error;
}
Пример #11
0
Файл: open.c Проект: 274914765/C
/*
 * access() needs to use the real uid/gid, not the effective uid/gid.
 * We do this by temporarily clearing all FS-related capabilities and
 * switching the fsuid/fsgid around to the real ones.
 */
asmlinkage long sys_faccessat(int dfd, const char __user *filename, int mode)
{
    struct nameidata nd;
    int old_fsuid, old_fsgid;
    kernel_cap_t uninitialized_var(old_cap);  /* !SECURE_NO_SETUID_FIXUP */
    int res;

    if (mode & ~S_IRWXO)    /* where's F_OK, X_OK, W_OK, R_OK? */
        return -EINVAL;

    old_fsuid = current->fsuid;
    old_fsgid = current->fsgid;

    current->fsuid = current->uid;
    current->fsgid = current->gid;

    if (!issecure(SECURE_NO_SETUID_FIXUP)) {
        /*
         * Clear the capabilities if we switch to a non-root user
         */
#ifndef CONFIG_SECURITY_FILE_CAPABILITIES
        /*
         * FIXME: There is a race here against sys_capset.  The
         * capabilities can change yet we will restore the old
         * value below.  We should hold task_capabilities_lock,
         * but we cannot because user_path_walk can sleep.
         */
#endif /* ndef CONFIG_SECURITY_FILE_CAPABILITIES */
        if (current->uid)
            old_cap = cap_set_effective(__cap_empty_set);
        else
            old_cap = cap_set_effective(current->cap_permitted);
    }

    res = __user_walk_fd(dfd, filename, LOOKUP_FOLLOW|LOOKUP_ACCESS, &nd);
    if (res)
        goto out;

    res = vfs_permission(&nd, mode);
    /* SuS v2 requires we report a read only fs too */
    if(res || !(mode & S_IWOTH) ||
       special_file(nd.path.dentry->d_inode->i_mode))
        goto out_path_release;
    /*
     * This is a rare case where using __mnt_is_readonly()
     * is OK without a mnt_want/drop_write() pair.  Since
     * no actual write to the fs is performed here, we do
     * not need to telegraph to that to anyone.
     *
     * By doing this, we accept that this access is
     * inherently racy and know that the fs may change
     * state before we even see this result.
     */
    if (__mnt_is_readonly(nd.path.mnt))
        res = -EROFS;

out_path_release:
    path_put(&nd.path);
out:
    current->fsuid = old_fsuid;
    current->fsgid = old_fsgid;

    if (!issecure(SECURE_NO_SETUID_FIXUP))
        cap_set_effective(old_cap);

    return res;
}