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