Linux Audio

Check our new training course

Loading...
  1// SPDX-License-Identifier: GPL-2.0-only
  2
  3/*
  4 * Copyright 2021 Google LLC.
  5 */
  6
  7#include <test_progs.h>
  8#include <cgroup_helpers.h>
  9#include <network_helpers.h>
 10
 11#include "cgroup_getset_retval_setsockopt.skel.h"
 12#include "cgroup_getset_retval_getsockopt.skel.h"
 13#include "cgroup_getset_retval_hooks.skel.h"
 14
 15#define SOL_CUSTOM	0xdeadbeef
 16
 17static int zero;
 18
 19static void test_setsockopt_set(int cgroup_fd, int sock_fd)
 20{
 21	struct cgroup_getset_retval_setsockopt *obj;
 22	struct bpf_link *link_set_eunatch = NULL;
 23
 24	obj = cgroup_getset_retval_setsockopt__open_and_load();
 25	if (!ASSERT_OK_PTR(obj, "skel-load"))
 26		return;
 27
 28	obj->bss->page_size = sysconf(_SC_PAGESIZE);
 29
 30	/* Attach setsockopt that sets EUNATCH, assert that
 31	 * we actually get that error when we run setsockopt()
 32	 */
 33	link_set_eunatch = bpf_program__attach_cgroup(obj->progs.set_eunatch,
 34						      cgroup_fd);
 35	if (!ASSERT_OK_PTR(link_set_eunatch, "cg-attach-set_eunatch"))
 36		goto close_bpf_object;
 37
 38	if (!ASSERT_ERR(setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR,
 39				   &zero, sizeof(int)), "setsockopt"))
 40		goto close_bpf_object;
 41	if (!ASSERT_EQ(errno, EUNATCH, "setsockopt-errno"))
 42		goto close_bpf_object;
 43
 44	if (!ASSERT_EQ(obj->bss->invocations, 1, "invocations"))
 45		goto close_bpf_object;
 46	if (!ASSERT_FALSE(obj->bss->assertion_error, "assertion_error"))
 47		goto close_bpf_object;
 48
 49close_bpf_object:
 50	bpf_link__destroy(link_set_eunatch);
 51
 52	cgroup_getset_retval_setsockopt__destroy(obj);
 53}
 54
 55static void test_setsockopt_set_and_get(int cgroup_fd, int sock_fd)
 56{
 57	struct cgroup_getset_retval_setsockopt *obj;
 58	struct bpf_link *link_set_eunatch = NULL, *link_get_retval = NULL;
 59
 60	obj = cgroup_getset_retval_setsockopt__open_and_load();
 61	if (!ASSERT_OK_PTR(obj, "skel-load"))
 62		return;
 63
 64	obj->bss->page_size = sysconf(_SC_PAGESIZE);
 65
 66	/* Attach setsockopt that sets EUNATCH, and one that gets the
 67	 * previously set errno. Assert that we get the same errno back.
 68	 */
 69	link_set_eunatch = bpf_program__attach_cgroup(obj->progs.set_eunatch,
 70						      cgroup_fd);
 71	if (!ASSERT_OK_PTR(link_set_eunatch, "cg-attach-set_eunatch"))
 72		goto close_bpf_object;
 73	link_get_retval = bpf_program__attach_cgroup(obj->progs.get_retval,
 74						     cgroup_fd);
 75	if (!ASSERT_OK_PTR(link_get_retval, "cg-attach-get_retval"))
 76		goto close_bpf_object;
 77
 78	if (!ASSERT_ERR(setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR,
 79				   &zero, sizeof(int)), "setsockopt"))
 80		goto close_bpf_object;
 81	if (!ASSERT_EQ(errno, EUNATCH, "setsockopt-errno"))
 82		goto close_bpf_object;
 83
 84	if (!ASSERT_EQ(obj->bss->invocations, 2, "invocations"))
 85		goto close_bpf_object;
 86	if (!ASSERT_FALSE(obj->bss->assertion_error, "assertion_error"))
 87		goto close_bpf_object;
 88	if (!ASSERT_EQ(obj->bss->retval_value, -EUNATCH, "retval_value"))
 89		goto close_bpf_object;
 90
 91close_bpf_object:
 92	bpf_link__destroy(link_set_eunatch);
 93	bpf_link__destroy(link_get_retval);
 94
 95	cgroup_getset_retval_setsockopt__destroy(obj);
 96}
 97
 98static void test_setsockopt_default_zero(int cgroup_fd, int sock_fd)
 99{
100	struct cgroup_getset_retval_setsockopt *obj;
101	struct bpf_link *link_get_retval = NULL;
102
103	obj = cgroup_getset_retval_setsockopt__open_and_load();
104	if (!ASSERT_OK_PTR(obj, "skel-load"))
105		return;
106
107	obj->bss->page_size = sysconf(_SC_PAGESIZE);
108
109	/* Attach setsockopt that gets the previously set errno.
110	 * Assert that, without anything setting one, we get 0.
111	 */
112	link_get_retval = bpf_program__attach_cgroup(obj->progs.get_retval,
113						     cgroup_fd);
114	if (!ASSERT_OK_PTR(link_get_retval, "cg-attach-get_retval"))
115		goto close_bpf_object;
116
117	if (!ASSERT_OK(setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR,
118				  &zero, sizeof(int)), "setsockopt"))
119		goto close_bpf_object;
120
121	if (!ASSERT_EQ(obj->bss->invocations, 1, "invocations"))
122		goto close_bpf_object;
123	if (!ASSERT_FALSE(obj->bss->assertion_error, "assertion_error"))
124		goto close_bpf_object;
125	if (!ASSERT_EQ(obj->bss->retval_value, 0, "retval_value"))
126		goto close_bpf_object;
127
128close_bpf_object:
129	bpf_link__destroy(link_get_retval);
130
131	cgroup_getset_retval_setsockopt__destroy(obj);
132}
133
134static void test_setsockopt_default_zero_and_set(int cgroup_fd, int sock_fd)
135{
136	struct cgroup_getset_retval_setsockopt *obj;
137	struct bpf_link *link_get_retval = NULL, *link_set_eunatch = NULL;
138
139	obj = cgroup_getset_retval_setsockopt__open_and_load();
140	if (!ASSERT_OK_PTR(obj, "skel-load"))
141		return;
142
143	obj->bss->page_size = sysconf(_SC_PAGESIZE);
144
145	/* Attach setsockopt that gets the previously set errno, and then
146	 * one that sets the errno to EUNATCH. Assert that the get does not
147	 * see EUNATCH set later, and does not prevent EUNATCH from being set.
148	 */
149	link_get_retval = bpf_program__attach_cgroup(obj->progs.get_retval,
150						     cgroup_fd);
151	if (!ASSERT_OK_PTR(link_get_retval, "cg-attach-get_retval"))
152		goto close_bpf_object;
153	link_set_eunatch = bpf_program__attach_cgroup(obj->progs.set_eunatch,
154						      cgroup_fd);
155	if (!ASSERT_OK_PTR(link_set_eunatch, "cg-attach-set_eunatch"))
156		goto close_bpf_object;
157
158	if (!ASSERT_ERR(setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR,
159				   &zero, sizeof(int)), "setsockopt"))
160		goto close_bpf_object;
161	if (!ASSERT_EQ(errno, EUNATCH, "setsockopt-errno"))
162		goto close_bpf_object;
163
164	if (!ASSERT_EQ(obj->bss->invocations, 2, "invocations"))
165		goto close_bpf_object;
166	if (!ASSERT_FALSE(obj->bss->assertion_error, "assertion_error"))
167		goto close_bpf_object;
168	if (!ASSERT_EQ(obj->bss->retval_value, 0, "retval_value"))
169		goto close_bpf_object;
170
171close_bpf_object:
172	bpf_link__destroy(link_get_retval);
173	bpf_link__destroy(link_set_eunatch);
174
175	cgroup_getset_retval_setsockopt__destroy(obj);
176}
177
178static void test_setsockopt_override(int cgroup_fd, int sock_fd)
179{
180	struct cgroup_getset_retval_setsockopt *obj;
181	struct bpf_link *link_set_eunatch = NULL, *link_set_eisconn = NULL;
182	struct bpf_link *link_get_retval = NULL;
183
184	obj = cgroup_getset_retval_setsockopt__open_and_load();
185	if (!ASSERT_OK_PTR(obj, "skel-load"))
186		return;
187
188	obj->bss->page_size = sysconf(_SC_PAGESIZE);
189
190	/* Attach setsockopt that sets EUNATCH, then one that sets EISCONN,
191	 * and then one that gets the exported errno. Assert both the syscall
192	 * and the helper sees the last set errno.
193	 */
194	link_set_eunatch = bpf_program__attach_cgroup(obj->progs.set_eunatch,
195						      cgroup_fd);
196	if (!ASSERT_OK_PTR(link_set_eunatch, "cg-attach-set_eunatch"))
197		goto close_bpf_object;
198	link_set_eisconn = bpf_program__attach_cgroup(obj->progs.set_eisconn,
199						      cgroup_fd);
200	if (!ASSERT_OK_PTR(link_set_eisconn, "cg-attach-set_eisconn"))
201		goto close_bpf_object;
202	link_get_retval = bpf_program__attach_cgroup(obj->progs.get_retval,
203						     cgroup_fd);
204	if (!ASSERT_OK_PTR(link_get_retval, "cg-attach-get_retval"))
205		goto close_bpf_object;
206
207	if (!ASSERT_ERR(setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR,
208				   &zero, sizeof(int)), "setsockopt"))
209		goto close_bpf_object;
210	if (!ASSERT_EQ(errno, EISCONN, "setsockopt-errno"))
211		goto close_bpf_object;
212
213	if (!ASSERT_EQ(obj->bss->invocations, 3, "invocations"))
214		goto close_bpf_object;
215	if (!ASSERT_FALSE(obj->bss->assertion_error, "assertion_error"))
216		goto close_bpf_object;
217	if (!ASSERT_EQ(obj->bss->retval_value, -EISCONN, "retval_value"))
218		goto close_bpf_object;
219
220close_bpf_object:
221	bpf_link__destroy(link_set_eunatch);
222	bpf_link__destroy(link_set_eisconn);
223	bpf_link__destroy(link_get_retval);
224
225	cgroup_getset_retval_setsockopt__destroy(obj);
226}
227
228static void test_setsockopt_legacy_eperm(int cgroup_fd, int sock_fd)
229{
230	struct cgroup_getset_retval_setsockopt *obj;
231	struct bpf_link *link_legacy_eperm = NULL, *link_get_retval = NULL;
232
233	obj = cgroup_getset_retval_setsockopt__open_and_load();
234	if (!ASSERT_OK_PTR(obj, "skel-load"))
235		return;
236
237	obj->bss->page_size = sysconf(_SC_PAGESIZE);
238
239	/* Attach setsockopt that return a reject without setting errno
240	 * (legacy reject), and one that gets the errno. Assert that for
241	 * backward compatibility the syscall result in EPERM, and this
242	 * is also visible to the helper.
243	 */
244	link_legacy_eperm = bpf_program__attach_cgroup(obj->progs.legacy_eperm,
245						       cgroup_fd);
246	if (!ASSERT_OK_PTR(link_legacy_eperm, "cg-attach-legacy_eperm"))
247		goto close_bpf_object;
248	link_get_retval = bpf_program__attach_cgroup(obj->progs.get_retval,
249						     cgroup_fd);
250	if (!ASSERT_OK_PTR(link_get_retval, "cg-attach-get_retval"))
251		goto close_bpf_object;
252
253	if (!ASSERT_ERR(setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR,
254				   &zero, sizeof(int)), "setsockopt"))
255		goto close_bpf_object;
256	if (!ASSERT_EQ(errno, EPERM, "setsockopt-errno"))
257		goto close_bpf_object;
258
259	if (!ASSERT_EQ(obj->bss->invocations, 2, "invocations"))
260		goto close_bpf_object;
261	if (!ASSERT_FALSE(obj->bss->assertion_error, "assertion_error"))
262		goto close_bpf_object;
263	if (!ASSERT_EQ(obj->bss->retval_value, -EPERM, "retval_value"))
264		goto close_bpf_object;
265
266close_bpf_object:
267	bpf_link__destroy(link_legacy_eperm);
268	bpf_link__destroy(link_get_retval);
269
270	cgroup_getset_retval_setsockopt__destroy(obj);
271}
272
273static void test_setsockopt_legacy_no_override(int cgroup_fd, int sock_fd)
274{
275	struct cgroup_getset_retval_setsockopt *obj;
276	struct bpf_link *link_set_eunatch = NULL, *link_legacy_eperm = NULL;
277	struct bpf_link *link_get_retval = NULL;
278
279	obj = cgroup_getset_retval_setsockopt__open_and_load();
280	if (!ASSERT_OK_PTR(obj, "skel-load"))
281		return;
282
283	obj->bss->page_size = sysconf(_SC_PAGESIZE);
284
285	/* Attach setsockopt that sets EUNATCH, then one that return a reject
286	 * without setting errno, and then one that gets the exported errno.
287	 * Assert both the syscall and the helper's errno are unaffected by
288	 * the second prog (i.e. legacy rejects does not override the errno
289	 * to EPERM).
290	 */
291	link_set_eunatch = bpf_program__attach_cgroup(obj->progs.set_eunatch,
292						      cgroup_fd);
293	if (!ASSERT_OK_PTR(link_set_eunatch, "cg-attach-set_eunatch"))
294		goto close_bpf_object;
295	link_legacy_eperm = bpf_program__attach_cgroup(obj->progs.legacy_eperm,
296						       cgroup_fd);
297	if (!ASSERT_OK_PTR(link_legacy_eperm, "cg-attach-legacy_eperm"))
298		goto close_bpf_object;
299	link_get_retval = bpf_program__attach_cgroup(obj->progs.get_retval,
300						     cgroup_fd);
301	if (!ASSERT_OK_PTR(link_get_retval, "cg-attach-get_retval"))
302		goto close_bpf_object;
303
304	if (!ASSERT_ERR(setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR,
305				   &zero, sizeof(int)), "setsockopt"))
306		goto close_bpf_object;
307	if (!ASSERT_EQ(errno, EUNATCH, "setsockopt-errno"))
308		goto close_bpf_object;
309
310	if (!ASSERT_EQ(obj->bss->invocations, 3, "invocations"))
311		goto close_bpf_object;
312	if (!ASSERT_FALSE(obj->bss->assertion_error, "assertion_error"))
313		goto close_bpf_object;
314	if (!ASSERT_EQ(obj->bss->retval_value, -EUNATCH, "retval_value"))
315		goto close_bpf_object;
316
317close_bpf_object:
318	bpf_link__destroy(link_set_eunatch);
319	bpf_link__destroy(link_legacy_eperm);
320	bpf_link__destroy(link_get_retval);
321
322	cgroup_getset_retval_setsockopt__destroy(obj);
323}
324
325static void test_getsockopt_get(int cgroup_fd, int sock_fd)
326{
327	struct cgroup_getset_retval_getsockopt *obj;
328	struct bpf_link *link_get_retval = NULL;
329	int buf;
330	socklen_t optlen = sizeof(buf);
331
332	obj = cgroup_getset_retval_getsockopt__open_and_load();
333	if (!ASSERT_OK_PTR(obj, "skel-load"))
334		return;
335
336	obj->bss->page_size = sysconf(_SC_PAGESIZE);
337
338	/* Attach getsockopt that gets previously set errno. Assert that the
339	 * error from kernel is in both ctx_retval_value and retval_value.
340	 */
341	link_get_retval = bpf_program__attach_cgroup(obj->progs.get_retval,
342						     cgroup_fd);
343	if (!ASSERT_OK_PTR(link_get_retval, "cg-attach-get_retval"))
344		goto close_bpf_object;
345
346	if (!ASSERT_ERR(getsockopt(sock_fd, SOL_CUSTOM, 0,
347				   &buf, &optlen), "getsockopt"))
348		goto close_bpf_object;
349	if (!ASSERT_EQ(errno, EOPNOTSUPP, "getsockopt-errno"))
350		goto close_bpf_object;
351
352	if (!ASSERT_EQ(obj->bss->invocations, 1, "invocations"))
353		goto close_bpf_object;
354	if (!ASSERT_FALSE(obj->bss->assertion_error, "assertion_error"))
355		goto close_bpf_object;
356	if (!ASSERT_EQ(obj->bss->retval_value, -EOPNOTSUPP, "retval_value"))
357		goto close_bpf_object;
358	if (!ASSERT_EQ(obj->bss->ctx_retval_value, -EOPNOTSUPP, "ctx_retval_value"))
359		goto close_bpf_object;
360
361close_bpf_object:
362	bpf_link__destroy(link_get_retval);
363
364	cgroup_getset_retval_getsockopt__destroy(obj);
365}
366
367static void test_getsockopt_override(int cgroup_fd, int sock_fd)
368{
369	struct cgroup_getset_retval_getsockopt *obj;
370	struct bpf_link *link_set_eisconn = NULL;
371	int buf;
372	socklen_t optlen = sizeof(buf);
373
374	obj = cgroup_getset_retval_getsockopt__open_and_load();
375	if (!ASSERT_OK_PTR(obj, "skel-load"))
376		return;
377
378	obj->bss->page_size = sysconf(_SC_PAGESIZE);
379
380	/* Attach getsockopt that sets retval to -EISCONN. Assert that this
381	 * overrides the value from kernel.
382	 */
383	link_set_eisconn = bpf_program__attach_cgroup(obj->progs.set_eisconn,
384						      cgroup_fd);
385	if (!ASSERT_OK_PTR(link_set_eisconn, "cg-attach-set_eisconn"))
386		goto close_bpf_object;
387
388	if (!ASSERT_ERR(getsockopt(sock_fd, SOL_CUSTOM, 0,
389				   &buf, &optlen), "getsockopt"))
390		goto close_bpf_object;
391	if (!ASSERT_EQ(errno, EISCONN, "getsockopt-errno"))
392		goto close_bpf_object;
393
394	if (!ASSERT_EQ(obj->bss->invocations, 1, "invocations"))
395		goto close_bpf_object;
396	if (!ASSERT_FALSE(obj->bss->assertion_error, "assertion_error"))
397		goto close_bpf_object;
398
399close_bpf_object:
400	bpf_link__destroy(link_set_eisconn);
401
402	cgroup_getset_retval_getsockopt__destroy(obj);
403}
404
405static void test_getsockopt_retval_sync(int cgroup_fd, int sock_fd)
406{
407	struct cgroup_getset_retval_getsockopt *obj;
408	struct bpf_link *link_set_eisconn = NULL, *link_clear_retval = NULL;
409	struct bpf_link *link_get_retval = NULL;
410	int buf;
411	socklen_t optlen = sizeof(buf);
412
413	obj = cgroup_getset_retval_getsockopt__open_and_load();
414	if (!ASSERT_OK_PTR(obj, "skel-load"))
415		return;
416
417	obj->bss->page_size = sysconf(_SC_PAGESIZE);
418
419	/* Attach getsockopt that sets retval to -EISCONN, and one that clears
420	 * ctx retval. Assert that the clearing ctx retval is synced to helper
421	 * and clears any errors both from kernel and BPF..
422	 */
423	link_set_eisconn = bpf_program__attach_cgroup(obj->progs.set_eisconn,
424						      cgroup_fd);
425	if (!ASSERT_OK_PTR(link_set_eisconn, "cg-attach-set_eisconn"))
426		goto close_bpf_object;
427	link_clear_retval = bpf_program__attach_cgroup(obj->progs.clear_retval,
428						       cgroup_fd);
429	if (!ASSERT_OK_PTR(link_clear_retval, "cg-attach-clear_retval"))
430		goto close_bpf_object;
431	link_get_retval = bpf_program__attach_cgroup(obj->progs.get_retval,
432						     cgroup_fd);
433	if (!ASSERT_OK_PTR(link_get_retval, "cg-attach-get_retval"))
434		goto close_bpf_object;
435
436	if (!ASSERT_OK(getsockopt(sock_fd, SOL_CUSTOM, 0,
437				  &buf, &optlen), "getsockopt"))
438		goto close_bpf_object;
439
440	if (!ASSERT_EQ(obj->bss->invocations, 3, "invocations"))
441		goto close_bpf_object;
442	if (!ASSERT_FALSE(obj->bss->assertion_error, "assertion_error"))
443		goto close_bpf_object;
444	if (!ASSERT_EQ(obj->bss->retval_value, 0, "retval_value"))
445		goto close_bpf_object;
446	if (!ASSERT_EQ(obj->bss->ctx_retval_value, 0, "ctx_retval_value"))
447		goto close_bpf_object;
448
449close_bpf_object:
450	bpf_link__destroy(link_set_eisconn);
451	bpf_link__destroy(link_clear_retval);
452	bpf_link__destroy(link_get_retval);
453
454	cgroup_getset_retval_getsockopt__destroy(obj);
455}
456
457struct exposed_hook {
458	const char *name;
459	int expected_err;
460} exposed_hooks[] = {
461
462#define BPF_RETVAL_HOOK(NAME, SECTION, CTX, EXPECTED_ERR) \
463	{ \
464		.name = #NAME, \
465		.expected_err = EXPECTED_ERR, \
466	},
467
468#include "cgroup_getset_retval_hooks.h"
469
470#undef BPF_RETVAL_HOOK
471};
472
473static void test_exposed_hooks(int cgroup_fd, int sock_fd)
474{
475	struct cgroup_getset_retval_hooks *skel;
476	struct bpf_program *prog;
477	int err;
478	int i;
479
480	for (i = 0; i < ARRAY_SIZE(exposed_hooks); i++) {
481		skel = cgroup_getset_retval_hooks__open();
482		if (!ASSERT_OK_PTR(skel, "cgroup_getset_retval_hooks__open"))
483			continue;
484
485		prog = bpf_object__find_program_by_name(skel->obj, exposed_hooks[i].name);
486		if (!ASSERT_NEQ(prog, NULL, "bpf_object__find_program_by_name"))
487			goto close_skel;
488
489		err = bpf_program__set_autoload(prog, true);
490		if (!ASSERT_OK(err, "bpf_program__set_autoload"))
491			goto close_skel;
492
493		err = cgroup_getset_retval_hooks__load(skel);
494		ASSERT_EQ(err, exposed_hooks[i].expected_err, "expected_err");
495
496close_skel:
497		cgroup_getset_retval_hooks__destroy(skel);
498	}
499}
500
501void test_cgroup_getset_retval(void)
502{
503	int cgroup_fd = -1;
504	int sock_fd = -1;
505
506	cgroup_fd = test__join_cgroup("/cgroup_getset_retval");
507	if (!ASSERT_GE(cgroup_fd, 0, "cg-create"))
508		goto close_fd;
509
510	sock_fd = start_server(AF_INET, SOCK_DGRAM, NULL, 0, 0);
511	if (!ASSERT_GE(sock_fd, 0, "start-server"))
512		goto close_fd;
513
514	if (test__start_subtest("setsockopt-set"))
515		test_setsockopt_set(cgroup_fd, sock_fd);
516
517	if (test__start_subtest("setsockopt-set_and_get"))
518		test_setsockopt_set_and_get(cgroup_fd, sock_fd);
519
520	if (test__start_subtest("setsockopt-default_zero"))
521		test_setsockopt_default_zero(cgroup_fd, sock_fd);
522
523	if (test__start_subtest("setsockopt-default_zero_and_set"))
524		test_setsockopt_default_zero_and_set(cgroup_fd, sock_fd);
525
526	if (test__start_subtest("setsockopt-override"))
527		test_setsockopt_override(cgroup_fd, sock_fd);
528
529	if (test__start_subtest("setsockopt-legacy_eperm"))
530		test_setsockopt_legacy_eperm(cgroup_fd, sock_fd);
531
532	if (test__start_subtest("setsockopt-legacy_no_override"))
533		test_setsockopt_legacy_no_override(cgroup_fd, sock_fd);
534
535	if (test__start_subtest("getsockopt-get"))
536		test_getsockopt_get(cgroup_fd, sock_fd);
537
538	if (test__start_subtest("getsockopt-override"))
539		test_getsockopt_override(cgroup_fd, sock_fd);
540
541	if (test__start_subtest("getsockopt-retval_sync"))
542		test_getsockopt_retval_sync(cgroup_fd, sock_fd);
543
544	if (test__start_subtest("exposed_hooks"))
545		test_exposed_hooks(cgroup_fd, sock_fd);
546
547close_fd:
548	close(cgroup_fd);
549}
1