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