1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Wrapper functions for 16bit uid back compatibility. All nicely tied 4 * together in the faint hope we can take the out in five years time. 5 */ 6 7 #include <linux/mm.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/cred.h> 17 #include <linux/syscalls.h> 18 19 #include <linux/uaccess.h> 20 21 #include "uid16.h" 22 23 SYSCALL_DEFINE3(chown16, const char __user *, filename, old_uid_t, user, old_gid_t, group) 24 { 25 return ksys_chown(filename, low2highuid(user), low2highgid(group)); 26 } 27 28 SYSCALL_DEFINE3(lchown16, const char __user *, filename, old_uid_t, user, old_gid_t, group) 29 { 30 return ksys_lchown(filename, low2highuid(user), low2highgid(group)); 31 } 32 33 SYSCALL_DEFINE3(fchown16, unsigned int, fd, old_uid_t, user, old_gid_t, group) 34 { 35 return ksys_fchown(fd, low2highuid(user), low2highgid(group)); 36 } 37 38 SYSCALL_DEFINE2(setregid16, old_gid_t, rgid, old_gid_t, egid) 39 { 40 return __sys_setregid(low2highgid(rgid), low2highgid(egid)); 41 } 42 43 SYSCALL_DEFINE1(setgid16, old_gid_t, gid) 44 { 45 return __sys_setgid(low2highgid(gid)); 46 } 47 48 SYSCALL_DEFINE2(setreuid16, old_uid_t, ruid, old_uid_t, euid) 49 { 50 return __sys_setreuid(low2highuid(ruid), low2highuid(euid)); 51 } 52 53 SYSCALL_DEFINE1(setuid16, old_uid_t, uid) 54 { 55 return __sys_setuid(low2highuid(uid)); 56 } 57 58 SYSCALL_DEFINE3(setresuid16, old_uid_t, ruid, old_uid_t, euid, old_uid_t, suid) 59 { 60 return __sys_setresuid(low2highuid(ruid), low2highuid(euid), 61 low2highuid(suid)); 62 } 63 64 SYSCALL_DEFINE3(getresuid16, old_uid_t __user *, ruidp, old_uid_t __user *, euidp, old_uid_t __user *, suidp) 65 { 66 const struct cred *cred = current_cred(); 67 int retval; 68 old_uid_t ruid, euid, suid; 69 70 ruid = high2lowuid(from_kuid_munged(cred->user_ns, cred->uid)); 71 euid = high2lowuid(from_kuid_munged(cred->user_ns, cred->euid)); 72 suid = high2lowuid(from_kuid_munged(cred->user_ns, cred->suid)); 73 74 if (!(retval = put_user(ruid, ruidp)) && 75 !(retval = put_user(euid, euidp))) 76 retval = put_user(suid, suidp); 77 78 return retval; 79 } 80 81 SYSCALL_DEFINE3(setresgid16, old_gid_t, rgid, old_gid_t, egid, old_gid_t, sgid) 82 { 83 return __sys_setresgid(low2highgid(rgid), low2highgid(egid), 84 low2highgid(sgid)); 85 } 86 87 SYSCALL_DEFINE3(getresgid16, old_gid_t __user *, rgidp, old_gid_t __user *, egidp, old_gid_t __user *, sgidp) 88 { 89 const struct cred *cred = current_cred(); 90 int retval; 91 old_gid_t rgid, egid, sgid; 92 93 rgid = high2lowgid(from_kgid_munged(cred->user_ns, cred->gid)); 94 egid = high2lowgid(from_kgid_munged(cred->user_ns, cred->egid)); 95 sgid = high2lowgid(from_kgid_munged(cred->user_ns, cred->sgid)); 96 97 if (!(retval = put_user(rgid, rgidp)) && 98 !(retval = put_user(egid, egidp))) 99 retval = put_user(sgid, sgidp); 100 101 return retval; 102 } 103 104 SYSCALL_DEFINE1(setfsuid16, old_uid_t, uid) 105 { 106 return __sys_setfsuid(low2highuid(uid)); 107 } 108 109 SYSCALL_DEFINE1(setfsgid16, old_gid_t, gid) 110 { 111 return __sys_setfsgid(low2highgid(gid)); 112 } 113 114 static int groups16_to_user(old_gid_t __user *grouplist, 115 struct group_info *group_info) 116 { 117 struct user_namespace *user_ns = current_user_ns(); 118 int i; 119 old_gid_t group; 120 kgid_t kgid; 121 122 for (i = 0; i < group_info->ngroups; i++) { 123 kgid = group_info->gid[i]; 124 group = high2lowgid(from_kgid_munged(user_ns, kgid)); 125 if (put_user(group, grouplist+i)) 126 return -EFAULT; 127 } 128 129 return 0; 130 } 131 132 static int groups16_from_user(struct group_info *group_info, 133 old_gid_t __user *grouplist) 134 { 135 struct user_namespace *user_ns = current_user_ns(); 136 int i; 137 old_gid_t group; 138 kgid_t kgid; 139 140 for (i = 0; i < group_info->ngroups; i++) { 141 if (get_user(group, grouplist+i)) 142 return -EFAULT; 143 144 kgid = make_kgid(user_ns, low2highgid(group)); 145 if (!gid_valid(kgid)) 146 return -EINVAL; 147 148 group_info->gid[i] = kgid; 149 } 150 151 return 0; 152 } 153 154 SYSCALL_DEFINE2(getgroups16, int, gidsetsize, old_gid_t __user *, grouplist) 155 { 156 const struct cred *cred = current_cred(); 157 int i; 158 159 if (gidsetsize < 0) 160 return -EINVAL; 161 162 i = cred->group_info->ngroups; 163 if (gidsetsize) { 164 if (i > gidsetsize) { 165 i = -EINVAL; 166 goto out; 167 } 168 if (groups16_to_user(grouplist, cred->group_info)) { 169 i = -EFAULT; 170 goto out; 171 } 172 } 173 out: 174 return i; 175 } 176 177 SYSCALL_DEFINE2(setgroups16, int, gidsetsize, old_gid_t __user *, grouplist) 178 { 179 struct group_info *group_info; 180 int retval; 181 182 if (!may_setgroups()) 183 return -EPERM; 184 if ((unsigned)gidsetsize > NGROUPS_MAX) 185 return -EINVAL; 186 187 group_info = groups_alloc(gidsetsize); 188 if (!group_info) 189 return -ENOMEM; 190 retval = groups16_from_user(group_info, grouplist); 191 if (retval) { 192 put_group_info(group_info); 193 return retval; 194 } 195 196 groups_sort(group_info); 197 retval = set_current_groups(group_info); 198 put_group_info(group_info); 199 200 return retval; 201 } 202 203 SYSCALL_DEFINE0(getuid16) 204 { 205 return high2lowuid(from_kuid_munged(current_user_ns(), current_uid())); 206 } 207 208 SYSCALL_DEFINE0(geteuid16) 209 { 210 return high2lowuid(from_kuid_munged(current_user_ns(), current_euid())); 211 } 212 213 SYSCALL_DEFINE0(getgid16) 214 { 215 return high2lowgid(from_kgid_munged(current_user_ns(), current_gid())); 216 } 217 218 SYSCALL_DEFINE0(getegid16) 219 { 220 return high2lowgid(from_kgid_munged(current_user_ns(), current_egid())); 221 } 222