Re: SELinux system configuration using CIPSO

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Tue, 2016-11-15 at 09:28 -0800, Casey Schaufler wrote:
> I am looking for an SELinux configuration that uses CIPSO.
> Ideally, it would be based on a readily available distro,
> but I'm willing to perform semi-heroic acts if I have too.
> I'm not in a position to develop it myself, nor would that
> really suit my nefarious purposes. Thank you.
> 
I put this together out of idle curiosity using the targeted policy as
no policy updates are required only netlabelctl commands. If you need
something else like policy config let me know and I'll see what I can
do.



> _______________________________________________
> Selinux mailing list
> Selinux@xxxxxxxxxxxxx
> To unsubscribe, send email to Selinux-leave@xxxxxxxxxxxxx.
> To get help, send an email containing "help" to Selinux-request@tycho
> .nsa.gov.
This is a simple CIPSO demo showing that separation across the network is
possible where there are two services on machine A and two clients on
machine B where client B1 can talk to service A1 but not A2 and
client B2 can talk to service A2 but not A1.

The demo shown requires:
1) Two systems with the NETLABEL kernel config and the "targeted" SELinux
   policy. Used Fedora 24 for demo as this does not require any additional
   configuration.

2) netlabel_tools and tcpdump installed on each system.

3) Machine "A" requires a server app installed and Machine "B" a client
   app. I've added the code below that can be copied and built/installed on
   each machine. Note that the binaries must be labeled bin_t so these were
   installed in /usr/local/bin.

4) The demo network used: 

           ----------  Ethernet         193.168.1.65 ----------
           | A1, A2 | <----------------------------> | B1, B2 |
           ---------- 193.168.1.78                   ----------


Basically the demo configures the network for CIPSO using netlabelctl(8) and
then runs the client / server apps using runcon(1) with different levels.
Because the targeted policy is being used there is only the single
s0 sensitivity with 1024 categories, however I think it does show the basics.

Demo 1 - Just prove the system works
-------------------------------------

On Machine A run a server from a terminal session:
server 9999

On Machine B run a client from a terminal session:
client 193.168.1.78 9999

There should be output from each app with an example client:

client 193.168.1.78 9999
open socket - Peer Context: system_u:object_r:unlabeled_t:s0
connect - No Peer Context Available
recv - No Peer Context Available

Information from Server in RED:
This is Message-1 from the server listening on port: 9999
Client source port: 40152
Server Context: unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
Server Peer Context: No Peer Context Available

Client Information in GREEN:
Client Context: unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
Client Peer Context: No Peer Context Available


#### Now exit the server session. ####

Demo 2 - Add cipso config
--------------------------

On Machine A run the following to set up cipso:
netlabelctl cipsov4 add pass doi:15 tags:5
netlabelctl map add domain:unconfined_t address:0.0.0.0/0 protocol:unlbl
netlabelctl map add domain:unconfined_t address:193.168.1.65 protocol:cipsov4,15
netlabelctl -p map list

On Machine B run:
netlabelctl cipsov4 add pass doi:15 tags:5
netlabelctl map add domain:unconfined_t address:0.0.0.0/0 protocol:unlbl
netlabelctl map add domain:unconfined_t address:193.168.1.78 protocol:cipsov4,15
netlabelctl -p map list

The output from the "netlabelctl -p map list" command should be like:
netlabelctl -p map list
Configured NetLabel domain mappings (2)
 domain: "unconfined_t"
   address: 193.168.1.78/32
    protocol: CIPSOv4, DOI = 15
   address: 0.0.0.0/0
    protocol: UNLABELED
 domain: DEFAULT
   protocol: UNLABELED


If okay then run the sessions shown in Demo 3 using "tcpdump -x -i <interface>"
to monitor the sessions. There is an example client tcpdump session showing the
relevant info after the demos.

Demo 3 - Check cipso network separation.
-----------------------------------------

On Machine A run two servers from separate terminal sessions:
A1
runcon -l s0:c10,c40.c50 server 9999
A2
runcon -l s0:c20,c100.c200 server 1111

On Machine B run two clients from separate terminal sessions:
B1 -> A1
runcon -l s0:c10,c40.c45 client 193.168.1.78 9999
B2 -> A2
runcon -l s0:c20,c100.c200 client 193.168.1.78 1111

