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