1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
2f08c3bdfSopenharmony_ci/*
3f08c3bdfSopenharmony_ci * Copyright (c) 2017 Fujitsu Ltd.
4f08c3bdfSopenharmony_ci * Author: Xiao Yang <yangx.jy@cn.fujitsu.com>
5f08c3bdfSopenharmony_ci */
6f08c3bdfSopenharmony_ci
7f08c3bdfSopenharmony_ci/*
8f08c3bdfSopenharmony_ci * Description:
9f08c3bdfSopenharmony_ci * fcntl(2) manpage states that an unprivileged user could not set the
10f08c3bdfSopenharmony_ci * pipe capacity above the limit in /proc/sys/fs/pipe-max-size.  However,
11f08c3bdfSopenharmony_ci * an unprivileged user could create a pipe whose initial capacity exceeds
12f08c3bdfSopenharmony_ci * the limit.  We add a regression test to check that pipe-max-size caps
13f08c3bdfSopenharmony_ci * the initial allocation for a new pipe for unprivileged users, but not
14f08c3bdfSopenharmony_ci * for privileged users.
15f08c3bdfSopenharmony_ci *
16f08c3bdfSopenharmony_ci * This kernel bug has been fixed by:
17f08c3bdfSopenharmony_ci *
18f08c3bdfSopenharmony_ci * commit 086e774a57fba4695f14383c0818994c0b31da7c
19f08c3bdfSopenharmony_ci * Author: Michael Kerrisk (man-pages) <mtk.manpages@gmail.com>
20f08c3bdfSopenharmony_ci * Date:   Tue Oct 11 13:53:43 2016 -0700
21f08c3bdfSopenharmony_ci *
22f08c3bdfSopenharmony_ci * pipe: cap initial pipe capacity according to pipe-max-size limit
23f08c3bdfSopenharmony_ci */
24f08c3bdfSopenharmony_ci
25f08c3bdfSopenharmony_ci#include <errno.h>
26f08c3bdfSopenharmony_ci#include <sys/types.h>
27f08c3bdfSopenharmony_ci#include <pwd.h>
28f08c3bdfSopenharmony_ci#include <unistd.h>
29f08c3bdfSopenharmony_ci#include <stdlib.h>
30f08c3bdfSopenharmony_ci
31f08c3bdfSopenharmony_ci#include "lapi/fcntl.h"
32f08c3bdfSopenharmony_ci#include "tst_test.h"
33f08c3bdfSopenharmony_ci
34f08c3bdfSopenharmony_cistatic int pipe_max_unpriv;
35f08c3bdfSopenharmony_cistatic int test_max_unpriv;
36f08c3bdfSopenharmony_cistatic int test_max_priv;
37f08c3bdfSopenharmony_cistatic struct passwd *pw;
38f08c3bdfSopenharmony_cistatic struct tcase {
39f08c3bdfSopenharmony_ci	int *exp_sz;
40f08c3bdfSopenharmony_ci	int exp_usr;
41f08c3bdfSopenharmony_ci	char *des;
42f08c3bdfSopenharmony_ci} tcases[] = {
43f08c3bdfSopenharmony_ci	{&test_max_unpriv, 1, "an unprivileged user"},
44f08c3bdfSopenharmony_ci	{&test_max_priv, 0, "a privileged user"}
45f08c3bdfSopenharmony_ci};
46f08c3bdfSopenharmony_ci
47f08c3bdfSopenharmony_cistatic void setup(void)
48f08c3bdfSopenharmony_ci{
49f08c3bdfSopenharmony_ci	test_max_unpriv = getpagesize();
50f08c3bdfSopenharmony_ci	test_max_priv = test_max_unpriv * 16;
51f08c3bdfSopenharmony_ci
52f08c3bdfSopenharmony_ci	if (!access("/proc/sys/fs/pipe-max-size", F_OK)) {
53f08c3bdfSopenharmony_ci		SAFE_FILE_SCANF("/proc/sys/fs/pipe-max-size", "%d",
54f08c3bdfSopenharmony_ci				&pipe_max_unpriv);
55f08c3bdfSopenharmony_ci		SAFE_FILE_PRINTF("/proc/sys/fs/pipe-max-size", "%d",
56f08c3bdfSopenharmony_ci				test_max_unpriv);
57f08c3bdfSopenharmony_ci	} else {
58f08c3bdfSopenharmony_ci		tst_brk(TCONF, "/proc/sys/fs/pipe-max-size doesn't exist");
59f08c3bdfSopenharmony_ci	}
60f08c3bdfSopenharmony_ci
61f08c3bdfSopenharmony_ci	pw = SAFE_GETPWNAM("nobody");
62f08c3bdfSopenharmony_ci}
63f08c3bdfSopenharmony_ci
64f08c3bdfSopenharmony_cistatic void cleanup(void)
65f08c3bdfSopenharmony_ci{
66f08c3bdfSopenharmony_ci	SAFE_FILE_PRINTF("/proc/sys/fs/pipe-max-size", "%d", pipe_max_unpriv);
67f08c3bdfSopenharmony_ci}
68f08c3bdfSopenharmony_ci
69f08c3bdfSopenharmony_cistatic int verify_pipe_size(int exp_pip_sz, char *desp)
70f08c3bdfSopenharmony_ci{
71f08c3bdfSopenharmony_ci	int get_size;
72f08c3bdfSopenharmony_ci	int fds[2];
73f08c3bdfSopenharmony_ci
74f08c3bdfSopenharmony_ci	SAFE_PIPE(fds);
75f08c3bdfSopenharmony_ci
76f08c3bdfSopenharmony_ci	get_size = fcntl(fds[1], F_GETPIPE_SZ);
77f08c3bdfSopenharmony_ci	if (get_size == -1) {
78f08c3bdfSopenharmony_ci		tst_res(TFAIL | TERRNO, "fcntl(2) with F_GETPIPE_SZ failed");
79f08c3bdfSopenharmony_ci		goto end;
80f08c3bdfSopenharmony_ci	}
81f08c3bdfSopenharmony_ci
82f08c3bdfSopenharmony_ci	if (get_size != exp_pip_sz) {
83f08c3bdfSopenharmony_ci		tst_res(TFAIL, "%s init the capacity of a pipe to %d "
84f08c3bdfSopenharmony_ci			"unexpectedly, expected %d", desp, get_size,
85f08c3bdfSopenharmony_ci			exp_pip_sz);
86f08c3bdfSopenharmony_ci	} else {
87f08c3bdfSopenharmony_ci		tst_res(TPASS, "%s init the capacity of a pipe to %d "
88f08c3bdfSopenharmony_ci			"successfully", desp, exp_pip_sz);
89f08c3bdfSopenharmony_ci	}
90f08c3bdfSopenharmony_ci
91f08c3bdfSopenharmony_ciend:
92f08c3bdfSopenharmony_ci	if (fds[0] > 0)
93f08c3bdfSopenharmony_ci		SAFE_CLOSE(fds[0]);
94f08c3bdfSopenharmony_ci
95f08c3bdfSopenharmony_ci	if (fds[1] > 0)
96f08c3bdfSopenharmony_ci		SAFE_CLOSE(fds[1]);
97f08c3bdfSopenharmony_ci
98f08c3bdfSopenharmony_ci	exit(0);
99f08c3bdfSopenharmony_ci}
100f08c3bdfSopenharmony_ci
101f08c3bdfSopenharmony_cistatic void do_test(unsigned int n)
102f08c3bdfSopenharmony_ci{
103f08c3bdfSopenharmony_ci	struct tcase *tc = &tcases[n];
104f08c3bdfSopenharmony_ci
105f08c3bdfSopenharmony_ci	if (!SAFE_FORK()) {
106f08c3bdfSopenharmony_ci		if (tc->exp_usr)
107f08c3bdfSopenharmony_ci			SAFE_SETUID(pw->pw_uid);
108f08c3bdfSopenharmony_ci
109f08c3bdfSopenharmony_ci		verify_pipe_size(*tc->exp_sz, tc->des);
110f08c3bdfSopenharmony_ci	}
111f08c3bdfSopenharmony_ci
112f08c3bdfSopenharmony_ci	tst_reap_children();
113f08c3bdfSopenharmony_ci}
114f08c3bdfSopenharmony_ci
115f08c3bdfSopenharmony_cistatic struct tst_test test = {
116f08c3bdfSopenharmony_ci	.needs_root = 1,
117f08c3bdfSopenharmony_ci	.forks_child = 1,
118f08c3bdfSopenharmony_ci	.tcnt = ARRAY_SIZE(tcases),
119f08c3bdfSopenharmony_ci	.setup = setup,
120f08c3bdfSopenharmony_ci	.cleanup = cleanup,
121f08c3bdfSopenharmony_ci	.test = do_test,
122f08c3bdfSopenharmony_ci	.tags = (const struct tst_tag[]) {
123f08c3bdfSopenharmony_ci		{"linux-git", "086e774a57fb"},
124f08c3bdfSopenharmony_ci		{}
125f08c3bdfSopenharmony_ci	}
126f08c3bdfSopenharmony_ci};
127