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.
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;
#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) ||
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) ||
&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;
}
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;
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;
/* 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;
}
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;
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:
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)
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
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;
extern int overflowuid;
extern int overflowgid;
+extern void __bad_uid(void);
+extern void __bad_gid(void);
+
#define DEFAULT_OVERFLOWUID 65534
#define DEFAULT_OVERFLOWGID 65534
#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 */
/*
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;
}