There should be valid output from each session, for example:

runcon -l s0:c10,c40.c45 client 193.168.1.78 9999
open socket - Peer Context: system_u:object_r:unlabeled_t:s0
connect - Peer Context: system_u:object_r:netlabel_peer_t:s0:c10,c40.c45
recv - Peer Context: system_u:object_r:netlabel_peer_t:s0:c10,c40.c45

Information from Server in RED:
This is Message-1 from the server listening on port: 9999
Client source port: 40250
Server Context: unconfined_u:unconfined_r:unconfined_t:s0:c10,c40.c50
Server Peer Context: system_u:object_r:netlabel_peer_t:s0:c10,c40.c45

Client Information in GREEN:
Client Context: unconfined_u:unconfined_r:unconfined_t:s0:c10,c40.c45
Client Peer Context: system_u:object_r:netlabel_peer_t:s0:c10,c40.c45

Note that because the client requested cats "c10,c40.c45" that is its
process and the client/server netlabel context.

Now try connecting client "B2" client to server "A1" (B2 -> A1):

runcon -l s0:c20,c100.c200 client 193.168.1.78 9999
open socket - Peer Context: system_u:object_r:unlabeled_t:s0
Client connect: No route to host

As can be seen the connection failed. The relevant tcpdump CIPSO info from
client B2 in the trace is (see
https://tools.ietf.org/html/draft-ietf-cipso-ipsecurity-01 for details):

x0010:  xxxx xxxx 8612 0000 000f 050c 0000 00c8 0064 0014 0014 0000 9cec 270f e7d8 92ff
That expands as follows:
86 = Option 134, 12 = Len, 0000 000f = DOI 15, 05 = Tag type, 0c = Tag Len, 00 = Aligment,
00 = Sensitivity s0, 00c8 0064 0014 0014 0000 = category info 200 100 20 20 

tcpdump -x -i enp9s0
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on enp9s0, link-type EN10MB (Ethernet), capture size 262144 bytes
12:42:55.302882 IP localhost.localdomain.40172 > 193.168.1.78.distinct: Flags [S], seq 3889730303, win 29200, options [mss 1460,sackOK,TS val 11171752 ecr 0,nop,wscale 7], length 0
	0x0000:  4a00 0050 e557 4000 4006 3def c1a8 0141
	0x0010:  c1a8 014e 8612 0000 000f 050c 0000 00c8
	0x0020:  0064 0014 0014 0000 9cec 270f e7d8 92ff
	0x0030:  0000 0000 a002 7210 860e 0000 0204 05b4
	0x0040:  0402 080a 00aa 77a8 0000 0000 0103 0307
12:42:55.303463 IP 193.168.1.78 > localhost.localdomain: ICMP host 193.168.1.78 unreachable - admin prohibited, length 88
	0x0000:  45c0 006c 39eb 0000 4001 ba06 c1a8 014e
	0x0010:  c1a8 0141 030a 8304 0000 0000 4a00 0050
	0x0020:  e557 4000 4006 3def c1a8 0141 c1a8 014e
	0x0030:  8612 0000 000f 050c 0000 00c8 0064 0014
	0x0040:  0014 0000 9cec 270f e7d8 92ff 0000 0000
	0x0050:  a002 7210 98e9 0000 0204 05b4 0402 080a
	0x0060:  00aa 77a8 0000 0000 0103 0307
12:43:00.307311 ARP, Request who-has localhost.localdomain tell 193.168.1.78, length 46
	0x0000:  0001 0800 0604 0001 74e6 e22b 7789 c1a8
	0x0010:  014e 0000 0000 0000 c1a8 0141 0000 0000
	0x0020:  0000 0000 0000 0000 0000 0000 0000
12:43:00.307340 ARP, Reply localhost.localdomain is-at f0:4d:a2:b5:bc:1d (oui Unknown), length 28
	0x0000:  0001 0800 0604 0002 f04d a2b5 bc1d c1a8
	0x0010:  0141 74e6 e22b 7789 c1a8 014e



Now you can use "runcon -l" to start sessions using different categories to
see the effect. However if you try something like:

runcon -l s0:c20,c100.c500 server 1111
runcon -l s0:c20,c100.c500 client 193.168.1.78 1111

The sessions will not talk. I guess it is something to do with the range (need
to ask an expert !!!).

#
############################ CLIENT CODE #####################################
#
/* gcc -o client -lselinux client.c
 * install -m 0755 client /usr/local/bin/client
 */

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <selinux/selinux.h>

#define MAXBUFFERSIZE 256
#define ENFORCING 1

#define RED	"\x1b[31m"
#define GREEN	"\x1b[32m"
#define RESET	"\x1b[0m"

int main(int argc, char *argv[])
{
	int sock_fd, bytes_received;
	char buffer[MAXBUFFERSIZE];
	struct hostent *server_info;
	struct sockaddr_in server_addr;
	short client_port;
	char *context, *peer_context, *peer_context_str;

	if (argc != 3) {
		fprintf(stderr, "usage: %s <address> <port>\n", argv[0]);
		exit(1);
	}

	client_port = atoi(argv[2]);

	server_info = gethostbyname(argv[1]);
	if (!server_info) {
		herror("Client gethostbyname");
		exit(1);
	}

	if (security_getenforce() != ENFORCING)
		printf("Should be in enforcing mode for valid testing\n");

	sock_fd = socket(PF_INET, SOCK_STREAM, 0);
	if (sock_fd == -1) {
		perror("Client Socket");
		exit(1);
	}

	if (getpeercon(sock_fd, &peer_context) < 0) {
		printf("open socket - No Peer Context Available\n");
	} else {
		printf("open socket - Peer Context: %s\n", peer_context);
		freecon(peer_context);
	}

	bzero((char *) &server_addr, sizeof(server_addr));
	server_addr.sin_family = AF_INET;
	server_addr.sin_port = htons(client_port);
	server_addr.sin_addr = *((struct in_addr *)server_info->h_addr);

	if (connect(sock_fd, (struct sockaddr *)&server_addr,
		     sizeof(struct sockaddr)) == -1) {
		perror("Client connect");
		exit(1);
	}

	if (getpeercon(sock_fd, &peer_context) < 0) {
		printf("connect - No Peer Context Available\n");
	} else {
		printf("connect - Peer Context: %s\n", peer_context);
		freecon(peer_context);
	}

	memset(buffer, 0, sizeof(buffer));
	bytes_received = recv(sock_fd, buffer, MAXBUFFERSIZE-1, 0);
	if (bytes_received == -1) {
		perror("Client recv");
		exit(1);
	}

	if (getpeercon(sock_fd, &peer_context) < 0) {
		printf("recv - No Peer Context Available\n");
	} else {
		printf("recv - Peer Context: %s\n", peer_context);
		freecon(peer_context);
	}

	buffer[bytes_received] = '\0'; /* Add null at end of line. */
	printf("\n%sInformation from Server in RED:\n%s%s\n",
		RED, buffer, RESET);

	/* Print the Clients context information */
	if (getcon(&context) < 0) {
		perror("Client context");
		exit(1);
	}

	if (getpeercon(sock_fd, &peer_context) < 0) {
		peer_context_str = strdup("No Peer Context Available");
	} else {
		peer_context_str = strdup(peer_context);
		freecon(peer_context);
	}
	printf("%sClient Information in GREEN:\n", GREEN);
	printf("Client Context: %s\nClient Peer Context: %s%s\n",
		context, peer_context_str, RESET);
	freecon(context);
	close(sock_fd);
	exit(0);
}


#
############################ SERVER CODE ####################################
#

/* gcc -o server -lselinux server.c
 * install -m 0755 server /usr/local/bin/server
 */

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/param.h>
#include <dirent.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <selinux/selinux.h>

#define MAXBUFFERSIZE 256

int main(int argc, char *argv[])
{
	short server_port;
	int sock_fd, new_sock_fd, message_id = 1;
	struct sockaddr_in server_addr;
	struct sockaddr_in client_addr;
	socklen_t sin_size;
	char buffer[MAXBUFFERSIZE];
	char *context, *peer_context;
	char *peer_context_str = NULL;

	if (argc < 2) {
		fprintf(stderr, "Usage: %s <port>\n", argv[0]);
		exit(1);
	}

	server_port = atoi(argv[1]);
	if (server_port == 0) {
		fprintf(stderr, "Usage: %s <port>\n", argv[0]);
		exit(1);
	}

	/* Add port info to send buffer and also display */
	sprintf(buffer, "Listening on port %d", server_port);
	printf("%s\n", buffer);

	sock_fd = socket(PF_INET, SOCK_STREAM, 0);
	if (sock_fd == -1) {
		perror("Server socket");
		exit(1);
	}

	if (getpeercon(sock_fd, &peer_context) < 0) {
		printf("open socket - No Peer Context Available\n");
	} else {
		printf("open socket - Peer Context: %s\n", peer_context);
		free(peer_context);
	}

	bzero((char *) &server_addr, sizeof(server_addr));
	server_addr.sin_family = AF_INET;
	server_addr.sin_port = htons(server_port);
	server_addr.sin_addr.s_addr = INADDR_ANY;

	if (bind(sock_fd, (struct sockaddr *)&server_addr,
			    sizeof(struct sockaddr)) == -1) {
		perror("Server bind");
		exit(1);
	}

	if (getpeercon(sock_fd, &peer_context) < 0) {
		printf("bind - No Peer Context Available\n");
	} else {
		printf("bind - Peer Context: %s\n", peer_context);
		free(peer_context);
	}

	if (listen(sock_fd, 5) == -1) {
		perror("Server listen");
		exit(1);
	}

	if (getpeercon(sock_fd, &peer_context) < 0) {
		printf("listen - No Peer Context Available\n");
	} else {
		printf("listen - Peer Context: %s\n", peer_context);
		free(peer_context);
	}

	while (1) {
		sin_size = sizeof(struct sockaddr_in);

		new_sock_fd = accept(sock_fd, (struct sockaddr *)&client_addr,
				     &sin_size);
		if (new_sock_fd == -1) {
			perror("Server accept");
			continue;
		}

		/* Get context assigned to the new socket */
		if (fgetfilecon_raw(new_sock_fd, &context) == -1) {
			perror("fgetfilecon_raw - FAILED");
			exit(1);
		}
		printf("accept on new socket - context assigned to new ");
		printf("socket is (using  fgetfilecon):\n\t%s\n", context);
		free(context);

		/* Then check if peer context is assigned to this new socket */
		if (getpeercon(new_sock_fd, &peer_context) < 0) {
			printf("accept new socket - No Peer Context Available\n");
		} else {
			printf("accept new socket - Peer Context: %s\n",
				peer_context);
			free(peer_context);
		}

		/* Get Server context information */
		if (getcon(&context) < 0) {
			perror("Server context");
			exit(1);
		}

		if (getpeercon(new_sock_fd, &peer_context) < 0) {
			peer_context_str = strdup("No Peer Context Available");
		} else {
			peer_context_str = strdup(peer_context);
			free(peer_context);
		}
		/* Clear the buffer of rubbish */
		memset(buffer, 0, sizeof(buffer));

		/* Print Server network information */
		printf("Server has connection from client: host = %s "
			"destination port = %d source port = %d\n",
			inet_ntoa(client_addr.sin_addr),
			ntohs(server_addr.sin_port),
			ntohs(client_addr.sin_port));

		printf("Server Context: %s\nServer Peer Context: %s\n",
			context, peer_context_str);

		/* Now send the buffer. */
		sprintf(buffer, "This is Message-%d from the server listening "
			"on port: %d\nClient source port: %d\n"
			"Server Context: %s\nServer Peer Context: %s\n",
			message_id, ntohs(server_addr.sin_port),
			ntohs(client_addr.sin_port),
			context, peer_context_str);

		if (send(new_sock_fd, buffer, strlen(buffer), 0) == -1)
			perror("Server send");

		message_id++;
		free(context);
		free(peer_context_str);
		close(new_sock_fd);
	}
	return 0;
}
_______________________________________________
Selinux mailing list
Selinux@xxxxxxxxxxxxx
To unsubscribe, send email to Selinux-leave@xxxxxxxxxxxxx.
To get help, send an email containing "help" to Selinux-request@xxxxxxxxxxxxx.

[Index of Archives]     [Selinux Refpolicy]     [Linux SGX]     [Fedora Users]     [Fedora Desktop]     [Yosemite Photos]     [Yosemite Camping]     [Yosemite Campsites]     [KDE Users]     [Gnome Users]

  Powered by Linux