Home | History | Annotate | Download | only in src
      1 /*
      2  * Callbacks for user-supplied memory allocation, supplemental
      3  * auditing, and locking routines.
      4  *
      5  * Author : Eamon Walsh <ewalsh (at) epoch.ncsc.mil>
      6  *
      7  * Netlink code derived in part from sample code by
      8  * James Morris <jmorris (at) redhat.com>.
      9  */
     10 
     11 #include <errno.h>
     12 #include <stdio.h>
     13 #include <stdlib.h>
     14 #include <stdint.h>
     15 #include <unistd.h>
     16 #include <fcntl.h>
     17 #include <string.h>
     18 #include <poll.h>
     19 #include <sys/types.h>
     20 #include <sys/socket.h>
     21 #include <linux/types.h>
     22 #include <linux/netlink.h>
     23 #include "callbacks.h"
     24 #include "selinux_netlink.h"
     25 #include "avc_internal.h"
     26 
     27 #ifndef NETLINK_SELINUX
     28 #define NETLINK_SELINUX 7
     29 #endif
     30 
     31 /* callback pointers */
     32 void *(*avc_func_malloc) (size_t) = NULL;
     33 void (*avc_func_free) (void *) = NULL;
     34 
     35 void (*avc_func_log) (const char *, ...) = NULL;
     36 void (*avc_func_audit) (void *, security_class_t, char *, size_t) = NULL;
     37 
     38 int avc_using_threads = 0;
     39 int avc_app_main_loop = 0;
     40 void *(*avc_func_create_thread) (void (*)(void)) = NULL;
     41 void (*avc_func_stop_thread) (void *) = NULL;
     42 
     43 void *(*avc_func_alloc_lock) (void) = NULL;
     44 void (*avc_func_get_lock) (void *) = NULL;
     45 void (*avc_func_release_lock) (void *) = NULL;
     46 void (*avc_func_free_lock) (void *) = NULL;
     47 
     48 /* message prefix string and avc enforcing mode */
     49 char avc_prefix[AVC_PREFIX_SIZE] = "uavc";
     50 int avc_running = 0;
     51 int avc_enforcing = 1;
     52 int avc_setenforce = 0;
     53 int avc_netlink_trouble = 0;
     54 
     55 /* netlink socket code */
     56 static int fd = -1;
     57 
     58 int avc_netlink_open(int blocking)
     59 {
     60 	int len, rc = 0;
     61 	struct sockaddr_nl addr;
     62 
     63 	fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_SELINUX);
     64 	if (fd < 0) {
     65 		rc = fd;
     66 		goto out;
     67 	}
     68 
     69 	fcntl(fd, F_SETFD, FD_CLOEXEC);
     70 	if (!blocking && fcntl(fd, F_SETFL, O_NONBLOCK)) {
     71 		close(fd);
     72 		fd = -1;
     73 		rc = -1;
     74 		goto out;
     75 	}
     76 
     77 	len = sizeof(addr);
     78 
     79 	memset(&addr, 0, len);
     80 	addr.nl_family = AF_NETLINK;
     81 	addr.nl_groups = SELNL_GRP_AVC;
     82 
     83 	if (bind(fd, (struct sockaddr *)&addr, len) < 0) {
     84 		close(fd);
     85 		fd = -1;
     86 		rc = -1;
     87 		goto out;
     88 	}
     89       out:
     90 	return rc;
     91 }
     92 
     93 void avc_netlink_close(void)
     94 {
     95 	if (fd >= 0)
     96 		close(fd);
     97 	fd = -1;
     98 }
     99 
    100 static int avc_netlink_receive(char *buf, unsigned buflen, int blocking)
    101 {
    102 	int rc;
    103 	struct pollfd pfd = { fd, POLLIN | POLLPRI, 0 };
    104 	struct sockaddr_nl nladdr;
    105 	socklen_t nladdrlen = sizeof nladdr;
    106 	struct nlmsghdr *nlh = (struct nlmsghdr *)buf;
    107 
    108 	do {
    109 		rc = poll(&pfd, 1, (blocking ? -1 : 0));
    110 	} while (rc < 0 && errno == EINTR);
    111 
    112 	if (rc == 0 && !blocking) {
    113 		errno = EWOULDBLOCK;
    114 		return -1;
    115 	}
    116 	else if (rc < 1) {
    117 		avc_log(SELINUX_ERROR, "%s:  netlink poll: error %d\n",
    118 			avc_prefix, errno);
    119 		return rc;
    120 	}
    121 
    122 	rc = recvfrom(fd, buf, buflen, 0, (struct sockaddr *)&nladdr,
    123 		      &nladdrlen);
    124 	if (rc < 0)
    125 		return rc;
    126 
    127 	if (nladdrlen != sizeof nladdr) {
    128 		avc_log(SELINUX_WARNING,
    129 			"%s:  warning: netlink address truncated, len %d?\n",
    130 			avc_prefix, nladdrlen);
    131 		return -1;
    132 	}
    133 
    134 	if (nladdr.nl_pid) {
    135 		avc_log(SELINUX_WARNING,
    136 			"%s:  warning: received spoofed netlink packet from: %d\n",
    137 			avc_prefix, nladdr.nl_pid);
    138 		return -1;
    139 	}
    140 
    141 	if (rc == 0) {
    142 		avc_log(SELINUX_WARNING,
    143 			"%s:  warning: received EOF on netlink socket\n",
    144 			avc_prefix);
    145 		errno = EBADFD;
    146 		return -1;
    147 	}
    148 
    149 	if (nlh->nlmsg_flags & MSG_TRUNC || nlh->nlmsg_len > (unsigned)rc) {
    150 		avc_log(SELINUX_WARNING,
    151 			"%s:  warning: incomplete netlink message\n",
    152 			avc_prefix);
    153 		return -1;
    154 	}
    155 
    156 	return 0;
    157 }
    158 
    159 static int avc_netlink_process(char *buf)
    160 {
    161 	int rc;
    162 	struct nlmsghdr *nlh = (struct nlmsghdr *)buf;
    163 
    164 	switch (nlh->nlmsg_type) {
    165 	case NLMSG_ERROR:{
    166 		struct nlmsgerr *err = NLMSG_DATA(nlh);
    167 
    168 		/* Netlink ack */
    169 		if (err->error == 0)
    170 			break;
    171 
    172 		errno = -err->error;
    173 		avc_log(SELINUX_ERROR,
    174 			"%s:  netlink error: %d\n", avc_prefix, errno);
    175 		return -1;
    176 	}
    177 
    178 	case SELNL_MSG_SETENFORCE:{
    179 		struct selnl_msg_setenforce *msg = NLMSG_DATA(nlh);
    180 		avc_log(SELINUX_INFO,
    181 			"%s:  received setenforce notice (enforcing=%d)\n",
    182 			avc_prefix, msg->val);
    183 		if (avc_setenforce)
    184 			break;
    185 		avc_enforcing = msg->val;
    186 		if (avc_enforcing && (rc = avc_ss_reset(0)) < 0) {
    187 			avc_log(SELINUX_ERROR,
    188 				"%s:  cache reset returned %d (errno %d)\n",
    189 				avc_prefix, rc, errno);
    190 			return rc;
    191 		}
    192 		rc = selinux_netlink_setenforce(msg->val);
    193 		if (rc < 0)
    194 			return rc;
    195 		break;
    196 	}
    197 
    198 	case SELNL_MSG_POLICYLOAD:{
    199 		struct selnl_msg_policyload *msg = NLMSG_DATA(nlh);
    200 		avc_log(SELINUX_INFO,
    201 			"%s:  received policyload notice (seqno=%d)\n",
    202 			avc_prefix, msg->seqno);
    203 		rc = avc_ss_reset(msg->seqno);
    204 		if (rc < 0) {
    205 			avc_log(SELINUX_ERROR,
    206 				"%s:  cache reset returned %d (errno %d)\n",
    207 				avc_prefix, rc, errno);
    208 			return rc;
    209 		}
    210 		rc = selinux_netlink_policyload(msg->seqno);
    211 		if (rc < 0)
    212 			return rc;
    213 		break;
    214 	}
    215 
    216 	default:
    217 		avc_log(SELINUX_WARNING,
    218 			"%s:  warning: unknown netlink message %d\n",
    219 			avc_prefix, nlh->nlmsg_type);
    220 	}
    221 	return 0;
    222 }
    223 
    224 int avc_netlink_check_nb(void)
    225 {
    226 	int rc;
    227 	char buf[1024] __attribute__ ((aligned));
    228 
    229 	while (1) {
    230 		errno = 0;
    231 		rc = avc_netlink_receive(buf, sizeof(buf), 0);
    232 		if (rc < 0) {
    233 			if (errno == EWOULDBLOCK)
    234 				return 0;
    235 			if (errno == 0 || errno == EINTR)
    236 				continue;
    237 			else {
    238 				avc_log(SELINUX_ERROR,
    239 					"%s:  netlink recvfrom: error %d\n",
    240 					avc_prefix, errno);
    241 				return rc;
    242 			}
    243 		}
    244 
    245 		(void)avc_netlink_process(buf);
    246 	}
    247 	return 0;
    248 }
    249 
    250 /* run routine for the netlink listening thread */
    251 void avc_netlink_loop(void)
    252 {
    253 	int rc;
    254 	char buf[1024] __attribute__ ((aligned));
    255 
    256 	while (1) {
    257 		errno = 0;
    258 		rc = avc_netlink_receive(buf, sizeof(buf), 1);
    259 		if (rc < 0) {
    260 			if (errno == 0 || errno == EINTR)
    261 				continue;
    262 			else {
    263 				avc_log(SELINUX_ERROR,
    264 					"%s:  netlink recvfrom: error %d\n",
    265 					avc_prefix, errno);
    266 				break;
    267 			}
    268 		}
    269 
    270 		rc = avc_netlink_process(buf);
    271 		if (rc < 0)
    272 			break;
    273 	}
    274 
    275 	close(fd);
    276 	fd = -1;
    277 	avc_netlink_trouble = 1;
    278 	avc_log(SELINUX_ERROR,
    279 		"%s:  netlink thread: errors encountered, terminating\n",
    280 		avc_prefix);
    281 }
    282 
    283 int avc_netlink_acquire_fd(void)
    284 {
    285     avc_app_main_loop = 1;
    286 
    287     return fd;
    288 }
    289 
    290 void avc_netlink_release_fd(void)
    291 {
    292     avc_app_main_loop = 0;
    293 }
    294