1 /* 2 * Wrapper functions for 16bit uid back compatibility. All nicely tied 3 * together in the faint hope we can take the out in five years time. 4 */ 5 6 #include <linux/mm.h> 7 #include <linux/utsname.h> 8 #include <linux/mman.h> 9 #include <linux/notifier.h> 10 #include <linux/reboot.h> 11 #include <linux/prctl.h> 12 #include <linux/capability.h> 13 #include <linux/init.h> 14 #include <linux/highuid.h> 15 #include <linux/security.h> 16 #include <linux/syscalls.h> 17 18 #include <asm/uaccess.h> 19 20 SYSCALL_DEFINE3(chown16, const char __user *, filename, old_uid_t, user, old_gid_t, group) 21 { 22 long ret = sys_chown(filename, low2highuid(user), low2highgid(group)); 23 /* avoid REGPARM breakage on x86: */ 24 asmlinkage_protect(3, ret, filename, user, group); 25 return ret; 26 } 27 28 SYSCALL_DEFINE3(lchown16, const char __user *, filename, old_uid_t, user, old_gid_t, group) 29 { 30 long ret = sys_lchown(filename, low2highuid(user), low2highgid(group)); 31 /* avoid REGPARM breakage on x86: */ 32 asmlinkage_protect(3, ret, filename, user, group); 33 return ret; 34 } 35 36 SYSCALL_DEFINE3(fchown16, unsigned int, fd, old_uid_t, user, old_gid_t, group) 37 { 38 long ret = sys_fchown(fd, low2highuid(user), low2highgid(group)); 39 /* avoid REGPARM breakage on x86: */ 40 asmlinkage_protect(3, ret, fd, user, group); 41 return ret; 42 } 43 44 SYSCALL_DEFINE2(setregid16, old_gid_t, rgid, old_gid_t, egid) 45 { 46 long ret = sys_setregid(low2highgid(rgid), low2highgid(egid)); 47 /* avoid REGPARM breakage on x86: */ 48 asmlinkage_protect(2, ret, rgid, egid); 49 return ret; 50 } 51 52 SYSCALL_DEFINE1(setgid16, old_gid_t, gid) 53 { 54 long ret = sys_setgid(low2highgid(gid)); 55 /* avoid REGPARM breakage on x86: */ 56 asmlinkage_protect(1, ret, gid); 57 return ret; 58 } 59 60 SYSCALL_DEFINE2(setreuid16, old_uid_t, ruid, old_uid_t, euid) 61 { 62 long ret = sys_setreuid(low2highuid(ruid), low2highuid(euid)); 63 /* avoid REGPARM breakage on x86: */ 64 asmlinkage_protect(2, ret, ruid, euid); 65 return ret; 66 } 67 68 SYSCALL_DEFINE1(setuid16, old_uid_t, uid) 69 { 70 long ret = sys_setuid(low2highuid(uid)); 71 /* avoid REGPARM breakage on x86: */ 72 asmlinkage_protect(1, ret, uid); 73 return ret; 74 } 75 76 SYSCALL_DEFINE3(setresuid16, old_uid_t, ruid, old_uid_t, euid, old_uid_t, suid) 77 { 78 long ret = sys_setresuid(low2highuid(ruid), low2highuid(euid), 79 low2highuid(suid)); 80 /* avoid REGPARM breakage on x86: */ 81 asmlinkage_protect(3, ret, ruid, euid, suid); 82 return ret; 83 } 84 85 SYSCALL_DEFINE3(getresuid16, old_uid_t __user *, ruid, old_uid_t __user *, euid, old_uid_t __user *, suid) 86 { 87 const struct cred *cred = current_cred(); 88 int retval; 89 90 if (!(retval = put_user(high2lowuid(cred->uid), ruid)) && 91 !(retval = put_user(high2lowuid(cred->euid), euid))) 92 retval = put_user(high2lowuid(cred->suid), suid); 93 94 return retval; 95 } 96 97 SYSCALL_DEFINE3(setresgid16, old_gid_t, rgid, old_gid_t, egid, old_gid_t, sgid) 98 { 99 long ret = sys_setresgid(low2highgid(rgid), low2highgid(egid), 100 low2highgid(sgid)); 101 /* avoid REGPARM breakage on x86: */ 102 asmlinkage_protect(3, ret, rgid, egid, sgid); 103 return ret; 104 } 105 106 107 SYSCALL_DEFINE3(getresgid16, old_gid_t __user *, rgid, old_gid_t __user *, egid, old_gid_t __user *, sgid) 108 { 109 const struct cred *cred = current_cred(); 110 int retval; 111 112 if (!(retval = put_user(high2lowgid(cred->gid), rgid)) && 113 !(retval = put_user(high2lowgid(cred->egid), egid))) 114 retval = put_user(high2lowgid(cred->sgid), sgid); 115 116 return retval; 117 } 118 119 SYSCALL_DEFINE1(setfsuid16, old_uid_t, uid) 120 { 121 long ret = sys_setfsuid(low2highuid(uid)); 122 /* avoid REGPARM breakage on x86: */ 123 asmlinkage_protect(1, ret, uid); 124 return ret; 125 } 126 127 SYSCALL_DEFINE1(setfsgid16, old_gid_t, gid) 128 { 129 long ret = sys_setfsgid(low2highgid(gid)); 130 /* avoid REGPARM breakage on x86: */ 131 asmlinkage_protect(1, ret, gid); 132 return ret; 133 } 134 135 static int groups16_to_user(old_gid_t __user *grouplist, 136 struct group_info *group_info) 137 { 138 int i; 139 old_gid_t group; 140 141 for (i = 0; i < group_info->ngroups; i++) { 142 group = high2lowgid(GROUP_AT(group_info, i)); 143 if (put_user(group, grouplist+i)) 144 return -EFAULT; 145 } 146 147 return 0; 148 } 149 150 static int groups16_from_user(struct group_info *group_info, 151 old_gid_t __user *grouplist) 152 { 153 int i; 154 old_gid_t group; 155 156 for (i = 0; i < group_info->ngroups; i++) { 157 if (get_user(group, grouplist+i)) 158 return -EFAULT; 159 GROUP_AT(group_info, i) = low2highgid(group); 160 } 161 162 return 0; 163 } 164 165 SYSCALL_DEFINE2(getgroups16, int, gidsetsize, old_gid_t __user *, grouplist) 166 { 167 const struct cred *cred = current_cred(); 168 int i; 169 170 if (gidsetsize < 0) 171 return -EINVAL; 172 173 i = cred->group_info->ngroups; 174 if (gidsetsize) { 175 if (i > gidsetsize) { 176 i = -EINVAL; 177 goto out; 178 } 179 if (groups16_to_user(grouplist, cred->group_info)) { 180 i = -EFAULT; 181 goto out; 182 } 183 } 184 out: 185 return i; 186 } 187 188 SYSCALL_DEFINE2(setgroups16, int, gidsetsize, old_gid_t __user *, grouplist) 189 { 190 struct group_info *group_info; 191 int retval; 192 193 if (!capable(CAP_SETGID)) 194 return -EPERM; 195 if ((unsigned)gidsetsize > NGROUPS_MAX) 196 return -EINVAL; 197 198 group_info = groups_alloc(gidsetsize); 199 if (!group_info) 200 return -ENOMEM; 201 retval = groups16_from_user(group_info, grouplist); 202 if (retval) { 203 put_group_info(group_info); 204 return retval; 205 } 206 207 retval = set_current_groups(group_info); 208 put_group_info(group_info); 209 210 return retval; 211 } 212 213 SYSCALL_DEFINE0(getuid16) 214 { 215 return high2lowuid(current_uid()); 216 } 217 218 SYSCALL_DEFINE0(geteuid16) 219 { 220 return high2lowuid(current_euid()); 221 } 222 223 SYSCALL_DEFINE0(getgid16) 224 { 225 return high2lowgid(current_gid()); 226 } 227 228 SYSCALL_DEFINE0(getegid16) 229 { 230 return high2lowgid(current_egid()); 231 } 232