129d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts/* 229d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts * Copyright 2012, Samsung Telecommunications of America 329d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts * Copyright (C) 2014 The Android Open Source Project 429d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts * 529d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts * Licensed under the Apache License, Version 2.0 (the "License"); 629d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts * you may not use this file except in compliance with the License. 729d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts * You may obtain a copy of the License at 829d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts * 929d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts * http://www.apache.org/licenses/LICENSE-2.0 1029d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts * 1129d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts * Unless required by applicable law or agreed to in writing, software 1229d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts * distributed under the License is distributed on an "AS IS" BASIS, 1329d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1429d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts * See the License for the specific language governing permissions and 1529d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts * limitations under the License. 1629d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts * 1729d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts * Written by William Roberts <w.roberts@sta.samsung.com> 1829d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts * 1929d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts */ 2029d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts 2129d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts#include <errno.h> 2229d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts#include <string.h> 2329d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts#include <unistd.h> 2429d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts 2529d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts#define LOG_TAG "libaudit" 2629d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts#include <log/log.h> 2729d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts 2829d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts#include "libaudit.h" 2929d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts 3029d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts/** 3129d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts * Waits for an ack from the kernel 3229d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts * @param fd 3329d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts * The netlink socket fd 3429d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts * @param seq 3529d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts * The current sequence number were acking on 3629d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts * @return 3729d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts * This function returns 0 on success, else -errno. 3829d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts */ 3929d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Robertsstatic int get_ack(int fd, int16_t seq) 4029d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts{ 4129d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts int rc; 4229d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts struct audit_message rep; 4329d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts 4429d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts /* Sanity check, this is an internal interface this shouldn't happen */ 4529d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts if (fd < 0) { 4629d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts return -EINVAL; 4729d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts } 4829d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts 4929d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts rc = audit_get_reply(fd, &rep, GET_REPLY_BLOCKING, MSG_PEEK); 5029d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts if (rc < 0) { 5129d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts return rc; 5229d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts } 5329d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts 5429d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts if (rep.nlh.nlmsg_type == NLMSG_ERROR) { 5529d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts audit_get_reply(fd, &rep, GET_REPLY_BLOCKING, 0); 5629d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts rc = ((struct nlmsgerr *)rep.data)->error; 5729d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts if (rc) { 5829d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts return -rc; 5929d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts } 6029d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts } 6129d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts 6229d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts if ((int16_t)rep.nlh.nlmsg_seq != seq) { 6329d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts SLOGW("Expected sequence number between user space and kernel space is out of skew, " 6429d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts "expected %u got %u", seq, rep.nlh.nlmsg_seq); 6529d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts } 6629d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts 6729d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts return 0; 6829d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts} 6929d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts 7029d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts/** 7129d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts * 7229d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts * @param fd 7329d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts * The netlink socket fd 7429d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts * @param type 7529d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts * The type of netlink message 7629d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts * @param data 7729d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts * The data to send 7829d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts * @param size 7929d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts * The length of the data in bytes 8029d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts * @return 8129d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts * This function returns a positive sequence number on success, else -errno. 8229d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts */ 8329d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Robertsstatic int audit_send(int fd, int type, const void *data, size_t size) 8429d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts{ 8529d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts int rc; 8629d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts static int16_t sequence = 0; 8729d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts struct audit_message req; 8829d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts struct sockaddr_nl addr; 8929d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts 9029d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts memset(&req, 0, sizeof(req)); 9129d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts memset(&addr, 0, sizeof(addr)); 9229d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts 9329d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts /* We always send netlink messaged */ 9429d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts addr.nl_family = AF_NETLINK; 9529d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts 9629d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts /* Set up the netlink headers */ 9729d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts req.nlh.nlmsg_type = type; 9829d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts req.nlh.nlmsg_len = NLMSG_SPACE(size); 9929d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts req.nlh.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; 10029d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts 10129d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts /* 10229d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts * Check for a valid fd, even though sendto would catch this, its easier 10329d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts * to always blindly increment the sequence number 10429d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts */ 10529d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts if (fd < 0) { 10629d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts return -EBADF; 10729d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts } 10829d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts 10929d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts /* Ensure the message is not too big */ 11029d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts if (NLMSG_SPACE(size) > MAX_AUDIT_MESSAGE_LENGTH) { 11129d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts SLOGE("netlink message is too large"); 11229d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts return -EINVAL; 11329d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts } 11429d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts 11529d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts /* Only memcpy in the data if it was specified */ 11629d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts if (size && data) { 11729d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts memcpy(NLMSG_DATA(&req.nlh), data, size); 11829d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts } 11929d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts 12029d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts /* 12129d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts * Only increment the sequence number on a guarantee 12229d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts * you will send it to the kernel. 12329d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts * 12429d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts * Also, the sequence is defined as a u32 in the kernel 12529d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts * struct. Using an int here might not work on 32/64 bit splits. A 12629d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts * signed 64 bit value can overflow a u32..but a u32 12729d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts * might not fit in the response, so we need to use s32. 12829d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts * Which is still kind of hackish since int could be 16 bits 12929d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts * in size. The only safe type to use here is a signed 16 13029d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts * bit value. 13129d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts */ 13229d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts req.nlh.nlmsg_seq = ++sequence; 13329d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts 13429d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts /* While failing and its due to interrupts */ 13529d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts 13629d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts rc = TEMP_FAILURE_RETRY(sendto(fd, &req, req.nlh.nlmsg_len, 0, 13729d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts (struct sockaddr*) &addr, sizeof(addr))); 13829d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts 13929d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts /* Not all the bytes were sent */ 14029d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts if (rc < 0) { 14129d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts rc = -errno; 14229d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts SLOGE("Error sending data over the netlink socket: %s", strerror(-errno)); 14329d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts goto out; 14429d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts } else if ((uint32_t) rc != req.nlh.nlmsg_len) { 14529d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts rc = -EPROTO; 14629d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts goto out; 14729d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts } 14829d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts 14929d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts /* We sent all the bytes, get the ack */ 15029d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts rc = get_ack(fd, sequence); 15129d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts 15229d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts /* If the ack failed, return the error, else return the sequence number */ 15329d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts rc = (rc == 0) ? (int) sequence : rc; 15429d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts 15529d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Robertsout: 15629d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts /* Don't let sequence roll to negative */ 15729d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts if (sequence < 0) { 15829d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts SLOGW("Auditd to Kernel sequence number has rolled over"); 15929d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts sequence = 0; 16029d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts } 16129d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts 16229d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts return rc; 16329d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts} 16429d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts 165c234a1b879d9c9d8e1a797c5dcf3098249945748Nick Kralevichint audit_setup(int fd, uint32_t pid) 16629d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts{ 16729d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts int rc; 16829d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts struct audit_message rep; 16929d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts struct audit_status status; 17029d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts 17129d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts memset(&status, 0, sizeof(status)); 17229d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts 17329d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts /* 17429d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts * In order to set the auditd PID we send an audit message over the netlink 17529d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts * socket with the pid field of the status struct set to our current pid, 17629d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts * and the the mask set to AUDIT_STATUS_PID 17729d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts */ 17829d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts status.pid = pid; 179c234a1b879d9c9d8e1a797c5dcf3098249945748Nick Kralevich status.mask = AUDIT_STATUS_PID | AUDIT_STATUS_RATE_LIMIT; 1809667a66019388fb09430d3f8896ccc531eb24ef5Nick Kralevich status.rate_limit = 20; // audit entries per second 18129d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts 18229d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts /* Let the kernel know this pid will be registering for audit events */ 18329d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts rc = audit_send(fd, AUDIT_SET, &status, sizeof(status)); 18429d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts if (rc < 0) { 18529d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts SLOGE("Could net set pid for audit events, error: %s", strerror(-rc)); 18629d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts return rc; 18729d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts } 18829d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts 18929d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts /* 19029d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts * In a request where we need to wait for a response, wait for the message 19129d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts * and discard it. This message confirms and sync's us with the kernel. 192c234a1b879d9c9d8e1a797c5dcf3098249945748Nick Kralevich * This daemon is now registered as the audit logger. 193c234a1b879d9c9d8e1a797c5dcf3098249945748Nick Kralevich * 194c234a1b879d9c9d8e1a797c5dcf3098249945748Nick Kralevich * TODO 195c234a1b879d9c9d8e1a797c5dcf3098249945748Nick Kralevich * If the daemon dies and restarts the message didn't come back, 196c234a1b879d9c9d8e1a797c5dcf3098249945748Nick Kralevich * so I went to non-blocking and it seemed to fix the bug. 197c234a1b879d9c9d8e1a797c5dcf3098249945748Nick Kralevich * Need to investigate further. 19829d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts */ 199c234a1b879d9c9d8e1a797c5dcf3098249945748Nick Kralevich audit_get_reply(fd, &rep, GET_REPLY_NONBLOCKING, 0); 20029d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts 20129d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts return 0; 20229d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts} 20329d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts 20429d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Robertsint audit_open() 20529d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts{ 206c234a1b879d9c9d8e1a797c5dcf3098249945748Nick Kralevich return socket(PF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_AUDIT); 20729d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts} 20829d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts 20929d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Robertsint audit_get_reply(int fd, struct audit_message *rep, reply_t block, int peek) 21029d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts{ 21129d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts ssize_t len; 21229d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts int flags; 21329d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts int rc = 0; 21429d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts 21529d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts struct sockaddr_nl nladdr; 21629d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts socklen_t nladdrlen = sizeof(nladdr); 21729d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts 21829d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts if (fd < 0) { 21929d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts return -EBADF; 22029d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts } 22129d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts 22229d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts /* Set up the flags for recv from */ 22329d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts flags = (block == GET_REPLY_NONBLOCKING) ? MSG_DONTWAIT : 0; 22429d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts flags |= peek; 22529d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts 22629d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts /* 22729d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts * Get the data from the netlink socket but on error we need to be carefull, 22829d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts * the interface shows that EINTR can never be returned, other errors, 22929d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts * however, can be returned. 23029d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts */ 23129d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts len = TEMP_FAILURE_RETRY(recvfrom(fd, rep, sizeof(*rep), flags, 23229d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts (struct sockaddr*) &nladdr, &nladdrlen)); 23329d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts 23429d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts /* 23529d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts * EAGAIN should be re-tried until success or another error manifests. 23629d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts */ 23729d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts if (len < 0) { 23829d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts rc = -errno; 23929d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts if (block == GET_REPLY_NONBLOCKING && rc == -EAGAIN) { 24029d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts /* If request is non blocking and errno is EAGAIN, just return 0 */ 24129d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts return 0; 24229d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts } 24329d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts SLOGE("Error receiving from netlink socket, error: %s", strerror(-rc)); 24429d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts return rc; 24529d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts } 24629d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts 24729d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts if (nladdrlen != sizeof(nladdr)) { 24829d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts SLOGE("Protocol fault, error: %s", strerror(EPROTO)); 24929d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts return -EPROTO; 25029d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts } 25129d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts 25229d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts /* Make sure the netlink message was not spoof'd */ 25329d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts if (nladdr.nl_pid) { 25429d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts SLOGE("Invalid netlink pid received, expected 0 got: %d", nladdr.nl_pid); 25529d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts return -EINVAL; 25629d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts } 25729d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts 25829d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts /* Check if the reply from the kernel was ok */ 25929d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts if (!NLMSG_OK(&rep->nlh, (size_t)len)) { 26029d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts rc = (len == sizeof(*rep)) ? -EFBIG : -EBADE; 26129d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts SLOGE("Bad kernel response %s", strerror(-rc)); 26229d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts } 26329d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts 26429d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts return rc; 26529d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts} 26629d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts 26729d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Robertsvoid audit_close(int fd) 26829d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts{ 26929d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts int rc = close(fd); 27029d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts if (rc < 0) { 27129d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts SLOGE("Attempting to close invalid fd %d, error: %s", fd, strerror(errno)); 27229d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts } 27329d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts return; 27429d238d2a8e12c131a4cfbccb912e525cca6b10dWilliam Roberts} 275