Add tests for sctp_socket type_transition rules and also using setsockcreatecon(3) Signed-off-by: Richard Haines <richard_c_haines@xxxxxxxxxxxxxx> --- policy/test_sctp.te | 57 ++++++++++++++++++++++++++++++++ tests/sctp/sctp_client.c | 19 +++++++++-- tests/sctp/sctp_common.c | 51 ++++++++++++++++++++++++++++ tests/sctp/sctp_common.h | 2 ++ tests/sctp/sctp_peeloff_client.c | 21 +++++++++--- tests/sctp/sctp_peeloff_server.c | 18 ++++++++-- tests/sctp/sctp_server.c | 18 ++++++++-- tests/sctp/test | 57 +++++++++++++++++++++++++++++++- 8 files changed, 231 insertions(+), 12 deletions(-) diff --git a/policy/test_sctp.te b/policy/test_sctp.te index 363e3c5..de82906 100644 --- a/policy/test_sctp.te +++ b/policy/test_sctp.te @@ -67,6 +67,11 @@ mcs_constrained(test_sctp_server_t) dontaudit test_sctp_server_t self:netlink_route_socket { create getattr bind }; dontaudit test_sctp_server_t self:udp_socket { getattr connect }; +# Set new socket context with setsockcreatecon(3): +type server_setsockcreatecon_newcon_t; +unconfined_runs_test(server_setsockcreatecon_newcon_t) +allow test_sctp_server_t server_setsockcreatecon_newcon_t:sctp_socket { create setopt write read }; + # ############################### Client ################################# # @@ -252,6 +257,58 @@ allow sctpsocketdomain sysctl_net_t:dir { search }; allow sctpsocketdomain self:udp_socket { create }; allow sctpsocketdomain self:unix_dgram_socket { create ioctl }; +# +##### Test type_transition rule for sctp_socket and setsockcreatecon(3) ##### +# +type test_sctp_new_type_client_t; +domain_type(test_sctp_new_type_client_t) +unconfined_runs_test(test_sctp_new_type_client_t) +typeattribute test_sctp_new_type_client_t testdomain; +typeattribute test_sctp_new_type_client_t sctpsocketdomain; +allow test_sctp_new_type_client_t self:sctp_socket create_stream_socket_perms; +allow test_sctp_server_t test_sctp_new_type_client_t:peer { recv }; +allow test_sctp_new_type_client_t test_sctp_server_t:peer { recv }; +allow test_sctp_new_type_client_t netlabel_sctp_peer_t:peer { recv }; +corenet_inout_generic_node(test_sctp_new_type_client_t) +corenet_inout_generic_if(test_sctp_new_type_client_t) + +# Set new socket context with type_transition rule: +type client_type_transition_newcon_t; +unconfined_runs_test(client_type_transition_newcon_t) +type_transition test_sctp_new_type_client_t test_sctp_new_type_client_t:sctp_socket client_type_transition_newcon_t; +allow test_sctp_new_type_client_t client_type_transition_newcon_t:sctp_socket { create getopt setopt connect write read }; +corenet_sctp_connect_generic_port(client_type_transition_newcon_t) +allow client_type_transition_newcon_t netlabel_peer_t:peer recv; +corenet_inout_generic_node(client_type_transition_newcon_t) +corenet_inout_generic_if(client_type_transition_newcon_t) + +# Set new socket context with setsockcreatecon(3): +type client_setsockcreatecon_newcon_t; +unconfined_runs_test(client_setsockcreatecon_newcon_t) +allow test_sctp_new_type_client_t client_setsockcreatecon_newcon_t:sctp_socket { create getopt setopt connect write read }; +corenet_sctp_connect_generic_port(client_setsockcreatecon_newcon_t) + +############# Deny sctp_socket { create } tests #################### +type test_sctp_new_type_deny_client_t; +domain_type(test_sctp_new_type_deny_client_t) +unconfined_runs_test(test_sctp_new_type_deny_client_t) +typeattribute test_sctp_new_type_deny_client_t testdomain; +typeattribute test_sctp_new_type_deny_client_t sctpsocketdomain; +allow test_sctp_new_type_deny_client_t self:sctp_socket create_stream_socket_perms; +allow test_sctp_server_t test_sctp_new_type_deny_client_t:peer { recv }; +allow test_sctp_new_type_deny_client_t test_sctp_server_t:peer { recv }; + +# Deny with type_transition rule: +type client_type_transition_newcon_deny_t; +unconfined_runs_test(client_type_transition_newcon_deny_t) +type_transition test_sctp_new_type_deny_client_t test_sctp_new_type_deny_client_t:sctp_socket client_type_transition_newcon_deny_t; +allow test_sctp_new_type_deny_client_t client_type_transition_newcon_deny_t:sctp_socket { getopt setopt }; + +# Deny with setsockcreatecon(3): +type client_setsockcreatecon_newcon_deny_t; +unconfined_runs_test(client_setsockcreatecon_newcon_deny_t) +allow test_sctp_new_type_client_t client_setsockcreatecon_newcon_deny_t:sctp_socket { getopt setopt }; + # ############ Allow these domains to be entered from sysadm domain ############ # diff --git a/tests/sctp/sctp_client.c b/tests/sctp/sctp_client.c index 2f527ed..ee6068a 100644 --- a/tests/sctp/sctp_client.c +++ b/tests/sctp/sctp_client.c @@ -3,13 +3,14 @@ static void usage(char *progname) { fprintf(stderr, - "usage: %s [-e expected_msg] [-v] [-n] [-x] stream|seq addr port\n" + "usage: %s [-e expected_msg] [-v] [-n] [-t type] [-x] stream|seq addr port\n" "\nWhere:\n\t" "-e Optional expected message from server e.g. \"nopeer\".\n\t" " If not present the client context will be used as a\n\t" " comparison with the servers reply.\n\t" "-n Do NOT call connect(3) or connectx(3).\n\t" + "-t New type for setsockcreatecon(3) test.\n\t" "-v Print context and ip options information.\n\t" "-x Use sctp_connectx(3) instead of connect(3).\n\t" "stream Use SCTP 1-to-1 style or:\n\t" @@ -27,10 +28,10 @@ int main(int argc, char **argv) char byte = 0x41, label[1024], *expected = NULL; bool verbose = false, connectx = false, no_connects = false; bool ipv4 = false, expect_ipopt = false; - char *context; + char *context, *sock_type = NULL; struct timeval tm; - while ((opt = getopt(argc, argv, "e:vxmni")) != -1) { + while ((opt = getopt(argc, argv, "e:vt:xmni")) != -1) { switch (opt) { case 'e': expected = optarg; @@ -44,6 +45,9 @@ int main(int argc, char **argv) case 'n': no_connects = true; break; + case 't': + sock_type = optarg; + break; case 'x': connectx = true; break; @@ -83,6 +87,15 @@ int main(int argc, char **argv) if (serverinfo->ai_family == AF_INET) ipv4 = true; + /* If -t option set new context for socket */ + if (sock_type) { + result = set_newsock_con(sock_type, "Client"); + if (result < 0) { + fprintf(stderr, "Failed setsockcreatecon(3)\n"); + exit(2); + } + } + sock = socket(serverinfo->ai_family, serverinfo->ai_socktype, serverinfo->ai_protocol); if (sock < 0) { diff --git a/tests/sctp/sctp_common.c b/tests/sctp/sctp_common.c index 8b65870..4b25435 100644 --- a/tests/sctp/sctp_common.c +++ b/tests/sctp/sctp_common.c @@ -113,6 +113,57 @@ void print_ip_option(int fd, bool ipv4, char *text) } } +/* Build new context for socket and set using setsockcreatecon(3) */ +int set_newsock_con(char *type, char *text) +{ + int result; + char *context, *newcon = NULL; + context_t con_t; + + result = getcon(&context); + if (result < 0) { + fprintf(stderr, "Failed to get %s context\n", text); + return -1; + } + + con_t = context_new(context); + if (!con_t) { + fprintf(stderr, "Unable to create context structure\n"); + free(context); + return -1; + } + + if (context_type_set(con_t, type)) { + fprintf(stderr, "Unable to set new socket type\n"); + free(context); + free(con_t); + return -1; + } + + newcon = context_str(con_t); + free(context); + free(con_t); + if (!newcon) { + fprintf(stderr, "Unable to obtain new socket context string\n"); + return -1; + } + + result = setsockcreatecon_raw(newcon); + if (result < 0) { + fprintf(stderr, "Failed to set new %s socket context: %s\n", + text, newcon); + free(newcon); + return -1; + } + + result = getsockcreatecon_raw(&context); + printf("%s new socket context: %s\n", text, context); + free(newcon); + free(context); + + return 0; +} + int set_subscr_events(int fd, int data_io, int assoc, int addr, int shutd) { struct sctp_event_subscribe subscr_events; diff --git a/tests/sctp/sctp_common.h b/tests/sctp/sctp_common.h index cb69f70..6547dca 100644 --- a/tests/sctp/sctp_common.h +++ b/tests/sctp/sctp_common.h @@ -19,6 +19,7 @@ #include <stdbool.h> #include <errno.h> #include <selinux/selinux.h> +#include <selinux/context.h> enum event_ret { EVENT_OK, @@ -31,6 +32,7 @@ void print_context(int fd, char *text); void print_addr_info(struct sockaddr *sin, char *text); char *get_ip_option(int fd, bool ipv4, socklen_t *opt_len); void print_ip_option(int fd, bool ipv4, char *text); +int set_newsock_con(char *type, char *text); int set_subscr_events(int fd, int data_io, int assoc, int addr, int shutd); int handle_event(void *buf, char *cmp_addr, sctp_assoc_t *assoc_id, bool verbose, char *text); diff --git a/tests/sctp/sctp_peeloff_client.c b/tests/sctp/sctp_peeloff_client.c index 2d42c72..5470494 100644 --- a/tests/sctp/sctp_peeloff_client.c +++ b/tests/sctp/sctp_peeloff_client.c @@ -3,13 +3,14 @@ static void usage(char *progname) { fprintf(stderr, - "usage: %s [-e expected_msg] [-v] [-n] [-x] addr port\n" + "usage: %s [-e expected_msg] [-v] [-n] [-t type] [-x] addr port\n" "\nWhere:\n\t" "-e Optional expected message from server e.g. \"nopeer\".\n\t" " If not present the client context will be used as a\n\t" " comparison with the servers reply.\n\t" "-n Do NOT call connect(3) or connectx(3).\n\t" + "-t New type for setsockcreatecon(3) test.\n\t" "-v Print context and ip options information.\n\t" "-x Use sctp_connectx(3) instead of connect(3).\n\t" "addr IPv4 or IPv6 address (e.g. 127.0.0.1 or ::1).\n\t" @@ -28,10 +29,10 @@ int main(int argc, char **argv) char byte = 0x41, label[1024], *expected = NULL; bool verbose = false, connectx = false, no_connects = false; bool ipv4 = false, expect_ipopt = false; - char *context; + char *context, *sock_type = NULL; struct timeval tm; - while ((opt = getopt(argc, argv, "e:vxmni")) != -1) { + while ((opt = getopt(argc, argv, "e:t:vxmni")) != -1) { switch (opt) { case 'e': expected = optarg; @@ -45,6 +46,9 @@ int main(int argc, char **argv) case 'n': no_connects = true; break; + case 't': + sock_type = optarg; + break; case 'x': connectx = true; break; @@ -187,11 +191,20 @@ int main(int argc, char **argv) exit(1); } + /* If -t option set new context for peeled off socket */ + if (sock_type) { + result = set_newsock_con(sock_type, "Peeloff Client"); + if (result < 0) { + fprintf(stderr, "Failed setsockcreatecon(3)\n"); + exit(20); + } + } + peeloff_sk = sctp_peeloff(sock, assoc_id); if (peeloff_sk < 0) { perror("Client sctp_peeloff"); close(sock); - exit(1); + exit(21); } if (verbose) { printf("Client sctp_peeloff(3) on sk: %d with association ID: %d\n", diff --git a/tests/sctp/sctp_peeloff_server.c b/tests/sctp/sctp_peeloff_server.c index bd797f2..f4347e1 100644 --- a/tests/sctp/sctp_peeloff_server.c +++ b/tests/sctp/sctp_peeloff_server.c @@ -3,12 +3,13 @@ static void usage(char *progname) { fprintf(stderr, - "usage: %s [-4] [-f file] [-i] [-n] [-v] port\n" + "usage: %s [-4] [-f file] [-i] [-n] [-t type] [-v] port\n" "\nWhere:\n\t" "-4 Listen on IPv4 addresses only.\n\t" "-f Write a line to the file when listening starts.\n\t" "-i Send IP Options as msg (default is peer label).\n\t" "-n No peer context will be available therefore send\n\t" + "-t New type for setsockcreatecon(3) test.\n\t" " \"nopeer\" message to client, otherwise the peer context\n\t" " will be retrieved and sent to client.\n\t" "-v Print context and ip options information.\n\t" @@ -24,10 +25,11 @@ int main(int argc, char **argv) struct sockaddr_storage sin; struct addrinfo hints, *res; char *peerlabel, *context, *flag_file = NULL, msglabel[256]; + char *sock_type = NULL; bool nopeer = false, verbose = false, ipv4 = false, snd_opt = false; unsigned short port; - while ((opt = getopt(argc, argv, "4f:inv")) != -1) { + while ((opt = getopt(argc, argv, "4f:int:v")) != -1) { switch (opt) { case '4': ipv4 = true; @@ -41,6 +43,9 @@ int main(int argc, char **argv) case 'n': nopeer = true; break; + case 't': + sock_type = optarg; + break; case 'v': verbose = true; break; @@ -162,6 +167,15 @@ int main(int argc, char **argv) exit(1); } + /* If -t option set new context for peeled off socket */ + if (sock_type) { + result = set_newsock_con(sock_type, "Peeloff Server"); + if (result < 0) { + fprintf(stderr, "Failed setsockcreatecon(3)\n"); + exit(1); + } + } + peeloff_sk = sctp_peeloff(sock, assoc_id); if (peeloff_sk < 0) { perror("Server sctp_peeloff"); diff --git a/tests/sctp/sctp_server.c b/tests/sctp/sctp_server.c index c53f46f..2a99dd0 100644 --- a/tests/sctp/sctp_server.c +++ b/tests/sctp/sctp_server.c @@ -3,7 +3,7 @@ static void usage(char *progname) { fprintf(stderr, - "usage: %s [-4] [-b ipv4_addr] [-f file] [-h addr] [-i] [-n] [-v] stream|seq port\n" + "usage: %s [-4] [-b ipv4_addr] [-f file] [-h addr] [-i] [-n] [-t type] [-v] stream|seq port\n" "\nWhere:\n\t" "-4 Listen on IPv4 addresses only (used for CIPSO tests).\n\t" "-b Call sctp_bindx(3) with the supplied IPv4 address.\n\t" @@ -14,6 +14,7 @@ static void usage(char *progname) "-i Send IP Options as msg (default is peer label).\n\t" "-n No peer label or IP option will be available therefore\n\t" " send \"nopeer\" message to client.\n\t" + "-t New type for setsockcreatecon(3) test.\n\t" "-v Print context and ip options information.\n\t" "stream Use SCTP 1-to-1 style or:\n\t" "seq use SCTP 1-to-Many style.\n\t" @@ -33,10 +34,11 @@ int main(int argc, char **argv) char byte, *peerlabel, msglabel[1024], if_name[30]; bool nopeer = false, verbose = false, ipv4 = false, snd_opt = false; char *context, *host_addr = NULL, *bindx_addr = NULL, *flag_file = NULL; + char *sock_type = NULL; struct sockaddr_in ipv4_addr; unsigned short port; - while ((opt = getopt(argc, argv, "4b:f:h:inv")) != -1) { + while ((opt = getopt(argc, argv, "4b:f:h:int:v")) != -1) { switch (opt) { case '4': ipv4 = true; @@ -56,6 +58,9 @@ int main(int argc, char **argv) case 'n': nopeer = true; break; + case 't': + sock_type = optarg; + break; case 'v': verbose = true; break; @@ -120,6 +125,15 @@ int main(int argc, char **argv) exit(1); } + /* If -t option set new context for socket */ + if (sock_type) { + result = set_newsock_con(sock_type, "Server"); + if (result < 0) { + fprintf(stderr, "Failed setsockcreatecon(3)\n"); + exit(2); + } + } + sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (sock < 0) { perror("Server socket"); diff --git a/tests/sctp/test b/tests/sctp/test index d4357ed..53111c1 100755 --- a/tests/sctp/test +++ b/tests/sctp/test @@ -33,7 +33,7 @@ BEGIN { plan skip_all => "SCTP not supported"; } else { - $test_count = 85; + $test_count = 90; # Set up a GRE tunnel over loopback to ensure we have enough addresses # for the ASCONF tests. @@ -1046,6 +1046,61 @@ if ($test_nft) { system "nft -f $basedir/nftables-flush"; } +# +## Tests for 'sctp_socket' using type_transition rule and setsockcreatecon(3) +# +print "# Testing type_transition rule and setsockcreatecon(3)\n"; + +# Start the stream server. +$pid = + server_start( "-t test_sctp_server_t", "sctp_server", "$v -n stream 1035" ); + +# Set a new context on the socket using setsockcreatecon(3): +$result = system +"runcon -t test_sctp_new_type_client_t $basedir/sctp_client $v -t client_setsockcreatecon_newcon_t -e nopeer stream 127.0.0.1 1035"; +ok( $result eq 0 ); + +# Kill the stream server. +server_end($pid); + +$pid = + server_start( "-t test_sctp_server_t", "sctp_server", "$v -n -4 seq 1035" ); + +# Set a new context on the peeled off socket using setsockcreatecon(3): +$result = system +"runcon -t test_sctp_new_type_client_t $basedir/sctp_peeloff_client $v -t client_setsockcreatecon_newcon_t -e nopeer 127.0.0.1 1035"; +ok( $result eq 0 ); + +# Deny sctp_socket { create } using setsockcreatecon(3) on the peeled off socket. +$result = system +"runcon -t test_sctp_new_type_client_t $basedir/sctp_peeloff_client $v -t client_setsockcreatecon_newcon_deny_t -e nopeer 127.0.0.1 1035"; +ok( $result >> 8 eq 21 ); + +# Deny sctp_socket { create } for the type_transition rule. +$result = system +"runcon -t test_sctp_new_type_deny_client_t $basedir/sctp_peeloff_client $v -t client_setsockcreatecon_newcon_deny_t -e nopeer 127.0.0.1 1035"; +ok( $result >> 8 eq 3 ); + +# Kill the stream server. +server_end($pid); + +# Set a new context on the server peeled off socket using setsockcreatecon(3) +# Note: to check that the peeled off context has changed, run locally that +# will show socket contexts. +$pid = server_start( + "-t test_sctp_server_t", + "sctp_peeloff_server", + "$v -t server_setsockcreatecon_newcon_t -n -4 1035", +); + +# Verify that client can communicate with the server. +$result = system +"runcon -t test_sctp_new_type_client_t $basedir/sctp_client $v -e nopeer seq 127.0.0.1 1035"; +ok( $result eq 0 ); + +# Kill the seq server. +server_end($pid); + system "ip link del mygre"; exit; -- 2.33.1