xref: /openbmc/linux/kernel/uid16.c (revision 8fa5723aa7e053d498336b48448b292fc2e0458b)
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/utsname.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/syscalls.h>
17 
18 #include <asm/uaccess.h>
19 
20 asmlinkage long sys_chown16(const char __user * filename, old_uid_t user, old_gid_t group)
21 {
22 	long ret = sys_chown(filename, low2highuid(user), low2highgid(group));
23 	/* avoid REGPARM breakage on x86: */
24 	asmlinkage_protect(3, ret, filename, user, group);
25 	return ret;
26 }
27 
28 asmlinkage long sys_lchown16(const char __user * filename, old_uid_t user, old_gid_t group)
29 {
30 	long ret = sys_lchown(filename, low2highuid(user), low2highgid(group));
31 	/* avoid REGPARM breakage on x86: */
32 	asmlinkage_protect(3, ret, filename, user, group);
33 	return ret;
34 }
35 
36 asmlinkage long sys_fchown16(unsigned int fd, old_uid_t user, old_gid_t group)
37 {
38 	long ret = sys_fchown(fd, low2highuid(user), low2highgid(group));
39 	/* avoid REGPARM breakage on x86: */
40 	asmlinkage_protect(3, ret, fd, user, group);
41 	return ret;
42 }
43 
44 asmlinkage long sys_setregid16(old_gid_t rgid, old_gid_t egid)
45 {
46 	long ret = sys_setregid(low2highgid(rgid), low2highgid(egid));
47 	/* avoid REGPARM breakage on x86: */
48 	asmlinkage_protect(2, ret, rgid, egid);
49 	return ret;
50 }
51 
52 asmlinkage long sys_setgid16(old_gid_t gid)
53 {
54 	long ret = sys_setgid(low2highgid(gid));
55 	/* avoid REGPARM breakage on x86: */
56 	asmlinkage_protect(1, ret, gid);
57 	return ret;
58 }
59 
60 asmlinkage long sys_setreuid16(old_uid_t ruid, old_uid_t euid)
61 {
62 	long ret = sys_setreuid(low2highuid(ruid), low2highuid(euid));
63 	/* avoid REGPARM breakage on x86: */
64 	asmlinkage_protect(2, ret, ruid, euid);
65 	return ret;
66 }
67 
68 asmlinkage long sys_setuid16(old_uid_t uid)
69 {
70 	long ret = sys_setuid(low2highuid(uid));
71 	/* avoid REGPARM breakage on x86: */
72 	asmlinkage_protect(1, ret, uid);
73 	return ret;
74 }
75 
76 asmlinkage long sys_setresuid16(old_uid_t ruid, old_uid_t euid, old_uid_t suid)
77 {
78 	long ret = sys_setresuid(low2highuid(ruid), low2highuid(euid),
79 				 low2highuid(suid));
80 	/* avoid REGPARM breakage on x86: */
81 	asmlinkage_protect(3, ret, ruid, euid, suid);
82 	return ret;
83 }
84 
85 asmlinkage long sys_getresuid16(old_uid_t __user *ruid, old_uid_t __user *euid, old_uid_t __user *suid)
86 {
87 	int retval;
88 
89 	if (!(retval = put_user(high2lowuid(current->uid), ruid)) &&
90 	    !(retval = put_user(high2lowuid(current->euid), euid)))
91 		retval = put_user(high2lowuid(current->suid), suid);
92 
93 	return retval;
94 }
95 
96 asmlinkage long sys_setresgid16(old_gid_t rgid, old_gid_t egid, old_gid_t sgid)
97 {
98 	long ret = sys_setresgid(low2highgid(rgid), low2highgid(egid),
99 				 low2highgid(sgid));
100 	/* avoid REGPARM breakage on x86: */
101 	asmlinkage_protect(3, ret, rgid, egid, sgid);
102 	return ret;
103 }
104 
105 asmlinkage long sys_getresgid16(old_gid_t __user *rgid, old_gid_t __user *egid, old_gid_t __user *sgid)
106 {
107 	int retval;
108 
109 	if (!(retval = put_user(high2lowgid(current->gid), rgid)) &&
110 	    !(retval = put_user(high2lowgid(current->egid), egid)))
111 		retval = put_user(high2lowgid(current->sgid), sgid);
112 
113 	return retval;
114 }
115 
116 asmlinkage long sys_setfsuid16(old_uid_t uid)
117 {
118 	long ret = sys_setfsuid(low2highuid(uid));
119 	/* avoid REGPARM breakage on x86: */
120 	asmlinkage_protect(1, ret, uid);
121 	return ret;
122 }
123 
124 asmlinkage long sys_setfsgid16(old_gid_t gid)
125 {
126 	long ret = sys_setfsgid(low2highgid(gid));
127 	/* avoid REGPARM breakage on x86: */
128 	asmlinkage_protect(1, ret, gid);
129 	return ret;
130 }
131 
132 static int groups16_to_user(old_gid_t __user *grouplist,
133     struct group_info *group_info)
134 {
135 	int i;
136 	old_gid_t group;
137 
138 	for (i = 0; i < group_info->ngroups; i++) {
139 		group = high2lowgid(GROUP_AT(group_info, i));
140 		if (put_user(group, grouplist+i))
141 			return -EFAULT;
142 	}
143 
144 	return 0;
145 }
146 
147 static int groups16_from_user(struct group_info *group_info,
148     old_gid_t __user *grouplist)
149 {
150 	int i;
151 	old_gid_t group;
152 
153 	for (i = 0; i < group_info->ngroups; i++) {
154 		if (get_user(group, grouplist+i))
155 			return  -EFAULT;
156 		GROUP_AT(group_info, i) = low2highgid(group);
157 	}
158 
159 	return 0;
160 }
161 
162 asmlinkage long sys_getgroups16(int gidsetsize, old_gid_t __user *grouplist)
163 {
164 	int i = 0;
165 
166 	if (gidsetsize < 0)
167 		return -EINVAL;
168 
169 	get_group_info(current->group_info);
170 	i = current->group_info->ngroups;
171 	if (gidsetsize) {
172 		if (i > gidsetsize) {
173 			i = -EINVAL;
174 			goto out;
175 		}
176 		if (groups16_to_user(grouplist, current->group_info)) {
177 			i = -EFAULT;
178 			goto out;
179 		}
180 	}
181 out:
182 	put_group_info(current->group_info);
183 	return i;
184 }
185 
186 asmlinkage long sys_setgroups16(int gidsetsize, old_gid_t __user *grouplist)
187 {
188 	struct group_info *group_info;
189 	int retval;
190 
191 	if (!capable(CAP_SETGID))
192 		return -EPERM;
193 	if ((unsigned)gidsetsize > NGROUPS_MAX)
194 		return -EINVAL;
195 
196 	group_info = groups_alloc(gidsetsize);
197 	if (!group_info)
198 		return -ENOMEM;
199 	retval = groups16_from_user(group_info, grouplist);
200 	if (retval) {
201 		put_group_info(group_info);
202 		return retval;
203 	}
204 
205 	retval = set_current_groups(group_info);
206 	put_group_info(group_info);
207 
208 	return retval;
209 }
210 
211 asmlinkage long sys_getuid16(void)
212 {
213 	return high2lowuid(current->uid);
214 }
215 
216 asmlinkage long sys_geteuid16(void)
217 {
218 	return high2lowuid(current->euid);
219 }
220 
221 asmlinkage long sys_getgid16(void)
222 {
223 	return high2lowgid(current->gid);
224 }
225 
226 asmlinkage long sys_getegid16(void)
227 {
228 	return high2lowgid(current->egid);
229 }
230