@@ -117,3 +117,7 @@ CONFIG_VFAT_FS=m
# They are not required for SELinux operation itself.
CONFIG_WATCH_QUEUE=y
CONFIG_KEY_NOTIFICATIONS=y
+
+# GTP module.
+# This is not required for SELinux operation itself.
+CONFIG_GTP=y
@@ -144,6 +144,11 @@ endif
endif
endif
+ifeq ($(shell test -e /usr/local/include/libgtpnl/gtpnl.h && echo true),true)
+TARGETS += test_gtp.te
+CIL_TARGETS += test_gtp.cil
+endif
+
ifeq (x$(DISTRO),$(filter x$(DISTRO),xRHEL4 xRHEL5 xRHEL6))
TARGETS:=$(filter-out test_overlayfs.te test_mqueue.te test_ibpkey.te, $(TARGETS))
endif
new file mode 100644
@@ -0,0 +1,18 @@
+(class gtp (add del get))
+(classorder (unordered gtp))
+
+(allow test_gtp-1_t self (gtp(add del get)))
+(allow test_gtp-2_t self (gtp(add del get)))
+(allow test_gtp-3_t self (gtp(add del get)))
+
+(allow test_gtp_no_add_pdp_t test_gtp-1_t (gtp(del get)))
+(allow test_gtp_no_del_pdp_t test_gtp-1_t (gtp(add get)))
+(allow test_gtp_no_get_pdp_dump_t test_gtp-1_t (gtp(add del)))
+(allow test_gtp_no_get_pdp_match_t test_gtp-1_t (gtp(add del)))
+
+;; Deny gtp for del_link
+(allow test_gtp_no_del_link_t self (gtp (add)))
+(allow test_gtp-1_t test_gtp_no_del_link_t (gtp (del)))
+
+;; Allow link to be deleted
+(allow test_gtp_no_add_link_t self (gtp (del)))
new file mode 100644
@@ -0,0 +1,96 @@
+#
+########### Test GTP device driver support ##############
+#
+attribute gtpdomain;
+
+# For CONFIG_GTP=m
+kernel_request_load_module(gtpdomain)
+
+################## Create gtp-1 domain ######################
+type test_gtp-1_t;
+domain_type(test_gtp-1_t)
+unconfined_runs_test(test_gtp-1_t)
+typeattribute test_gtp-1_t testdomain;
+typeattribute test_gtp-1_t gtpdomain;
+
+################## Create gtp-2 domain ######################
+type test_gtp-2_t;
+domain_type(test_gtp-2_t)
+unconfined_runs_test(test_gtp-2_t)
+typeattribute test_gtp-2_t testdomain;
+typeattribute test_gtp-2_t gtpdomain;
+
+################## Create gtp-3 domain ######################
+type test_gtp-3_t;
+domain_type(test_gtp-3_t)
+unconfined_runs_test(test_gtp-3_t)
+typeattribute test_gtp-3_t testdomain;
+typeattribute test_gtp-3_t gtpdomain;
+
+# Common gtp rules:
+allow gtpdomain self:capability { net_admin };
+allow gtpdomain self:netlink_generic_socket *;
+allow gtpdomain self:netlink_route_socket *;
+allow gtpdomain self:udp_socket *;
+allow gtpdomain test_file_t:dir read;
+allow gtpdomain user_home_t:file { execute getattr open read };
+corecmd_check_exec_shell(gtpdomain)
+corecmd_exec_bin(gtpdomain)
+corecmd_mmap_bin_files(gtpdomain)
+corecmd_shell_entry_type(gtpdomain)
+corenet_udp_bind_generic_node(gtpdomain)
+corenet_udp_bind_generic_port(gtpdomain)
+kernel_read_network_state(gtpdomain)
+miscfiles_exec_test_files(gtpdomain)
+userdom_list_user_home_dirs(gtpdomain)
+userdom_manage_user_home_content_dirs(gtpdomain)
+userdom_map_user_home_files(gtpdomain)
+userdom_read_user_home_content_symlinks(gtpdomain)
+
+####################### Deny gtp { add_link } ##########################
+type test_gtp_no_add_link_t;
+domain_type(test_gtp_no_add_link_t)
+unconfined_runs_test(test_gtp_no_add_link_t)
+typeattribute test_gtp_no_add_link_t testdomain;
+typeattribute test_gtp_no_add_link_t gtpdomain;
+
+####################### Deny gtp { del_link } ##########################
+type test_gtp_no_del_link_t;
+domain_type(test_gtp_no_del_link_t)
+unconfined_runs_test(test_gtp_no_del_link_t)
+typeattribute test_gtp_no_del_link_t testdomain;
+typeattribute test_gtp_no_del_link_t gtpdomain;
+
+################## Deny gtp { add_pdp } ########################
+type test_gtp_no_add_pdp_t;
+domain_type(test_gtp_no_add_pdp_t)
+unconfined_runs_test(test_gtp_no_add_pdp_t)
+typeattribute test_gtp_no_add_pdp_t testdomain;
+typeattribute test_gtp_no_add_pdp_t gtpdomain;
+
+################## Deny gtp { del_pdp } ########################
+type test_gtp_no_del_pdp_t;
+domain_type(test_gtp_no_del_pdp_t)
+unconfined_runs_test(test_gtp_no_del_pdp_t)
+typeattribute test_gtp_no_del_pdp_t testdomain;
+typeattribute test_gtp_no_del_pdp_t gtpdomain;
+
+################## Deny gtp { get_pdp } ########################
+type test_gtp_no_get_pdp_dump_t;
+domain_type(test_gtp_no_get_pdp_dump_t)
+unconfined_runs_test(test_gtp_no_get_pdp_dump_t)
+typeattribute test_gtp_no_get_pdp_dump_t testdomain;
+typeattribute test_gtp_no_get_pdp_dump_t gtpdomain;
+
+################## Deny gtp { get_pdp } ########################
+type test_gtp_no_get_pdp_match_t;
+domain_type(test_gtp_no_get_pdp_match_t)
+unconfined_runs_test(test_gtp_no_get_pdp_match_t)
+typeattribute test_gtp_no_get_pdp_match_t testdomain;
+typeattribute test_gtp_no_get_pdp_match_t gtpdomain;
+
+#
+########### Allow these domains to be entered from sysadm domain ############
+#
+miscfiles_domain_entry_test_files(gtpdomain)
+userdom_sysadm_entry_spec_domtrans_to(gtpdomain)
@@ -129,6 +129,10 @@ SUBDIRS += watchkey
endif
endif
+ifeq ($(shell test -e /usr/local/include/libgtpnl/gtpnl.h && echo true),true)
+SUBDIRS += gtp
+endif
+
ifeq ($(DISTRO),RHEL4)
SUBDIRS:=$(filter-out bounds dyntrace dyntrans inet_socket mmap nnp_nosuid overlay unix_socket, $(SUBDIRS))
endif
new file mode 100644
@@ -0,0 +1,2 @@
+gtp-link
+gtp-tunnel
new file mode 100644
@@ -0,0 +1,123 @@
+Testing LSM/SELinux GTP Kernel Hooks
+====================================
+
+These tests were performed on Fedora 32 Workstation with the 'targeted' policy
+using an updated kernel with the GTP RFC kernel patches.
+
+The basic process is:
+1) Build kernel with RFC LSM/GTP/SELinux patches (use the
+ selinux-testsuite/defconfig file to set correct config if required).
+2) Setup the selinux-testsuite and add the GTP test patch.
+3) Build/install the libgtpnl library using a patch from the selinux-testsuite
+ as this will allow errors to be returned by the library functions.
+4) Build/run selinux-testsuite for all SELinux tests (sets up the environment).
+5) Run the GTP tests locally to see more info.
+6) Remove the selinux-testsuite policy.
+
+#
+#### Start #####
+#
+
+Build and install a kernel with the "Add LSM/SELinux support for GPRS
+Tunneling Protocol (GTP)" patch set, [1] was used for these tests.
+
+NOTE: The selinux-testsuite/defconfig file contains kernel config info to
+build a suitable kernel. See selinux-testsuite/README.md
+
+Make a test build directory e.g.:
+mkdir /home/GTP-TEST
+
+#
+#### Setup SELinux-testsuite ######
+#
+cd /home/GTP-TEST
+git clone https://github.com/SELinuxProject/selinux-testsuite.git
+cd selinux-testsuite
+
+Install the testsuite RFC GTP Patch: "selinux-testsuite: Add GTP tests"
+
+This will add the GTP tests. There will be in selinux-testsuite/tests/gtp:
+1) GTP-README - These install/build/run instructions.
+2) Update-libgtpnl-for-SELinux-testsuite-GTP-tests.patch - This contains
+ changes required to return ERRNO and add gtp_match_tunnel function to
+ the libgtpnl library and tools.
+3) gtp-link.c and gtp-tunnel.c - These are the modified files from
+ libgtpnl/tools as the local Makefile will build these.
+4) test - A perl test script.
+
+#
+##### Setup and build/install the libgtpnl library ######
+#
+Note: The install process will install the library and include files by
+default in /usr/local/..):
+cd /home/GTP-TEST
+git clone git://git.osmocom.org/libgtpnl.git
+cd libgtpnl
+patch -p1 < ../selinux-testsuite/tests/gtp/Update-libgtpnl-for-SELinux-testsuite-GTP-tests.patch
+autoreconf -fi && ./configure && make && make install
+
+Now build and run the SELinux-testsuite:
+cd /home/GTP-TEST/selinux-testsuite
+setenforce 1
+make test
+
+If there is a build error it is most likely to be the 'module_load' test that
+requires the kernel version devel to be installed. If it is not then comment
+out the test in tests/Makefile.
+
+All other tests should run correctly. The GTP test will be last and there
+should be one error reported:
+
+# Failed test 'FIXME: Fails gtp_list_tunnel() as no callback error.
+Audit log should have: allow test_gtp_no_get_pdp_dump_t test_gtp_t:gtp get;'
+# at gtp/test line 76.
+
+This happens because the kernel/netlink does not return an error when
+'gtp-tunnel list' is called and the permission is denied, however the audit.log
+indicates the denial. Any idea for a fix ??. Tried various kernel/netlink
+changes to no avail. Netlink documentation seems to imply that it should work.
+
+To run the GTP tests locally and see more information:
+
+cd tests/gtp
+# Clear audit log file:
+> /var/log/audit/audit.log
+# Run tests showing extra info:
+./test
+# Check audit log for denials:
+audit2allow -p /etc/selinux/targeted/policy/policy.32 < /var/log/audit/audit.log
+
+The output should consist of the following entries:
+#============= test_gtp-2_t ==============
+allow test_gtp-2_t test_gtp-1_t:gtp { del get };
+
+#============= test_gtp_no_add_link_t ==============
+allow test_gtp_no_add_link_t self:gtp add;
+
+#============= test_gtp_no_add_pdp_t ==============
+allow test_gtp_no_add_pdp_t test_gtp-1_t:gtp add;
+
+#============= test_gtp_no_del_link_t ==============
+allow test_gtp_no_del_link_t self:gtp del;
+
+#============= test_gtp_no_del_pdp_t ==============
+allow test_gtp_no_del_pdp_t test_gtp-1_t:gtp del;
+
+#============= test_gtp_no_get_pdp_dump_t ==============
+allow test_gtp_no_get_pdp_dump_t test_gtp-1_t:gtp get;
+
+#============= test_gtp_no_get_pdp_match_t ==============
+allow test_gtp_no_get_pdp_match_t test_gtp-1_t:gtp get;
+
+
+IMPORTANT: Remove the selinux-testsuite test policy when finished as it will
+stop any libgtpnl functions from working in other SELinux domains:
+
+cd /home/GTP-TEST/selinux-testsuite
+make -C policy unload
+
+libgtpnl functions should now work in any domain.
+
+The End
+
+[1] https://github.com/SELinuxProject/selinux-kernel
new file mode 100644
@@ -0,0 +1,8 @@
+TARGETS = gtp-link gtp-tunnel
+CFLAGS ?= -Wall
+LDLIBS += -l mnl -lgtpnl
+
+all: $(TARGETS)
+
+clean:
+ rm -f $(TARGETS)
new file mode 100644
@@ -0,0 +1,366 @@
+libgtpnl: Allow SELinux-testsuite to run tests on GTP
+
+This allows the GTP functions to return errno when running
+test so that EACCES can be detected.
+
+Added 'gtp-tunnel match <device> <ver> <tid>' for testing
+permissions.
+
+Added to gtp-link options to pass port numbers when adding device in
+the same namespace.
+
+NOTE: gtp_list_tunnel() does not return an error when pdp_get denied.
+Could not find reason for this. gtp_match_tunnel() does return error
+when pdp_get denied.
+
+---
+ include/libgtpnl/gtpnl.h | 1 +
+ src/gtp-genl.c | 47 +++++++++++++++++++++++++----
+ src/libgtpnl.map | 1 +
+ tools/gtp-link.c | 37 ++++++++++++++++++-----
+ tools/gtp-tunnel.c | 64 +++++++++++++++++++++++++++++++++++-----
+ 5 files changed, 130 insertions(+), 20 deletions(-)
+
+diff --git a/include/libgtpnl/gtpnl.h b/include/libgtpnl/gtpnl.h
+index 6cd9f46..1bc427d 100644
+--- a/include/libgtpnl/gtpnl.h
++++ b/include/libgtpnl/gtpnl.h
+@@ -27,5 +27,6 @@ struct gtp_tunnel;
+ int gtp_add_tunnel(int genl_id, struct mnl_socket *nl, struct gtp_tunnel *t);
+ int gtp_del_tunnel(int genl_id, struct mnl_socket *nl, struct gtp_tunnel *t);
+ int gtp_list_tunnel(int genl_id, struct mnl_socket *nl);
++int gtp_match_tunnel(int genl_id, struct mnl_socket *nl, struct gtp_tunnel *t);
+
+ #endif
+diff --git a/src/gtp-genl.c b/src/gtp-genl.c
+index f12f872..fe24625 100644
+--- a/src/gtp-genl.c
++++ b/src/gtp-genl.c
+@@ -25,6 +25,7 @@
+ #include <string.h>
+ #include <unistd.h>
+ #include <time.h>
++#include <errno.h>
+ #include <arpa/inet.h>
+ #include <sys/socket.h>
+ #include <netinet/in.h>
+@@ -66,6 +67,7 @@ int gtp_add_tunnel(int genl_id, struct mnl_socket *nl, struct gtp_tunnel *t)
+ struct nlmsghdr *nlh;
+ char buf[MNL_SOCKET_BUFFER_SIZE];
+ uint32_t seq = time(NULL);
++ int ret;
+
+ if (t->gtp_version > GTP_V1) {
+ fprintf(stderr, "wrong GTP version %u, use v0 or v1\n",
+@@ -77,8 +79,12 @@ int gtp_add_tunnel(int genl_id, struct mnl_socket *nl, struct gtp_tunnel *t)
+ GTP_CMD_NEWPDP);
+ gtp_build_payload(nlh, t);
+
+- if (genl_socket_talk(nl, nlh, seq, NULL, NULL) < 0)
++ ret = genl_socket_talk(nl, nlh, seq, NULL, NULL);
++ if (ret < 0) {
++ ret = errno;
+ perror("genl_socket_talk");
++ return ret;
++ }
+
+ return 0;
+ }
+@@ -89,13 +95,19 @@ int gtp_del_tunnel(int genl_id, struct mnl_socket *nl, struct gtp_tunnel *t)
+ char buf[MNL_SOCKET_BUFFER_SIZE];
+ struct nlmsghdr *nlh;
+ uint32_t seq = time(NULL);
++ int ret;
+
+ nlh = genl_nlmsg_build_hdr(buf, genl_id, NLM_F_ACK, ++seq,
+ GTP_CMD_DELPDP);
+ gtp_build_payload(nlh, t);
+
+- if (genl_socket_talk(nl, nlh, seq, NULL, NULL) < 0)
++ ret = genl_socket_talk(nl, nlh, seq, NULL, NULL);
++ /* Kernel void gtp_dellink() does not pass errors back to userspace */
++ if (ret < 0) {
++ ret = errno;
+ perror("genl_socket_talk");
++ return ret;
++ }
+
+ return 0;
+ }
+@@ -194,15 +206,40 @@ int gtp_list_tunnel(int genl_id, struct mnl_socket *nl)
+ char buf[MNL_SOCKET_BUFFER_SIZE];
+ struct nlmsghdr *nlh;
+ uint32_t seq = time(NULL);
++ int ret;
+
+- nlh = genl_nlmsg_build_hdr(buf, genl_id, NLM_F_DUMP, 0,
++ nlh = genl_nlmsg_build_hdr(buf, genl_id, NLM_F_DUMP | NLM_F_ACK, ++seq,
+ GTP_CMD_GETPDP);
+
+- if (genl_socket_talk(nl, nlh, seq, genl_gtp_attr_cb, NULL) < 0) {
++ ret = genl_socket_talk(nl, nlh, seq, genl_gtp_attr_cb, NULL);
++ if (ret < 0) {
++ ret = errno;
+ perror("genl_socket_talk");
+- return 0;
++ return ret;
+ }
+
+ return 0;
+ }
+ EXPORT_SYMBOL(gtp_list_tunnel);
++
++int gtp_match_tunnel(int genl_id, struct mnl_socket *nl, struct gtp_tunnel *t)
++{
++ char buf[MNL_SOCKET_BUFFER_SIZE];
++ struct nlmsghdr *nlh;
++ uint32_t seq = time(NULL);
++ int ret;
++
++ nlh = genl_nlmsg_build_hdr(buf, genl_id, NLM_F_MATCH | NLM_F_ACK, ++seq,
++ GTP_CMD_GETPDP);
++ gtp_build_payload(nlh, t);
++
++ ret = genl_socket_talk(nl, nlh, seq, genl_gtp_attr_cb, NULL);
++ if (ret < 0) {
++ ret = errno;
++ perror("genl_socket_talk");
++ return ret;
++ }
++
++ return 0;
++}
++EXPORT_SYMBOL(gtp_match_tunnel);
+diff --git a/src/libgtpnl.map b/src/libgtpnl.map
+index 804f8b3..4556758 100644
+--- a/src/libgtpnl.map
++++ b/src/libgtpnl.map
+@@ -14,6 +14,7 @@ global:
+ gtp_add_tunnel;
+ gtp_del_tunnel;
+ gtp_list_tunnel;
++ gtp_match_tunnel;
+
+ gtp_tunnel_alloc;
+ gtp_tunnel_free;
+diff --git a/tools/gtp-link.c b/tools/gtp-link.c
+index 8367c6e..e88e349 100644
+--- a/tools/gtp-link.c
++++ b/tools/gtp-link.c
+@@ -27,6 +27,7 @@
+ #include <unistd.h>
+ #include <string.h>
+ #include <time.h>
++#include <errno.h>
+ #include <netinet/in.h>
+ #include <arpa/inet.h>
+
+@@ -44,35 +45,53 @@ int main(int argc, char *argv[])
+ {
+ char buf[MNL_SOCKET_BUFFER_SIZE];
+ int ret, sgsn_mode = 0;
++ int port1, port2;
+
+ if (argc < 3) {
+- printf("Usage: %s <add|del> <device>\n", argv[0]);
++ printf("Usage: %s <add|del> <device> [--sgsn] [port1] [port2]\n",
++ argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ if (!strcmp(argv[1], "del")) {
+ printf("destroying gtp interface...\n");
+- if (gtp_dev_destroy(argv[2]) < 0)
++
++ ret = gtp_dev_destroy(argv[2]);
++ /* Kernel gtp_dellink() does not pass errors back to userspace */
++ if (ret < 0) {
++ ret = errno;
+ perror("gtp_dev_destroy");
++ }
+
+- return 0;
++ return ret;
+ }
+
+- if (argc > 3 && !strcmp(argv[3], "--sgsn"))
++ port1 = 3386;
++ port2 = 2152;
++
++ if (argc > 3 && !strcmp(argv[3], "--sgsn")) {
+ sgsn_mode = 1;
++ if (argc == 6) {
++ port1 = atoi(argv[4]);
++ port2 = atoi(argv[5]);
++ }
++ } else if (argc == 5) {
++ port1 = atoi(argv[3]);
++ port2 = atoi(argv[4]);
++ }
+
+ int fd1 = socket(AF_INET, SOCK_DGRAM, 0);
+ int fd2 = socket(AF_INET, SOCK_DGRAM, 0);
+ struct sockaddr_in sockaddr_fd1 = {
+ .sin_family = AF_INET,
+- .sin_port = htons(3386),
++ .sin_port = htons(port1),
+ .sin_addr = {
+ .s_addr = INADDR_ANY,
+ },
+ };
+ struct sockaddr_in sockaddr_fd2 = {
+ .sin_family = AF_INET,
+- .sin_port = htons(2152),
++ .sin_port = htons(port2),
+ .sin_addr = {
+ .s_addr = INADDR_ANY,
+ },
+@@ -94,13 +113,15 @@ int main(int argc, char *argv[])
+ else
+ ret = gtp_dev_create(-1, argv[2], fd1, fd2);
+ if (ret < 0) {
+- perror("cannot create GTP device\n");
+- exit(EXIT_FAILURE);
++ ret = errno;
++ perror("cannot create GTP device");
++ return ret;
+ }
+
+ fprintf(stderr, "WARNING: attaching dummy socket descriptors. Keep "
+ "this process running for testing purposes.\n");
+
++
+ while (1) {
+ struct sockaddr_in addr;
+ socklen_t len = sizeof(addr);
+diff --git a/tools/gtp-tunnel.c b/tools/gtp-tunnel.c
+index 513ff4a..8fb7fa2 100644
+--- a/tools/gtp-tunnel.c
++++ b/tools/gtp-tunnel.c
+@@ -27,6 +27,7 @@
+ #include <string.h>
+ #include <unistd.h>
+ #include <time.h>
++
+ #include <arpa/inet.h>
+ #include <sys/socket.h>
+ #include <netinet/in.h>
+@@ -56,7 +57,7 @@ add_tunnel(int argc, char *argv[], int genl_id, struct mnl_socket *nl)
+ uint32_t gtp_ifidx;
+ struct in_addr ms, sgsn;
+ uint32_t gtp_version;
+- int optidx;
++ int optidx, ret;
+
+ if (argc < 7 || argc > 8) {
+ add_usage(argv[0]);
+@@ -107,10 +108,11 @@ add_tunnel(int argc, char *argv[], int genl_id, struct mnl_socket *nl)
+ }
+ gtp_tunnel_set_sgsn_ip4(t, &sgsn);
+
+- gtp_add_tunnel(genl_id, nl, t);
++ /* Returns 0 or errno */
++ ret = gtp_add_tunnel(genl_id, nl, t);
+
+ gtp_tunnel_free(t);
+- return 0;
++ return ret;
+ }
+
+ static int
+@@ -118,6 +120,7 @@ del_tunnel(int argc, char *argv[], int genl_id, struct mnl_socket *nl)
+ {
+ struct gtp_tunnel *t;
+ uint32_t gtp_ifidx;
++ int ret;
+
+ if (argc != 5) {
+ printf("%s add <gtp device> <version> <tid>\n",
+@@ -146,10 +149,11 @@ del_tunnel(int argc, char *argv[], int genl_id, struct mnl_socket *nl)
+ return EXIT_FAILURE;
+ }
+
+- gtp_del_tunnel(genl_id, nl, t);
++ /* Returns 0 or errno */
++ ret = gtp_del_tunnel(genl_id, nl, t);
+
+ gtp_tunnel_free(t);
+- return 0;
++ return ret;
+ }
+
+ struct gtp_pdp {
+@@ -170,7 +174,51 @@ struct gtp_pdp {
+ static int
+ list_tunnel(int argc, char *argv[], int genl_id, struct mnl_socket *nl)
+ {
+- return gtp_list_tunnel(genl_id, nl);
++ int ret;
++
++ ret = gtp_list_tunnel(genl_id, nl);
++ return ret;
++}
++
++static int
++match_tunnel(int argc, char *argv[], int genl_id, struct mnl_socket *nl)
++{
++ struct gtp_tunnel *t;
++ uint32_t gtp_ifidx;
++ int ret;
++
++ if (argc != 5) {
++ printf("%s match <gtp device> <version> <tid>\n",
++ argv[0]);
++ return EXIT_FAILURE;
++ }
++
++ t = gtp_tunnel_alloc();
++
++ gtp_ifidx = if_nametoindex(argv[2]);
++ if (gtp_ifidx == 0) {
++ fprintf(stderr, "wrong GTP interface %s\n", argv[2]);
++ return EXIT_FAILURE;
++ }
++ gtp_tunnel_set_ifidx(t, gtp_ifidx);
++
++ if (strcmp(argv[3], "v0") == 0) {
++ gtp_tunnel_set_version(t, GTP_V0);
++ gtp_tunnel_set_tid(t, atoi(argv[4]));
++ } else if (strcmp(argv[3], "v1") == 0) {
++ gtp_tunnel_set_version(t, GTP_V1);
++ gtp_tunnel_set_i_tei(t, atoi(argv[4]));
++ } else {
++ fprintf(stderr, "wrong GTP version %s, use v0 or v1\n",
++ argv[3]);
++ return EXIT_FAILURE;
++ }
++
++ /* Returns 0 or errno */
++ ret = gtp_match_tunnel(genl_id, nl, t);
++
++ gtp_tunnel_free(t);
++ return ret;
+ }
+
+ int main(int argc, char *argv[])
+@@ -180,7 +228,7 @@ int main(int argc, char *argv[])
+ int ret;
+
+ if (argc < 2) {
+- printf("%s <add|delete|list> [<options,...>]\n", argv[0]);
++ printf("%s <add|delete|list|match> [<options,...>]\n", argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+@@ -202,6 +250,8 @@ int main(int argc, char *argv[])
+ ret = del_tunnel(argc, argv, genl_id, nl);
+ else if (strncmp(argv[1], "list", strlen(argv[1])) == 0)
+ ret = list_tunnel(argc, argv, genl_id, nl);
++ else if (strncmp(argv[1], "match", strlen(argv[1])) == 0)
++ ret = match_tunnel(argc, argv, genl_id, nl);
+ else {
+ printf("Unknown command `%s'\n", argv[1]);
+ exit(EXIT_FAILURE);
+--
+2.26.2
+
new file mode 100644
@@ -0,0 +1,134 @@
+/* Command line utility to create GTP link */
+
+/* (C) 2014 by sysmocom - s.f.m.c. GmbH
+ * (C) 2016 by Pablo Neira Ayuso <pablo@netfilter.org>
+ *
+ * Author: Pablo Neira Ayuso <pablo@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+#include <libmnl/libmnl.h>
+#include <linux/if.h>
+#include <linux/if_link.h>
+#include <linux/rtnetlink.h>
+
+#include <linux/gtp.h>
+#include <linux/if_link.h>
+
+#include <libgtpnl/gtpnl.h>
+
+int main(int argc, char *argv[])
+{
+ char buf[MNL_SOCKET_BUFFER_SIZE];
+ int ret, sgsn_mode = 0;
+ int port1, port2;
+
+ if (argc < 3) {
+ printf("Usage: %s <add|del> <device> [--sgsn] [port1] [port2]\n",
+ argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ if (!strcmp(argv[1], "del")) {
+ printf("destroying gtp interface...\n");
+
+ ret = gtp_dev_destroy(argv[2]);
+ /* Kernel gtp_dellink() does not pass errors back to userspace */
+ if (ret < 0) {
+ ret = errno;
+ perror("gtp_dev_destroy");
+ }
+
+ return ret;
+ }
+
+ port1 = 3386;
+ port2 = 2152;
+
+ if (argc > 3 && !strcmp(argv[3], "--sgsn")) {
+ sgsn_mode = 1;
+ if (argc == 6) {
+ port1 = atoi(argv[4]);
+ port2 = atoi(argv[5]);
+ }
+ } else if (argc == 5) {
+ port1 = atoi(argv[3]);
+ port2 = atoi(argv[4]);
+ }
+
+ int fd1 = socket(AF_INET, SOCK_DGRAM, 0);
+ int fd2 = socket(AF_INET, SOCK_DGRAM, 0);
+ struct sockaddr_in sockaddr_fd1 = {
+ .sin_family = AF_INET,
+ .sin_port = htons(port1),
+ .sin_addr = {
+ .s_addr = INADDR_ANY,
+ },
+ };
+ struct sockaddr_in sockaddr_fd2 = {
+ .sin_family = AF_INET,
+ .sin_port = htons(port2),
+ .sin_addr = {
+ .s_addr = INADDR_ANY,
+ },
+ };
+
+ if (bind(fd1, (struct sockaddr *) &sockaddr_fd1,
+ sizeof(sockaddr_fd1)) < 0) {
+ perror("bind");
+ exit(EXIT_FAILURE);
+ }
+ if (bind(fd2, (struct sockaddr *) &sockaddr_fd2,
+ sizeof(sockaddr_fd2)) < 0) {
+ perror("bind");
+ exit(EXIT_FAILURE);
+ }
+
+ if (sgsn_mode)
+ ret = gtp_dev_create_sgsn(-1, argv[2], fd1, fd2);
+ else
+ ret = gtp_dev_create(-1, argv[2], fd1, fd2);
+ if (ret < 0) {
+ ret = errno;
+ perror("cannot create GTP device");
+ return ret;
+ }
+
+ fprintf(stderr, "WARNING: attaching dummy socket descriptors. Keep "
+ "this process running for testing purposes.\n");
+
+ while (1) {
+ struct sockaddr_in addr;
+ socklen_t len = sizeof(addr);
+
+ ret = recvfrom(fd1, buf, sizeof(buf), 0,
+ (struct sockaddr *)&addr, &len);
+ printf("received %d bytes via UDP socket\n", ret);
+ }
+
+ return 0;
+}
new file mode 100644
@@ -0,0 +1,263 @@
+/* Command line utility to create GTP tunnels (PDP contexts) */
+
+/* (C) 2014 by sysmocom - s.f.m.c. GmbH
+ * (C) 2016 by Pablo Neira Ayuso <pablo@netfilter.org>
+ *
+ * Author: Pablo Neira Ayuso <pablo@gnumonks.org>
+ *
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#include <inttypes.h>
+
+#include <libmnl/libmnl.h>
+#include <linux/genetlink.h>
+
+#include <linux/gtp.h>
+#include <linux/if_link.h>
+#include <libgtpnl/gtp.h>
+#include <libgtpnl/gtpnl.h>
+
+static void add_usage(const char *name)
+{
+ printf("%s add <gtp device> <v0> <tid> <ms-addr> <sgsn-addr>\n",
+ name);
+ printf("%s add <gtp device> <v1> <i_tei> <o_tei> <ms-addr> <sgsn-addr>\n",
+ name);
+}
+
+static int
+add_tunnel(int argc, char *argv[], int genl_id, struct mnl_socket *nl)
+{
+ struct gtp_tunnel *t;
+ uint32_t gtp_ifidx;
+ struct in_addr ms, sgsn;
+ uint32_t gtp_version;
+ int optidx, ret;
+
+ if (argc < 7 || argc > 8) {
+ add_usage(argv[0]);
+ return EXIT_FAILURE;
+ }
+
+ t = gtp_tunnel_alloc();
+ optidx = 2;
+
+ gtp_ifidx = if_nametoindex(argv[optidx]);
+ if (gtp_ifidx == 0) {
+ fprintf(stderr, "wrong GTP interface %s\n", argv[optidx]);
+ return EXIT_FAILURE;
+ }
+ gtp_tunnel_set_ifidx(t, gtp_ifidx);
+
+ optidx++;
+
+ if (strcmp(argv[optidx], "v0") == 0)
+ gtp_version = GTP_V0;
+ else if (strcmp(argv[optidx], "v1") == 0)
+ gtp_version = GTP_V1;
+ else {
+ fprintf(stderr, "wrong GTP version %s, use v0 or v1\n",
+ argv[optidx]);
+ return EXIT_FAILURE;
+ }
+ gtp_tunnel_set_version(t, gtp_version);
+
+ optidx++;
+
+ if (gtp_version == GTP_V0)
+ gtp_tunnel_set_tid(t, atoi(argv[optidx++]));
+ else if (gtp_version == GTP_V1) {
+ gtp_tunnel_set_i_tei(t, atoi(argv[optidx++]));
+ gtp_tunnel_set_o_tei(t, atoi(argv[optidx++]));
+ }
+
+ if (inet_aton(argv[optidx++], &ms) < 0) {
+ perror("bad address for ms");
+ exit(EXIT_FAILURE);
+ }
+ gtp_tunnel_set_ms_ip4(t, &ms);
+
+ if (inet_aton(argv[optidx++], &sgsn) < 0) {
+ perror("bad address for sgsn");
+ exit(EXIT_FAILURE);
+ }
+ gtp_tunnel_set_sgsn_ip4(t, &sgsn);
+
+ /* Returns 0 or errno */
+ ret = gtp_add_tunnel(genl_id, nl, t);
+
+ gtp_tunnel_free(t);
+ return ret;
+}
+
+static int
+del_tunnel(int argc, char *argv[], int genl_id, struct mnl_socket *nl)
+{
+ struct gtp_tunnel *t;
+ uint32_t gtp_ifidx;
+ int ret;
+
+ if (argc != 5) {
+ printf("%s add <gtp device> <version> <tid>\n",
+ argv[0]);
+ return EXIT_FAILURE;
+ }
+
+ t = gtp_tunnel_alloc();
+
+ gtp_ifidx = if_nametoindex(argv[2]);
+ if (gtp_ifidx == 0) {
+ fprintf(stderr, "wrong GTP interface %s\n", argv[2]);
+ return EXIT_FAILURE;
+ }
+ gtp_tunnel_set_ifidx(t, gtp_ifidx);
+
+ if (strcmp(argv[3], "v0") == 0) {
+ gtp_tunnel_set_version(t, GTP_V0);
+ gtp_tunnel_set_tid(t, atoi(argv[4]));
+ } else if (strcmp(argv[3], "v1") == 0) {
+ gtp_tunnel_set_version(t, GTP_V1);
+ gtp_tunnel_set_i_tei(t, atoi(argv[4]));
+ } else {
+ fprintf(stderr, "wrong GTP version %s, use v0 or v1\n",
+ argv[3]);
+ return EXIT_FAILURE;
+ }
+
+ /* Returns 0 or errno */
+ ret = gtp_del_tunnel(genl_id, nl, t);
+
+ gtp_tunnel_free(t);
+ return ret;
+}
+
+struct gtp_pdp {
+ uint32_t version;
+ union {
+ struct {
+ uint64_t tid;
+ } v0;
+ struct {
+ uint32_t i_tei;
+ uint32_t o_tei;
+ } v1;
+ } u;
+ struct in_addr sgsn_addr;
+ struct in_addr ms_addr;
+};
+
+static int
+list_tunnel(int argc, char *argv[], int genl_id, struct mnl_socket *nl)
+{
+ int ret;
+
+ ret = gtp_list_tunnel(genl_id, nl);
+ return ret;
+}
+
+static int
+match_tunnel(int argc, char *argv[], int genl_id, struct mnl_socket *nl)
+{
+ struct gtp_tunnel *t;
+ uint32_t gtp_ifidx;
+ int ret;
+
+ if (argc != 5) {
+ printf("%s match <gtp device> <version> <tid>\n",
+ argv[0]);
+ return EXIT_FAILURE;
+ }
+
+ t = gtp_tunnel_alloc();
+
+ gtp_ifidx = if_nametoindex(argv[2]);
+ if (gtp_ifidx == 0) {
+ fprintf(stderr, "wrong GTP interface %s\n", argv[2]);
+ return EXIT_FAILURE;
+ }
+ gtp_tunnel_set_ifidx(t, gtp_ifidx);
+
+ if (strcmp(argv[3], "v0") == 0) {
+ gtp_tunnel_set_version(t, GTP_V0);
+ gtp_tunnel_set_tid(t, atoi(argv[4]));
+ } else if (strcmp(argv[3], "v1") == 0) {
+ gtp_tunnel_set_version(t, GTP_V1);
+ gtp_tunnel_set_i_tei(t, atoi(argv[4]));
+ } else {
+ fprintf(stderr, "wrong GTP version %s, use v0 or v1\n",
+ argv[3]);
+ return EXIT_FAILURE;
+ }
+
+ /* Returns 0 or errno */
+ ret = gtp_match_tunnel(genl_id, nl, t);
+
+ gtp_tunnel_free(t);
+ return ret;
+}
+
+int main(int argc, char *argv[])
+{
+ struct mnl_socket *nl;
+ int32_t genl_id;
+ int ret;
+
+ if (argc < 2) {
+ printf("%s <add|delete|list|match> [<options,...>]\n", argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ nl = genl_socket_open();
+ if (nl == NULL) {
+ perror("mnl_socket_open");
+ exit(EXIT_FAILURE);
+ }
+
+ genl_id = genl_lookup_family(nl, "gtp");
+ if (genl_id < 0) {
+ printf("not found gtp genl family\n");
+ exit(EXIT_FAILURE);
+ }
+
+ if (strncmp(argv[1], "add", strlen(argv[1])) == 0)
+ ret = add_tunnel(argc, argv, genl_id, nl);
+ else if (strncmp(argv[1], "delete", strlen(argv[1])) == 0)
+ ret = del_tunnel(argc, argv, genl_id, nl);
+ else if (strncmp(argv[1], "list", strlen(argv[1])) == 0)
+ ret = list_tunnel(argc, argv, genl_id, nl);
+ else if (strncmp(argv[1], "match", strlen(argv[1])) == 0)
+ ret = match_tunnel(argc, argv, genl_id, nl);
+ else {
+ printf("Unknown command `%s'\n", argv[1]);
+ exit(EXIT_FAILURE);
+ }
+
+ mnl_socket_close(nl);
+
+ return ret;
+}
new file mode 100755
@@ -0,0 +1,169 @@
+#!/usr/bin/perl
+use Test::More;
+
+BEGIN {
+ $basedir = $0;
+ $basedir =~ s|(.*)/[^/]*|$1|;
+
+ plan tests => 20;
+}
+
+sub add_link {
+ my ( $runcon_args, $args ) = @_;
+ my $pid;
+
+ if ( ( $pid = fork() ) == 0 ) {
+ exec "runcon $runcon_args $basedir/gtp-link $args";
+ }
+
+ # Wait for it to initialize.
+ sleep 1;
+ return $pid;
+}
+
+sub del_link {
+ my ($pid) = @_;
+
+ kill KILL, $pid;
+ waitpid $pid, 0;
+}
+
+############ Basic tests for GTP #############
+print "Test GTP device driver support\n";
+$pid = add_link( "-t test_gtp-1_t", "add gtp-1 2>&1" );
+
+print "Test GTP device driver support\n";
+$result = system
+"runcon -t test_gtp-1_t $basedir/gtp-tunnel add gtp-1 v1 100 200 127.0.0.1 127.0.0.1";
+ok( $result eq 0 );
+
+$result = system
+"runcon -t test_gtp-1_t $basedir/gtp-tunnel add gtp-1 v1 200 300 127.0.0.2 127.0.0.2";
+ok( $result eq 0 );
+
+$result = system
+"runcon -t test_gtp-1_t $basedir/gtp-tunnel add gtp-1 v0 300 127.0.0.3 127.0.0.3";
+ok( $result eq 0 );
+
+$result = system "runcon -t test_gtp-1_t $basedir/gtp-tunnel list";
+ok( $result eq 0 );
+
+$result =
+ system "runcon -t test_gtp-1_t $basedir/gtp-tunnel match gtp-1 v1 200";
+ok( $result eq 0 );
+
+########### Test Deny permissions ####################
+print "Test Deny permissions\n";
+
+# Deny gtp { add } - EACCES
+$result = system
+"runcon -t test_gtp_no_add_pdp_t $basedir/gtp-tunnel add gtp-1 v0 400 127.0.0.4 127.0.0.4 2>&1";
+ok( $result >> 8 eq 13 );
+
+# Deny gtp { del } - EACCES
+$result = system
+"runcon -t test_gtp_no_del_pdp_t $basedir/gtp-tunnel delete gtp-1 v1 100 2>&1";
+ok( $result >> 8 eq 13 );
+
+# Deny gtp { get } (gtp-tunnel list) - EACCES
+# Test returns 0 not EACCES as gtp_list_tunnel() with NLM_F_DUMP does
+# not pass errors back via the gtp-genl.c genl_gtp_attr_cb() callback.
+# The documentation found suggests that it should !!!!
+# The audit log will show the denial:
+# allow test_gtp_no_get_pdp_dump_t test_gtp-1_t:gtp get;
+$result =
+ system "runcon -t test_gtp_no_get_pdp_dump_t $basedir/gtp-tunnel list 2>&1";
+ok(
+ $result >> 8 eq 13,
+"FIXME: Fails gtp_list_tunnel() as no callback error. Audit log should have: allow test_gtp_no_get_pdp_dump_t test_gtp-1_t:gtp get;"
+);
+
+print "Deny gtp { get } (gtp-tunnel match) - EACCES\n";
+$result =
+ system
+"runcon -t test_gtp_no_get_pdp_match_t $basedir/gtp-tunnel match gtp-1 v0 300 2>&1";
+ok( $result >> 8 eq 13 );
+
+# Kill the link.
+$result = system "runcon -t test_gtp-1_t $basedir/gtp-link del gtp-1";
+ok( $result eq 0 );
+del_link($pid);
+
+# Add link to test deny gtp delete link
+$pid = add_link( "-t test_gtp_no_del_link_t", "add gtp-1 2>&1" );
+
+# Test returns 0 not EACCES as kernel void gtp_dellink() does not
+# pass errors back to userspace. The audit log should show
+# allow test_gtp_no_del_link_t self:gtp del;
+$result =
+ system "runcon -t test_gtp_no_del_link_t $basedir/gtp-link del gtp-1 2>&1";
+ok(
+ $result eq 0,
+"PASS: Kernel void gtp_dellink() does not pass errors back. Audit log should have: allow test_gtp_no_del_link_t self:gtp del;"
+);
+
+# Kill the link.
+$result = system "runcon -t test_gtp-1_t $basedir/gtp-link del gtp-1";
+del_link($pid);
+
+# Deny gtp { add } - EACCES
+$result =
+ system "runcon -t test_gtp_no_add_link_t $basedir/gtp-link add gtp-2 2>&1";
+ok( $result >> 8 eq 13 );
+
+#
+print
+"Create three GTP devices with different security contexts in same namespace\n";
+#
+$port1 = "3386";
+$port2 = "2152";
+
+$pid1 = add_link( "-t test_gtp-1_t", "add gtp-1 $port1 $port2 2>&1" );
+
+$result = system
+"runcon -t test_gtp-1_t $basedir/gtp-tunnel add gtp-1 v1 200 100 172.99.0.1 172.0.0.1";
+ok( $result eq 0 );
+
+$port1++;
+$port2++;
+$pid2 = add_link( "-t test_gtp-2_t", "add gtp-2 $port1 $port2 2>&1" );
+$result = system
+"runcon -t test_gtp-2_t $basedir/gtp-tunnel add gtp-2 v1 200 100 172.99.0.2 172.0.0.2";
+ok( $result eq 0 );
+
+$result = system
+"runcon -t test_gtp-2_t $basedir/gtp-tunnel list gtp-2 v1 200 100 172.99.0.2 172.0.0.2";
+ok( $result eq 0 );
+
+$result =
+ system "runcon -t test_gtp-2_t $basedir/gtp-tunnel match gtp-1 v1 200 2>&1";
+ok( $result >> 8 eq 13 );
+
+$port1++;
+$port2++;
+$pid3 = add_link( "-t test_gtp-3_t", "add gtp-3 $port1 $port2 2>&1" );
+
+# Use test_gtp-2_t to kill link 1.
+$result = system "runcon -t test_gtp-2_t $basedir/gtp-link del gtp-1";
+ok(
+ $result eq 0,
+"PASS: Kernel void gtp_dellink() does not pass errors back. Audit log should have: allow test_gtp-2_t test_gtp-1_t:gtp del;"
+);
+del_link($pid1);
+
+# Kill link 1.
+$result = system "runcon -t test_gtp-1_t $basedir/gtp-link del gtp-1";
+ok( $result eq 0 );
+del_link($pid1);
+
+# Kill link 2.
+$result = system "runcon -t test_gtp-2_t $basedir/gtp-link del gtp-2";
+ok( $result eq 0 );
+del_link($pid2);
+
+# Kill link 3.
+$result = system "runcon -t test_gtp-3_t $basedir/gtp-link del gtp-3";
+ok( $result eq 0 );
+del_link($pid3);
+
+exit;
Add tests to support the GTP driver. Read the selinux-testsuite/tests/gtp/GTP-README for setup details. Notes: 1) The kernel does not pass back errors on delete link. Need to check audit log for deny gtp { del }. 2) The kernel or the libgtpnl library does not pass back errors on gtp { get }. Seems to be bug or as designed !!. Check audit log for deny. Signed-off-by: Richard Haines <richard_c_haines@btinternet.com> --- defconfig | 4 + policy/Makefile | 5 + policy/test_gtp.cil | 18 + policy/test_gtp.te | 96 +++++ tests/Makefile | 4 + tests/gtp/.gitignore | 2 + tests/gtp/GTP-README | 123 ++++++ tests/gtp/Makefile | 8 + ...tpnl-for-SELinux-testsuite-GTP-tests.patch | 366 ++++++++++++++++++ tests/gtp/gtp-link.c | 134 +++++++ tests/gtp/gtp-tunnel.c | 263 +++++++++++++ tests/gtp/test | 169 ++++++++ 12 files changed, 1192 insertions(+) create mode 100644 policy/test_gtp.cil create mode 100644 policy/test_gtp.te create mode 100644 tests/gtp/.gitignore create mode 100644 tests/gtp/GTP-README create mode 100644 tests/gtp/Makefile create mode 100644 tests/gtp/Update-libgtpnl-for-SELinux-testsuite-GTP-tests.patch create mode 100644 tests/gtp/gtp-link.c create mode 100644 tests/gtp/gtp-tunnel.c create mode 100755 tests/gtp/test