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(from: user_ns, low2highgid(group)); |
145 | if (!gid_valid(gid: 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, group_info: 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 | |