1 /*
2 * IFLA_AF_SPEC netlink attribute decoding check.
3 *
4 * Copyright (c) 2018 The strace developers.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 #include "tests.h"
31
32 #include <inttypes.h>
33 #include <stdio.h>
34 #include <stddef.h>
35 #include "test_nlattr.h"
36
37 #include <linux/if.h>
38 #include <linux/if_arp.h>
39 #ifdef HAVE_LINUX_IF_LINK_H
40 # include <linux/if_link.h>
41 #endif
42 #include <linux/rtnetlink.h>
43
44 #if !HAVE_DECL_IFLA_AF_SPEC
45 enum { IFLA_AF_SPEC = 26 };
46 #endif
47
48 #define XLAT_MACROS_ONLY
49 # include "xlat/rtnl_ifla_af_spec_inet_attrs.h"
50 # include "xlat/rtnl_ifla_af_spec_inet6_attrs.h"
51 #undef XLAT_MACROS_ONLY
52
53 #ifndef HAVE_STRUCT_IFLA_CACHEINFO
54 struct ifla_cacheinfo {
55 uint32_t max_reasm_len;
56 uint32_t tstamp;
57 uint32_t reachable_time;
58 uint32_t retrans_time;
59 };
60 #endif
61
62 #define IFLA_ATTR IFLA_AF_SPEC
63 #include "nlattr_ifla.h"
64
65 #define AF_SPEC_FUNCS(family_) \
66 static void \
67 init_##family_##_msg(struct nlmsghdr *const nlh, \
68 const unsigned int msg_len) \
69 { \
70 init_ifinfomsg(nlh, msg_len); \
71 \
72 struct nlattr *nla = NLMSG_ATTR(nlh, hdrlen); \
73 nla += 1; \
74 SET_STRUCT(struct nlattr, nla, \
75 .nla_len = msg_len - NLMSG_SPACE(hdrlen) \
76 - NLA_HDRLEN, \
77 .nla_type = family_, \
78 ); \
79 } \
80 \
81 static void \
82 print_##family_##_msg(const unsigned int msg_len) \
83 { \
84 print_ifinfomsg(msg_len); \
85 printf(", {{nla_len=%u, nla_type=" #family_ "}", \
86 msg_len - NLMSG_SPACE(hdrlen) - NLA_HDRLEN); \
87 } \
88 /* end of AF_SPEC_FUNCS definition */
89
90 AF_SPEC_FUNCS(AF_INET)
AF_SPEC_FUNCS(AF_INET6)91 AF_SPEC_FUNCS(AF_INET6)
92
93 static void
94 print_arr_val(uint32_t *val, size_t idx, const char *idx_str)
95 {
96 if (idx_str)
97 printf("[%s] = ", idx_str);
98 else
99 printf("[%zu] = ", idx);
100
101 printf("%d", *val);
102 }
103
104 static void
print_arr_uval(uint64_t * val,size_t idx,const char * idx_str)105 print_arr_uval(uint64_t *val, size_t idx, const char *idx_str)
106 {
107 if (idx_str)
108 printf("[%s] = ", idx_str);
109 else
110 printf("[%zu] = ", idx);
111
112 printf("%" PRIu64, *val);
113 }
114
115 static void
print_inet_conf_val(uint32_t * val,size_t idx)116 print_inet_conf_val(uint32_t *val, size_t idx)
117 {
118 static const char * const strs[] = {
119 "IPV4_DEVCONF_FORWARDING-1",
120 "IPV4_DEVCONF_MC_FORWARDING-1",
121 };
122
123 print_arr_val(val, idx, idx < ARRAY_SIZE(strs) ? strs[idx] : NULL);
124 }
125
126
127 static void
print_inet6_conf_val(uint32_t * val,size_t idx)128 print_inet6_conf_val(uint32_t *val, size_t idx)
129 {
130 static const char * const strs[] = {
131 "DEVCONF_FORWARDING",
132 "DEVCONF_HOPLIMIT",
133 };
134
135 print_arr_val(val, idx, idx < ARRAY_SIZE(strs) ? strs[idx] : NULL);
136 }
137
138 static void
print_inet6_stats_val(uint64_t * val,size_t idx)139 print_inet6_stats_val(uint64_t *val, size_t idx)
140 {
141 static const char * const strs[] = {
142 "IPSTATS_MIB_NUM",
143 "IPSTATS_MIB_INPKTS",
144 };
145
146 print_arr_uval(val, idx, idx < ARRAY_SIZE(strs) ? strs[idx] : NULL);
147 }
148
149 static void
print_icmp6_stats_val(uint64_t * val,size_t idx)150 print_icmp6_stats_val(uint64_t *val, size_t idx)
151 {
152 static const char * const strs[] = {
153 "ICMP6_MIB_NUM",
154 "ICMP6_MIB_INMSGS",
155 "ICMP6_MIB_INERRORS",
156 "ICMP6_MIB_OUTMSGS",
157 "ICMP6_MIB_OUTERRORS",
158 "ICMP6_MIB_CSUMERRORS",
159 "6 /* ICMP6_MIB_??? */",
160 };
161
162 print_arr_uval(val, idx, idx < ARRAY_SIZE(strs) ? strs[idx] : NULL);
163 }
164
165 int
main(void)166 main(void)
167 {
168 static const uint8_t unknown_msg[] = { 0xab, 0xac, 0xdb, 0xcd };
169
170 skip_if_unavailable("/proc/self/fd/");
171
172 const int fd = create_nl_socket(NETLINK_ROUTE);
173
174 const unsigned int hdrlen = sizeof(struct ifinfomsg);
175 void *nlh0 = midtail_alloc(NLMSG_SPACE(hdrlen), 3 * NLA_HDRLEN + 256);
176
177 static char pattern[4096];
178 fill_memory_ex(pattern, sizeof(pattern), 'a', 'z' - 'a' + 1);
179
180
181 /* unknown AF_* */
182 TEST_NESTED_NLATTR_OBJECT(fd, nlh0, hdrlen,
183 init_ifinfomsg, print_ifinfomsg,
184 AF_UNIX, pattern, unknown_msg,
185 printf("\"\\xab\\xac\\xdb\\xcd\""));
186
187 /* AF_INET */
188 TEST_NESTED_NLATTR_OBJECT_EX_(fd, nlh0, hdrlen,
189 init_AF_INET_msg, print_AF_INET_msg,
190 0, "IFLA_INET_UNSPEC", pattern,
191 unknown_msg, print_quoted_hex, 2,
192 printf("\"\\xab\\xac\\xdb\\xcd\""));
193 TEST_NESTED_NLATTR_OBJECT_EX_(fd, nlh0, hdrlen,
194 init_AF_INET_msg, print_AF_INET_msg,
195 2, "0x2 /* IFLA_INET_??? */", pattern,
196 unknown_msg, print_quoted_hex, 2,
197 printf("\"\\xab\\xac\\xdb\\xcd\""));
198
199 /* AF_INET: IFLA_INET_CONF */
200 uint32_t inet_conf_vals[] = { 0xdeadc0de, 0xda7aface };
201 TEST_NESTED_NLATTR_ARRAY_EX(fd, nlh0, hdrlen,
202 init_AF_INET_msg, print_AF_INET_msg,
203 IFLA_INET_CONF, pattern,
204 inet_conf_vals, 2, print_inet_conf_val);
205
206 /* AF_INET6 */
207 TEST_NESTED_NLATTR_OBJECT_EX_(fd, nlh0, hdrlen,
208 init_AF_INET6_msg, print_AF_INET6_msg,
209 0, "IFLA_INET6_UNSPEC", pattern,
210 unknown_msg, print_quoted_hex, 2,
211 printf("\"\\xab\\xac\\xdb\\xcd\""));
212 TEST_NESTED_NLATTR_OBJECT_EX_(fd, nlh0, hdrlen,
213 init_AF_INET6_msg, print_AF_INET6_msg,
214 9, "0x9 /* IFLA_INET6_??? */", pattern,
215 unknown_msg, print_quoted_hex, 2,
216 printf("\"\\xab\\xac\\xdb\\xcd\""));
217
218 /* AF_INET6: IFLA_INET6_FLAGS */
219 static const struct {
220 uint32_t flags;
221 const char *str;
222 } inet6_flags[] = {
223 { 0xf, "0xf /* IF_??? */" },
224 { 0x10, "IF_RS_SENT" },
225 { 0xc0, "IF_RA_MANAGED|IF_RA_OTHERCONF" },
226 { 0xdeadc0de, "IF_RS_SENT|IF_RA_MANAGED|IF_RA_OTHERCONF"
227 "|IF_READY|0x5eadc00e" },
228 };
229
230 for (size_t i = 0; i < ARRAY_SIZE(inet6_flags); i++) {
231 TEST_NESTED_NLATTR_OBJECT_EX_(fd, nlh0, hdrlen,
232 init_AF_INET6_msg,
233 print_AF_INET6_msg,
234 1, "IFLA_INET6_FLAGS", pattern,
235 inet6_flags[i].flags,
236 print_quoted_hex, 2,
237 printf("%s", inet6_flags[i].str));
238 }
239
240 /* AF_INET6: IFLA_INET6_CONF */
241 uint32_t inet6_conf_vals[] = { 0xdeadc0de, 0xda7aface };
242 TEST_NESTED_NLATTR_ARRAY_EX(fd, nlh0, hdrlen,
243 init_AF_INET6_msg, print_AF_INET6_msg,
244 IFLA_INET6_CONF, pattern,
245 inet6_conf_vals, 2, print_inet6_conf_val);
246
247 /* AF_INET6: IFLA_INET6_STATS */
248 uint64_t inet6_stats_vals[] = { 0xdeadc0deda7aface, 0xdec0deedbadc0ded };
249 TEST_NESTED_NLATTR_ARRAY_EX(fd, nlh0, hdrlen,
250 init_AF_INET6_msg, print_AF_INET6_msg,
251 IFLA_INET6_STATS, pattern,
252 inet6_stats_vals, 2, print_inet6_stats_val);
253
254 /* AF_INET6: IFLA_INET6_MCAST */
255 TEST_NESTED_NLATTR_OBJECT_EX_(fd, nlh0, hdrlen,
256 init_AF_INET6_msg, print_AF_INET6_msg,
257 4, "IFLA_INET6_MCAST", pattern,
258 unknown_msg, print_quoted_hex, 2,
259 printf("\"\\xab\\xac\\xdb\\xcd\""));
260
261 /* AF_INET6: IFLA_INET6_CACHEINFO */
262 static const struct ifla_cacheinfo ci = {
263 0xbadc0ded, 0xfacebeef, 0xdecafeed, 0xdeadfeed,
264 };
265 TEST_NESTED_NLATTR_OBJECT_EX_(fd, nlh0, hdrlen,
266 init_AF_INET6_msg, print_AF_INET6_msg,
267 5, "IFLA_INET6_CACHEINFO", pattern,
268 ci, print_quoted_hex, 2,
269 PRINT_FIELD_U("{", ci, max_reasm_len);
270 PRINT_FIELD_U(", ", ci, tstamp);
271 PRINT_FIELD_U(", ", ci, reachable_time);
272 PRINT_FIELD_U(", ", ci, retrans_time);
273 printf("}"));
274
275 /* AF_INET6: IFLA_INET6_ICMP6STATS */
276 uint64_t icmp6_stats_vals[] = {
277 0xdeadc0deda7aface, 0xdec0deedbadc0ded, 0xfacebeefdeadfeed,
278 0xdeadc0deda7afacd, 0xdec0deedbadc0dee, 0xfacebeefdeadfeef,
279 0xdeadc0deda7afacc
280 };
281 TEST_NESTED_NLATTR_ARRAY_EX(fd, nlh0, hdrlen,
282 init_AF_INET6_msg, print_AF_INET6_msg,
283 IFLA_INET6_ICMP6STATS, pattern,
284 icmp6_stats_vals, 2, print_icmp6_stats_val);
285
286 /* AF_INET6: IFLA_INET6_TOKEN */
287 uint8_t inet6_addr[16] = {
288 0xba, 0xdc, 0x0d, 0xed, 0xfa, 0xce, 0xbe, 0xef,
289 0xde, 0xca, 0xfe, 0xed, 0xde, 0xad, 0xfe, 0xed,
290 };
291 TEST_NESTED_NLATTR_OBJECT_EX_(fd, nlh0, hdrlen,
292 init_AF_INET6_msg, print_AF_INET6_msg,
293 7, "IFLA_INET6_TOKEN", pattern,
294 inet6_addr, print_quoted_hex, 2,
295 printf("badc:ded:face:beef:deca:feed"
296 ":dead:feed"));
297
298 /* AF_INET6: IFLA_INET6_ */
299 static const struct {
300 uint8_t flags;
301 const char *str;
302 } agms[] = {
303 { 0x0, "IN6_ADDR_GEN_MODE_EUI64" },
304 { 0x3, "IN6_ADDR_GEN_MODE_RANDOM" },
305 { 0x4, "0x4 /* IN6_ADDR_GEN_MODE_??? */" },
306 { 0xff, "0xff /* IN6_ADDR_GEN_MODE_??? */" },
307 };
308
309 for (size_t i = 0; i < ARRAY_SIZE(agms); i++) {
310 TEST_NESTED_NLATTR_OBJECT_EX_(fd, nlh0, hdrlen,
311 init_AF_INET6_msg,
312 print_AF_INET6_msg,
313 8, "IFLA_INET6_ADDR_GEN_MODE",
314 pattern, agms[i].flags,
315 print_quoted_hex, 2,
316 printf("%s", agms[i].str));
317 }
318
319
320 puts("+++ exited with 0 +++");
321 return 0;
322 }
323