1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) 2018 Michael Moese <[email protected]>
4 */
5 /* The commit 0fb44559ffd6 af_unix: move unix_mknod() out of bindlock
6 * changed the behavior of bind() for STREAM UNIX domain sockets if
7 */
8
9 #include <errno.h>
10 #include <limits.h>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14
15 #include "tst_kvercmp.h"
16 #include "tst_test.h"
17 #include "tst_safe_net.h"
18
19 #define SNAME_A "socket.1"
20 #define SNAME_B "socket.2"
21
22 static int sock1, sock2;
23 static struct sockaddr_un sun1, sun2;
24
run(void)25 static void run(void)
26 {
27 /*
28 * Once a STREAM UNIX domain socket has been bound, it can't be
29 * rebound.
30 */
31 TST_EXP_FAIL(bind(sock1, (struct sockaddr *)&sun2, sizeof(sun2)),
32 EINVAL, "re-bind() socket");
33
34 /*
35 * Since a socket is already bound to the pathname, it can't be bound
36 * to a second socket. Expected error is EADDRINUSE.
37 */
38 TST_EXP_FAIL(bind(sock2, (struct sockaddr *)&sun1, sizeof(sun1)),
39 EADDRINUSE, "bind() with bound pathname");
40
41 /*
42 * Kernel is buggy since it creates the node in fileystem first, then
43 * locks the socket and does all the checks and the node is not removed
44 * in the error path. For now we will unlink the node here so that the
45 * test works fine when the run() function is executed in a loop.
46 * From v5.14-rc1 the kernel has fix above issue.
47 */
48 if (tst_kvercmp(5, 14, 0) >= 0)
49 TST_EXP_FAIL(unlink(SNAME_B), ENOENT, "check exist of SNAME_B");
50 else
51 unlink(SNAME_B);
52 }
53
setup(void)54 static void setup(void)
55 {
56 sock1 = SAFE_SOCKET(PF_UNIX, SOCK_STREAM, 0);
57 sock2 = SAFE_SOCKET(PF_UNIX, SOCK_STREAM, 0);
58
59 sun1.sun_family = AF_UNIX;
60 sun2.sun_family = AF_UNIX;
61
62 if (sprintf(sun1.sun_path, "%s", SNAME_A) < (int) strlen(SNAME_A)) {
63 tst_res(TFAIL, "sprintf failed");
64 return;
65 }
66
67 if (sprintf(sun2.sun_path, "%s", SNAME_B) < (int) strlen(SNAME_B)) {
68 tst_res(TFAIL, "sprintf failed");
69 return;
70 }
71
72 SAFE_BIND(sock1, (struct sockaddr *)&sun1, sizeof(sun1));
73 }
74
cleanup(void)75 static void cleanup(void)
76 {
77 SAFE_CLOSE(sock1);
78 SAFE_CLOSE(sock2);
79 }
80
81 static struct tst_test test = {
82 .setup = setup,
83 .cleanup = cleanup,
84 .test_all = run,
85 .needs_tmpdir = 1,
86 };
87