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