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