]> git.neil.brown.name Git - history.git/commitdiff
[PATCH] UID16 fixes
authorAndi Kleen <ak@muc.de>
Mon, 6 Oct 2003 08:15:36 +0000 (01:15 -0700)
committerLinus Torvalds <torvalds@home.osdl.org>
Mon, 6 Oct 2003 08:15:36 +0000 (01:15 -0700)
This fixes CONFIG_UID16 problems on x86-64 as discussed earlier.

CONFIG_UID16 now only selects the inclusion of kernel/uid16.c, all
conversions are triggered dynamically based on type sizes.  This allows
x86-64 to both include uid16.c for emulation purposes, but not truncate
uids to 16bit in sys_newstat.

- Replace the old macros from linux/highuid.h with new SET_UID/SET_GID
  macros that do type checking. Based on Linus' proposal.

- Fix everybody to use them.

- Clean up some cruft in the x86-64 32bit emulation allowed by this
  (other 32bit emulations could be cleaned too, but I'm too lazy for
  that right now)

- Add one missing EOVERFLOW check in x86-64 32bit sys_newstat while
  I was at it.

arch/mips/kernel/linux32.c
arch/x86_64/ia32/sys_ia32.c
fs/binfmt_elf.c
fs/ncpfs/ioctl.c
fs/smbfs/inode.c
fs/smbfs/ioctl.c
fs/stat.c
include/asm-x86_64/posix_types.h
include/linux/highuid.h
ipc/util.c

index 186a1933ad72802186c6f93f19b7fc43dce9e1cb..be36d9c9fb4325b922a3be8d41de7e26f083b350 100644 (file)
@@ -79,8 +79,8 @@ int cp_compat_stat(struct kstat *stat, struct compat_stat *statbuf)
        tmp.st_ino = stat->ino;
        tmp.st_mode = stat->mode;
        tmp.st_nlink = stat->nlink;
-       SET_STAT_UID(tmp, stat->uid);
-       SET_STAT_GID(tmp, stat->gid);
+       SET_UID(tmp.st_uid, stat->uid);
+       SET_GID(tmp.st_gid, stat->gid);
        tmp.st_rdev = new_encode_dev(stat->rdev);
        tmp.st_size = stat->size;
        tmp.st_atime = stat->atime.tv_sec;
index abf9bd34c6fe8244b5918427c5a11b1de3be4170..f3846c1c606f20cd17ffbcc82baa8ec7a64466bf 100644 (file)
@@ -61,6 +61,7 @@
 #include <linux/compat.h>
 #include <linux/vfs.h>
 #include <linux/ptrace.h>
+#include <linux/highuid.h>
 #include <asm/mman.h>
 #include <asm/types.h>
 #include <asm/uaccess.h>
 #define ROUND_UP(x,a)  ((__typeof__(x))(((unsigned long)(x) + ((a) - 1)) & ~((a) - 1)))
 #define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
 
