|
@@ -510,46 +510,37 @@ SYSCALL_DEFINE4(fstatat64, int, dfd, const char __user *, filename,
|
|
|
}
|
|
|
#endif /* __ARCH_WANT_STAT64 || __ARCH_WANT_COMPAT_STAT64 */
|
|
|
|
|
|
-static inline int __put_timestamp(struct timespec *kts,
|
|
|
- struct statx_timestamp __user *uts)
|
|
|
+static noinline_for_stack int
|
|
|
+cp_statx(const struct kstat *stat, struct statx __user *buffer)
|
|
|
{
|
|
|
- return (__put_user(kts->tv_sec, &uts->tv_sec ) ||
|
|
|
- __put_user(kts->tv_nsec, &uts->tv_nsec ) ||
|
|
|
- __put_user(0, &uts->__reserved ));
|
|
|
-}
|
|
|
-
|
|
|
-/*
|
|
|
- * Set the statx results.
|
|
|
- */
|
|
|
-static long statx_set_result(struct kstat *stat, struct statx __user *buffer)
|
|
|
-{
|
|
|
- uid_t uid = from_kuid_munged(current_user_ns(), stat->uid);
|
|
|
- gid_t gid = from_kgid_munged(current_user_ns(), stat->gid);
|
|
|
-
|
|
|
- if (__put_user(stat->result_mask, &buffer->stx_mask ) ||
|
|
|
- __put_user(stat->mode, &buffer->stx_mode ) ||
|
|
|
- __clear_user(&buffer->__spare0, sizeof(buffer->__spare0)) ||
|
|
|
- __put_user(stat->nlink, &buffer->stx_nlink ) ||
|
|
|
- __put_user(uid, &buffer->stx_uid ) ||
|
|
|
- __put_user(gid, &buffer->stx_gid ) ||
|
|
|
- __put_user(stat->attributes, &buffer->stx_attributes ) ||
|
|
|
- __put_user(stat->blksize, &buffer->stx_blksize ) ||
|
|
|
- __put_user(MAJOR(stat->rdev), &buffer->stx_rdev_major ) ||
|
|
|
- __put_user(MINOR(stat->rdev), &buffer->stx_rdev_minor ) ||
|
|
|
- __put_user(MAJOR(stat->dev), &buffer->stx_dev_major ) ||
|
|
|
- __put_user(MINOR(stat->dev), &buffer->stx_dev_minor ) ||
|
|
|
- __put_timestamp(&stat->atime, &buffer->stx_atime ) ||
|
|
|
- __put_timestamp(&stat->btime, &buffer->stx_btime ) ||
|
|
|
- __put_timestamp(&stat->ctime, &buffer->stx_ctime ) ||
|
|
|
- __put_timestamp(&stat->mtime, &buffer->stx_mtime ) ||
|
|
|
- __put_user(stat->ino, &buffer->stx_ino ) ||
|
|
|
- __put_user(stat->size, &buffer->stx_size ) ||
|
|
|
- __put_user(stat->blocks, &buffer->stx_blocks ) ||
|
|
|
- __clear_user(&buffer->__spare1, sizeof(buffer->__spare1)) ||
|
|
|
- __clear_user(&buffer->__spare2, sizeof(buffer->__spare2)))
|
|
|
- return -EFAULT;
|
|
|
-
|
|
|
- return 0;
|
|
|
+ struct statx tmp;
|
|
|
+
|
|
|
+ memset(&tmp, 0, sizeof(tmp));
|
|
|
+
|
|
|
+ tmp.stx_mask = stat->result_mask;
|
|
|
+ tmp.stx_blksize = stat->blksize;
|
|
|
+ tmp.stx_attributes = stat->attributes;
|
|
|
+ tmp.stx_nlink = stat->nlink;
|
|
|
+ tmp.stx_uid = from_kuid_munged(current_user_ns(), stat->uid);
|
|
|
+ tmp.stx_gid = from_kgid_munged(current_user_ns(), stat->gid);
|
|
|
+ tmp.stx_mode = stat->mode;
|
|
|
+ tmp.stx_ino = stat->ino;
|
|
|
+ tmp.stx_size = stat->size;
|
|
|
+ tmp.stx_blocks = stat->blocks;
|
|
|
+ tmp.stx_atime.tv_sec = stat->atime.tv_sec;
|
|
|
+ tmp.stx_atime.tv_nsec = stat->atime.tv_nsec;
|
|
|
+ tmp.stx_btime.tv_sec = stat->btime.tv_sec;
|
|
|
+ tmp.stx_btime.tv_nsec = stat->btime.tv_nsec;
|
|
|
+ tmp.stx_ctime.tv_sec = stat->ctime.tv_sec;
|
|
|
+ tmp.stx_ctime.tv_nsec = stat->ctime.tv_nsec;
|
|
|
+ tmp.stx_mtime.tv_sec = stat->mtime.tv_sec;
|
|
|
+ tmp.stx_mtime.tv_nsec = stat->mtime.tv_nsec;
|
|
|
+ tmp.stx_rdev_major = MAJOR(stat->rdev);
|
|
|
+ tmp.stx_rdev_minor = MINOR(stat->rdev);
|
|
|
+ tmp.stx_dev_major = MAJOR(stat->dev);
|
|
|
+ tmp.stx_dev_minor = MINOR(stat->dev);
|
|
|
+
|
|
|
+ return copy_to_user(buffer, &tmp, sizeof(tmp)) ? -EFAULT : 0;
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -573,8 +564,6 @@ SYSCALL_DEFINE5(statx,
|
|
|
|
|
|
if ((flags & AT_STATX_SYNC_TYPE) == AT_STATX_SYNC_TYPE)
|
|
|
return -EINVAL;
|
|
|
- if (!access_ok(VERIFY_WRITE, buffer, sizeof(*buffer)))
|
|
|
- return -EFAULT;
|
|
|
|
|
|
if (filename)
|
|
|
error = vfs_statx(dfd, filename, flags, &stat, mask);
|
|
@@ -582,7 +571,8 @@ SYSCALL_DEFINE5(statx,
|
|
|
error = vfs_statx_fd(dfd, &stat, mask, flags);
|
|
|
if (error)
|
|
|
return error;
|
|
|
- return statx_set_result(&stat, buffer);
|
|
|
+
|
|
|
+ return cp_statx(&stat, buffer);
|
|
|
}
|
|
|
|
|
|
/* Caller is here responsible for sufficient locking (ie. inode->i_lock) */
|