2020#include <netinet/in.h>
2121#include <pwd.h>
2222#include <sys/capability.h>
23+ #include <sys/prctl.h>
2324#include <sys/socket.h>
2425#include <sys/wait.h>
2526#include <unistd.h>
@@ -66,8 +67,9 @@ static void show_capabilities(void) {
6667 cap_free (text );
6768}
6869
69- static int setup_tests (void ) {
70+ static int setup_tests (bool * run_ambient ) {
7071 struct passwd * nobody ;
72+ int r ;
7173
7274 nobody = getpwnam ("nobody" );
7375 if (!nobody ) {
@@ -77,6 +79,18 @@ static int setup_tests(void) {
7779 test_uid = nobody -> pw_uid ;
7880 test_gid = nobody -> pw_gid ;
7981
82+ * run_ambient = false;
83+
84+ r = prctl (PR_CAP_AMBIENT , PR_CAP_AMBIENT_CLEAR_ALL , 0 , 0 , 0 );
85+
86+ /* There's support for PR_CAP_AMBIENT if the prctl() call
87+ * succeeded or error code was something else than EINVAL. The
88+ * EINVAL check should be good enough to rule out false
89+ * positives. */
90+
91+ if (r >= 0 || errno != EINVAL )
92+ * run_ambient = true;
93+
8094 return 0 ;
8195}
8296
@@ -140,23 +154,73 @@ static void test_have_effective_cap(void) {
140154 assert_se (!have_effective_cap (CAP_CHOWN ));
141155}
142156
157+ static void test_update_inherited_set (void ) {
158+ cap_t caps ;
159+ uint64_t set = 0 ;
160+ cap_flag_value_t fv ;
161+
162+ caps = cap_get_proc ();
163+ assert_se (caps );
164+ assert_se (!cap_get_flag (caps , CAP_CHOWN , CAP_INHERITABLE , & fv ));
165+ assert (fv == CAP_CLEAR );
166+
167+ set = (UINT64_C (1 ) << CAP_CHOWN );
168+
169+ assert_se (!capability_update_inherited_set (caps , set ));
170+ assert_se (!cap_get_flag (caps , CAP_CHOWN , CAP_INHERITABLE , & fv ));
171+ assert (fv == CAP_SET );
172+
173+ cap_free (caps );
174+ }
175+
176+ static void test_set_ambient_caps (void ) {
177+ cap_t caps ;
178+ uint64_t set = 0 ;
179+ cap_flag_value_t fv ;
180+
181+ caps = cap_get_proc ();
182+ assert_se (caps );
183+ assert_se (!cap_get_flag (caps , CAP_CHOWN , CAP_INHERITABLE , & fv ));
184+ assert (fv == CAP_CLEAR );
185+ cap_free (caps );
186+
187+ assert_se (prctl (PR_CAP_AMBIENT , PR_CAP_AMBIENT_IS_SET , CAP_CHOWN , 0 , 0 ) == 0 );
188+
189+ set = (UINT64_C (1 ) << CAP_CHOWN );
190+
191+ assert_se (!capability_ambient_set_apply (set , true));
192+
193+ caps = cap_get_proc ();
194+ assert_se (!cap_get_flag (caps , CAP_CHOWN , CAP_INHERITABLE , & fv ));
195+ assert (fv == CAP_SET );
196+ cap_free (caps );
197+
198+ assert_se (prctl (PR_CAP_AMBIENT , PR_CAP_AMBIENT_IS_SET , CAP_CHOWN , 0 , 0 ) == 1 );
199+ }
200+
143201int main (int argc , char * argv []) {
144202 int r ;
203+ bool run_ambient ;
145204
146205 log_parse_environment ();
147206 log_open ();
148207
149208 if (getuid () != 0 )
150209 return EXIT_TEST_SKIP ;
151210
152- r = setup_tests ();
211+ r = setup_tests (& run_ambient );
153212 if (r < 0 )
154213 return - r ;
155214
156215 show_capabilities ();
157216
158217 test_drop_privileges ();
218+ test_update_inherited_set ();
219+
159220 fork_test (test_have_effective_cap );
160221
222+ if (run_ambient )
223+ fork_test (test_set_ambient_caps );
224+
161225 return 0 ;
162226}
0 commit comments