1*f012ee0cSGordon Ross /*
2*f012ee0cSGordon Ross * Copyright 2016 Jeremy Allison
3*f012ee0cSGordon Ross *
4*f012ee0cSGordon Ross * Permission is hereby granted, free of charge, to any person obtaining a
5*f012ee0cSGordon Ross * copy of this software and associated documentation files (the "Software"),
6*f012ee0cSGordon Ross * to deal in the Software without restriction, including without limitation
7*f012ee0cSGordon Ross * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8*f012ee0cSGordon Ross * and/or sell copies of the Software, and to permit persons to whom the
9*f012ee0cSGordon Ross * Software is furnished to do so, subject to the following conditions:
10*f012ee0cSGordon Ross *
11*f012ee0cSGordon Ross * The above copyright notice and this permission notice shall be included
12*f012ee0cSGordon Ross * in all copies or substantial portions of the Software.
13*f012ee0cSGordon Ross *
14*f012ee0cSGordon Ross * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15*f012ee0cSGordon Ross * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16*f012ee0cSGordon Ross * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17*f012ee0cSGordon Ross * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18*f012ee0cSGordon Ross * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19*f012ee0cSGordon Ross * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20*f012ee0cSGordon Ross * DEALINGS IN THE SOFTWARE.
21*f012ee0cSGordon Ross */
22*f012ee0cSGordon Ross
23*f012ee0cSGordon Ross /*
24*f012ee0cSGordon Ross * This is a regression test for a (former) problem in illumos
25*f012ee0cSGordon Ross * where a program that tries to send on a "connected" AF_UNIX
26*f012ee0cSGordon Ross * _datagram_ socket fails if: (a) the file system path used for
27*f012ee0cSGordon Ross * the socket requires privileges to access, and (b) a process
28*f012ee0cSGordon Ross * with privileges to access that path does a connect() to that
29*f012ee0cSGordon Ross * address and then drops privileges. In that case, a sendmsg()
30*f012ee0cSGordon Ross * call where the "to" address is left blank should succeed.
31*f012ee0cSGordon Ross * Before the fix for illumos 7590 that would fail.
32*f012ee0cSGordon Ross *
33*f012ee0cSGordon Ross * This program must be run as root. The expected output is:
34*f012ee0cSGordon Ross *
35*f012ee0cSGordon Ross * non_priv_send - sendmsg fail (expected) Permission denied
36*f012ee0cSGordon Ross * CLIENT:TEST0
37*f012ee0cSGordon Ross * SERVER:TEST0
38*f012ee0cSGordon Ross * CLIENT:TEST1
39*f012ee0cSGordon Ross * SERVER:TEST1
40*f012ee0cSGordon Ross * CLIENT:TEST2
41*f012ee0cSGordon Ross * SERVER:TEST2
42*f012ee0cSGordon Ross * CLIENT:TEST3
43*f012ee0cSGordon Ross * SERVER:TEST3
44*f012ee0cSGordon Ross * CLIENT:TEST4
45*f012ee0cSGordon Ross * SERVER:TEST4
46*f012ee0cSGordon Ross *
47*f012ee0cSGordon Ross * Without the fix for 7590, one would see:
48*f012ee0cSGordon Ross * non_priv_send - sendmsg fail (expected) Permission denied
49*f012ee0cSGordon Ross * CLIENT:TEST0
50*f012ee0cSGordon Ross * ./sendtest - sendmsg fail Permission denied
51*f012ee0cSGordon Ross */
52*f012ee0cSGordon Ross
53*f012ee0cSGordon Ross #include <sys/param.h>
54*f012ee0cSGordon Ross #include <sys/types.h>
55*f012ee0cSGordon Ross #include <sys/stat.h>
56*f012ee0cSGordon Ross #include <sys/socket.h>
57*f012ee0cSGordon Ross #include <sys/un.h>
58*f012ee0cSGordon Ross #include <stdio.h>
59*f012ee0cSGordon Ross #include <unistd.h>
60*f012ee0cSGordon Ross #include <string.h>
61*f012ee0cSGordon Ross #include <errno.h>
62*f012ee0cSGordon Ross #include <stdint.h>
63*f012ee0cSGordon Ross #include <stdlib.h>
64*f012ee0cSGordon Ross
65*f012ee0cSGordon Ross static int
server(struct sockaddr_un * addr)66*f012ee0cSGordon Ross server(struct sockaddr_un *addr)
67*f012ee0cSGordon Ross {
68*f012ee0cSGordon Ross int ret;
69*f012ee0cSGordon Ross pid_t pid;
70*f012ee0cSGordon Ross int sock;
71*f012ee0cSGordon Ross unsigned int i;
72*f012ee0cSGordon Ross
73*f012ee0cSGordon Ross pid = fork();
74*f012ee0cSGordon Ross if (pid == (pid_t)-1) {
75*f012ee0cSGordon Ross fprintf(stderr, "server - fork fail %s\n", strerror(errno));
76*f012ee0cSGordon Ross return (-1);
77*f012ee0cSGordon Ross }
78*f012ee0cSGordon Ross
79*f012ee0cSGordon Ross if (pid != 0) {
80*f012ee0cSGordon Ross /* Parent. */
81*f012ee0cSGordon Ross return (0);
82*f012ee0cSGordon Ross }
83*f012ee0cSGordon Ross
84*f012ee0cSGordon Ross /* Child. */
85*f012ee0cSGordon Ross sock = socket(AF_UNIX, SOCK_DGRAM, 0);
86*f012ee0cSGordon Ross if (sock == -1) {
87*f012ee0cSGordon Ross fprintf(stderr, "server - socket fail %s\n", strerror(errno));
88*f012ee0cSGordon Ross exit(1);
89*f012ee0cSGordon Ross }
90*f012ee0cSGordon Ross
91*f012ee0cSGordon Ross ret = bind(sock, (struct sockaddr *)addr, sizeof (*addr));
92*f012ee0cSGordon Ross
93*f012ee0cSGordon Ross if (ret == -1) {
94*f012ee0cSGordon Ross fprintf(stderr, "server - bind fail %s\n", strerror(errno));
95*f012ee0cSGordon Ross exit(1);
96*f012ee0cSGordon Ross }
97*f012ee0cSGordon Ross
98*f012ee0cSGordon Ross for (i = 0; i < 5; i++) {
99*f012ee0cSGordon Ross struct iovec iov;
100*f012ee0cSGordon Ross struct msghdr msg;
101*f012ee0cSGordon Ross uint8_t buf[4096];
102*f012ee0cSGordon Ross
103*f012ee0cSGordon Ross iov = (struct iovec) {
104*f012ee0cSGordon Ross .iov_base = buf,
105*f012ee0cSGordon Ross .iov_len = sizeof (buf)
106*f012ee0cSGordon Ross };
107*f012ee0cSGordon Ross
108*f012ee0cSGordon Ross msg = (struct msghdr) {
109*f012ee0cSGordon Ross .msg_iov = &iov,
110*f012ee0cSGordon Ross .msg_iovlen = 1,
111*f012ee0cSGordon Ross };
112*f012ee0cSGordon Ross
113*f012ee0cSGordon Ross ret = recvmsg(sock, &msg, 0);
114*f012ee0cSGordon Ross if (ret == -1) {
115*f012ee0cSGordon Ross fprintf(stderr, "server - recvmsg fail %s\n",
116*f012ee0cSGordon Ross strerror(errno));
117*f012ee0cSGordon Ross exit(1);
118*f012ee0cSGordon Ross }
119*f012ee0cSGordon Ross
120*f012ee0cSGordon Ross printf("SERVER:%s\n", (char *)msg.msg_iov->iov_base);
121*f012ee0cSGordon Ross fflush(stdout);
122*f012ee0cSGordon Ross }
123*f012ee0cSGordon Ross
124*f012ee0cSGordon Ross exit(0);
125*f012ee0cSGordon Ross }
126*f012ee0cSGordon Ross
127*f012ee0cSGordon Ross static void
non_priv_send(struct sockaddr_un * addr,int uid)128*f012ee0cSGordon Ross non_priv_send(struct sockaddr_un *addr, int uid)
129*f012ee0cSGordon Ross {
130*f012ee0cSGordon Ross pid_t pid;
131*f012ee0cSGordon Ross int sock;
132*f012ee0cSGordon Ross int ret;
133*f012ee0cSGordon Ross struct iovec iov;
134*f012ee0cSGordon Ross struct msghdr msg;
135*f012ee0cSGordon Ross uint8_t buf[4096];
136*f012ee0cSGordon Ross
137*f012ee0cSGordon Ross pid = fork();
138*f012ee0cSGordon Ross if (pid == (pid_t)-1) {
139*f012ee0cSGordon Ross fprintf(stderr, "non_priv_send - fork fail %s\n",
140*f012ee0cSGordon Ross strerror(errno));
141*f012ee0cSGordon Ross return;
142*f012ee0cSGordon Ross }
143*f012ee0cSGordon Ross
144*f012ee0cSGordon Ross if (pid != 0) {
145*f012ee0cSGordon Ross /* Parent. */
146*f012ee0cSGordon Ross return;
147*f012ee0cSGordon Ross }
148*f012ee0cSGordon Ross
149*f012ee0cSGordon Ross /* Child. */
150*f012ee0cSGordon Ross memcpy(buf, "TEST1\n", sizeof ("TEST1\n"));
151*f012ee0cSGordon Ross
152*f012ee0cSGordon Ross iov = (struct iovec) {
153*f012ee0cSGordon Ross .iov_base = buf,
154*f012ee0cSGordon Ross .iov_len = sizeof (buf),
155*f012ee0cSGordon Ross };
156*f012ee0cSGordon Ross
157*f012ee0cSGordon Ross msg = (struct msghdr) {
158*f012ee0cSGordon Ross .msg_name = addr,
159*f012ee0cSGordon Ross .msg_namelen = sizeof (*addr),
160*f012ee0cSGordon Ross .msg_iov = &iov,
161*f012ee0cSGordon Ross .msg_iovlen = 1,
162*f012ee0cSGordon Ross };
163*f012ee0cSGordon Ross
164*f012ee0cSGordon Ross sock = socket(AF_UNIX, SOCK_DGRAM, 0);
165*f012ee0cSGordon Ross if (sock == -1) {
166*f012ee0cSGordon Ross fprintf(stderr, "non_priv_send - socket fail %s\n",
167*f012ee0cSGordon Ross strerror(errno));
168*f012ee0cSGordon Ross exit(1);
169*f012ee0cSGordon Ross }
170*f012ee0cSGordon Ross
171*f012ee0cSGordon Ross ret = setreuid(uid, uid);
172*f012ee0cSGordon Ross if (ret == -1) {
173*f012ee0cSGordon Ross fprintf(stderr, "non_priv_send - setresuid fail %s\n",
174*f012ee0cSGordon Ross strerror(errno));
175*f012ee0cSGordon Ross exit(1);
176*f012ee0cSGordon Ross }
177*f012ee0cSGordon Ross
178*f012ee0cSGordon Ross ret = sendmsg(sock, &msg, 0);
179*f012ee0cSGordon Ross
180*f012ee0cSGordon Ross if (ret == -1) {
181*f012ee0cSGordon Ross printf("non_priv_send - sendmsg fail (expected) %s\n",
182*f012ee0cSGordon Ross strerror(errno));
183*f012ee0cSGordon Ross exit(0);
184*f012ee0cSGordon Ross }
185*f012ee0cSGordon Ross
186*f012ee0cSGordon Ross fprintf(stderr, "non_priv_send - UNEXPECTED sendmsg OK\n");
187*f012ee0cSGordon Ross exit(1);
188*f012ee0cSGordon Ross }
189*f012ee0cSGordon Ross
190*f012ee0cSGordon Ross /*
191*f012ee0cSGordon Ross * This should be a place only root is allowed to write.
192*f012ee0cSGordon Ross * The test will create and destroy this directory.
193*f012ee0cSGordon Ross */
194*f012ee0cSGordon Ross char testdir[100] = "/var/run/os-tests-sockfs";
195*f012ee0cSGordon Ross struct sockaddr_un addr;
196*f012ee0cSGordon Ross int test_uid = UID_NOBODY;
197*f012ee0cSGordon Ross
198*f012ee0cSGordon Ross int
main(int argc,char ** argv)199*f012ee0cSGordon Ross main(int argc, char **argv)
200*f012ee0cSGordon Ross {
201*f012ee0cSGordon Ross int ret;
202*f012ee0cSGordon Ross int sock;
203*f012ee0cSGordon Ross unsigned int i;
204*f012ee0cSGordon Ross uid_t us = geteuid();
205*f012ee0cSGordon Ross
206*f012ee0cSGordon Ross /* Ensure we're root. */
207*f012ee0cSGordon Ross if (us != 0) {
208*f012ee0cSGordon Ross fprintf(stderr, "%s: need to be root\n", argv[0]);
209*f012ee0cSGordon Ross exit(1);
210*f012ee0cSGordon Ross }
211*f012ee0cSGordon Ross
212*f012ee0cSGordon Ross if (argc > 1) {
213*f012ee0cSGordon Ross ret = strlcpy(testdir, argv[1], sizeof (testdir));
214*f012ee0cSGordon Ross if (ret >= sizeof (testdir)) {
215*f012ee0cSGordon Ross fprintf(stderr, "%s: too long\n", argv[1]);
216*f012ee0cSGordon Ross exit(1);
217*f012ee0cSGordon Ross }
218*f012ee0cSGordon Ross }
219*f012ee0cSGordon Ross
220*f012ee0cSGordon Ross addr.sun_family = AF_UNIX;
221*f012ee0cSGordon Ross (void) sprintf(addr.sun_path, "%s/s", testdir);
222*f012ee0cSGordon Ross
223*f012ee0cSGordon Ross if (mkdir(testdir, 0700) != 0) {
224*f012ee0cSGordon Ross switch (errno) {
225*f012ee0cSGordon Ross case EEXIST:
226*f012ee0cSGordon Ross case EISDIR:
227*f012ee0cSGordon Ross break;
228*f012ee0cSGordon Ross default:
229*f012ee0cSGordon Ross perror(testdir);
230*f012ee0cSGordon Ross exit(1);
231*f012ee0cSGordon Ross }
232*f012ee0cSGordon Ross }
233*f012ee0cSGordon Ross (void) unlink(addr.sun_path);
234*f012ee0cSGordon Ross
235*f012ee0cSGordon Ross /* Set up the server. */
236*f012ee0cSGordon Ross ret = server(&addr);
237*f012ee0cSGordon Ross if (ret == -1) {
238*f012ee0cSGordon Ross fprintf(stderr, "%s - server fork fail %s\n",
239*f012ee0cSGordon Ross argv[0], strerror(errno));
240*f012ee0cSGordon Ross exit(1);
241*f012ee0cSGordon Ross }
242*f012ee0cSGordon Ross
243*f012ee0cSGordon Ross sleep(1);
244*f012ee0cSGordon Ross
245*f012ee0cSGordon Ross /* Chec non-priv client - should fail. */
246*f012ee0cSGordon Ross non_priv_send(&addr, test_uid);
247*f012ee0cSGordon Ross
248*f012ee0cSGordon Ross sleep(1);
249*f012ee0cSGordon Ross
250*f012ee0cSGordon Ross /* Create and connect the socket endpoint. */
251*f012ee0cSGordon Ross
252*f012ee0cSGordon Ross sock = socket(AF_UNIX, SOCK_DGRAM, 0);
253*f012ee0cSGordon Ross if (sock == -1) {
254*f012ee0cSGordon Ross fprintf(stderr, "%s - socket fail %s\n",
255*f012ee0cSGordon Ross argv[0], strerror(errno));
256*f012ee0cSGordon Ross exit(1);
257*f012ee0cSGordon Ross }
258*f012ee0cSGordon Ross
259*f012ee0cSGordon Ross ret = connect(sock, (struct sockaddr *)&addr, sizeof (addr));
260*f012ee0cSGordon Ross if (ret == -1) {
261*f012ee0cSGordon Ross fprintf(stderr, "%s - connect fail %s\n",
262*f012ee0cSGordon Ross argv[0], strerror(errno));
263*f012ee0cSGordon Ross exit(1);
264*f012ee0cSGordon Ross }
265*f012ee0cSGordon Ross
266*f012ee0cSGordon Ross /*
267*f012ee0cSGordon Ross * Now lose all privilages.
268*f012ee0cSGordon Ross * The sendmsg() should still succeed as
269*f012ee0cSGordon Ross * 'sock' has been connected to the endpoint,
270*f012ee0cSGordon Ross * even though we don't have permissions as
271*f012ee0cSGordon Ross * the non privileged user to access the
272*f012ee0cSGordon Ross * UNIX domain socket.
273*f012ee0cSGordon Ross */
274*f012ee0cSGordon Ross
275*f012ee0cSGordon Ross ret = setreuid(test_uid, test_uid);
276*f012ee0cSGordon Ross if (ret == -1) {
277*f012ee0cSGordon Ross printf("%s - setresuid fail %s\n",
278*f012ee0cSGordon Ross argv[0], strerror(errno));
279*f012ee0cSGordon Ross exit(1);
280*f012ee0cSGordon Ross }
281*f012ee0cSGordon Ross
282*f012ee0cSGordon Ross for (i = 0; i < 5; i++) {
283*f012ee0cSGordon Ross struct iovec iov;
284*f012ee0cSGordon Ross struct msghdr msg;
285*f012ee0cSGordon Ross uint8_t buf[4096];
286*f012ee0cSGordon Ross
287*f012ee0cSGordon Ross memcpy(buf, "TEST0", sizeof ("TEST0"));
288*f012ee0cSGordon Ross buf[4] = '0' + i;
289*f012ee0cSGordon Ross
290*f012ee0cSGordon Ross printf("CLIENT:%s\n", buf);
291*f012ee0cSGordon Ross
292*f012ee0cSGordon Ross iov = (struct iovec) {
293*f012ee0cSGordon Ross .iov_base = buf,
294*f012ee0cSGordon Ross .iov_len = sizeof (buf),
295*f012ee0cSGordon Ross };
296*f012ee0cSGordon Ross
297*f012ee0cSGordon Ross msg = (struct msghdr) {
298*f012ee0cSGordon Ross /*
299*f012ee0cSGordon Ross * If not for the dropped privileges that are
300*f012ee0cSGordon Ross * the essential feature of this test, a more
301*f012ee0cSGordon Ross * common practice would be to fill in the
302*f012ee0cSGordon Ross * .msg_name, .msg_namelen fields here.
303*f012ee0cSGordon Ross * However, when we've dropped privileges,
304*f012ee0cSGordon Ross * and when we do specify the "to" address,
305*f012ee0cSGordon Ross * the kernel does permission checks and the
306*f012ee0cSGordon Ross * sendmsg fails with permission denied.
307*f012ee0cSGordon Ross * So long as we do _not_ fill in the "to"
308*f012ee0cSGordon Ross * address, send on a connected dgram socket
309*f012ee0cSGordon Ross * is supposed to work. Before the fix for
310*f012ee0cSGordon Ross * illumos 7590, that would fail.
311*f012ee0cSGordon Ross */
312*f012ee0cSGordon Ross .msg_iov = &iov,
313*f012ee0cSGordon Ross .msg_iovlen = 1,
314*f012ee0cSGordon Ross };
315*f012ee0cSGordon Ross
316*f012ee0cSGordon Ross ret = sendmsg(sock, &msg, 0);
317*f012ee0cSGordon Ross
318*f012ee0cSGordon Ross if (ret == -1) {
319*f012ee0cSGordon Ross fprintf(stderr, "%s - sendmsg fail %s\n",
320*f012ee0cSGordon Ross argv[0], strerror(errno));
321*f012ee0cSGordon Ross exit(1);
322*f012ee0cSGordon Ross }
323*f012ee0cSGordon Ross
324*f012ee0cSGordon Ross fflush(stdout);
325*f012ee0cSGordon Ross sleep(1);
326*f012ee0cSGordon Ross }
327*f012ee0cSGordon Ross
328*f012ee0cSGordon Ross close(sock);
329*f012ee0cSGordon Ross return (0);
330*f012ee0cSGordon Ross }
331