]> granicus.if.org Git - strace/blob - tests/so_peercred.c
net: enhance decoding of getsockopt(SO_PEERCRED)
[strace] / tests / so_peercred.c
1 /*
2  * Check decoding of SO_PEERCRED socket option.
3  *
4  * Copyright (c) 2017 Dmitry V. Levin <ldv@altlinux.org>
5  * Copyright (c) 2017-2018 The strace developers.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. The name of the author may not be used to endorse or promote products
17  *    derived from this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 #include "tests.h"
32
33 #include <stddef.h>
34 #include <stdio.h>
35 #include <string.h>
36 #include <sys/socket.h>
37 #include <unistd.h>
38
39 #include "print_fields.h"
40
41 static const char *errstr;
42
43 static int
44 get_peercred(int fd, void *val, socklen_t *len)
45 {
46         int rc = getsockopt(fd, SOL_SOCKET, SO_PEERCRED, val, len);
47         errstr = sprintrc(rc);
48         return rc;
49 }
50
51 static const char *
52 so_str(void)
53 {
54         static char buf[256];
55
56         if (!buf[0]) {
57 #if XLAT_RAW
58                 snprintf(buf, sizeof(buf),
59                          "%#x, %#x", SOL_SOCKET, SO_PEERCRED);
60 #elif XLAT_VERBOSE
61                 snprintf(buf, sizeof(buf),
62                          "%#x /* SOL_SOCKET */, %#x /* SO_PEERCRED */",
63                          SOL_SOCKET, SO_PEERCRED);
64 #else
65                 snprintf(buf, sizeof(buf),
66                          "SOL_SOCKET, SO_PEERCRED");
67 #endif
68         }
69
70         return buf;
71 }
72
73 int
74 main(void)
75 {
76         TAIL_ALLOC_OBJECT_CONST_PTR(struct ucred, peercred);
77         TAIL_ALLOC_OBJECT_CONST_PTR(socklen_t, len);
78
79         const unsigned int sizeof_pid = sizeof(peercred->pid);
80         struct ucred *const pid = tail_alloc(sizeof_pid);
81
82         const unsigned int sizeof_pid_truncated = sizeof_pid - 1;
83         struct ucred *const pid_truncated =
84                 tail_alloc(sizeof_pid_truncated);
85
86         const unsigned int sizeof_uid = offsetofend(struct ucred, uid);
87         struct ucred *const uid = tail_alloc(sizeof_uid);
88
89         const unsigned int sizeof_uid_truncated = sizeof_uid - 1;
90         struct ucred *const uid_truncated =
91                 tail_alloc(sizeof_uid_truncated);
92
93         const unsigned int sizeof_gid_truncated =
94                 offsetofend(struct ucred, gid) - 1;
95         struct ucred *const gid_truncated =
96                 tail_alloc(sizeof_gid_truncated);
97
98         int sv[2];
99         if (socketpair(AF_UNIX, SOCK_STREAM, 0, sv))
100                 perror_msg_and_skip("socketpair AF_UNIX SOCK_STREAM");
101
102         /* classic getsockopt */
103         *len = sizeof(*peercred);
104         get_peercred(sv[0], peercred, len);
105         printf("getsockopt(%d, %s", sv[0], so_str());
106         PRINT_FIELD_D(", {", *peercred, pid);
107         PRINT_FIELD_UID(", ", *peercred, uid);
108         PRINT_FIELD_UID(", ", *peercred, gid);
109         printf("}, [%d]) = %s\n", *len, errstr);
110
111         /* getsockopt with zero optlen */
112         *len = 0;
113         get_peercred(sv[0], peercred, len);
114         printf("getsockopt(%d, %s, %p, [0]) = %s\n",
115                sv[0], so_str(), peercred, errstr);
116
117         /* getsockopt with optlen larger than necessary - shortened */
118         *len = sizeof(*peercred) + 1;
119         get_peercred(sv[0], peercred, len);
120         printf("getsockopt(%d, %s", sv[0], so_str());
121         PRINT_FIELD_D(", {", *peercred, pid);
122         PRINT_FIELD_UID(", ", *peercred, uid);
123         PRINT_FIELD_UID(", ", *peercred, gid);
124         printf("}, [%u->%d]) = %s\n",
125                (unsigned int) sizeof(*peercred) + 1, *len, errstr);
126
127         /*
128          * getsockopt with optlen less than offsetofend(struct ucred, pid):
129          * the part of struct ucred.pid is printed in hex.
130          */
131         *len = sizeof_pid_truncated;
132         get_peercred(sv[0], pid_truncated, len);
133         printf("getsockopt(%d, %s, {pid=", sv[0], so_str());
134         print_quoted_hex(pid_truncated, *len);
135         printf("}, [%d]) = %s\n", *len, errstr);
136
137         /*
138          * getsockopt with optlen equals to sizeof(struct ucred.pid):
139          * struct ucred.uid and struct ucred.gid are not printed.
140          */
141         *len = sizeof_pid;
142         get_peercred(sv[0], pid, len);
143         printf("getsockopt(%d, %s", sv[0], so_str());
144         PRINT_FIELD_D(", {", *pid, pid);
145         printf("}, [%d]) = %s\n", *len, errstr);
146
147         /*
148          * getsockopt with optlen greater than sizeof(struct ucred.pid)
149          * but smaller than offsetofend(struct ucred, uid):
150          * the part of struct ucred.uid is printed in hex.
151          */
152         *len = sizeof_uid_truncated;
153         get_peercred(sv[0], uid_truncated, len);
154         /*
155          * Copy to a properly aligned structure to avoid unaligned access
156          * to struct ucred.pid field.
157          */
158         memcpy(uid, uid_truncated, sizeof_uid_truncated);
159         printf("getsockopt(%d, %s", sv[0], so_str());
160         PRINT_FIELD_D(", {", *uid, pid);
161         printf(", uid=");
162         print_quoted_hex(&uid->uid, sizeof_uid_truncated -
163                                     offsetof(struct ucred, uid));
164         printf("}, [%d]) = %s\n", *len, errstr);
165
166         /*
167          * getsockopt with optlen equals to offsetofend(struct ucred, uid):
168          * struct ucred.gid is not printed.
169          */
170         *len = sizeof_uid;
171         get_peercred(sv[0], uid, len);
172         printf("getsockopt(%d, %s", sv[0], so_str());
173         PRINT_FIELD_D(", {", *uid, pid);
174         PRINT_FIELD_UID(", ", *uid, uid);
175         printf("}, [%d]) = %s\n", *len, errstr);
176
177         /*
178          * getsockopt with optlen greater than sizeof(struct ucred.uid)
179          * but smaller than offsetofend(struct ucred, gid):
180          * the part of struct ucred.gid is printed in hex.
181          */
182         *len = sizeof_gid_truncated;
183         get_peercred(sv[0], gid_truncated, len);
184         /*
185          * Copy to a properly aligned structure to avoid unaligned access
186          * to struct ucred.pid and struct ucred.uid fields.
187          */
188         memcpy(peercred, gid_truncated, sizeof_gid_truncated);
189         printf("getsockopt(%d, %s", sv[0], so_str());
190         PRINT_FIELD_D(", {", *peercred, pid);
191         PRINT_FIELD_UID(", ", *peercred, uid);
192         printf(", gid=");
193         print_quoted_hex(&peercred->gid, sizeof_gid_truncated -
194                                     offsetof(struct ucred, gid));
195         printf("}, [%d]) = %s\n", *len, errstr);
196
197         /* getsockopt optval EFAULT */
198         *len = sizeof(*peercred);
199         get_peercred(sv[0], &peercred->uid, len);
200         printf("getsockopt(%d, %s, %p, [%d]) = %s\n",
201                sv[0], so_str(), &peercred->uid, *len, errstr);
202
203         /* getsockopt optlen EFAULT */
204         get_peercred(sv[0], peercred, len + 1);
205         printf("getsockopt(%d, %s, %p, %p) = %s\n",
206                sv[0], so_str(), peercred, len + 1, errstr);
207
208         puts("+++ exited with 0 +++");
209         return 0;
210 }