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