-#undef high2lowuid
-#undef high2lowgid
-#undef low2highuid
-#undef low2highgid
-
-#define high2lowuid(uid) ((uid) > 65535) ? (u16)overflowuid : (u16)(uid)
-#define high2lowgid(gid) ((gid) > 65535) ? (u16)overflowgid : (u16)(gid)
-#define low2highuid(uid) ((uid) == (u16)-1) ? (uid_t)-1 : (uid_t)(uid)
-#define low2highgid(gid) ((gid) == (u16)-1) ? (gid_t)-1 : (gid_t)(gid)
-extern int overflowuid,overflowgid; 
-
 int cp_compat_stat(struct kstat *kbuf, struct compat_stat *ubuf)
 {
+       typeof(ubuf->st_uid) uid = 0;
+       typeof(ubuf->st_gid) gid = 0;
+       SET_UID(uid, kbuf->uid);
+       SET_GID(gid, kbuf->gid);
        if (!old_valid_dev(kbuf->dev) || !old_valid_dev(kbuf->rdev))
                return -EOVERFLOW;
+       if (kbuf->size >= 0x7fffffff)
+               return -EOVERFLOW;
        if (verify_area(VERIFY_WRITE, ubuf, sizeof(struct compat_stat)) ||
            __put_user (old_encode_dev(kbuf->dev), &ubuf->st_dev) ||
            __put_user (kbuf->ino, &ubuf->st_ino) ||
            __put_user (kbuf->mode, &ubuf->st_mode) ||
            __put_user (kbuf->nlink, &ubuf->st_nlink) ||
-           __put_user (kbuf->uid, &ubuf->st_uid) ||
-           __put_user (kbuf->gid, &ubuf->st_gid) ||
+           __put_user (uid, &ubuf->st_uid) ||
+           __put_user (gid, &ubuf->st_gid) ||
            __put_user (old_encode_dev(kbuf->rdev), &ubuf->st_rdev) ||
            __put_user (kbuf->size, &ubuf->st_size) ||
            __put_user (kbuf->atime.tv_sec, &ubuf->st_atime) ||
@@ -120,14 +116,18 @@ int cp_compat_stat(struct kstat *kbuf, struct compat_stat *ubuf)
 static int
 cp_stat64(struct stat64 *ubuf, struct kstat *stat)
 {
+       typeof(ubuf->st_uid) uid = 0;
+       typeof(ubuf->st_gid) gid = 0;
+       SET_UID(uid, stat->uid);
+       SET_GID(gid, stat->gid);
        if (verify_area(VERIFY_WRITE, ubuf, sizeof(struct stat64)) ||
            __put_user(huge_encode_dev(stat->dev), &ubuf->st_dev) ||
            __put_user (stat->ino, &ubuf->__st_ino) ||
            __put_user (stat->ino, &ubuf->st_ino) ||
            __put_user (stat->mode, &ubuf->st_mode) ||
            __put_user (stat->nlink, &ubuf->st_nlink) ||
-           __put_user (stat->uid, &ubuf->st_uid) ||
-           __put_user (stat->gid, &ubuf->st_gid) ||
+           __put_user (uid, &ubuf->st_uid) ||
+           __put_user (gid, &ubuf->st_gid) ||
            __put_user (huge_encode_dev(stat->rdev), &ubuf->st_rdev) ||
            __put_user (stat->size, &ubuf->st_size) ||
            __put_user (stat->atime.tv_sec, &ubuf->st_atime) ||
@@ -1701,8 +1701,8 @@ static int nfs_exp32_trans(struct nfsctl_arg *karg, struct nfsctl_arg32 *arg32)
                      &arg32->ca32_export.ex32_anon_uid);
        err |= __get_user(karg->ca_export.ex_anon_gid,
                      &arg32->ca32_export.ex32_anon_gid);
-       karg->ca_export.ex_anon_uid = high2lowuid(karg->ca_export.ex_anon_uid);
-       karg->ca_export.ex_anon_gid = high2lowgid(karg->ca_export.ex_anon_gid);
+       SET_UID(karg->ca_export.ex_anon_uid, karg->ca_export.ex_anon_uid);
+       SET_GID(karg->ca_export.ex_anon_gid, karg->ca_export.ex_anon_gid);
        return err;
 }
 
index 505c73aa94eed8d5300d64cf222e40bc172309b9..e8abe0dde5ac73c6aed943f2cc4d6844b73b7b19 100644 (file)
@@ -1120,8 +1120,8 @@ static void fill_psinfo(struct elf_prpsinfo *psinfo, struct task_struct *p,
        psinfo->pr_zomb = psinfo->pr_sname == 'Z';
        psinfo->pr_nice = task_nice(p);
        psinfo->pr_flag = p->flags;
-       psinfo->pr_uid = NEW_TO_OLD_UID(p->uid);
-       psinfo->pr_gid = NEW_TO_OLD_GID(p->gid);
+       SET_UID(psinfo->pr_uid, p->uid);
+       SET_GID(psinfo->pr_gid, p->gid);
        strncpy(psinfo->pr_fname, p->comm, sizeof(psinfo->pr_fname));
        
        return;
index fb3e550a9abcc8f6c72c814b02655aa9902ccdfe..a25f957ad574dbbfe0da41a098e32a6b06d9e91f 100644 (file)
@@ -112,7 +112,7 @@ int ncp_ioctl(struct inode *inode, struct file *filp,
                                return -EINVAL;
                        }
                        /* TODO: info.addr = server->m.serv_addr; */
-                       info.mounted_uid        = NEW_TO_OLD_UID(server->m.mounted_uid);
+                       SET_UID(info.mounted_uid, server->m.mounted_uid);
                        info.connection         = server->connection;
                        info.buffer_size        = server->buffer_size;
                        info.volume_number      = NCP_FINFO(inode)->volNumber;
@@ -637,11 +637,13 @@ outrel:
        /* NCP_IOC_GETMOUNTUID may be same as NCP_IOC_GETMOUNTUID2,
            so we have this out of switch */
        if (cmd == NCP_IOC_GETMOUNTUID) {
+               __kernel_uid_t uid = 0;
                if ((permission(inode, MAY_READ, NULL) != 0)
                    && (current->uid != server->m.mounted_uid)) {
                        return -EACCES;
                }
-               if (put_user(NEW_TO_OLD_UID(server->m.mounted_uid), (__kernel_uid_t *) arg))
+               SET_UID(uid, server->m.mounted_uid);
+               if (put_user(uid, (__kernel_uid_t *) arg))
                        return -EFAULT;
                return 0;
        }
index 85d97d4cb6d5d5527f159ca8d4cf36414a59f185..1a22ef00cd25be04161bca15608d61002631260a 100644 (file)
@@ -551,8 +551,8 @@ int smb_fill_super(struct super_block *sb, void *raw_data, int silent)
        if (ver == SMB_MOUNT_OLDVERSION) {
                mnt->version = oldmnt->version;
 
-               mnt->uid = OLD_TO_NEW_UID(oldmnt->uid);
-               mnt->gid = OLD_TO_NEW_GID(oldmnt->gid);
+               SET_UID(mnt->uid, oldmnt->uid);
+               SET_GID(mnt->gid, oldmnt->gid);
 
                mnt->file_mode = (oldmnt->file_mode & S_IRWXUGO) | S_IFREG;
                mnt->dir_mode = (oldmnt->dir_mode & S_IRWXUGO) | S_IFDIR;
index 235f583d953c86b021a17c6c85f6557671dffa4f..4b48899eac230504fc8ba54e98adc6271ebcb06f 100644 (file)
@@ -31,12 +31,15 @@ smb_ioctl(struct inode *inode, struct file *filp,
        int result = -EINVAL;
 
        switch (cmd) {
+               uid16_t uid16 = 0;
+               uid_t uid32 = 0;
        case SMB_IOC_GETMOUNTUID:
-               result = put_user(NEW_TO_OLD_UID(server->mnt->mounted_uid),
-                                 (uid16_t *) arg);
+               SET_UID(uid16, server->mnt->mounted_uid);
+               result = put_user(uid16, (uid16_t *) arg);
                break;
        case SMB_IOC_GETMOUNTUID32:
-               result = put_user(server->mnt->mounted_uid, (uid_t *) arg);
+               SET_UID(uid32, server->mnt->mounted_uid);
+               result = put_user(uid32, (uid_t *) arg);
                break;
 
        case SMB_IOC_NEWCONN:
index 7e541b066c5e7d3245772081c659ced1ab30e90e..617e75f0e94f158a46afaadeaef5ae9f518324a6 100644 (file)
--- a/fs/stat.c
+++ b/fs/stat.c
@@ -121,8 +121,8 @@ static int cp_old_stat(struct kstat *stat, struct __old_kernel_stat __user * sta
        tmp.st_ino = stat->ino;
        tmp.st_mode = stat->mode;
        tmp.st_nlink = stat->nlink;
-       SET_OLDSTAT_UID(tmp, stat->uid);
-       SET_OLDSTAT_GID(tmp, stat->gid);
+       SET_UID(tmp.st_uid, stat->uid);
+       SET_GID(tmp.st_gid, stat->gid);
        tmp.st_rdev = old_encode_dev(stat->rdev);
 #if BITS_PER_LONG == 32
        if (stat->size > MAX_NON_LFS)
@@ -189,8 +189,8 @@ static int cp_new_stat(struct kstat *stat, struct stat __user *statbuf)
        tmp.st_ino = stat->ino;
        tmp.st_mode = stat->mode;
        tmp.st_nlink = stat->nlink;
-       SET_STAT_UID(tmp, stat->uid);
-       SET_STAT_GID(tmp, stat->gid);
+       SET_UID(tmp.st_uid, stat->uid);
+       SET_GID(tmp.st_gid, stat->gid);
 #if BITS_PER_LONG == 32
        tmp.st_rdev = old_encode_dev(stat->rdev);
 #else
index b28ed4955fa3e04ea24fa18ee024d874fcc956ae..9926aa43775b82304209c38c7bc6a5a3c712d0fe 100644 (file)
@@ -36,8 +36,8 @@ typedef struct {
        int     val[2];
 } __kernel_fsid_t;
 
-typedef __kernel_uid_t __kernel_old_uid_t;
-typedef __kernel_gid_t __kernel_old_gid_t;
+typedef unsigned short __kernel_old_uid_t;
+typedef unsigned short __kernel_old_gid_t;
 typedef __kernel_uid_t __kernel_uid32_t;
 typedef __kernel_gid_t __kernel_gid32_t;
 
index 9d0bdcbc2080d2b0163ea8732699171e640f1e8a..3ca170db446c9e7b6dcc39f88d3d10293b114c54 100644 (file)
@@ -35,6 +35,9 @@
 extern int overflowuid;
 extern int overflowgid;
 
+extern void __bad_uid(void);
+extern void __bad_gid(void);
+
 #define DEFAULT_OVERFLOWUID    65534
 #define DEFAULT_OVERFLOWGID    65534
 
@@ -50,36 +53,36 @@ extern int overflowgid;
 #define low2highuid(uid) ((uid) == (old_uid_t)-1 ? (uid_t)-1 : (uid_t)(uid))
 #define low2highgid(gid) ((gid) == (old_gid_t)-1 ? (gid_t)-1 : (gid_t)(gid))
 
-/* Avoid extra ifdefs with these macros */
-
-#define SET_UID16(var, uid)    var = high2lowuid(uid)
-#define SET_GID16(var, gid)    var = high2lowgid(gid)
-#define NEW_TO_OLD_UID(uid)    high2lowuid(uid)
-#define NEW_TO_OLD_GID(gid)    high2lowgid(gid)
-#define OLD_TO_NEW_UID(uid)    low2highuid(uid)
-#define OLD_TO_NEW_GID(gid)    low2highgid(gid)
-
-/* specific to fs/stat.c */
-#define SET_OLDSTAT_UID(stat, uid)     (stat).st_uid = high2lowuid(uid)
-#define SET_OLDSTAT_GID(stat, gid)     (stat).st_gid = high2lowgid(gid)
-#define SET_STAT_UID(stat, uid)                (stat).st_uid = high2lowuid(uid)
-#define SET_STAT_GID(stat, gid)                (stat).st_gid = high2lowgid(gid)
+/* uid/gid input should be always 32bit uid_t */
+#define SET_UID(var, uid)      \
+       do {                    \
+       if (sizeof(var) == sizeof(old_uid_t)) (var) = high2lowuid(uid); \
+       else if (sizeof(var) >= sizeof(uid)) (var) = (uid); \
+       else __bad_uid(); \
+       } while(0)
+
+#define SET_GID(var, gid)      \
+       do {                    \
+       if (sizeof(var) == sizeof(old_gid_t)) (var) = high2lowgid(gid); \
+       else if (sizeof(var) >= sizeof(gid)) (var) = (gid); \
+       else __bad_gid(); \
+       } while(0)
 
 #else
 
-#define SET_UID16(var, uid)    do { ; } while (0)
-#define SET_GID16(var, gid)    do { ; } while (0)
-#define NEW_TO_OLD_UID(uid)    (uid)
-#define NEW_TO_OLD_GID(gid)    (gid)
-#define OLD_TO_NEW_UID(uid)    (uid)
-#define OLD_TO_NEW_GID(gid)    (gid)
+#define SET_UID(var,uid) \
+       do { \
+       if (sizeof(var) < sizeof(uid)) __bad_uid(); \
+       (var) = (uid); \
+       } while (0)
 
-#define SET_OLDSTAT_UID(stat, uid)     (stat).st_uid = (uid)
-#define SET_OLDSTAT_GID(stat, gid)     (stat).st_gid = (gid)
-#define SET_STAT_UID(stat, uid)                (stat).st_uid = (uid)
-#define SET_STAT_GID(stat, gid)                (stat).st_gid = (gid)
+#define SET_GID(var,gid) \
+       do { \
+       if (sizeof(var) < sizeof(gid)) __bad_gid(); \
+       (var) = (gid); \
+       } while (0);
 
-#endif /* CONFIG_UID16 */
+#endif /* !CONFIG_UID16 */
 
 
 /*
index 07bcb8d80a722354c49f76b11c5189981b5fd005..806b2d7084f1647169f77e6cc2d9221d7ece535f 100644 (file)
@@ -421,10 +421,10 @@ void kernel_to_ipc64_perm (struct kern_ipc_perm *in, struct ipc64_perm *out)
 void ipc64_perm_to_ipc_perm (struct ipc64_perm *in, struct ipc_perm *out)
 {
        out->key        = in->key;
-       out->uid        = NEW_TO_OLD_UID(in->uid);
-       out->gid        = NEW_TO_OLD_GID(in->gid);
-       out->cuid       = NEW_TO_OLD_UID(in->cuid);
-       out->cgid       = NEW_TO_OLD_GID(in->cgid);
+       SET_UID(out->uid, in->uid);
+       SET_GID(out->gid, in->gid);
+       SET_UID(out->cuid, in->cuid);
+       SET_GID(out->cgid, in->cgid);
        out->mode       = in->mode;
        out->seq        = in->seq;
 }