147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner/*
247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner * Callbacks for user-supplied memory allocation, supplemental
347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner * auditing, and locking routines.
447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner *
547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner * Author : Eamon Walsh <ewalsh@epoch.ncsc.mil>
647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner *
747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner * Netlink code derived in part from sample code by
847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner * James Morris <jmorris@redhat.com>.
947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner */
1047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
1147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner#include <errno.h>
1247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner#include <stdio.h>
1347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner#include <stdlib.h>
1447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner#include <stdint.h>
1547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner#include <unistd.h>
1647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner#include <fcntl.h>
1747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner#include <string.h>
1847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner#include <poll.h>
1947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner#include <sys/types.h>
2047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner#include <sys/socket.h>
2147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner#include <linux/types.h>
2247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner#include <linux/netlink.h>
2347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner#include "callbacks.h"
2447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner#include "selinux_netlink.h"
2547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner#include "avc_internal.h"
2647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
2747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner#ifndef NETLINK_SELINUX
2847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner#define NETLINK_SELINUX 7
2947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner#endif
3047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
3147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner/* callback pointers */
3247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnervoid *(*avc_func_malloc) (size_t) = NULL;
3347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnervoid (*avc_func_free) (void *) = NULL;
3447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
3547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnervoid (*avc_func_log) (const char *, ...) = NULL;
3647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnervoid (*avc_func_audit) (void *, security_class_t, char *, size_t) = NULL;
3747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
3847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnerint avc_using_threads = 0;
3947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnerint avc_app_main_loop = 0;
4047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnervoid *(*avc_func_create_thread) (void (*)(void)) = NULL;
4147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnervoid (*avc_func_stop_thread) (void *) = NULL;
4247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
4347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnervoid *(*avc_func_alloc_lock) (void) = NULL;
4447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnervoid (*avc_func_get_lock) (void *) = NULL;
4547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnervoid (*avc_func_release_lock) (void *) = NULL;
4647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnervoid (*avc_func_free_lock) (void *) = NULL;
4747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
4847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner/* message prefix string and avc enforcing mode */
4947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnerchar avc_prefix[AVC_PREFIX_SIZE] = "uavc";
5047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnerint avc_running = 0;
5147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnerint avc_enforcing = 1;
5247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnerint avc_setenforce = 0;
5347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnerint avc_netlink_trouble = 0;
5447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
5547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner/* netlink socket code */
5647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnerstatic int fd = -1;
5747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
5847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnerint avc_netlink_open(int blocking)
5947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner{
6047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	int len, rc = 0;
6147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	struct sockaddr_nl addr;
6247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
6347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_SELINUX);
6447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	if (fd < 0) {
6547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		rc = fd;
6647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		goto out;
6747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	}
6847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
6947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	fcntl(fd, F_SETFD, FD_CLOEXEC);
7047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	if (!blocking && fcntl(fd, F_SETFL, O_NONBLOCK)) {
7147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		close(fd);
7247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		fd = -1;
7347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		rc = -1;
7447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		goto out;
7547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	}
7647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
7747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	len = sizeof(addr);
7847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
7947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	memset(&addr, 0, len);
8047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	addr.nl_family = AF_NETLINK;
8147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	addr.nl_groups = SELNL_GRP_AVC;
8247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
8347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	if (bind(fd, (struct sockaddr *)&addr, len) < 0) {
8447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		close(fd);
8547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		fd = -1;
8647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		rc = -1;
8747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		goto out;
8847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	}
8947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner      out:
9047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	return rc;
9147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner}
9247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
9347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnervoid avc_netlink_close(void)
9447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner{
9547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	if (fd >= 0)
9647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		close(fd);
9747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	fd = -1;
9847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner}
9947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
10047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnerstatic int avc_netlink_receive(char *buf, unsigned buflen, int blocking)
10147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner{
10247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	int rc;
10347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	struct pollfd pfd = { fd, POLLIN | POLLPRI, 0 };
10447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	struct sockaddr_nl nladdr;
10547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	socklen_t nladdrlen = sizeof nladdr;
10647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	struct nlmsghdr *nlh = (struct nlmsghdr *)buf;
10747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
10847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	do {
10947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		rc = poll(&pfd, 1, (blocking ? -1 : 0));
11047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	} while (rc < 0 && errno == EINTR);
11147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
11247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	if (rc == 0 && !blocking) {
11347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		errno = EWOULDBLOCK;
11447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		return -1;
11547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	}
11647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	else if (rc < 1) {
11747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		avc_log(SELINUX_ERROR, "%s:  netlink poll: error %d\n",
11847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			avc_prefix, errno);
11947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		return rc;
12047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	}
12147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
12247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	rc = recvfrom(fd, buf, buflen, 0, (struct sockaddr *)&nladdr,
12347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		      &nladdrlen);
12447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	if (rc < 0)
12547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		return rc;
12647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
12747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	if (nladdrlen != sizeof nladdr) {
12847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		avc_log(SELINUX_WARNING,
12947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			"%s:  warning: netlink address truncated, len %d?\n",
13047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			avc_prefix, nladdrlen);
13147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		return -1;
13247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	}
13347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
13447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	if (nladdr.nl_pid) {
13547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		avc_log(SELINUX_WARNING,
13647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			"%s:  warning: received spoofed netlink packet from: %d\n",
13747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			avc_prefix, nladdr.nl_pid);
13847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		return -1;
13947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	}
14047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
14147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	if (rc == 0) {
14247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		avc_log(SELINUX_WARNING,
14347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			"%s:  warning: received EOF on netlink socket\n",
14447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			avc_prefix);
14547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		errno = EBADFD;
14647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		return -1;
14747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	}
14847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
14947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	if (nlh->nlmsg_flags & MSG_TRUNC || nlh->nlmsg_len > (unsigned)rc) {
15047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		avc_log(SELINUX_WARNING,
15147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			"%s:  warning: incomplete netlink message\n",
15247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			avc_prefix);
15347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		return -1;
15447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	}
15547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
15647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	return 0;
15747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner}
15847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
15947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnerstatic int avc_netlink_process(char *buf)
16047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner{
16147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	int rc;
16247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	struct nlmsghdr *nlh = (struct nlmsghdr *)buf;
16347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
16447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	switch (nlh->nlmsg_type) {
16547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	case NLMSG_ERROR:{
16647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		struct nlmsgerr *err = NLMSG_DATA(nlh);
16747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
16847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		/* Netlink ack */
16947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		if (err->error == 0)
17047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			break;
17147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
17247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		errno = -err->error;
17347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		avc_log(SELINUX_ERROR,
17447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			"%s:  netlink error: %d\n", avc_prefix, errno);
17547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		return -1;
17647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	}
17747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
17847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	case SELNL_MSG_SETENFORCE:{
17947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		struct selnl_msg_setenforce *msg = NLMSG_DATA(nlh);
18047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		avc_log(SELINUX_INFO,
18147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			"%s:  received setenforce notice (enforcing=%d)\n",
18247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			avc_prefix, msg->val);
18347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		if (avc_setenforce)
18447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			break;
18547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		avc_enforcing = msg->val;
18647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		if (avc_enforcing && (rc = avc_ss_reset(0)) < 0) {
18747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			avc_log(SELINUX_ERROR,
18847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				"%s:  cache reset returned %d (errno %d)\n",
18947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				avc_prefix, rc, errno);
19047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			return rc;
19147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		}
19247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		rc = selinux_netlink_setenforce(msg->val);
19347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		if (rc < 0)
19447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			return rc;
19547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		break;
19647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	}
19747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
19847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	case SELNL_MSG_POLICYLOAD:{
19947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		struct selnl_msg_policyload *msg = NLMSG_DATA(nlh);
20047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		avc_log(SELINUX_INFO,
20147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			"%s:  received policyload notice (seqno=%d)\n",
20247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			avc_prefix, msg->seqno);
20347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		rc = avc_ss_reset(msg->seqno);
20447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		if (rc < 0) {
20547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			avc_log(SELINUX_ERROR,
20647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				"%s:  cache reset returned %d (errno %d)\n",
20747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				avc_prefix, rc, errno);
20847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			return rc;
20947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		}
21047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		rc = selinux_netlink_policyload(msg->seqno);
21147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		if (rc < 0)
21247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			return rc;
21347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		break;
21447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	}
21547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
21647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	default:
21747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		avc_log(SELINUX_WARNING,
21847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			"%s:  warning: unknown netlink message %d\n",
21947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			avc_prefix, nlh->nlmsg_type);
22047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	}
22147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	return 0;
22247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner}
22347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
22447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnerint avc_netlink_check_nb(void)
22547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner{
22647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	int rc;
22747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	char buf[1024] __attribute__ ((aligned));
22847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
22947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	while (1) {
23047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		errno = 0;
23147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		rc = avc_netlink_receive(buf, sizeof(buf), 0);
23247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		if (rc < 0) {
23347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			if (errno == EWOULDBLOCK)
23447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				return 0;
23547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			if (errno == 0 || errno == EINTR)
23647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				continue;
23747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			else {
23847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				avc_log(SELINUX_ERROR,
23947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner					"%s:  netlink recvfrom: error %d\n",
24047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner					avc_prefix, errno);
24147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				return rc;
24247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			}
24347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		}
24447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
24547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		(void)avc_netlink_process(buf);
24647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	}
24747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	return 0;
24847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner}
24947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
25047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner/* run routine for the netlink listening thread */
25147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnervoid avc_netlink_loop(void)
25247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner{
25347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	int rc;
25447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	char buf[1024] __attribute__ ((aligned));
25547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
25647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	while (1) {
25747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		errno = 0;
25847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		rc = avc_netlink_receive(buf, sizeof(buf), 1);
25947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		if (rc < 0) {
26047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			if (errno == 0 || errno == EINTR)
26147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				continue;
26247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			else {
26347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				avc_log(SELINUX_ERROR,
26447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner					"%s:  netlink recvfrom: error %d\n",
26547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner					avc_prefix, errno);
26647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner				break;
26747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			}
26847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		}
26947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
27047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		rc = avc_netlink_process(buf);
27147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		if (rc < 0)
27247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner			break;
27347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	}
27447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
27547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	close(fd);
27647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	fd = -1;
27747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	avc_netlink_trouble = 1;
27847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner	avc_log(SELINUX_ERROR,
27947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		"%s:  netlink thread: errors encountered, terminating\n",
28047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner		avc_prefix);
28147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner}
28247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
28347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnerint avc_netlink_acquire_fd(void)
28447173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner{
28547173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner    avc_app_main_loop = 1;
28647173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
28747173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner    return fd;
28847173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner}
28947173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner
29047173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turnervoid avc_netlink_release_fd(void)
29147173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner{
29247173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner    avc_app_main_loop = 0;
29347173c7d6704f1258b2d85537caa09185f6920c8David 'Digit' Turner}
294