hfsplus: check read_mapping_page() return value
[safe/jmp/linux-2.6] / fs / compat.c
index ee80ff3..5f9ec44 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/fcntl.h>
 #include <linux/namei.h>
 #include <linux/file.h>
+#include <linux/fdtable.h>
 #include <linux/vfs.h>
 #include <linux/ioctl.h>
 #include <linux/init.h>
@@ -136,6 +137,45 @@ asmlinkage long compat_sys_utimes(char __user *filename, struct compat_timeval _
        return compat_sys_futimesat(AT_FDCWD, filename, t);
 }
 
+static int cp_compat_stat(struct kstat *stat, struct compat_stat __user *ubuf)
+{
+       compat_ino_t ino = stat->ino;
+       typeof(ubuf->st_uid) uid = 0;
+       typeof(ubuf->st_gid) gid = 0;
+       int err;
+
+       SET_UID(uid, stat->uid);
+       SET_GID(gid, stat->gid);
+
+       if ((u64) stat->size > MAX_NON_LFS ||
+           !old_valid_dev(stat->dev) ||
+           !old_valid_dev(stat->rdev))
+               return -EOVERFLOW;
+       if (sizeof(ino) < sizeof(stat->ino) && ino != stat->ino)
+               return -EOVERFLOW;
+
+       if (clear_user(ubuf, sizeof(*ubuf)))
+               return -EFAULT;
+
+       err  = __put_user(old_encode_dev(stat->dev), &ubuf->st_dev);
+       err |= __put_user(ino, &ubuf->st_ino);
+       err |= __put_user(stat->mode, &ubuf->st_mode);
+       err |= __put_user(stat->nlink, &ubuf->st_nlink);
+       err |= __put_user(uid, &ubuf->st_uid);
+       err |= __put_user(gid, &ubuf->st_gid);
+       err |= __put_user(old_encode_dev(stat->rdev), &ubuf->st_rdev);
+       err |= __put_user(stat->size, &ubuf->st_size);
+       err |= __put_user(stat->atime.tv_sec, &ubuf->st_atime);
+       err |= __put_user(stat->atime.tv_nsec, &ubuf->st_atime_nsec);
+       err |= __put_user(stat->mtime.tv_sec, &ubuf->st_mtime);
+       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(char __user * filename,
                struct compat_stat __user *statbuf)
 {
@@ -196,8 +236,8 @@ static int put_compat_statfs(struct compat_statfs __user *ubuf, struct kstatfs *
 {
        
        if (sizeof ubuf->f_blocks == 4) {
-               if ((kbuf->f_blocks | kbuf->f_bfree | kbuf->f_bavail) &
-                   0xffffffff00000000ULL)
+               if ((kbuf->f_blocks | kbuf->f_bfree | kbuf->f_bavail |
+                    kbuf->f_bsize | kbuf->f_frsize) & 0xffffffff00000000ULL)
                        return -EOVERFLOW;
                /* f_files and f_ffree may be -1; it's okay
                 * to stuff that into 32 bits */
@@ -233,18 +273,18 @@ static int put_compat_statfs(struct compat_statfs __user *ubuf, struct kstatfs *
  * The following statfs calls are copies of code from fs/open.c and
  * should be checked against those from time to time
  */
-asmlinkage long compat_sys_statfs(const char __user *path, struct compat_statfs __user *buf)
+asmlinkage long compat_sys_statfs(const char __user *pathname, struct compat_statfs __user *buf)
 {
-       struct nameidata nd;
+       struct path path;
        int error;
 
-       error = user_path_walk(path, &nd);
+       error = user_path(pathname, &path);
        if (!error) {
                struct kstatfs tmp;
-               error = vfs_statfs(nd.dentry, &tmp);
+               error = vfs_statfs(path.dentry, &tmp);
                if (!error)
                        error = put_compat_statfs(buf, &tmp);
-               path_release(&nd);
+               path_put(&path);
        }
        return error;
 }
@@ -270,8 +310,8 @@ out:
 static int put_compat_statfs64(struct compat_statfs64 __user *ubuf, struct kstatfs *kbuf)
 {
        if (sizeof ubuf->f_blocks == 4) {
-               if ((kbuf->f_blocks | kbuf->f_bfree | kbuf->f_bavail) &
-                   0xffffffff00000000ULL)
+               if ((kbuf->f_blocks | kbuf->f_bfree | kbuf->f_bavail |
+                    kbuf->f_bsize | kbuf->f_frsize) & 0xffffffff00000000ULL)
                        return -EOVERFLOW;
                /* f_files and f_ffree may be -1; it's okay
                 * to stuff that into 32 bits */
@@ -298,21 +338,21 @@ static int put_compat_statfs64(struct compat_statfs64 __user *ubuf, struct kstat
        return 0;
 }
 
-asmlinkage long compat_sys_statfs64(const char __user *path, compat_size_t sz, struct compat_statfs64 __user *buf)
+asmlinkage long compat_sys_statfs64(const char __user *pathname, compat_size_t sz, struct compat_statfs64 __user *buf)
 {
-       struct nameidata nd;
+       struct path path;
        int error;
 
        if (sz != sizeof(*buf))
                return -EINVAL;
 
-       error = user_path_walk(path, &nd);
+       error = user_path(pathname, &path);
        if (!error) {
                struct kstatfs tmp;
-               error = vfs_statfs(nd.dentry, &tmp);
+               error = vfs_statfs(path.dentry, &tmp);
                if (!error)
                        error = put_compat_statfs64(buf, &tmp);
-               path_release(&nd);
+               path_put(&path);
        }
        return error;
 }
@@ -702,9 +742,6 @@ static int do_nfs4_super_data_conv(void *raw_data)
                real->flags = raw->flags;
                real->version = raw->version;
        }
-       else {
-               return -EINVAL;
-       }
 
        return 0;
 }
@@ -794,8 +831,10 @@ static int compat_fillonedir(void *__buf, const char *name, int namlen,
        if (buf->result)
                return -EINVAL;
        d_ino = ino;
-       if (sizeof(d_ino) < sizeof(ino) && d_ino != ino)
+       if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
+               buf->result = -EOVERFLOW;
                return -EOVERFLOW;
+       }
        buf->result++;
        dirent = buf->dirent;
        if (!access_ok(VERIFY_WRITE, dirent,
@@ -864,8 +903,10 @@ static int compat_filldir(void *__buf, const char *name, int namlen,
        if (reclen > buf->count)
                return -EINVAL;
        d_ino = ino;
-       if (sizeof(d_ino) < sizeof(ino) && d_ino != ino)
+       if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) {
+               buf->error = -EOVERFLOW;
                return -EOVERFLOW;
+       }
        dirent = buf->previous;
        if (dirent) {
                if (__put_user(offset, &dirent->d_off))
@@ -1237,7 +1278,7 @@ static int compat_count(compat_uptr_t __user *argv, int max)
                        if (!p)
                                break;
                        argv++;
-                       if(++i > max)
+                       if (i++ >= max)
                                return -E2BIG;
                }
        }
@@ -1407,7 +1448,7 @@ int compat_do_execve(char * filename,
                /* execve success */
                security_bprm_free(bprm);
                acct_update_integrals(current);
-               kfree(bprm);
+               free_bprm(bprm);
                return retval;
        }
 
@@ -1426,7 +1467,7 @@ out_file:
        }
 
 out_kfree:
-       kfree(bprm);
+       free_bprm(bprm);
 
 out_ret:
        return retval;
@@ -1637,7 +1678,7 @@ sticky:
        return ret;
 }
 
-#ifdef TIF_RESTORE_SIGMASK
+#ifdef HAVE_SET_RESTORE_SIGMASK
 asmlinkage long compat_sys_pselect7(int n, compat_ulong_t __user *inp,
        compat_ulong_t __user *outp, compat_ulong_t __user *exp,
        struct compat_timespec __user *tsp, compat_sigset_t __user *sigmask,
@@ -1723,7 +1764,7 @@ sticky:
                if (sigmask) {
                        memcpy(&current->saved_sigmask, &sigsaved,
                                        sizeof(sigsaved));
-                       set_thread_flag(TIF_RESTORE_SIGMASK);
+                       set_restore_sigmask();
                }
        } else if (sigmask)
                sigprocmask(SIG_SETMASK, &sigsaved, NULL);
@@ -1794,7 +1835,7 @@ asmlinkage long compat_sys_ppoll(struct pollfd __user *ufds,
                if (sigmask) {
                        memcpy(&current->saved_sigmask, &sigsaved,
                                sizeof(sigsaved));
-                       set_thread_flag(TIF_RESTORE_SIGMASK);
+                       set_restore_sigmask();
                }
                ret = -ERESTARTNOHAND;
        } else if (sigmask)
@@ -1828,7 +1869,7 @@ sticky:
 
        return ret;
 }
-#endif /* TIF_RESTORE_SIGMASK */
+#endif /* HAVE_SET_RESTORE_SIGMASK */
 
 #if defined(CONFIG_NFSD) || defined(CONFIG_NFSD_MODULE)
 /* Stuff for NFS server syscalls... */
@@ -2083,7 +2124,7 @@ long asmlinkage compat_sys_nfsservctl(int cmd, void *notused, void *notused2)
 
 #ifdef CONFIG_EPOLL
 
-#ifdef TIF_RESTORE_SIGMASK
+#ifdef HAVE_SET_RESTORE_SIGMASK
 asmlinkage long compat_sys_epoll_pwait(int epfd,
                        struct compat_epoll_event __user *events,
                        int maxevents, int timeout,
@@ -2120,22 +2161,22 @@ asmlinkage long compat_sys_epoll_pwait(int epfd,
                if (err == -EINTR) {
                        memcpy(&current->saved_sigmask, &sigsaved,
                               sizeof(sigsaved));
-                       set_thread_flag(TIF_RESTORE_SIGMASK);
+                       set_restore_sigmask();
                } else
                        sigprocmask(SIG_SETMASK, &sigsaved, NULL);
        }
 
        return err;
 }
-#endif /* TIF_RESTORE_SIGMASK */
+#endif /* HAVE_SET_RESTORE_SIGMASK */
 
 #endif /* CONFIG_EPOLL */
 
 #ifdef CONFIG_SIGNALFD
 
-asmlinkage long compat_sys_signalfd(int ufd,
-                                   const compat_sigset_t __user *sigmask,
-                                   compat_size_t sigsetsize)
+asmlinkage long compat_sys_signalfd4(int ufd,
+                                    const compat_sigset_t __user *sigmask,
+                                    compat_size_t sigsetsize, int flags)
 {
        compat_sigset_t ss32;
        sigset_t tmp;
@@ -2150,9 +2191,15 @@ asmlinkage long compat_sys_signalfd(int ufd,
        if (copy_to_user(ksigmask, &tmp, sizeof(sigset_t)))
                return -EFAULT;
 
-       return sys_signalfd(ufd, ksigmask, sizeof(sigset_t));
+       return sys_signalfd4(ufd, ksigmask, sizeof(sigset_t), flags);
 }
 
+asmlinkage long compat_sys_signalfd(int ufd,
+                                   const compat_sigset_t __user *sigmask,
+                                   compat_size_t sigsetsize)
+{
+       return compat_sys_signalfd4(ufd, sigmask, sigsetsize, 0);
+}
 #endif /* CONFIG_SIGNALFD */
 
 #ifdef CONFIG_TIMERFD