1// SPDX-License-Identifier: GPL-2.0
2// Copyright (c) 2018 Facebook
3
4#define _GNU_SOURCE
5
6#include <stdio.h>
7#include <stdlib.h>
8#include <unistd.h>
9
10#include <arpa/inet.h>
11#include <netinet/in.h>
12#include <sys/types.h>
13#include <sys/select.h>
14#include <sys/socket.h>
15
16#include <linux/filter.h>
17
18#include <bpf/bpf.h>
19#include <bpf/libbpf.h>
20
21#include "cgroup_helpers.h"
22#include "bpf_util.h"
23
24#ifndef ENOTSUPP
25# define ENOTSUPP 524
26#endif
27
28#define CG_PATH	"/foo"
29#define CONNECT4_PROG_PATH	"./connect4_prog.bpf.o"
30#define CONNECT6_PROG_PATH	"./connect6_prog.bpf.o"
31#define SENDMSG4_PROG_PATH	"./sendmsg4_prog.bpf.o"
32#define SENDMSG6_PROG_PATH	"./sendmsg6_prog.bpf.o"
33#define RECVMSG4_PROG_PATH	"./recvmsg4_prog.bpf.o"
34#define RECVMSG6_PROG_PATH	"./recvmsg6_prog.bpf.o"
35#define BIND4_PROG_PATH		"./bind4_prog.bpf.o"
36#define BIND6_PROG_PATH		"./bind6_prog.bpf.o"
37
38#define SERV4_IP		"192.168.1.254"
39#define SERV4_REWRITE_IP	"127.0.0.1"
40#define SRC4_IP			"172.16.0.1"
41#define SRC4_REWRITE_IP		"127.0.0.4"
42#define SERV4_PORT		4040
43#define SERV4_REWRITE_PORT	4444
44
45#define SERV6_IP		"face:b00c:1234:5678::abcd"
46#define SERV6_REWRITE_IP	"::1"
47#define SERV6_V4MAPPED_IP	"::ffff:192.168.0.4"
48#define SRC6_IP			"::1"
49#define SRC6_REWRITE_IP		"::6"
50#define WILDCARD6_IP		"::"
51#define SERV6_PORT		6060
52#define SERV6_REWRITE_PORT	6666
53
54#define INET_NTOP_BUF	40
55
56struct sock_addr_test;
57
58typedef int (*load_fn)(const struct sock_addr_test *test);
59typedef int (*info_fn)(int, struct sockaddr *, socklen_t *);
60
61char bpf_log_buf[BPF_LOG_BUF_SIZE];
62
63struct sock_addr_test {
64	const char *descr;
65	/* BPF prog properties */
66	load_fn loadfn;
67	enum bpf_attach_type expected_attach_type;
68	enum bpf_attach_type attach_type;
69	/* Socket properties */
70	int domain;
71	int type;
72	/* IP:port pairs for BPF prog to override */
73	const char *requested_ip;
74	unsigned short requested_port;
75	const char *expected_ip;
76	unsigned short expected_port;
77	const char *expected_src_ip;
78	/* Expected test result */
79	enum {
80		LOAD_REJECT,
81		ATTACH_REJECT,
82		ATTACH_OKAY,
83		SYSCALL_EPERM,
84		SYSCALL_ENOTSUPP,
85		SUCCESS,
86	} expected_result;
87};
88
89static int bind4_prog_load(const struct sock_addr_test *test);
90static int bind6_prog_load(const struct sock_addr_test *test);
91static int connect4_prog_load(const struct sock_addr_test *test);
92static int connect6_prog_load(const struct sock_addr_test *test);
93static int sendmsg_allow_prog_load(const struct sock_addr_test *test);
94static int sendmsg_deny_prog_load(const struct sock_addr_test *test);
95static int recvmsg_allow_prog_load(const struct sock_addr_test *test);
96static int recvmsg_deny_prog_load(const struct sock_addr_test *test);
97static int sendmsg4_rw_asm_prog_load(const struct sock_addr_test *test);
98static int recvmsg4_rw_c_prog_load(const struct sock_addr_test *test);
99static int sendmsg4_rw_c_prog_load(const struct sock_addr_test *test);
100static int sendmsg6_rw_asm_prog_load(const struct sock_addr_test *test);
101static int recvmsg6_rw_c_prog_load(const struct sock_addr_test *test);
102static int sendmsg6_rw_c_prog_load(const struct sock_addr_test *test);
103static int sendmsg6_rw_v4mapped_prog_load(const struct sock_addr_test *test);
104static int sendmsg6_rw_wildcard_prog_load(const struct sock_addr_test *test);
105
106static struct sock_addr_test tests[] = {
107	/* bind */
108	{
109		"bind4: load prog with wrong expected attach type",
110		bind4_prog_load,
111		BPF_CGROUP_INET6_BIND,
112		BPF_CGROUP_INET4_BIND,
113		AF_INET,
114		SOCK_STREAM,
115		NULL,
116		0,
117		NULL,
118		0,
119		NULL,
120		LOAD_REJECT,
121	},
122	{
123		"bind4: attach prog with wrong attach type",
124		bind4_prog_load,
125		BPF_CGROUP_INET4_BIND,
126		BPF_CGROUP_INET6_BIND,
127		AF_INET,
128		SOCK_STREAM,
129		NULL,
130		0,
131		NULL,
132		0,
133		NULL,
134		ATTACH_REJECT,
135	},
136	{
137		"bind4: rewrite IP & TCP port in",
138		bind4_prog_load,
139		BPF_CGROUP_INET4_BIND,
140		BPF_CGROUP_INET4_BIND,
141		AF_INET,
142		SOCK_STREAM,
143		SERV4_IP,
144		SERV4_PORT,
145		SERV4_REWRITE_IP,
146		SERV4_REWRITE_PORT,
147		NULL,
148		SUCCESS,
149	},
150	{
151		"bind4: rewrite IP & UDP port in",
152		bind4_prog_load,
153		BPF_CGROUP_INET4_BIND,
154		BPF_CGROUP_INET4_BIND,
155		AF_INET,
156		SOCK_DGRAM,
157		SERV4_IP,
158		SERV4_PORT,
159		SERV4_REWRITE_IP,
160		SERV4_REWRITE_PORT,
161		NULL,
162		SUCCESS,
163	},
164	{
165		"bind6: load prog with wrong expected attach type",
166		bind6_prog_load,
167		BPF_CGROUP_INET4_BIND,
168		BPF_CGROUP_INET6_BIND,
169		AF_INET6,
170		SOCK_STREAM,
171		NULL,
172		0,
173		NULL,
174		0,
175		NULL,
176		LOAD_REJECT,
177	},
178	{
179		"bind6: attach prog with wrong attach type",
180		bind6_prog_load,
181		BPF_CGROUP_INET6_BIND,
182		BPF_CGROUP_INET4_BIND,
183		AF_INET,
184		SOCK_STREAM,
185		NULL,
186		0,
187		NULL,
188		0,
189		NULL,
190		ATTACH_REJECT,
191	},
192	{
193		"bind6: rewrite IP & TCP port in",
194		bind6_prog_load,
195		BPF_CGROUP_INET6_BIND,
196		BPF_CGROUP_INET6_BIND,
197		AF_INET6,
198		SOCK_STREAM,
199		SERV6_IP,
200		SERV6_PORT,
201		SERV6_REWRITE_IP,
202		SERV6_REWRITE_PORT,
203		NULL,
204		SUCCESS,
205	},
206	{
207		"bind6: rewrite IP & UDP port in",
208		bind6_prog_load,
209		BPF_CGROUP_INET6_BIND,
210		BPF_CGROUP_INET6_BIND,
211		AF_INET6,
212		SOCK_DGRAM,
213		SERV6_IP,
214		SERV6_PORT,
215		SERV6_REWRITE_IP,
216		SERV6_REWRITE_PORT,
217		NULL,
218		SUCCESS,
219	},
220
221	/* connect */
222	{
223		"connect4: load prog with wrong expected attach type",
224		connect4_prog_load,
225		BPF_CGROUP_INET6_CONNECT,
226		BPF_CGROUP_INET4_CONNECT,
227		AF_INET,
228		SOCK_STREAM,
229		NULL,
230		0,
231		NULL,
232		0,
233		NULL,
234		LOAD_REJECT,
235	},
236	{
237		"connect4: attach prog with wrong attach type",
238		connect4_prog_load,
239		BPF_CGROUP_INET4_CONNECT,
240		BPF_CGROUP_INET6_CONNECT,
241		AF_INET,
242		SOCK_STREAM,
243		NULL,
244		0,
245		NULL,
246		0,
247		NULL,
248		ATTACH_REJECT,
249	},
250	{
251		"connect4: rewrite IP & TCP port",
252		connect4_prog_load,
253		BPF_CGROUP_INET4_CONNECT,
254		BPF_CGROUP_INET4_CONNECT,
255		AF_INET,
256		SOCK_STREAM,
257		SERV4_IP,
258		SERV4_PORT,
259		SERV4_REWRITE_IP,
260		SERV4_REWRITE_PORT,
261		SRC4_REWRITE_IP,
262		SUCCESS,
263	},
264	{
265		"connect4: rewrite IP & UDP port",
266		connect4_prog_load,
267		BPF_CGROUP_INET4_CONNECT,
268		BPF_CGROUP_INET4_CONNECT,
269		AF_INET,
270		SOCK_DGRAM,
271		SERV4_IP,
272		SERV4_PORT,
273		SERV4_REWRITE_IP,
274		SERV4_REWRITE_PORT,
275		SRC4_REWRITE_IP,
276		SUCCESS,
277	},
278	{
279		"connect6: load prog with wrong expected attach type",
280		connect6_prog_load,
281		BPF_CGROUP_INET4_CONNECT,
282		BPF_CGROUP_INET6_CONNECT,
283		AF_INET6,
284		SOCK_STREAM,
285		NULL,
286		0,
287		NULL,
288		0,
289		NULL,
290		LOAD_REJECT,
291	},
292	{
293		"connect6: attach prog with wrong attach type",
294		connect6_prog_load,
295		BPF_CGROUP_INET6_CONNECT,
296		BPF_CGROUP_INET4_CONNECT,
297		AF_INET,
298		SOCK_STREAM,
299		NULL,
300		0,
301		NULL,
302		0,
303		NULL,
304		ATTACH_REJECT,
305	},
306	{
307		"connect6: rewrite IP & TCP port",
308		connect6_prog_load,
309		BPF_CGROUP_INET6_CONNECT,
310		BPF_CGROUP_INET6_CONNECT,
311		AF_INET6,
312		SOCK_STREAM,
313		SERV6_IP,
314		SERV6_PORT,
315		SERV6_REWRITE_IP,
316		SERV6_REWRITE_PORT,
317		SRC6_REWRITE_IP,
318		SUCCESS,
319	},
320	{
321		"connect6: rewrite IP & UDP port",
322		connect6_prog_load,
323		BPF_CGROUP_INET6_CONNECT,
324		BPF_CGROUP_INET6_CONNECT,
325		AF_INET6,
326		SOCK_DGRAM,
327		SERV6_IP,
328		SERV6_PORT,
329		SERV6_REWRITE_IP,
330		SERV6_REWRITE_PORT,
331		SRC6_REWRITE_IP,
332		SUCCESS,
333	},
334
335	/* sendmsg */
336	{
337		"sendmsg4: load prog with wrong expected attach type",
338		sendmsg4_rw_asm_prog_load,
339		BPF_CGROUP_UDP6_SENDMSG,
340		BPF_CGROUP_UDP4_SENDMSG,
341		AF_INET,
342		SOCK_DGRAM,
343		NULL,
344		0,
345		NULL,
346		0,
347		NULL,
348		LOAD_REJECT,
349	},
350	{
351		"sendmsg4: attach prog with wrong attach type",
352		sendmsg4_rw_asm_prog_load,
353		BPF_CGROUP_UDP4_SENDMSG,
354		BPF_CGROUP_UDP6_SENDMSG,
355		AF_INET,
356		SOCK_DGRAM,
357		NULL,
358		0,
359		NULL,
360		0,
361		NULL,
362		ATTACH_REJECT,
363	},
364	{
365		"sendmsg4: rewrite IP & port (asm)",
366		sendmsg4_rw_asm_prog_load,
367		BPF_CGROUP_UDP4_SENDMSG,
368		BPF_CGROUP_UDP4_SENDMSG,
369		AF_INET,
370		SOCK_DGRAM,
371		SERV4_IP,
372		SERV4_PORT,
373		SERV4_REWRITE_IP,
374		SERV4_REWRITE_PORT,
375		SRC4_REWRITE_IP,
376		SUCCESS,
377	},
378	{
379		"sendmsg4: rewrite IP & port (C)",
380		sendmsg4_rw_c_prog_load,
381		BPF_CGROUP_UDP4_SENDMSG,
382		BPF_CGROUP_UDP4_SENDMSG,
383		AF_INET,
384		SOCK_DGRAM,
385		SERV4_IP,
386		SERV4_PORT,
387		SERV4_REWRITE_IP,
388		SERV4_REWRITE_PORT,
389		SRC4_REWRITE_IP,
390		SUCCESS,
391	},
392	{
393		"sendmsg4: deny call",
394		sendmsg_deny_prog_load,
395		BPF_CGROUP_UDP4_SENDMSG,
396		BPF_CGROUP_UDP4_SENDMSG,
397		AF_INET,
398		SOCK_DGRAM,
399		SERV4_IP,
400		SERV4_PORT,
401		SERV4_REWRITE_IP,
402		SERV4_REWRITE_PORT,
403		SRC4_REWRITE_IP,
404		SYSCALL_EPERM,
405	},
406	{
407		"sendmsg6: load prog with wrong expected attach type",
408		sendmsg6_rw_asm_prog_load,
409		BPF_CGROUP_UDP4_SENDMSG,
410		BPF_CGROUP_UDP6_SENDMSG,
411		AF_INET6,
412		SOCK_DGRAM,
413		NULL,
414		0,
415		NULL,
416		0,
417		NULL,
418		LOAD_REJECT,
419	},
420	{
421		"sendmsg6: attach prog with wrong attach type",
422		sendmsg6_rw_asm_prog_load,
423		BPF_CGROUP_UDP6_SENDMSG,
424		BPF_CGROUP_UDP4_SENDMSG,
425		AF_INET6,
426		SOCK_DGRAM,
427		NULL,
428		0,
429		NULL,
430		0,
431		NULL,
432		ATTACH_REJECT,
433	},
434	{
435		"sendmsg6: rewrite IP & port (asm)",
436		sendmsg6_rw_asm_prog_load,
437		BPF_CGROUP_UDP6_SENDMSG,
438		BPF_CGROUP_UDP6_SENDMSG,
439		AF_INET6,
440		SOCK_DGRAM,
441		SERV6_IP,
442		SERV6_PORT,
443		SERV6_REWRITE_IP,
444		SERV6_REWRITE_PORT,
445		SRC6_REWRITE_IP,
446		SUCCESS,
447	},
448	{
449		"sendmsg6: rewrite IP & port (C)",
450		sendmsg6_rw_c_prog_load,
451		BPF_CGROUP_UDP6_SENDMSG,
452		BPF_CGROUP_UDP6_SENDMSG,
453		AF_INET6,
454		SOCK_DGRAM,
455		SERV6_IP,
456		SERV6_PORT,
457		SERV6_REWRITE_IP,
458		SERV6_REWRITE_PORT,
459		SRC6_REWRITE_IP,
460		SUCCESS,
461	},
462	{
463		"sendmsg6: IPv4-mapped IPv6",
464		sendmsg6_rw_v4mapped_prog_load,
465		BPF_CGROUP_UDP6_SENDMSG,
466		BPF_CGROUP_UDP6_SENDMSG,
467		AF_INET6,
468		SOCK_DGRAM,
469		SERV6_IP,
470		SERV6_PORT,
471		SERV6_REWRITE_IP,
472		SERV6_REWRITE_PORT,
473		SRC6_REWRITE_IP,
474		SYSCALL_ENOTSUPP,
475	},
476	{
477		"sendmsg6: set dst IP = [::] (BSD'ism)",
478		sendmsg6_rw_wildcard_prog_load,
479		BPF_CGROUP_UDP6_SENDMSG,
480		BPF_CGROUP_UDP6_SENDMSG,
481		AF_INET6,
482		SOCK_DGRAM,
483		SERV6_IP,
484		SERV6_PORT,
485		SERV6_REWRITE_IP,
486		SERV6_REWRITE_PORT,
487		SRC6_REWRITE_IP,
488		SUCCESS,
489	},
490	{
491		"sendmsg6: preserve dst IP = [::] (BSD'ism)",
492		sendmsg_allow_prog_load,
493		BPF_CGROUP_UDP6_SENDMSG,
494		BPF_CGROUP_UDP6_SENDMSG,
495		AF_INET6,
496		SOCK_DGRAM,
497		WILDCARD6_IP,
498		SERV6_PORT,
499		SERV6_REWRITE_IP,
500		SERV6_PORT,
501		SRC6_IP,
502		SUCCESS,
503	},
504	{
505		"sendmsg6: deny call",
506		sendmsg_deny_prog_load,
507		BPF_CGROUP_UDP6_SENDMSG,
508		BPF_CGROUP_UDP6_SENDMSG,
509		AF_INET6,
510		SOCK_DGRAM,
511		SERV6_IP,
512		SERV6_PORT,
513		SERV6_REWRITE_IP,
514		SERV6_REWRITE_PORT,
515		SRC6_REWRITE_IP,
516		SYSCALL_EPERM,
517	},
518
519	/* recvmsg */
520	{
521		"recvmsg4: return code ok",
522		recvmsg_allow_prog_load,
523		BPF_CGROUP_UDP4_RECVMSG,
524		BPF_CGROUP_UDP4_RECVMSG,
525		AF_INET,
526		SOCK_DGRAM,
527		NULL,
528		0,
529		NULL,
530		0,
531		NULL,
532		ATTACH_OKAY,
533	},
534	{
535		"recvmsg4: return code !ok",
536		recvmsg_deny_prog_load,
537		BPF_CGROUP_UDP4_RECVMSG,
538		BPF_CGROUP_UDP4_RECVMSG,
539		AF_INET,
540		SOCK_DGRAM,
541		NULL,
542		0,
543		NULL,
544		0,
545		NULL,
546		LOAD_REJECT,
547	},
548	{
549		"recvmsg6: return code ok",
550		recvmsg_allow_prog_load,
551		BPF_CGROUP_UDP6_RECVMSG,
552		BPF_CGROUP_UDP6_RECVMSG,
553		AF_INET6,
554		SOCK_DGRAM,
555		NULL,
556		0,
557		NULL,
558		0,
559		NULL,
560		ATTACH_OKAY,
561	},
562	{
563		"recvmsg6: return code !ok",
564		recvmsg_deny_prog_load,
565		BPF_CGROUP_UDP6_RECVMSG,
566		BPF_CGROUP_UDP6_RECVMSG,
567		AF_INET6,
568		SOCK_DGRAM,
569		NULL,
570		0,
571		NULL,
572		0,
573		NULL,
574		LOAD_REJECT,
575	},
576	{
577		"recvmsg4: rewrite IP & port (C)",
578		recvmsg4_rw_c_prog_load,
579		BPF_CGROUP_UDP4_RECVMSG,
580		BPF_CGROUP_UDP4_RECVMSG,
581		AF_INET,
582		SOCK_DGRAM,
583		SERV4_REWRITE_IP,
584		SERV4_REWRITE_PORT,
585		SERV4_REWRITE_IP,
586		SERV4_REWRITE_PORT,
587		SERV4_IP,
588		SUCCESS,
589	},
590	{
591		"recvmsg6: rewrite IP & port (C)",
592		recvmsg6_rw_c_prog_load,
593		BPF_CGROUP_UDP6_RECVMSG,
594		BPF_CGROUP_UDP6_RECVMSG,
595		AF_INET6,
596		SOCK_DGRAM,
597		SERV6_REWRITE_IP,
598		SERV6_REWRITE_PORT,
599		SERV6_REWRITE_IP,
600		SERV6_REWRITE_PORT,
601		SERV6_IP,
602		SUCCESS,
603	},
604};
605
606static int mk_sockaddr(int domain, const char *ip, unsigned short port,
607		       struct sockaddr *addr, socklen_t addr_len)
608{
609	struct sockaddr_in6 *addr6;
610	struct sockaddr_in *addr4;
611
612	if (domain != AF_INET && domain != AF_INET6) {
613		log_err("Unsupported address family");
614		return -1;
615	}
616
617	memset(addr, 0, addr_len);
618
619	if (domain == AF_INET) {
620		if (addr_len < sizeof(struct sockaddr_in))
621			return -1;
622		addr4 = (struct sockaddr_in *)addr;
623		addr4->sin_family = domain;
624		addr4->sin_port = htons(port);
625		if (inet_pton(domain, ip, (void *)&addr4->sin_addr) != 1) {
626			log_err("Invalid IPv4: %s", ip);
627			return -1;
628		}
629	} else if (domain == AF_INET6) {
630		if (addr_len < sizeof(struct sockaddr_in6))
631			return -1;
632		addr6 = (struct sockaddr_in6 *)addr;
633		addr6->sin6_family = domain;
634		addr6->sin6_port = htons(port);
635		if (inet_pton(domain, ip, (void *)&addr6->sin6_addr) != 1) {
636			log_err("Invalid IPv6: %s", ip);
637			return -1;
638		}
639	}
640
641	return 0;
642}
643
644static int load_insns(const struct sock_addr_test *test,
645		      const struct bpf_insn *insns, size_t insns_cnt)
646{
647	LIBBPF_OPTS(bpf_prog_load_opts, opts);
648	int ret;
649
650	opts.expected_attach_type = test->expected_attach_type;
651	opts.log_buf = bpf_log_buf;
652	opts.log_size = BPF_LOG_BUF_SIZE;
653
654	ret = bpf_prog_load(BPF_PROG_TYPE_CGROUP_SOCK_ADDR, NULL, "GPL", insns, insns_cnt, &opts);
655	if (ret < 0 && test->expected_result != LOAD_REJECT) {
656		log_err(">>> Loading program error.\n"
657			">>> Verifier output:\n%s\n-------\n", bpf_log_buf);
658	}
659
660	return ret;
661}
662
663static int load_path(const struct sock_addr_test *test, const char *path)
664{
665	struct bpf_object *obj;
666	struct bpf_program *prog;
667	int err;
668
669	obj = bpf_object__open_file(path, NULL);
670	err = libbpf_get_error(obj);
671	if (err) {
672		log_err(">>> Opening BPF object (%s) error.\n", path);
673		return -1;
674	}
675
676	prog = bpf_object__next_program(obj, NULL);
677	if (!prog)
678		goto err_out;
679
680	bpf_program__set_type(prog, BPF_PROG_TYPE_CGROUP_SOCK_ADDR);
681	bpf_program__set_expected_attach_type(prog, test->expected_attach_type);
682	bpf_program__set_flags(prog, BPF_F_TEST_RND_HI32);
683
684	err = bpf_object__load(obj);
685	if (err) {
686		if (test->expected_result != LOAD_REJECT)
687			log_err(">>> Loading program (%s) error.\n", path);
688		goto err_out;
689	}
690
691	return bpf_program__fd(prog);
692err_out:
693	bpf_object__close(obj);
694	return -1;
695}
696
697static int bind4_prog_load(const struct sock_addr_test *test)
698{
699	return load_path(test, BIND4_PROG_PATH);
700}
701
702static int bind6_prog_load(const struct sock_addr_test *test)
703{
704	return load_path(test, BIND6_PROG_PATH);
705}
706
707static int connect4_prog_load(const struct sock_addr_test *test)
708{
709	return load_path(test, CONNECT4_PROG_PATH);
710}
711
712static int connect6_prog_load(const struct sock_addr_test *test)
713{
714	return load_path(test, CONNECT6_PROG_PATH);
715}
716
717static int xmsg_ret_only_prog_load(const struct sock_addr_test *test,
718				   int32_t rc)
719{
720	struct bpf_insn insns[] = {
721		/* return rc */
722		BPF_MOV64_IMM(BPF_REG_0, rc),
723		BPF_EXIT_INSN(),
724	};
725	return load_insns(test, insns, ARRAY_SIZE(insns));
726}
727
728static int sendmsg_allow_prog_load(const struct sock_addr_test *test)
729{
730	return xmsg_ret_only_prog_load(test, /*rc*/ 1);
731}
732
733static int sendmsg_deny_prog_load(const struct sock_addr_test *test)
734{
735	return xmsg_ret_only_prog_load(test, /*rc*/ 0);
736}
737
738static int recvmsg_allow_prog_load(const struct sock_addr_test *test)
739{
740	return xmsg_ret_only_prog_load(test, /*rc*/ 1);
741}
742
743static int recvmsg_deny_prog_load(const struct sock_addr_test *test)
744{
745	return xmsg_ret_only_prog_load(test, /*rc*/ 0);
746}
747
748static int sendmsg4_rw_asm_prog_load(const struct sock_addr_test *test)
749{
750	struct sockaddr_in dst4_rw_addr;
751	struct in_addr src4_rw_ip;
752
753	if (inet_pton(AF_INET, SRC4_REWRITE_IP, (void *)&src4_rw_ip) != 1) {
754		log_err("Invalid IPv4: %s", SRC4_REWRITE_IP);
755		return -1;
756	}
757
758	if (mk_sockaddr(AF_INET, SERV4_REWRITE_IP, SERV4_REWRITE_PORT,
759			(struct sockaddr *)&dst4_rw_addr,
760			sizeof(dst4_rw_addr)) == -1)
761		return -1;
762
763	struct bpf_insn insns[] = {
764		BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
765
766		/* if (sk.family == AF_INET && */
767		BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
768			    offsetof(struct bpf_sock_addr, family)),
769		BPF_JMP_IMM(BPF_JNE, BPF_REG_7, AF_INET, 8),
770
771		/*     sk.type == SOCK_DGRAM)  { */
772		BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
773			    offsetof(struct bpf_sock_addr, type)),
774		BPF_JMP_IMM(BPF_JNE, BPF_REG_7, SOCK_DGRAM, 6),
775
776		/*      msg_src_ip4 = src4_rw_ip */
777		BPF_MOV32_IMM(BPF_REG_7, src4_rw_ip.s_addr),
778		BPF_STX_MEM(BPF_W, BPF_REG_6, BPF_REG_7,
779			    offsetof(struct bpf_sock_addr, msg_src_ip4)),
780
781		/*      user_ip4 = dst4_rw_addr.sin_addr */
782		BPF_MOV32_IMM(BPF_REG_7, dst4_rw_addr.sin_addr.s_addr),
783		BPF_STX_MEM(BPF_W, BPF_REG_6, BPF_REG_7,
784			    offsetof(struct bpf_sock_addr, user_ip4)),
785
786		/*      user_port = dst4_rw_addr.sin_port */
787		BPF_MOV32_IMM(BPF_REG_7, dst4_rw_addr.sin_port),
788		BPF_STX_MEM(BPF_W, BPF_REG_6, BPF_REG_7,
789			    offsetof(struct bpf_sock_addr, user_port)),
790		/* } */
791
792		/* return 1 */
793		BPF_MOV64_IMM(BPF_REG_0, 1),
794		BPF_EXIT_INSN(),
795	};
796
797	return load_insns(test, insns, ARRAY_SIZE(insns));
798}
799
800static int recvmsg4_rw_c_prog_load(const struct sock_addr_test *test)
801{
802	return load_path(test, RECVMSG4_PROG_PATH);
803}
804
805static int sendmsg4_rw_c_prog_load(const struct sock_addr_test *test)
806{
807	return load_path(test, SENDMSG4_PROG_PATH);
808}
809
810static int sendmsg6_rw_dst_asm_prog_load(const struct sock_addr_test *test,
811					 const char *rw_dst_ip)
812{
813	struct sockaddr_in6 dst6_rw_addr;
814	struct in6_addr src6_rw_ip;
815
816	if (inet_pton(AF_INET6, SRC6_REWRITE_IP, (void *)&src6_rw_ip) != 1) {
817		log_err("Invalid IPv6: %s", SRC6_REWRITE_IP);
818		return -1;
819	}
820
821	if (mk_sockaddr(AF_INET6, rw_dst_ip, SERV6_REWRITE_PORT,
822			(struct sockaddr *)&dst6_rw_addr,
823			sizeof(dst6_rw_addr)) == -1)
824		return -1;
825
826	struct bpf_insn insns[] = {
827		BPF_MOV64_REG(BPF_REG_6, BPF_REG_1),
828
829		/* if (sk.family == AF_INET6) { */
830		BPF_LDX_MEM(BPF_W, BPF_REG_7, BPF_REG_6,
831			    offsetof(struct bpf_sock_addr, family)),
832		BPF_JMP_IMM(BPF_JNE, BPF_REG_7, AF_INET6, 18),
833
834#define STORE_IPV6_WORD_N(DST, SRC, N)					       \
835		BPF_MOV32_IMM(BPF_REG_7, SRC[N]),			       \
836		BPF_STX_MEM(BPF_W, BPF_REG_6, BPF_REG_7,		       \
837			    offsetof(struct bpf_sock_addr, DST[N]))
838
839#define STORE_IPV6(DST, SRC)						       \
840		STORE_IPV6_WORD_N(DST, SRC, 0),				       \
841		STORE_IPV6_WORD_N(DST, SRC, 1),				       \
842		STORE_IPV6_WORD_N(DST, SRC, 2),				       \
843		STORE_IPV6_WORD_N(DST, SRC, 3)
844
845		STORE_IPV6(msg_src_ip6, src6_rw_ip.s6_addr32),
846		STORE_IPV6(user_ip6, dst6_rw_addr.sin6_addr.s6_addr32),
847
848		/*      user_port = dst6_rw_addr.sin6_port */
849		BPF_MOV32_IMM(BPF_REG_7, dst6_rw_addr.sin6_port),
850		BPF_STX_MEM(BPF_W, BPF_REG_6, BPF_REG_7,
851			    offsetof(struct bpf_sock_addr, user_port)),
852
853		/* } */
854
855		/* return 1 */
856		BPF_MOV64_IMM(BPF_REG_0, 1),
857		BPF_EXIT_INSN(),
858	};
859
860	return load_insns(test, insns, ARRAY_SIZE(insns));
861}
862
863static int sendmsg6_rw_asm_prog_load(const struct sock_addr_test *test)
864{
865	return sendmsg6_rw_dst_asm_prog_load(test, SERV6_REWRITE_IP);
866}
867
868static int recvmsg6_rw_c_prog_load(const struct sock_addr_test *test)
869{
870	return load_path(test, RECVMSG6_PROG_PATH);
871}
872
873static int sendmsg6_rw_v4mapped_prog_load(const struct sock_addr_test *test)
874{
875	return sendmsg6_rw_dst_asm_prog_load(test, SERV6_V4MAPPED_IP);
876}
877
878static int sendmsg6_rw_wildcard_prog_load(const struct sock_addr_test *test)
879{
880	return sendmsg6_rw_dst_asm_prog_load(test, WILDCARD6_IP);
881}
882
883static int sendmsg6_rw_c_prog_load(const struct sock_addr_test *test)
884{
885	return load_path(test, SENDMSG6_PROG_PATH);
886}
887
888static int cmp_addr(const struct sockaddr_storage *addr1,
889		    const struct sockaddr_storage *addr2, int cmp_port)
890{
891	const struct sockaddr_in *four1, *four2;
892	const struct sockaddr_in6 *six1, *six2;
893
894	if (addr1->ss_family != addr2->ss_family)
895		return -1;
896
897	if (addr1->ss_family == AF_INET) {
898		four1 = (const struct sockaddr_in *)addr1;
899		four2 = (const struct sockaddr_in *)addr2;
900		return !((four1->sin_port == four2->sin_port || !cmp_port) &&
901			 four1->sin_addr.s_addr == four2->sin_addr.s_addr);
902	} else if (addr1->ss_family == AF_INET6) {
903		six1 = (const struct sockaddr_in6 *)addr1;
904		six2 = (const struct sockaddr_in6 *)addr2;
905		return !((six1->sin6_port == six2->sin6_port || !cmp_port) &&
906			 !memcmp(&six1->sin6_addr, &six2->sin6_addr,
907				 sizeof(struct in6_addr)));
908	}
909
910	return -1;
911}
912
913static int cmp_sock_addr(info_fn fn, int sock1,
914			 const struct sockaddr_storage *addr2, int cmp_port)
915{
916	struct sockaddr_storage addr1;
917	socklen_t len1 = sizeof(addr1);
918
919	memset(&addr1, 0, len1);
920	if (fn(sock1, (struct sockaddr *)&addr1, (socklen_t *)&len1) != 0)
921		return -1;
922
923	return cmp_addr(&addr1, addr2, cmp_port);
924}
925
926static int cmp_local_ip(int sock1, const struct sockaddr_storage *addr2)
927{
928	return cmp_sock_addr(getsockname, sock1, addr2, /*cmp_port*/ 0);
929}
930
931static int cmp_local_addr(int sock1, const struct sockaddr_storage *addr2)
932{
933	return cmp_sock_addr(getsockname, sock1, addr2, /*cmp_port*/ 1);
934}
935
936static int cmp_peer_addr(int sock1, const struct sockaddr_storage *addr2)
937{
938	return cmp_sock_addr(getpeername, sock1, addr2, /*cmp_port*/ 1);
939}
940
941static int start_server(int type, const struct sockaddr_storage *addr,
942			socklen_t addr_len)
943{
944	int fd;
945
946	fd = socket(addr->ss_family, type, 0);
947	if (fd == -1) {
948		log_err("Failed to create server socket");
949		goto out;
950	}
951
952	if (bind(fd, (const struct sockaddr *)addr, addr_len) == -1) {
953		log_err("Failed to bind server socket");
954		goto close_out;
955	}
956
957	if (type == SOCK_STREAM) {
958		if (listen(fd, 128) == -1) {
959			log_err("Failed to listen on server socket");
960			goto close_out;
961		}
962	}
963
964	goto out;
965close_out:
966	close(fd);
967	fd = -1;
968out:
969	return fd;
970}
971
972static int connect_to_server(int type, const struct sockaddr_storage *addr,
973			     socklen_t addr_len)
974{
975	int domain;
976	int fd = -1;
977
978	domain = addr->ss_family;
979
980	if (domain != AF_INET && domain != AF_INET6) {
981		log_err("Unsupported address family");
982		goto err;
983	}
984
985	fd = socket(domain, type, 0);
986	if (fd == -1) {
987		log_err("Failed to create client socket");
988		goto err;
989	}
990
991	if (connect(fd, (const struct sockaddr *)addr, addr_len) == -1) {
992		log_err("Fail to connect to server");
993		goto err;
994	}
995
996	goto out;
997err:
998	close(fd);
999	fd = -1;
1000out:
1001	return fd;
1002}
1003
1004int init_pktinfo(int domain, struct cmsghdr *cmsg)
1005{
1006	struct in6_pktinfo *pktinfo6;
1007	struct in_pktinfo *pktinfo4;
1008
1009	if (domain == AF_INET) {
1010		cmsg->cmsg_level = SOL_IP;
1011		cmsg->cmsg_type = IP_PKTINFO;
1012		cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
1013		pktinfo4 = (struct in_pktinfo *)CMSG_DATA(cmsg);
1014		memset(pktinfo4, 0, sizeof(struct in_pktinfo));
1015		if (inet_pton(domain, SRC4_IP,
1016			      (void *)&pktinfo4->ipi_spec_dst) != 1)
1017			return -1;
1018	} else if (domain == AF_INET6) {
1019		cmsg->cmsg_level = SOL_IPV6;
1020		cmsg->cmsg_type = IPV6_PKTINFO;
1021		cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
1022		pktinfo6 = (struct in6_pktinfo *)CMSG_DATA(cmsg);
1023		memset(pktinfo6, 0, sizeof(struct in6_pktinfo));
1024		if (inet_pton(domain, SRC6_IP,
1025			      (void *)&pktinfo6->ipi6_addr) != 1)
1026			return -1;
1027	} else {
1028		return -1;
1029	}
1030
1031	return 0;
1032}
1033
1034static int sendmsg_to_server(int type, const struct sockaddr_storage *addr,
1035			     socklen_t addr_len, int set_cmsg, int flags,
1036			     int *syscall_err)
1037{
1038	union {
1039		char buf[CMSG_SPACE(sizeof(struct in6_pktinfo))];
1040		struct cmsghdr align;
1041	} control6;
1042	union {
1043		char buf[CMSG_SPACE(sizeof(struct in_pktinfo))];
1044		struct cmsghdr align;
1045	} control4;
1046	struct msghdr hdr;
1047	struct iovec iov;
1048	char data = 'a';
1049	int domain;
1050	int fd = -1;
1051
1052	domain = addr->ss_family;
1053
1054	if (domain != AF_INET && domain != AF_INET6) {
1055		log_err("Unsupported address family");
1056		goto err;
1057	}
1058
1059	fd = socket(domain, type, 0);
1060	if (fd == -1) {
1061		log_err("Failed to create client socket");
1062		goto err;
1063	}
1064
1065	memset(&iov, 0, sizeof(iov));
1066	iov.iov_base = &data;
1067	iov.iov_len = sizeof(data);
1068
1069	memset(&hdr, 0, sizeof(hdr));
1070	hdr.msg_name = (void *)addr;
1071	hdr.msg_namelen = addr_len;
1072	hdr.msg_iov = &iov;
1073	hdr.msg_iovlen = 1;
1074
1075	if (set_cmsg) {
1076		if (domain == AF_INET) {
1077			hdr.msg_control = &control4;
1078			hdr.msg_controllen = sizeof(control4.buf);
1079		} else if (domain == AF_INET6) {
1080			hdr.msg_control = &control6;
1081			hdr.msg_controllen = sizeof(control6.buf);
1082		}
1083		if (init_pktinfo(domain, CMSG_FIRSTHDR(&hdr))) {
1084			log_err("Fail to init pktinfo");
1085			goto err;
1086		}
1087	}
1088
1089	if (sendmsg(fd, &hdr, flags) != sizeof(data)) {
1090		log_err("Fail to send message to server");
1091		*syscall_err = errno;
1092		goto err;
1093	}
1094
1095	goto out;
1096err:
1097	close(fd);
1098	fd = -1;
1099out:
1100	return fd;
1101}
1102
1103static int fastconnect_to_server(const struct sockaddr_storage *addr,
1104				 socklen_t addr_len)
1105{
1106	int sendmsg_err;
1107
1108	return sendmsg_to_server(SOCK_STREAM, addr, addr_len, /*set_cmsg*/0,
1109				 MSG_FASTOPEN, &sendmsg_err);
1110}
1111
1112static int recvmsg_from_client(int sockfd, struct sockaddr_storage *src_addr)
1113{
1114	struct timeval tv;
1115	struct msghdr hdr;
1116	struct iovec iov;
1117	char data[64];
1118	fd_set rfds;
1119
1120	FD_ZERO(&rfds);
1121	FD_SET(sockfd, &rfds);
1122
1123	tv.tv_sec = 2;
1124	tv.tv_usec = 0;
1125
1126	if (select(sockfd + 1, &rfds, NULL, NULL, &tv) <= 0 ||
1127	    !FD_ISSET(sockfd, &rfds))
1128		return -1;
1129
1130	memset(&iov, 0, sizeof(iov));
1131	iov.iov_base = data;
1132	iov.iov_len = sizeof(data);
1133
1134	memset(&hdr, 0, sizeof(hdr));
1135	hdr.msg_name = src_addr;
1136	hdr.msg_namelen = sizeof(struct sockaddr_storage);
1137	hdr.msg_iov = &iov;
1138	hdr.msg_iovlen = 1;
1139
1140	return recvmsg(sockfd, &hdr, 0);
1141}
1142
1143static int init_addrs(const struct sock_addr_test *test,
1144		      struct sockaddr_storage *requested_addr,
1145		      struct sockaddr_storage *expected_addr,
1146		      struct sockaddr_storage *expected_src_addr)
1147{
1148	socklen_t addr_len = sizeof(struct sockaddr_storage);
1149
1150	if (mk_sockaddr(test->domain, test->expected_ip, test->expected_port,
1151			(struct sockaddr *)expected_addr, addr_len) == -1)
1152		goto err;
1153
1154	if (mk_sockaddr(test->domain, test->requested_ip, test->requested_port,
1155			(struct sockaddr *)requested_addr, addr_len) == -1)
1156		goto err;
1157
1158	if (test->expected_src_ip &&
1159	    mk_sockaddr(test->domain, test->expected_src_ip, 0,
1160			(struct sockaddr *)expected_src_addr, addr_len) == -1)
1161		goto err;
1162
1163	return 0;
1164err:
1165	return -1;
1166}
1167
1168static int run_bind_test_case(const struct sock_addr_test *test)
1169{
1170	socklen_t addr_len = sizeof(struct sockaddr_storage);
1171	struct sockaddr_storage requested_addr;
1172	struct sockaddr_storage expected_addr;
1173	int clientfd = -1;
1174	int servfd = -1;
1175	int err = 0;
1176
1177	if (init_addrs(test, &requested_addr, &expected_addr, NULL))
1178		goto err;
1179
1180	servfd = start_server(test->type, &requested_addr, addr_len);
1181	if (servfd == -1)
1182		goto err;
1183
1184	if (cmp_local_addr(servfd, &expected_addr))
1185		goto err;
1186
1187	/* Try to connect to server just in case */
1188	clientfd = connect_to_server(test->type, &expected_addr, addr_len);
1189	if (clientfd == -1)
1190		goto err;
1191
1192	goto out;
1193err:
1194	err = -1;
1195out:
1196	close(clientfd);
1197	close(servfd);
1198	return err;
1199}
1200
1201static int run_connect_test_case(const struct sock_addr_test *test)
1202{
1203	socklen_t addr_len = sizeof(struct sockaddr_storage);
1204	struct sockaddr_storage expected_src_addr;
1205	struct sockaddr_storage requested_addr;
1206	struct sockaddr_storage expected_addr;
1207	int clientfd = -1;
1208	int servfd = -1;
1209	int err = 0;
1210
1211	if (init_addrs(test, &requested_addr, &expected_addr,
1212		       &expected_src_addr))
1213		goto err;
1214
1215	/* Prepare server to connect to */
1216	servfd = start_server(test->type, &expected_addr, addr_len);
1217	if (servfd == -1)
1218		goto err;
1219
1220	clientfd = connect_to_server(test->type, &requested_addr, addr_len);
1221	if (clientfd == -1)
1222		goto err;
1223
1224	/* Make sure src and dst addrs were overridden properly */
1225	if (cmp_peer_addr(clientfd, &expected_addr))
1226		goto err;
1227
1228	if (cmp_local_ip(clientfd, &expected_src_addr))
1229		goto err;
1230
1231	if (test->type == SOCK_STREAM) {
1232		/* Test TCP Fast Open scenario */
1233		clientfd = fastconnect_to_server(&requested_addr, addr_len);
1234		if (clientfd == -1)
1235			goto err;
1236
1237		/* Make sure src and dst addrs were overridden properly */
1238		if (cmp_peer_addr(clientfd, &expected_addr))
1239			goto err;
1240
1241		if (cmp_local_ip(clientfd, &expected_src_addr))
1242			goto err;
1243	}
1244
1245	goto out;
1246err:
1247	err = -1;
1248out:
1249	close(clientfd);
1250	close(servfd);
1251	return err;
1252}
1253
1254static int run_xmsg_test_case(const struct sock_addr_test *test, int max_cmsg)
1255{
1256	socklen_t addr_len = sizeof(struct sockaddr_storage);
1257	struct sockaddr_storage expected_addr;
1258	struct sockaddr_storage server_addr;
1259	struct sockaddr_storage sendmsg_addr;
1260	struct sockaddr_storage recvmsg_addr;
1261	int clientfd = -1;
1262	int servfd = -1;
1263	int set_cmsg;
1264	int err = 0;
1265
1266	if (test->type != SOCK_DGRAM)
1267		goto err;
1268
1269	if (init_addrs(test, &sendmsg_addr, &server_addr, &expected_addr))
1270		goto err;
1271
1272	/* Prepare server to sendmsg to */
1273	servfd = start_server(test->type, &server_addr, addr_len);
1274	if (servfd == -1)
1275		goto err;
1276
1277	for (set_cmsg = 0; set_cmsg <= max_cmsg; ++set_cmsg) {
1278		if (clientfd >= 0)
1279			close(clientfd);
1280
1281		clientfd = sendmsg_to_server(test->type, &sendmsg_addr,
1282					     addr_len, set_cmsg, /*flags*/0,
1283					     &err);
1284		if (err)
1285			goto out;
1286		else if (clientfd == -1)
1287			goto err;
1288
1289		/* Try to receive message on server instead of using
1290		 * getpeername(2) on client socket, to check that client's
1291		 * destination address was rewritten properly, since
1292		 * getpeername(2) doesn't work with unconnected datagram
1293		 * sockets.
1294		 *
1295		 * Get source address from recvmsg(2) as well to make sure
1296		 * source was rewritten properly: getsockname(2) can't be used
1297		 * since socket is unconnected and source defined for one
1298		 * specific packet may differ from the one used by default and
1299		 * returned by getsockname(2).
1300		 */
1301		if (recvmsg_from_client(servfd, &recvmsg_addr) == -1)
1302			goto err;
1303
1304		if (cmp_addr(&recvmsg_addr, &expected_addr, /*cmp_port*/0))
1305			goto err;
1306	}
1307
1308	goto out;
1309err:
1310	err = -1;
1311out:
1312	close(clientfd);
1313	close(servfd);
1314	return err;
1315}
1316
1317static int run_test_case(int cgfd, const struct sock_addr_test *test)
1318{
1319	int progfd = -1;
1320	int err = 0;
1321
1322	printf("Test case: %s .. ", test->descr);
1323
1324	progfd = test->loadfn(test);
1325	if (test->expected_result == LOAD_REJECT && progfd < 0)
1326		goto out;
1327	else if (test->expected_result == LOAD_REJECT || progfd < 0)
1328		goto err;
1329
1330	err = bpf_prog_attach(progfd, cgfd, test->attach_type,
1331			      BPF_F_ALLOW_OVERRIDE);
1332	if (test->expected_result == ATTACH_REJECT && err) {
1333		err = 0; /* error was expected, reset it */
1334		goto out;
1335	} else if (test->expected_result == ATTACH_REJECT || err) {
1336		goto err;
1337	} else if (test->expected_result == ATTACH_OKAY) {
1338		err = 0;
1339		goto out;
1340	}
1341
1342	switch (test->attach_type) {
1343	case BPF_CGROUP_INET4_BIND:
1344	case BPF_CGROUP_INET6_BIND:
1345		err = run_bind_test_case(test);
1346		break;
1347	case BPF_CGROUP_INET4_CONNECT:
1348	case BPF_CGROUP_INET6_CONNECT:
1349		err = run_connect_test_case(test);
1350		break;
1351	case BPF_CGROUP_UDP4_SENDMSG:
1352	case BPF_CGROUP_UDP6_SENDMSG:
1353		err = run_xmsg_test_case(test, 1);
1354		break;
1355	case BPF_CGROUP_UDP4_RECVMSG:
1356	case BPF_CGROUP_UDP6_RECVMSG:
1357		err = run_xmsg_test_case(test, 0);
1358		break;
1359	default:
1360		goto err;
1361	}
1362
1363	if (test->expected_result == SYSCALL_EPERM && err == EPERM) {
1364		err = 0; /* error was expected, reset it */
1365		goto out;
1366	}
1367
1368	if (test->expected_result == SYSCALL_ENOTSUPP && err == ENOTSUPP) {
1369		err = 0; /* error was expected, reset it */
1370		goto out;
1371	}
1372
1373	if (err || test->expected_result != SUCCESS)
1374		goto err;
1375
1376	goto out;
1377err:
1378	err = -1;
1379out:
1380	/* Detaching w/o checking return code: best effort attempt. */
1381	if (progfd != -1)
1382		bpf_prog_detach(cgfd, test->attach_type);
1383	close(progfd);
1384	printf("[%s]\n", err ? "FAIL" : "PASS");
1385	return err;
1386}
1387
1388static int run_tests(int cgfd)
1389{
1390	int passes = 0;
1391	int fails = 0;
1392	int i;
1393
1394	for (i = 0; i < ARRAY_SIZE(tests); ++i) {
1395		if (run_test_case(cgfd, &tests[i]))
1396			++fails;
1397		else
1398			++passes;
1399	}
1400	printf("Summary: %d PASSED, %d FAILED\n", passes, fails);
1401	return fails ? -1 : 0;
1402}
1403
1404int main(int argc, char **argv)
1405{
1406	int cgfd = -1;
1407	int err = 0;
1408
1409	if (argc < 2) {
1410		fprintf(stderr,
1411			"%s has to be run via %s.sh. Skip direct run.\n",
1412			argv[0], argv[0]);
1413		exit(err);
1414	}
1415
1416	cgfd = cgroup_setup_and_join(CG_PATH);
1417	if (cgfd < 0)
1418		goto err;
1419
1420	/* Use libbpf 1.0 API mode */
1421	libbpf_set_strict_mode(LIBBPF_STRICT_ALL);
1422
1423	if (run_tests(cgfd))
1424		goto err;
1425
1426	goto out;
1427err:
1428	err = -1;
1429out:
1430	close(cgfd);
1431	cleanup_cgroup_environment();
1432	return err;
1433}
1434