Commit fcf83067 authored by Al Viro's avatar Al Viro

vfs: fix compat_sys_stat() handling of overflows in st_nlink

Massaged cp_compat_stat() into form closer to cp_new_stat(); the only
real issue had been in handling of st_nlink overflows - native 32bit
stat(2) returns -EOVERFLOW in such situations, compat one silently
loses upper bits.
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent dcdbed85
...@@ -131,41 +131,35 @@ asmlinkage long compat_sys_utimes(const char __user *filename, struct compat_tim ...@@ -131,41 +131,35 @@ asmlinkage long compat_sys_utimes(const char __user *filename, struct compat_tim
static int cp_compat_stat(struct kstat *stat, struct compat_stat __user *ubuf) static int cp_compat_stat(struct kstat *stat, struct compat_stat __user *ubuf)
{ {
compat_ino_t ino = stat->ino; struct compat_stat tmp;
typeof(ubuf->st_uid) uid = 0;
typeof(ubuf->st_gid) gid = 0;
int err;
SET_UID(uid, stat->uid); if (!old_valid_dev(stat->dev) || !old_valid_dev(stat->rdev))
SET_GID(gid, stat->gid); return -EOVERFLOW;
if ((u64) stat->size > MAX_NON_LFS || memset(&tmp, 0, sizeof(tmp));
!old_valid_dev(stat->dev) || tmp.st_dev = old_encode_dev(stat->dev);
!old_valid_dev(stat->rdev)) tmp.st_ino = stat->ino;
if (sizeof(tmp.st_ino) < sizeof(stat->ino) && tmp.st_ino != stat->ino)
return -EOVERFLOW; return -EOVERFLOW;
if (sizeof(ino) < sizeof(stat->ino) && ino != stat->ino) tmp.st_mode = stat->mode;
tmp.st_nlink = stat->nlink;
if (tmp.st_nlink != stat->nlink)
return -EOVERFLOW; return -EOVERFLOW;
SET_UID(tmp.st_uid, stat->uid);
if (clear_user(ubuf, sizeof(*ubuf))) SET_GID(tmp.st_gid, stat->gid);
return -EFAULT; tmp.st_rdev = old_encode_dev(stat->rdev);
if ((u64) stat->size > MAX_NON_LFS)
err = __put_user(old_encode_dev(stat->dev), &ubuf->st_dev); return -EOVERFLOW;
err |= __put_user(ino, &ubuf->st_ino); tmp.st_size = stat->size;
err |= __put_user(stat->mode, &ubuf->st_mode); tmp.st_atime = stat->atime.tv_sec;
err |= __put_user(stat->nlink, &ubuf->st_nlink); tmp.st_atime_nsec = stat->atime.tv_nsec;
err |= __put_user(uid, &ubuf->st_uid); tmp.st_mtime = stat->mtime.tv_sec;
err |= __put_user(gid, &ubuf->st_gid); tmp.st_mtime_nsec = stat->mtime.tv_nsec;
err |= __put_user(old_encode_dev(stat->rdev), &ubuf->st_rdev); tmp.st_ctime = stat->ctime.tv_sec;
err |= __put_user(stat->size, &ubuf->st_size); tmp.st_ctime_nsec = stat->ctime.tv_nsec;
err |= __put_user(stat->atime.tv_sec, &ubuf->st_atime); tmp.st_blocks = stat->blocks;
err |= __put_user(stat->atime.tv_nsec, &ubuf->st_atime_nsec); tmp.st_blksize = stat->blksize;
err |= __put_user(stat->mtime.tv_sec, &ubuf->st_mtime); return copy_to_user(ubuf, &tmp, sizeof(tmp)) ? -EFAULT : 0;
err |= __put_user(stat->mtime.tv_nsec, &ubuf->st_mtime_nsec);
err |= __put_user(stat->ctime.tv_sec, &ubuf->st_ctime);
err |= __put_user(stat->ctime.tv_nsec, &ubuf->st_ctime_nsec);
err |= __put_user(stat->blksize, &ubuf->st_blksize);
err |= __put_user(stat->blocks, &ubuf->st_blocks);
return err;
} }
asmlinkage long compat_sys_newstat(const char __user * filename, asmlinkage long compat_sys_newstat(const char __user * filename,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment