1 /* Copyright (c) 2015-2019, The Tor Project, Inc. */
2 /* See LICENSE for licensing information */
4 #include "core/or/or.h"
5 #include "lib/process/setuid.h"
7 #ifdef HAVE_SYS_CAPABILITY_H
8 #include <sys/capability.h>
14 #define TEST_BUILT_WITH_CAPS 0
15 #define TEST_HAVE_CAPS 1
16 #define TEST_ROOT_CAN_BIND_LOW 2
18 #define TEST_SETUID_KEEPCAPS 4
19 #define TEST_SETUID_STRICT 5
25 { "built-with-caps", TEST_BUILT_WITH_CAPS
},
26 { "have-caps", TEST_HAVE_CAPS
},
27 { "root-bind-low", TEST_ROOT_CAN_BIND_LOW
},
28 { "setuid", TEST_SETUID
},
29 { "setuid-keepcaps", TEST_SETUID_KEEPCAPS
},
30 { "setuid-strict", TEST_SETUID_STRICT
},
35 /* 0 on no, 1 on yes, -1 on failure. */
37 check_can_bind_low_ports(void)
40 struct sockaddr_in sin
;
41 memset(&sin
, 0, sizeof(sin
));
42 sin
.sin_family
= AF_INET
;
44 for (port
= 600; port
< 1024; ++port
) {
45 sin
.sin_port
= htons(port
);
46 tor_socket_t fd
= socket(AF_INET
, SOCK_STREAM
, IPPROTO_TCP
);
47 if (! SOCKET_OK(fd
)) {
53 if (setsockopt(fd
, SOL_SOCKET
,SO_REUSEADDR
, (void*)&one
,
54 (socklen_t
)sizeof(one
))) {
56 tor_close_socket_simple(fd
);
60 int res
= bind(fd
, (struct sockaddr
*)&sin
, sizeof(sin
));
61 tor_close_socket_simple(fd
);
64 /* bind was successful */
66 } else if (errno
== EACCES
|| errno
== EPERM
) {
67 /* Got a permission-denied error. */
69 } else if (errno
== EADDRINUSE
) {
70 /* Huh; somebody is using that port. */
78 #endif /* !defined(_WIN32) */
81 main(int argc
, char **argv
)
88 fprintf(stderr
, "This test is not supported on your OS.\n");
90 #else /* !(defined(_WIN32)) */
94 fprintf(stderr
, "I want 2 arguments: a username and a command.\n");
98 fprintf(stderr
, "This test only works when it's run as root.\n");
105 for (i
= 0; which_test
[i
].name
; ++i
) {
106 if (!strcmp(which_test
[i
].name
, testname
)) {
107 test_id
= which_test
[i
].test_id
;
112 fprintf(stderr
, "Unrecognized test '%s'\n", testname
);
116 #ifdef HAVE_LINUX_CAPABILITIES
117 const int have_cap_support
= 1;
119 const int have_cap_support
= 0;
125 log_severity_list_t sev
;
126 memset(&sev
, 0, sizeof(sev
));
127 set_log_severity_config(LOG_WARN
, LOG_ERR
, &sev
);
128 add_stream_log(&sev
, "", fileno(stderr
));
132 case TEST_BUILT_WITH_CAPS
:
133 /* Succeed if we were built with capability support. */
134 okay
= have_cap_support
;
137 /* Succeed if "capabilities work" == "we were built with capability
139 okay
= have_cap_support
== have_capability_support();
141 case TEST_ROOT_CAN_BIND_LOW
:
142 /* Succeed if root can bind low ports. */
143 okay
= check_can_bind_low_ports() == 1;
146 /* Succeed if we can do a setuid with no capability retention, and doing
147 * so makes us lose the ability to bind low ports */
148 case TEST_SETUID_KEEPCAPS
:
149 /* Succeed if we can do a setuid with capability retention, and doing so
150 * does not make us lose the ability to bind low ports */
152 int keepcaps
= (test_id
== TEST_SETUID_KEEPCAPS
);
153 okay
= switch_id(username
, keepcaps
? SWITCH_ID_KEEP_BINDLOW
: 0) == 0;
155 okay
= check_can_bind_low_ports() == keepcaps
;
159 case TEST_SETUID_STRICT
:
160 /* Succeed if, after a setuid, we cannot setuid back, and we cannot
161 * re-grab any capabilities. */
162 okay
= switch_id(username
, SWITCH_ID_KEEP_BINDLOW
) == 0;
164 /* We'd better not be able to setuid back! */
165 if (setuid(0) == 0 || errno
!= EPERM
) {
169 #ifdef HAVE_LINUX_CAPABILITIES
171 cap_t caps
= cap_get_proc();
172 const cap_value_t caplist
[] = {
175 cap_set_flag(caps
, CAP_PERMITTED
, 1, caplist
, CAP_SET
);
176 if (cap_set_proc(caps
) == 0 || errno
!= EPERM
) {
181 #endif /* defined(HAVE_LINUX_CAPABILITIES) */
184 fprintf(stderr
, "Unsupported test '%s'\n", testname
);
190 fprintf(stderr
, "Test %s failed!\n", testname
);
193 return (okay
? 0 : 1);
194 #endif /* defined(_WIN32) */