aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2006-10-03 04:13:46 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-10-03 11:03:40 -0400
commitafefdbb28a0a2af689926c30b94a14aea6036719 (patch)
tree6ee500575cac928cd90045bcf5b691cf2b8daa09 /arch
parent1d32849b14bc8792e6f35ab27dd990d74b16126c (diff)
[PATCH] VFS: Make filldir_t and struct kstat deal in 64-bit inode numbers
These patches make the kernel pass 64-bit inode numbers internally when communicating to userspace, even on a 32-bit system. They are required because some filesystems have intrinsic 64-bit inode numbers: NFS3+ and XFS for example. The 64-bit inode numbers are then propagated to userspace automatically where the arch supports it. Problems have been seen with userspace (eg: ld.so) using the 64-bit inode number returned by stat64() or getdents64() to differentiate files, and failing because the 64-bit inode number space was compressed to 32-bits, and so overlaps occur. This patch: Make filldir_t take a 64-bit inode number and struct kstat carry a 64-bit inode number so that 64-bit inode numbers can be passed back to userspace. The stat functions then returns the full 64-bit inode number where available and where possible. If it is not possible to represent the inode number supplied by the filesystem in the field provided by userspace, then error EOVERFLOW will be issued. Similarly, the getdents/readdir functions now pass the full 64-bit inode number to userspace where possible, returning EOVERFLOW instead when a directory entry is encountered that can't be properly represented. Note that this means that some inodes will not be stat'able on a 32-bit system with old libraries where they were before - but it does mean that there will be no ambiguity over what a 32-bit inode number refers to. Note similarly that directory scans may be cut short with an error on a 32-bit system with old libraries where the scan would work before for the same reasons. It is judged unlikely that this situation will occur because modern glibc uses 64-bit capable versions of stat and getdents class functions exclusively, and that older systems are unlikely to encounter unrepresentable inode numbers anyway. [akpm: alpha build fix] Signed-off-by: David Howells <dhowells@redhat.com> Cc: Trond Myklebust <trond.myklebust@fys.uio.no> Cc: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch')
-rw-r--r--arch/alpha/kernel/osf_sys.c8
-rw-r--r--arch/ia64/ia32/sys_ia32.c23
-rw-r--r--arch/mips/kernel/linux32.c2
-rw-r--r--arch/mips/kernel/sysirix.c10
-rw-r--r--arch/parisc/hpux/fs.c6
-rw-r--r--arch/parisc/kernel/sys_parisc32.c19
-rw-r--r--arch/powerpc/kernel/sys_ppc32.c15
-rw-r--r--arch/s390/kernel/compat_linux.c5
-rw-r--r--arch/sparc/kernel/sys_sunos.c16
-rw-r--r--arch/sparc64/kernel/sys_sparc32.c5
-rw-r--r--arch/sparc64/kernel/sys_sunos32.c12
-rw-r--r--arch/sparc64/solaris/fs.c7
-rw-r--r--arch/x86_64/ia32/sys_ia32.c7
13 files changed, 110 insertions, 25 deletions
diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c
index 8a31fc1bfb15..ad6173651995 100644
--- a/arch/alpha/kernel/osf_sys.c
+++ b/arch/alpha/kernel/osf_sys.c
@@ -111,22 +111,26 @@ struct osf_dirent_callback {
111 111
112static int 112static int
113osf_filldir(void *__buf, const char *name, int namlen, loff_t offset, 113osf_filldir(void *__buf, const char *name, int namlen, loff_t offset,
114 ino_t ino, unsigned int d_type) 114 u64 ino, unsigned int d_type)
115{ 115{
116 struct osf_dirent __user *dirent; 116 struct osf_dirent __user *dirent;
117 struct osf_dirent_callback *buf = (struct osf_dirent_callback *) __buf; 117 struct osf_dirent_callback *buf = (struct osf_dirent_callback *) __buf;
118 unsigned int reclen = ROUND_UP(NAME_OFFSET + namlen + 1); 118 unsigned int reclen = ROUND_UP(NAME_OFFSET + namlen + 1);
119 unsigned int d_ino;
119 120
120 buf->error = -EINVAL; /* only used if we fail */ 121 buf->error = -EINVAL; /* only used if we fail */
121 if (reclen > buf->count) 122 if (reclen > buf->count)
122 return -EINVAL; 123 return -EINVAL;
124 d_ino = ino;
125 if (sizeof(d_ino) < sizeof(ino) && d_ino != ino)
126 return -EOVERFLOW;
123 if (buf->basep) { 127 if (buf->basep) {
124 if (put_user(offset, buf->basep)) 128 if (put_user(offset, buf->basep))
125 return -EFAULT; 129 return -EFAULT;
126 buf->basep = NULL; 130 buf->basep = NULL;
127 } 131 }
128 dirent = buf->dirent; 132 dirent = buf->dirent;
129 put_user(ino, &dirent->d_ino); 133 put_user(d_ino, &dirent->d_ino);
130 put_user(namlen, &dirent->d_namlen); 134 put_user(namlen, &dirent->d_namlen);
131 put_user(reclen, &dirent->d_reclen); 135 put_user(reclen, &dirent->d_reclen);
132 if (copy_to_user(dirent->d_name, name, namlen) || 136 if (copy_to_user(dirent->d_name, name, namlen) ||
diff --git a/arch/ia64/ia32/sys_ia32.c b/arch/ia64/ia32/sys_ia32.c
index bddbd22706ed..9d6a3f210148 100644
--- a/arch/ia64/ia32/sys_ia32.c
+++ b/arch/ia64/ia32/sys_ia32.c
@@ -125,6 +125,7 @@ sys32_execve (char __user *name, compat_uptr_t __user *argv, compat_uptr_t __use
125 125
126int cp_compat_stat(struct kstat *stat, struct compat_stat __user *ubuf) 126int cp_compat_stat(struct kstat *stat, struct compat_stat __user *ubuf)
127{ 127{
128 compat_ino_t ino;
128 int err; 129 int err;
129 130
130 if ((u64) stat->size > MAX_NON_LFS || 131 if ((u64) stat->size > MAX_NON_LFS ||
@@ -132,11 +133,15 @@ int cp_compat_stat(struct kstat *stat, struct compat_stat __user *ubuf)
132 !old_valid_dev(stat->rdev)) 133 !old_valid_dev(stat->rdev))
133 return -EOVERFLOW; 134 return -EOVERFLOW;
134 135
136 ino = stat->ino;
137 if (sizeof(ino) < sizeof(stat->ino) && ino != stat->ino)
138 return -EOVERFLOW;
139
135 if (clear_user(ubuf, sizeof(*ubuf))) 140 if (clear_user(ubuf, sizeof(*ubuf)))
136 return -EFAULT; 141 return -EFAULT;
137 142
138 err = __put_user(old_encode_dev(stat->dev), &ubuf->st_dev); 143 err = __put_user(old_encode_dev(stat->dev), &ubuf->st_dev);
139 err |= __put_user(stat->ino, &ubuf->st_ino); 144 err |= __put_user(ino, &ubuf->st_ino);
140 err |= __put_user(stat->mode, &ubuf->st_mode); 145 err |= __put_user(stat->mode, &ubuf->st_mode);
141 err |= __put_user(stat->nlink, &ubuf->st_nlink); 146 err |= __put_user(stat->nlink, &ubuf->st_nlink);
142 err |= __put_user(high2lowuid(stat->uid), &ubuf->st_uid); 147 err |= __put_user(high2lowuid(stat->uid), &ubuf->st_uid);
@@ -1222,16 +1227,20 @@ struct readdir32_callback {
1222}; 1227};
1223 1228
1224static int 1229static int
1225filldir32 (void *__buf, const char *name, int namlen, loff_t offset, ino_t ino, 1230filldir32 (void *__buf, const char *name, int namlen, loff_t offset, u64 ino,
1226 unsigned int d_type) 1231 unsigned int d_type)
1227{ 1232{
1228 struct compat_dirent __user * dirent; 1233 struct compat_dirent __user * dirent;
1229 struct getdents32_callback * buf = (struct getdents32_callback *) __buf; 1234 struct getdents32_callback * buf = (struct getdents32_callback *) __buf;
1230 int reclen = ROUND_UP(offsetof(struct compat_dirent, d_name) + namlen + 1, 4); 1235 int reclen = ROUND_UP(offsetof(struct compat_dirent, d_name) + namlen + 1, 4);
1236 u32 d_ino;
1231 1237
1232 buf->error = -EINVAL; /* only used if we fail.. */ 1238 buf->error = -EINVAL; /* only used if we fail.. */
1233 if (reclen > buf->count) 1239 if (reclen > buf->count)
1234 return -EINVAL; 1240 return -EINVAL;
1241 d_ino = ino;
1242 if (sizeof(d_ino) < sizeof(ino) && d_ino != ino)
1243 return -EOVERFLOW;
1235 buf->error = -EFAULT; /* only used if we fail.. */ 1244 buf->error = -EFAULT; /* only used if we fail.. */
1236 dirent = buf->previous; 1245 dirent = buf->previous;
1237 if (dirent) 1246 if (dirent)
@@ -1239,7 +1248,7 @@ filldir32 (void *__buf, const char *name, int namlen, loff_t offset, ino_t ino,
1239 return -EFAULT; 1248 return -EFAULT;
1240 dirent = buf->current_dir; 1249 dirent = buf->current_dir;
1241 buf->previous = dirent; 1250 buf->previous = dirent;
1242 if (put_user(ino, &dirent->d_ino) 1251 if (put_user(d_ino, &dirent->d_ino)
1243 || put_user(reclen, &dirent->d_reclen) 1252 || put_user(reclen, &dirent->d_reclen)
1244 || copy_to_user(dirent->d_name, name, namlen) 1253 || copy_to_user(dirent->d_name, name, namlen)
1245 || put_user(0, dirent->d_name + namlen)) 1254 || put_user(0, dirent->d_name + namlen))
@@ -1287,17 +1296,21 @@ out:
1287} 1296}
1288 1297
1289static int 1298static int
1290fillonedir32 (void * __buf, const char * name, int namlen, loff_t offset, ino_t ino, 1299fillonedir32 (void * __buf, const char * name, int namlen, loff_t offset, u64 ino,
1291 unsigned int d_type) 1300 unsigned int d_type)
1292{ 1301{
1293 struct readdir32_callback * buf = (struct readdir32_callback *) __buf; 1302 struct readdir32_callback * buf = (struct readdir32_callback *) __buf;
1294 struct old_linux32_dirent __user * dirent; 1303 struct old_linux32_dirent __user * dirent;
1304 u32 d_ino;
1295 1305
1296 if (buf->count) 1306 if (buf->count)
1297 return -EINVAL; 1307 return -EINVAL;
1308 d_ino = ino;
1309 if (sizeof(d_ino) < sizeof(ino) && d_ino != ino)
1310 return -EOVERFLOW;
1298 buf->count++; 1311 buf->count++;
1299 dirent = buf->dirent; 1312 dirent = buf->dirent;
1300 if (put_user(ino, &dirent->d_ino) 1313 if (put_user(d_ino, &dirent->d_ino)
1301 || put_user(offset, &dirent->d_offset) 1314 || put_user(offset, &dirent->d_offset)
1302 || put_user(namlen, &dirent->d_namlen) 1315 || put_user(namlen, &dirent->d_namlen)
1303 || copy_to_user(dirent->d_name, name, namlen) 1316 || copy_to_user(dirent->d_name, name, namlen)
diff --git a/arch/mips/kernel/linux32.c b/arch/mips/kernel/linux32.c
index 52cada45b353..53f4171fc188 100644
--- a/arch/mips/kernel/linux32.c
+++ b/arch/mips/kernel/linux32.c
@@ -77,6 +77,8 @@ int cp_compat_stat(struct kstat *stat, struct compat_stat __user *statbuf)
77 memset(&tmp, 0, sizeof(tmp)); 77 memset(&tmp, 0, sizeof(tmp));
78 tmp.st_dev = new_encode_dev(stat->dev); 78 tmp.st_dev = new_encode_dev(stat->dev);
79 tmp.st_ino = stat->ino; 79 tmp.st_ino = stat->ino;
80 if (sizeof(tmp.st_ino) < sizeof(stat->ino) && tmp.st_ino != stat->ino)
81 return -EOVERFLOW;
80 tmp.st_mode = stat->mode; 82 tmp.st_mode = stat->mode;
81 tmp.st_nlink = stat->nlink; 83 tmp.st_nlink = stat->nlink;
82 SET_UID(tmp.st_uid, stat->uid); 84 SET_UID(tmp.st_uid, stat->uid);
diff --git a/arch/mips/kernel/sysirix.c b/arch/mips/kernel/sysirix.c
index 11bb97174972..93c74fefff76 100644
--- a/arch/mips/kernel/sysirix.c
+++ b/arch/mips/kernel/sysirix.c
@@ -1739,12 +1739,13 @@ struct irix_dirent32_callback {
1739#define ROUND_UP32(x) (((x)+sizeof(u32)-1) & ~(sizeof(u32)-1)) 1739#define ROUND_UP32(x) (((x)+sizeof(u32)-1) & ~(sizeof(u32)-1))
1740 1740
1741static int irix_filldir32(void *__buf, const char *name, 1741static int irix_filldir32(void *__buf, const char *name,
1742 int namlen, loff_t offset, ino_t ino, unsigned int d_type) 1742 int namlen, loff_t offset, u64 ino, unsigned int d_type)
1743{ 1743{
1744 struct irix_dirent32 __user *dirent; 1744 struct irix_dirent32 __user *dirent;
1745 struct irix_dirent32_callback *buf = __buf; 1745 struct irix_dirent32_callback *buf = __buf;
1746 unsigned short reclen = ROUND_UP32(NAME_OFFSET32(dirent) + namlen + 1); 1746 unsigned short reclen = ROUND_UP32(NAME_OFFSET32(dirent) + namlen + 1);
1747 int err = 0; 1747 int err = 0;
1748 u32 d_ino;
1748 1749
1749#ifdef DEBUG_GETDENTS 1750#ifdef DEBUG_GETDENTS
1750 printk("\nirix_filldir32[reclen<%d>namlen<%d>count<%d>]", 1751 printk("\nirix_filldir32[reclen<%d>namlen<%d>count<%d>]",
@@ -1753,12 +1754,15 @@ static int irix_filldir32(void *__buf, const char *name,
1753 buf->error = -EINVAL; /* only used if we fail.. */ 1754 buf->error = -EINVAL; /* only used if we fail.. */
1754 if (reclen > buf->count) 1755 if (reclen > buf->count)
1755 return -EINVAL; 1756 return -EINVAL;
1757 d_ino = ino;
1758 if (sizeof(d_ino) < sizeof(ino) && d_ino != ino)
1759 return -EOVERFLOW;
1756 dirent = buf->previous; 1760 dirent = buf->previous;
1757 if (dirent) 1761 if (dirent)
1758 err = __put_user(offset, &dirent->d_off); 1762 err = __put_user(offset, &dirent->d_off);
1759 dirent = buf->current_dir; 1763 dirent = buf->current_dir;
1760 err |= __put_user(dirent, &buf->previous); 1764 err |= __put_user(dirent, &buf->previous);
1761 err |= __put_user(ino, &dirent->d_ino); 1765 err |= __put_user(d_ino, &dirent->d_ino);
1762 err |= __put_user(reclen, &dirent->d_reclen); 1766 err |= __put_user(reclen, &dirent->d_reclen);
1763 err |= copy_to_user((char __user *)dirent->d_name, name, namlen) ? -EFAULT : 0; 1767 err |= copy_to_user((char __user *)dirent->d_name, name, namlen) ? -EFAULT : 0;
1764 err |= __put_user(0, &dirent->d_name[namlen]); 1768 err |= __put_user(0, &dirent->d_name[namlen]);
@@ -1837,7 +1841,7 @@ struct irix_dirent64_callback {
1837#define ROUND_UP64(x) (((x)+sizeof(u64)-1) & ~(sizeof(u64)-1)) 1841#define ROUND_UP64(x) (((x)+sizeof(u64)-1) & ~(sizeof(u64)-1))
1838 1842
1839static int irix_filldir64(void *__buf, const char *name, 1843static int irix_filldir64(void *__buf, const char *name,
1840 int namlen, loff_t offset, ino_t ino, unsigned int d_type) 1844 int namlen, loff_t offset, u64 ino, unsigned int d_type)
1841{ 1845{
1842 struct irix_dirent64 __user *dirent; 1846 struct irix_dirent64 __user *dirent;
1843 struct irix_dirent64_callback * buf = __buf; 1847 struct irix_dirent64_callback * buf = __buf;
diff --git a/arch/parisc/hpux/fs.c b/arch/parisc/hpux/fs.c
index d7c80edf4489..6e79dbf3f6bd 100644
--- a/arch/parisc/hpux/fs.c
+++ b/arch/parisc/hpux/fs.c
@@ -77,17 +77,21 @@ static int filldir(void * __buf, const char * name, int namlen, loff_t offset,
77{ 77{
78 struct hpux_dirent * dirent; 78 struct hpux_dirent * dirent;
79 struct getdents_callback * buf = (struct getdents_callback *) __buf; 79 struct getdents_callback * buf = (struct getdents_callback *) __buf;
80 ino_t d_ino;
80 int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1); 81 int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1);
81 82
82 buf->error = -EINVAL; /* only used if we fail.. */ 83 buf->error = -EINVAL; /* only used if we fail.. */
83 if (reclen > buf->count) 84 if (reclen > buf->count)
84 return -EINVAL; 85 return -EINVAL;
86 d_ino = ino;
87 if (sizeof(d_ino) < sizeof(ino) && d_ino != ino)
88 return -EOVERFLOW;
85 dirent = buf->previous; 89 dirent = buf->previous;
86 if (dirent) 90 if (dirent)
87 put_user(offset, &dirent->d_off); 91 put_user(offset, &dirent->d_off);
88 dirent = buf->current_dir; 92 dirent = buf->current_dir;
89 buf->previous = dirent; 93 buf->previous = dirent;
90 put_user(ino, &dirent->d_ino); 94 put_user(d_ino, &dirent->d_ino);
91 put_user(reclen, &dirent->d_reclen); 95 put_user(reclen, &dirent->d_reclen);
92 put_user(namlen, &dirent->d_namlen); 96 put_user(namlen, &dirent->d_namlen);
93 copy_to_user(dirent->d_name, name, namlen); 97 copy_to_user(dirent->d_name, name, namlen);
diff --git a/arch/parisc/kernel/sys_parisc32.c b/arch/parisc/kernel/sys_parisc32.c
index b74869803081..e3b30bc36453 100644
--- a/arch/parisc/kernel/sys_parisc32.c
+++ b/arch/parisc/kernel/sys_parisc32.c
@@ -237,14 +237,19 @@ int sys32_settimeofday(struct compat_timeval __user *tv, struct timezone __user
237 237
238int cp_compat_stat(struct kstat *stat, struct compat_stat __user *statbuf) 238int cp_compat_stat(struct kstat *stat, struct compat_stat __user *statbuf)
239{ 239{
240 compat_ino_t ino;
240 int err; 241 int err;
241 242
242 if (stat->size > MAX_NON_LFS || !new_valid_dev(stat->dev) || 243 if (stat->size > MAX_NON_LFS || !new_valid_dev(stat->dev) ||
243 !new_valid_dev(stat->rdev)) 244 !new_valid_dev(stat->rdev))
244 return -EOVERFLOW; 245 return -EOVERFLOW;
245 246
247 ino = stat->ino;
248 if (sizeof(ino) < sizeof(stat->ino) && ino != stat->ino)
249 return -EOVERFLOW;
250
246 err = put_user(new_encode_dev(stat->dev), &statbuf->st_dev); 251 err = put_user(new_encode_dev(stat->dev), &statbuf->st_dev);
247 err |= put_user(stat->ino, &statbuf->st_ino); 252 err |= put_user(ino, &statbuf->st_ino);
248 err |= put_user(stat->mode, &statbuf->st_mode); 253 err |= put_user(stat->mode, &statbuf->st_mode);
249 err |= put_user(stat->nlink, &statbuf->st_nlink); 254 err |= put_user(stat->nlink, &statbuf->st_nlink);
250 err |= put_user(0, &statbuf->st_reserved1); 255 err |= put_user(0, &statbuf->st_reserved1);
@@ -312,16 +317,20 @@ filldir32 (void *__buf, const char *name, int namlen, loff_t offset, ino_t ino,
312 struct linux32_dirent __user * dirent; 317 struct linux32_dirent __user * dirent;
313 struct getdents32_callback * buf = (struct getdents32_callback *) __buf; 318 struct getdents32_callback * buf = (struct getdents32_callback *) __buf;
314 int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1, 4); 319 int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1, 4);
320 u32 d_ino;
315 321
316 buf->error = -EINVAL; /* only used if we fail.. */ 322 buf->error = -EINVAL; /* only used if we fail.. */
317 if (reclen > buf->count) 323 if (reclen > buf->count)
318 return -EINVAL; 324 return -EINVAL;
325 d_ino = ino;
326 if (sizeof(d_ino) < sizeof(ino) && d_ino != ino)
327 return -EOVERFLOW;
319 dirent = buf->previous; 328 dirent = buf->previous;
320 if (dirent) 329 if (dirent)
321 put_user(offset, &dirent->d_off); 330 put_user(offset, &dirent->d_off);
322 dirent = buf->current_dir; 331 dirent = buf->current_dir;
323 buf->previous = dirent; 332 buf->previous = dirent;
324 put_user(ino, &dirent->d_ino); 333 put_user(d_ino, &dirent->d_ino);
325 put_user(reclen, &dirent->d_reclen); 334 put_user(reclen, &dirent->d_reclen);
326 copy_to_user(dirent->d_name, name, namlen); 335 copy_to_user(dirent->d_name, name, namlen);
327 put_user(0, dirent->d_name + namlen); 336 put_user(0, dirent->d_name + namlen);
@@ -371,12 +380,16 @@ fillonedir32 (void * __buf, const char * name, int namlen, loff_t offset, ino_t
371{ 380{
372 struct readdir32_callback * buf = (struct readdir32_callback *) __buf; 381 struct readdir32_callback * buf = (struct readdir32_callback *) __buf;
373 struct old_linux32_dirent __user * dirent; 382 struct old_linux32_dirent __user * dirent;
383 u32 d_ino;
374 384
375 if (buf->count) 385 if (buf->count)
376 return -EINVAL; 386 return -EINVAL;
387 d_ino = ino;
388 if (sizeof(d_ino) < sizeof(ino) && d_ino != ino)
389 return -EOVERFLOW;
377 buf->count++; 390 buf->count++;
378 dirent = buf->dirent; 391 dirent = buf->dirent;
379 put_user(ino, &dirent->d_ino); 392 put_user(d_ino, &dirent->d_ino);
380 put_user(offset, &dirent->d_offset); 393 put_user(offset, &dirent->d_offset);
381 put_user(namlen, &dirent->d_namlen); 394 put_user(namlen, &dirent->d_namlen);
382 copy_to_user(dirent->d_name, name, namlen); 395 copy_to_user(dirent->d_name, name, namlen);
diff --git a/arch/powerpc/kernel/sys_ppc32.c b/arch/powerpc/kernel/sys_ppc32.c
index 5e391fc25340..d15c33e95959 100644
--- a/arch/powerpc/kernel/sys_ppc32.c
+++ b/arch/powerpc/kernel/sys_ppc32.c
@@ -69,16 +69,20 @@ struct readdir_callback32 {
69}; 69};
70 70
71static int fillonedir(void * __buf, const char * name, int namlen, 71static int fillonedir(void * __buf, const char * name, int namlen,
72 off_t offset, ino_t ino, unsigned int d_type) 72 off_t offset, u64 ino, unsigned int d_type)
73{ 73{
74 struct readdir_callback32 * buf = (struct readdir_callback32 *) __buf; 74 struct readdir_callback32 * buf = (struct readdir_callback32 *) __buf;
75 struct old_linux_dirent32 __user * dirent; 75 struct old_linux_dirent32 __user * dirent;
76 ino_t d_ino;
76 77
77 if (buf->count) 78 if (buf->count)
78 return -EINVAL; 79 return -EINVAL;
80 d_ino = ino;
81 if (sizeof(d_ino) < sizeof(ino) && d_ino != ino)
82 return -EOVERFLOW;
79 buf->count++; 83 buf->count++;
80 dirent = buf->dirent; 84 dirent = buf->dirent;
81 put_user(ino, &dirent->d_ino); 85 put_user(d_ino, &dirent->d_ino);
82 put_user(offset, &dirent->d_offset); 86 put_user(offset, &dirent->d_offset);
83 put_user(namlen, &dirent->d_namlen); 87 put_user(namlen, &dirent->d_namlen);
84 copy_to_user(dirent->d_name, name, namlen); 88 copy_to_user(dirent->d_name, name, namlen);
@@ -120,15 +124,20 @@ asmlinkage long ppc32_select(u32 n, compat_ulong_t __user *inp,
120 124
121int cp_compat_stat(struct kstat *stat, struct compat_stat __user *statbuf) 125int cp_compat_stat(struct kstat *stat, struct compat_stat __user *statbuf)
122{ 126{
127 compat_ino_t ino;
123 long err; 128 long err;
124 129
125 if (stat->size > MAX_NON_LFS || !new_valid_dev(stat->dev) || 130 if (stat->size > MAX_NON_LFS || !new_valid_dev(stat->dev) ||
126 !new_valid_dev(stat->rdev)) 131 !new_valid_dev(stat->rdev))
127 return -EOVERFLOW; 132 return -EOVERFLOW;
128 133
134 ino = stat->ino;
135 if (sizeof(ino) < sizeof(stat->ino) && ino != stat->ino)
136 return -EOVERFLOW;
137
129 err = access_ok(VERIFY_WRITE, statbuf, sizeof(*statbuf)) ? 0 : -EFAULT; 138 err = access_ok(VERIFY_WRITE, statbuf, sizeof(*statbuf)) ? 0 : -EFAULT;
130 err |= __put_user(new_encode_dev(stat->dev), &statbuf->st_dev); 139 err |= __put_user(new_encode_dev(stat->dev), &statbuf->st_dev);
131 err |= __put_user(stat->ino, &statbuf->st_ino); 140 err |= __put_user(ino, &statbuf->st_ino);
132 err |= __put_user(stat->mode, &statbuf->st_mode); 141 err |= __put_user(stat->mode, &statbuf->st_mode);
133 err |= __put_user(stat->nlink, &statbuf->st_nlink); 142 err |= __put_user(stat->nlink, &statbuf->st_nlink);
134 err |= __put_user(stat->uid, &statbuf->st_uid); 143 err |= __put_user(stat->uid, &statbuf->st_uid);
diff --git a/arch/s390/kernel/compat_linux.c b/arch/s390/kernel/compat_linux.c
index c46e3d48e410..e15e1489aef5 100644
--- a/arch/s390/kernel/compat_linux.c
+++ b/arch/s390/kernel/compat_linux.c
@@ -357,11 +357,16 @@ asmlinkage long sys32_ftruncate64(unsigned int fd, unsigned long high, unsigned
357 357
358int cp_compat_stat(struct kstat *stat, struct compat_stat __user *statbuf) 358int cp_compat_stat(struct kstat *stat, struct compat_stat __user *statbuf)
359{ 359{
360 compat_ino_t ino;
360 int err; 361 int err;
361 362
362 if (!old_valid_dev(stat->dev) || !old_valid_dev(stat->rdev)) 363 if (!old_valid_dev(stat->dev) || !old_valid_dev(stat->rdev))
363 return -EOVERFLOW; 364 return -EOVERFLOW;
364 365
366 ino = stat->ino;
367 if (sizeof(ino) < sizeof(stat->ino) && ino != stat->ino)
368 return -EOVERFLOW;
369
365 err = put_user(old_encode_dev(stat->dev), &statbuf->st_dev); 370 err = put_user(old_encode_dev(stat->dev), &statbuf->st_dev);
366 err |= put_user(stat->ino, &statbuf->st_ino); 371 err |= put_user(stat->ino, &statbuf->st_ino);
367 err |= put_user(stat->mode, &statbuf->st_mode); 372 err |= put_user(stat->mode, &statbuf->st_mode);
diff --git a/arch/sparc/kernel/sys_sunos.c b/arch/sparc/kernel/sys_sunos.c
index 9d2cd97d1c3a..6f3ac548ee66 100644
--- a/arch/sparc/kernel/sys_sunos.c
+++ b/arch/sparc/kernel/sys_sunos.c
@@ -325,21 +325,25 @@ struct sunos_dirent_callback {
325#define ROUND_UP(x) (((x)+sizeof(long)-1) & ~(sizeof(long)-1)) 325#define ROUND_UP(x) (((x)+sizeof(long)-1) & ~(sizeof(long)-1))
326 326
327static int sunos_filldir(void * __buf, const char * name, int namlen, 327static int sunos_filldir(void * __buf, const char * name, int namlen,
328 loff_t offset, ino_t ino, unsigned int d_type) 328 loff_t offset, u64 ino, unsigned int d_type)
329{ 329{
330 struct sunos_dirent __user *dirent; 330 struct sunos_dirent __user *dirent;
331 struct sunos_dirent_callback * buf = __buf; 331 struct sunos_dirent_callback * buf = __buf;
332 unsigned long d_ino;
332 int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1); 333 int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1);
333 334
334 buf->error = -EINVAL; /* only used if we fail.. */ 335 buf->error = -EINVAL; /* only used if we fail.. */
335 if (reclen > buf->count) 336 if (reclen > buf->count)
336 return -EINVAL; 337 return -EINVAL;
338 d_ino = ino;
339 if (sizeof(d_ino) < sizeof(ino) && d_ino != ino)
340 return -EOVERFLOW;
337 dirent = buf->previous; 341 dirent = buf->previous;
338 if (dirent) 342 if (dirent)
339 put_user(offset, &dirent->d_off); 343 put_user(offset, &dirent->d_off);
340 dirent = buf->curr; 344 dirent = buf->curr;
341 buf->previous = dirent; 345 buf->previous = dirent;
342 put_user(ino, &dirent->d_ino); 346 put_user(d_ino, &dirent->d_ino);
343 put_user(namlen, &dirent->d_namlen); 347 put_user(namlen, &dirent->d_namlen);
344 put_user(reclen, &dirent->d_reclen); 348 put_user(reclen, &dirent->d_reclen);
345 copy_to_user(dirent->d_name, name, namlen); 349 copy_to_user(dirent->d_name, name, namlen);
@@ -406,19 +410,23 @@ struct sunos_direntry_callback {
406}; 410};
407 411
408static int sunos_filldirentry(void * __buf, const char * name, int namlen, 412static int sunos_filldirentry(void * __buf, const char * name, int namlen,
409 loff_t offset, ino_t ino, unsigned int d_type) 413 loff_t offset, u64 ino, unsigned int d_type)
410{ 414{
411 struct sunos_direntry __user *dirent; 415 struct sunos_direntry __user *dirent;
412 struct sunos_direntry_callback *buf = __buf; 416 struct sunos_direntry_callback *buf = __buf;
417 unsigned long d_ino;
413 int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1); 418 int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1);
414 419
415 buf->error = -EINVAL; /* only used if we fail.. */ 420 buf->error = -EINVAL; /* only used if we fail.. */
416 if (reclen > buf->count) 421 if (reclen > buf->count)
417 return -EINVAL; 422 return -EINVAL;
423 d_ino = ino;
424 if (sizeof(d_ino) < sizeof(ino) && d_ino != ino)
425 return -EOVERFLOW;
418 dirent = buf->previous; 426 dirent = buf->previous;
419 dirent = buf->curr; 427 dirent = buf->curr;
420 buf->previous = dirent; 428 buf->previous = dirent;
421 put_user(ino, &dirent->d_ino); 429 put_user(d_ino, &dirent->d_ino);
422 put_user(namlen, &dirent->d_namlen); 430 put_user(namlen, &dirent->d_namlen);
423 put_user(reclen, &dirent->d_reclen); 431 put_user(reclen, &dirent->d_reclen);
424 copy_to_user(dirent->d_name, name, namlen); 432 copy_to_user(dirent->d_name, name, namlen);
diff --git a/arch/sparc64/kernel/sys_sparc32.c b/arch/sparc64/kernel/sys_sparc32.c
index 69444f266e2d..dbc6d1a3be1f 100644
--- a/arch/sparc64/kernel/sys_sparc32.c
+++ b/arch/sparc64/kernel/sys_sparc32.c
@@ -337,12 +337,17 @@ asmlinkage long sys32_ftruncate64(unsigned int fd, unsigned long high, unsigned
337 337
338int cp_compat_stat(struct kstat *stat, struct compat_stat __user *statbuf) 338int cp_compat_stat(struct kstat *stat, struct compat_stat __user *statbuf)
339{ 339{
340 compat_ino_t ino;
340 int err; 341 int err;
341 342
342 if (stat->size > MAX_NON_LFS || !old_valid_dev(stat->dev) || 343 if (stat->size > MAX_NON_LFS || !old_valid_dev(stat->dev) ||
343 !old_valid_dev(stat->rdev)) 344 !old_valid_dev(stat->rdev))
344 return -EOVERFLOW; 345 return -EOVERFLOW;
345 346
347 ino = stat->ino;
348 if (sizeof(ino) < sizeof(stat->ino) && ino != stat->ino)
349 return -EOVERFLOW;
350
346 err = put_user(old_encode_dev(stat->dev), &statbuf->st_dev); 351 err = put_user(old_encode_dev(stat->dev), &statbuf->st_dev);
347 err |= put_user(stat->ino, &statbuf->st_ino); 352 err |= put_user(stat->ino, &statbuf->st_ino);
348 err |= put_user(stat->mode, &statbuf->st_mode); 353 err |= put_user(stat->mode, &statbuf->st_mode);
diff --git a/arch/sparc64/kernel/sys_sunos32.c b/arch/sparc64/kernel/sys_sunos32.c
index 953296b73f3f..e414c8ef0225 100644
--- a/arch/sparc64/kernel/sys_sunos32.c
+++ b/arch/sparc64/kernel/sys_sunos32.c
@@ -280,16 +280,20 @@ static int sunos_filldir(void * __buf, const char * name, int namlen,
280 struct sunos_dirent __user *dirent; 280 struct sunos_dirent __user *dirent;
281 struct sunos_dirent_callback * buf = (struct sunos_dirent_callback *) __buf; 281 struct sunos_dirent_callback * buf = (struct sunos_dirent_callback *) __buf;
282 int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1); 282 int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1);
283 u32 d_ino;
283 284
284 buf->error = -EINVAL; /* only used if we fail.. */ 285 buf->error = -EINVAL; /* only used if we fail.. */
285 if (reclen > buf->count) 286 if (reclen > buf->count)
286 return -EINVAL; 287 return -EINVAL;
288 d_ino = ino;
289 if (sizeof(d_ino) < sizeof(ino) && d_ino != ino)
290 return -EOVERFLOW;
287 dirent = buf->previous; 291 dirent = buf->previous;
288 if (dirent) 292 if (dirent)
289 put_user(offset, &dirent->d_off); 293 put_user(offset, &dirent->d_off);
290 dirent = buf->curr; 294 dirent = buf->curr;
291 buf->previous = dirent; 295 buf->previous = dirent;
292 put_user(ino, &dirent->d_ino); 296 put_user(d_ino, &dirent->d_ino);
293 put_user(namlen, &dirent->d_namlen); 297 put_user(namlen, &dirent->d_namlen);
294 put_user(reclen, &dirent->d_reclen); 298 put_user(reclen, &dirent->d_reclen);
295 if (copy_to_user(dirent->d_name, name, namlen)) 299 if (copy_to_user(dirent->d_name, name, namlen))
@@ -363,14 +367,18 @@ static int sunos_filldirentry(void * __buf, const char * name, int namlen,
363 struct sunos_direntry_callback * buf = 367 struct sunos_direntry_callback * buf =
364 (struct sunos_direntry_callback *) __buf; 368 (struct sunos_direntry_callback *) __buf;
365 int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1); 369 int reclen = ROUND_UP(NAME_OFFSET(dirent) + namlen + 1);
370 u32 d_ino;
366 371
367 buf->error = -EINVAL; /* only used if we fail.. */ 372 buf->error = -EINVAL; /* only used if we fail.. */
368 if (reclen > buf->count) 373 if (reclen > buf->count)
369 return -EINVAL; 374 return -EINVAL;
375 d_ino = ino;
376 if (sizeof(d_ino) < sizeof(ino) && d_ino != ino)
377 return -EOVERFLOW;
370 dirent = buf->previous; 378 dirent = buf->previous;
371 dirent = buf->curr; 379 dirent = buf->curr;
372 buf->previous = dirent; 380 buf->previous = dirent;
373 put_user(ino, &dirent->d_ino); 381 put_user(d_ino, &dirent->d_ino);
374 put_user(namlen, &dirent->d_namlen); 382 put_user(namlen, &dirent->d_namlen);
375 put_user(reclen, &dirent->d_reclen); 383 put_user(reclen, &dirent->d_reclen);
376 if (copy_to_user(dirent->d_name, name, namlen)) 384 if (copy_to_user(dirent->d_name, name, namlen))
diff --git a/arch/sparc64/solaris/fs.c b/arch/sparc64/solaris/fs.c
index 0f0eb6aa1c40..12a940cc791f 100644
--- a/arch/sparc64/solaris/fs.c
+++ b/arch/sparc64/solaris/fs.c
@@ -82,12 +82,17 @@ struct sol_stat64 {
82 82
83static inline int putstat(struct sol_stat __user *ubuf, struct kstat *kbuf) 83static inline int putstat(struct sol_stat __user *ubuf, struct kstat *kbuf)
84{ 84{
85 u32 ino;
86
85 if (kbuf->size > MAX_NON_LFS || 87 if (kbuf->size > MAX_NON_LFS ||
86 !sysv_valid_dev(kbuf->dev) || 88 !sysv_valid_dev(kbuf->dev) ||
87 !sysv_valid_dev(kbuf->rdev)) 89 !sysv_valid_dev(kbuf->rdev))
88 return -EOVERFLOW; 90 return -EOVERFLOW;
91 ino = kbuf->ino;
92 if (sizeof(ino) < sizeof(kbuf->ino) && ino != kbuf->ino)
93 return -EOVERFLOW;
89 if (put_user (sysv_encode_dev(kbuf->dev), &ubuf->st_dev) || 94 if (put_user (sysv_encode_dev(kbuf->dev), &ubuf->st_dev) ||
90 __put_user (kbuf->ino, &ubuf->st_ino) || 95 __put_user (ino, &ubuf->st_ino) ||
91 __put_user (kbuf->mode, &ubuf->st_mode) || 96 __put_user (kbuf->mode, &ubuf->st_mode) ||
92 __put_user (kbuf->nlink, &ubuf->st_nlink) || 97 __put_user (kbuf->nlink, &ubuf->st_nlink) ||
93 __put_user (kbuf->uid, &ubuf->st_uid) || 98 __put_user (kbuf->uid, &ubuf->st_uid) ||
diff --git a/arch/x86_64/ia32/sys_ia32.c b/arch/x86_64/ia32/sys_ia32.c
index 26a01717cc1a..c9bac3af29d6 100644
--- a/arch/x86_64/ia32/sys_ia32.c
+++ b/arch/x86_64/ia32/sys_ia32.c
@@ -76,6 +76,8 @@
76 76
77int cp_compat_stat(struct kstat *kbuf, struct compat_stat __user *ubuf) 77int cp_compat_stat(struct kstat *kbuf, struct compat_stat __user *ubuf)
78{ 78{
79 compat_ino_t ino;
80
79 typeof(ubuf->st_uid) uid = 0; 81 typeof(ubuf->st_uid) uid = 0;
80 typeof(ubuf->st_gid) gid = 0; 82 typeof(ubuf->st_gid) gid = 0;
81 SET_UID(uid, kbuf->uid); 83 SET_UID(uid, kbuf->uid);
@@ -84,9 +86,12 @@ int cp_compat_stat(struct kstat *kbuf, struct compat_stat __user *ubuf)
84 return -EOVERFLOW; 86 return -EOVERFLOW;
85 if (kbuf->size >= 0x7fffffff) 87 if (kbuf->size >= 0x7fffffff)
86 return -EOVERFLOW; 88 return -EOVERFLOW;
89 ino = kbuf->ino;
90 if (sizeof(ino) < sizeof(kbuf->ino) && ino != kbuf->ino)
91 return -EOVERFLOW;
87 if (!access_ok(VERIFY_WRITE, ubuf, sizeof(struct compat_stat)) || 92 if (!access_ok(VERIFY_WRITE, ubuf, sizeof(struct compat_stat)) ||
88 __put_user (old_encode_dev(kbuf->dev), &ubuf->st_dev) || 93 __put_user (old_encode_dev(kbuf->dev), &ubuf->st_dev) ||
89 __put_user (kbuf->ino, &ubuf->st_ino) || 94 __put_user (ino, &ubuf->st_ino) ||
90 __put_user (kbuf->mode, &ubuf->st_mode) || 95 __put_user (kbuf->mode, &ubuf->st_mode) ||
91 __put_user (kbuf->nlink, &ubuf->st_nlink) || 96 __put_user (kbuf->nlink, &ubuf->st_nlink) ||
92 __put_user (uid, &ubuf->st_uid) || 97 __put_user (uid, &ubuf->st_uid) ||